Redis以高性能而被广泛使用,所以我们必须重视可能会影响redis性能的阻塞点。
我们从redis交互的对象的角度出发,思考哪些对象的哪些操作将会给redis性能带来风险。
交互对象有客户端,涉及网络io,键值对操作.磁盘,涉及持久化.主从节点,涉及RDB传输.集群交互,涉及slot的迁移
网络IO时快时慢,但是redis的IO多路复用机制,所以主线程并不会阻塞等待请求,键值对的操作的快慢,慢的键值对操作必然影响到redis的性能,怎么评判快慢,就看复杂度是否是O(N)。通常是集合的遍历或者聚合操作,例如HGETALL或者SMEMBERS等。所以尽量避免此类 操作.此外,删除操作通常是我们忽视的一个点,虽然redis是惰性删除,主线程将删除操作封装成一个任务放入队列后返回客户端完成操作,以子线程完成del操作,但是由于操作系统的内存机制,会在空出的内存空间放入一个空闲的内存块链表,用于方便后续管理,假如我们释放的内存空间很大,这就成为一个阻塞点,所以我们要避免bigkey的删除,建议使用UNLINK命令,另外在redis cluster数据迁移的时候,bigkey也会造成阻塞,因为rediscluster是同步迁移,同时要注意的是,主从复制的时候,从库接收主库的RDB,需要FLUSHDB清库从而加载RDB,建议通过FLUSHDB ASYNC异步清库,虽然现在都是初次RDB加载接下来通过AOF增量复制,但是RDB加载这个过程的快慢,取决于RDB的大小,也是不可忽视的一个阻塞点
redis是单线程,所以我们从cpu的角度思考看看。首先说一下逻辑核和物理核的概念,主流cpu的一个物理核会有两个超线程,即是逻辑核,逻辑核共用L1 L2 L3缓存,物理核共用L3缓存。还有一种多CPU架构,就是有多个cpu,称为cpu socket1 cpu socket2等等,他们各有自己的3级缓存和内存,并不共享,他们之间的访问属于远端内存访问。那么他们对cpu有什么影响呢?我接过一个接口,很大的接口,一次访问,得起二三十个线程并发访问下游,况且我用的语言是java,线程模型是1:1,不比go这种N:M的线程模型来得好用,这种场景下,context switch的消耗是一大痛点,因为在cpu核上运行时,线程得保存栈指针,寄存器值等,同时一些频繁的指令和数据会被缓存到L1 L2缓存上,对于当前的主流cpu,都是多核超线程的,发生context switch的场景是频繁的,每调度一次,一些请求就会受到影响从而延迟明显高于其他请求,我们可以让redis实例固定运行在一个cpu物理核心上,注意是物理核心,因为redis主线程启动后,操作系统的pthread_creat会创建3个子线程,用于AOF日志写,键值对删除及文件关闭的异步,如果是逻辑核的话,子线程会和主线程竞争cpu了,taskset -c 0,1 ./redis-server 这条命令可以完成这个效果,-c 0 是指定cpu核的编号,如果我们工作中有redis的尾延迟的要求达不到的话,可以尝试这个操作,另外因为我们在删除key的时候,会造成内存碎片,我们要通过active-defrag-cycle-min 和active-defrag-cycle-min两个参数控制自动清理时cpu的占用率,尤其是max的阈值设置,避免内存清理的时候,内存拷贝的量比较大的时候阻塞redis