📫作者简介:小明java问道之路,2022年度博客之星全国TOP3,专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化,文章内容兼具广度、深度、大厂技术方案,对待技术喜欢推理加验证,就职于知名金融公司后端高级工程师。
📫 热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长。
🏆 2022博客之星TOP3 | CSDN博客专家 | 后端领域优质创作者 | CSDN内容合伙人
🏆 InfoQ(极客邦)签约作者、阿里云专家 | 签约博主、51CTO专家 | TOP红人、华为云享专家
🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~
🍅 文末获取联系 🍅 👇🏻 精彩专栏推荐订阅收藏 👇🏻
专栏系列(点击解锁)
学习路线(点击解锁)
知识定位
全面讲解MySQL知识与企业级MySQL实战 🔥计算机底层原理🔥
本文目录
本文导读
本文讨论了CPU架构对Redis性能的影响,首先了解了,存储器层次结构和CPU的层次结构,以及当前主流CPU物理核与逻辑核架构(NUMA结构)、CPU运行架构,然后分析CPU多核对Redis性能的影响以及CPU的NUMA架构对Redis性能的影响。
一、存储器层次结构(CSAPP第6章)
存储器系统(memory system)是存储设备的层次结构,没有容量、成本和访问时间。如果程序所需的数据在寄存器中,则指令可以立即使用该数据;
如果数据存储在缓存中,则获取4~75个时钟周期的数据;当数据存储在存储器中时,需要数百个时钟周期;如果数据存储在磁盘中,则需要数千万个时钟周期。可以看出,程序倾向于使用接近或等于最近使用的指令/数据的地址的指令或数据。
二、CPU的层次结构
1、CPU物理核与逻辑核架构
CPU通常有多个核(运行物理内核),每个内核都可以运行程序。CPU的每个物理核都有一个1级缓存(Level1cache,L1cache,称为L1缓存),包括1级指令缓存、1级数据缓存和专用2级缓存(Level2cache,L2 cache,称为L2缓存)。物理内核的私有缓存意味着缓存空间只能由当前物理内核使用,其他物理内核无法访问内核的缓存空间。因为L1和L2缓存是每个物理核私有的,所以,当数据或指令保存在L1、L2缓存时,物理核访问它们的延迟不超过10纳秒,速度非常快。如果Redis把要运行的指令或存取的数据保存在L1和L2缓存的话,就能高速地访问这些指令和数据。如图,CPU物理核的架构。
这些L1和L2高速缓存的大小受到处理器制造技术的限制,通常仅在KB级别,不能存储太多数据。因此,不同的物理内核也将共享一个公共的3级缓存(Level3cache,L3cache,简称L3cache)。三级缓存可以使用大量存储资源,因此它通常很大,可以达到几MB到几十MB,这允许应用程序缓存更多数据。当L1和L2缓存中没有数据缓存时,可以访问L3以尽可能避免访问内存。在当前主流CPU处理器中,每个物理内核通常运行两个超线程,也称为逻辑内核,同一物理内核的逻辑内核将共享L1和L2缓存。
2、CPU运行架构
在主流服务器上,一个CPU处理器有10到20个物理内核。同时,为了提高服务器的处理能力,服务器上通常有多个CPU处理器(也称为多个CPU插槽Socket)。每个处理器都有自己的物理内核(包括L1和L2缓存)、L3缓存和连接的内存。同时,不同的处理器通过总线连接。
三、CPU多核对Redis性能的影响
当在CPU内核上运行时,应用程序需要记录自己的软件和硬件资源信息(如堆栈指针、CPU内核的寄存器值等),此信息为运行时信息。同时,应用程序访问最频繁的指令和数据也将缓存在L1和L2组存储中,以提高执行速度。
然而,在多核CPU场景中,一旦应用程序需要在新的CPU内核上运行,则需要将运行时信息重新加载到新的CPU核心。此外,新CPU核心的L1和L2缓存还需要重新加载数据和指令,这将增加程序的运行时间。所以要避免Redis总是在不同CPU核上来回调度执行。于是,可以把Redis实例和CPU核绑定。
当context switch(线程上下文切换,在CPU多核环境中,一个线程首先在一个CPU核上运行,然后切换到另一个CPU内核,然后发生上下文切换)发生时,需要将Redis主线程的运行时信息重新加载到另一CPU核,此时,L1和L2缓存在另一CPU内核上,Redis实例在运行之前没有经常访问的指令和数据技术,因此这些指令和数据需要从L3缓存甚至从内存中重新加载。
重新加载过程需要一些时间,此外,Redis实例需要等待重新加载过程完成,然后才能开始处理请求。因此,这也会导致某些请求的处理时间增加。如果在CPU多核场景中,Redis实例经常被安排在不同的CPU核上运行,那么对Redis实例的请求处理时间的影响将更大。每次调度请求时,一些请求都会受到重新加载运行时信息、指令和数据的过程的影响,这会导致一些请求的延迟明显高于其他请求。
四、CPU的NUMA架构对Redis性能的影响
为了提高Redis的网络性能,将操作系统的网络中断处理程序绑定到CPU内核,可以避免网络中断处理程序在不同内核上来回调度和执行,并可以有效提高Redis的网络处理性能。
但是,网络中断程序需要与Redis实例交互以获取网络数据。一旦网络中断程序绑定到内核,我们需要注意Redis实例绑定到哪个内核,这将影响Redis访问网络数据的效率。
在CPU的NUMA架构下(在多核CPU架构下,程序访问Socket本地和远端的延迟不一致,称为非统一内存访问架构,Non-Unifrom Memory Access,NUMA),当网络中断处理器(网络中断处理器从网卡读取数据并将数据写入操作系统内核维护的内存缓冲区。内核将通过epoll机制触发事件,并将数据从内核内存缓冲区复制到自己的内存空间)时。Redis实例分别和CPU核绑定后,就会有一个潜在的风险,如果网络中断处理程序和Redis实例各自所绑的CPU核不在同一个CPUSocket上,那么,Redis实例读取网络数据时,就需要跨CPU Socket访问内存,这个过程会花费较多时间。
在CPU的NUMA架构下,CPU内核的编号规则不是先对一个CPU Socket中的所有逻辑内核进行编码,然后再对下一个CPU Socket中的逻辑内核进行编号,而是先对每个CPU Socket中每个物理内核的第一个逻辑内核进行排序,然后对每个CPU Socket中每个物理核心的第二个逻辑内核编号。
总结
本文讨论了CPU架构对Redis性能的影响,首先了解了,存储器层次结构和CPU的层次结构,以及当前主流CPU物理核与逻辑核架构(NUMA结构)、CPU运行架构,然后分析CPU多核对Redis性能的影响以及CPU的NUMA架构对Redis性能的影响。
在多核CPU架构中,如果Redis在不同的内核上运行,则需要频繁的上下文切换。这个过程会增加Redis的执行时间,客户端也会观察到高尾部延迟。因此,建议您在Redis运行时将实例绑定到内核,这样可以重用内核上的L1和L2缓存,并减少响应延迟。
为了提高Redis的网络性能,网络中断处理程序也将绑定到CPU内核。在这种情况下,如果服务器使用NUMA架构,一旦Redis实例被分派到与中断处理程序不同的CPU Socke,它将通过CPU Socke访问网络数据,这将降低Redis的性能。因此,我建议您将Redis实例和网络中断处理程序绑定到同一CPU Socke下的不同内核,这样可以提高Redis的运行性能。