# 关于The Impact of Thread-Per-Core Architecture on
Application Tail Latency读后总结

这个[paper](https://penberg.org/papers/tpc-ancs19.pdf)主要是讲了`Thread-Per-Core`架构对应用层的长尾延迟的影响；根据最后的总结是在配置合理的情况下会有一个比较好的效果的；`Thread-Per-Core`这个系统架构一开始我接触的时候出现在[Scylladb](https://www.scylladb.com/),它还有对应的一个framework叫做seastar，是一个C++的框架，用来支持这种模型的；

### 1 这个架构的好处

随着单core的整个摩尔瓶颈的到来，目前现代的硬件设备都是用多core来提升性能的，但是平时我们使用的multicore的编程方式随着线程的变多会导致整体的内核切换的消耗就变得突出的，而且多核编程会涉及到thread-safe的问题，就会加入很多所谓的同步的机制，也从一定程度上导致core对性能提升比较缓慢；paper从几个方面进行了分析：

1. CPU affinity: 中文叫做亲和性，linux内核的调度算法不保证一个线程前一个时刻在A cpu执行，下一个时刻可能跑到了CPU B上运行，这个会带来的问题其实还挺多的。主要在于cache的实效从而带来的性能的损耗，这个损耗还是很明确的；
    
2. Thread synchronization: 本质上是因为存在相互都要访问的公共资源，为了保证thread-safe,就必须进行同步机制的；但是这个会带来所谓的损耗；尤其是lock机制的加入会将本身是并行的操作在某一个环节变成串行的，公共资源越多，本质上core的增加未必能提升所谓的性能，可能还有反向作用；redis的整个架构就是单线程+异步的方式，基于的理论估计是减少竞争和内存操作本身就很快；
    
3. OS interfaces: 一方面提到了Linux的async机制做的一般，不过iouring加入之后估计可以提升不少；其他的主要是说的是用户态和内核态的context切换的消耗和内存copy用户态的内存的消耗等；目前iouring我感觉应该是解决了一大部分的问题吧；
    

关于这个架构，paper author提出了三个架构：

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1730020683640/59e54974-52f1-4a67-af0f-4ddbdd41a0f6.png align="center")

a. shared-everything

b. shared-nothing

c. shared-something

分别说一下各自的确定；a这种的话解决了cpu的亲和性的问题，但是解决不了thread-synchronization的问题；而b这种架构的问题在于1. 负载均衡的问题 2. core与core之间有状态了，请求与请求之间就有了状态； 一个请求访问了A cpu，下次连接断掉之后可能会访问B，但是B的内存没有它的数据，这就产生了问题；所以才会有c，大部分不分享，一些信息进行分享的；

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1730021076598/d784c429-6366-48ed-9773-c7df90ccae7d.png align="center")

c架构+NUMA的架构，尽可能将控制在同一个a NUMA domain；

paper还提到了关于NIC和软中断的问题；通常情况下网络package过来通过softirq来进行通知application，而当package很多的时候会通过thread主动的loop来获得package的；paper提出专门指定cpu去负责网络package，并且获得package也是对应的业务thread的数据，通过这种方式让业务cpu能全力做事情，而不会被各种软中断打断处理网络请求；

### 2 最终的测试

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1730021510260/55f5935d-418f-4903-a8f0-f2e7312f27de.png align="center")

几个变量：

1. 硬件的不同，一个是现代的高级硬件，一个是传统的硬件
    
2. IRQ的亲和性是否绑定
    
3. 是否关闭IRQ的balance
    
4. memcache和sphinxd
    

结果：

1. 从read 延迟来看，几种模式其实都差不多的，在相同的硬件上sphinxd会稍微好一些的；C中可以看到，当IRQ亲和性开启+关闭balance的话，并且随着连接数变多的时候效果会好不少，C中的第一张图；
    
2. 从update latency来看，整体的提升了67%或者47%的效果；
    

从结果来说是有效果的，看样子能减少50%的长尾延迟。

### 3 后面的研究

1. 请求的路由；其实这个架构有点类似于基于core的分布式架构，每个core只做自己想管的工作，那么关于请求的路由就很重要的；目前用的是message-pass，如果请求错误量很大的话，就会导致整体的请求转移消耗就变大的；
    
2. 负载均衡，结合上一个问题，需要客户端去感知当前的core建立的连接是错误的连接，需要切换一些的，但是需要client的配合
    
3. os interfaces： 这个方面的思考就是kernel-bypass，但是这其实很麻烦的，需要application思考更多的东西，现在有一个叫做Demikernel在重新设计os接口，可以让应用层可以无感知，高度抽象的是用户spdk、dbdk等等类似的工具；
    
4. 将负载卸载到硬件上去，比如用fpga来做一部分的计算什么的，但是这样就变复杂的了；
    
5. 应用层的创新；
