Redis备忘(二)

 内存回收: redis

       有时候发现10g的Redis删掉1g的key,内存占用没啥变化,由于内存页分配,有的页面可能还存在key,整个页面不能回收。算法

 

 主从同步:数据库

     CAP原理:一致性 可用性 分区容忍性数组

     redis主从是异步同步数据的,因此并不知足一致性要求(redis是最终一致性),主节点修改后,当即返回,即便主从断开,主节点依然正常服务,因此知足可用性。缓存

     增量同步:主节点将指令记录在ringbuffer中,从节点执行同步,并向主节点反馈同步到的偏移量,网络环境很差时,buffer中的指令会覆盖,这时候须要快照同步。安全

     快照同步:主库bgsave将内存数据快照到磁盘,再传送到从节点,从加载后通知主节点继续进行增量同步。若是快照时间太长,增量同步的buffer仍是会被覆盖,网络

        只能再次快照同步,有可能会快照同步死循环。 因此请务必配置合适的buffer大小。多线程

        单个Redis的内存不宜过大,内存太大会致使 rdb 文件过大,主从全量同步延迟太长app

    Redis无盘复制:dom

         主节点快照同步时,IO太大了,2.8之后能够快照同步时一边遍历内存,一边经过套接字将数据发送到从节点。

 

 集群方案:

   1.Sentinel:

            主从方案中无法自动切换主从。由此引入Sentinel集群

            Sentinel监控主从,若是主挂了自动选择一个最优的从做为主,其余从会和新的主创建主从关系

            客户端首先链接sentinel,经过其找到主节点地址

            主从切换后客户端会重连新的主,怎么实现:处理修改性命令的时候捕获了一个异常 ReadOnlyError,捕获到后将全部旧链接关闭,重连

 

   2.Codis:

           Codis无状态,能够部署多个节点。只是简单将key转发给服务端,将结果返回客户端。

           原理:将全部key划分红1024个slot,将客户端传过来的key作crc32后对1024取模决定存到哪一个slot,slot对应到后面的多个Redis机器之一。 

                     Codis内部维护了Slot和背后机器的映射关系。不一样Codis实例之间用etcd或zk同步槽位映射关系

                     经过Dashboard 能够修改槽位信息,当修改后,Codis会监听到变化并从新同步槽位关系

                     执行mget命令时,Codis会将key分散到多个机器查询,而后返回归并结果。

           集群扩容:若是查询一个正在迁移的key,Codis会强制该key当即迁移,而后去新机器上查询(因此value别太大)

  3.Redis Cluster:

         客户端向一个错误的节点发出了指令(即key所在槽位不归本身管理),该节点会让客户端重定向到另外一个节点,客户端更新本身的槽位映射表

  4.  Redis Stream:

        和Kafka相比,内部没有partition, 若是想要分区,须要建立多个stream,手动分区

  5.监控:info, monitor , 能够经过监控异步同步数据失败次数,据此修改buffer大小

  6.分布式锁:

         主节点上申请了锁,可是忽然主从切换了,锁还没来得及同步, 可使用Redlock

         须要提供多个 Redis 实例,这些实例以前相互独立没有主从关系,加锁时,它会向过半节点发送setnx,过半set成功则加锁成功;

         还须要考虑出错重试、时钟漂移等不少细节问题,会形成性能降低。

  7.过时策略:

        同一时间太多的 key 过时,以致于忙不过来?线上指令出现卡顿?

        除了定时遍历(集中处理)以外,它还会使用惰性策略(零散处理)来删除过时的key

        1s 10次过时扫描,不会扫描整个过时字典,而是贪心策略:

               1.从过时字典中随机 20 个 key,删除过时的

               2.过时的 key 比率超过 1/4,重复步骤1

        若是大批的key同时过时仍是可能线上请求形成卡顿,因此最好给过时时间设置一个随机范围。

 

  8. LRU:

       Redis支持maxmemory配置, 超过最大内存后能够有如下几种 maxmemory-policy: 

       1. noeviction不可写库

       2. volatile-lru:尝试淘汰设置了过时时间的key,优先淘汰最少使用的

       3. volatile-ttl:跟上面同样,不过剩余ttl小的先淘汰

       4. allkeys-lru:淘汰的是全体key,即没过时也会淘汰

       5. allkeys-random

       6. volatile-random

        Redis为实现近似 LRU 算法,它给每一个key增长了最后一次被访问的时间戳。执行写操做时,发现内存超过maxmemory,执行一次LRU淘汰算法:

      随机采样出5个key,淘汰掉最旧的,若是仍是超过maxmemory就继续随机采样淘汰。

 

   9. 删除优化:

       del删除的key包含元素过多,也会形成单线程卡顿,4.0引入了unlink 指令,对删除操做懒处理,丢给后台线程异步回收内存

  

   10. 数据安全:rename-command flushall ""

   11. 渐进式Rehash: dict结构内部包含两个hashtable,一般状况下只有一个hashtable是有值的; 大字典的扩容比较耗时间,Redis单线程很难承受

         迁移数据操做埋伏在当前字典的后续指令中(新的元素挂接到新的数组下面),还会在定时任务中对字典进行主动搬迁。

 

  12. 不要对Redis进行绑核,毕竟还有RDB,AOF这些异步操做

       建议设置swappiness

 

 

  13. 缓存使用的问题:

      缓存穿透:

         1. 返回空:缺点,须要更多内存,若是是攻击问题更严重,能够设置过时时间

         2. 布隆过滤器

         3. 高可用+降级

         4. 提早演练

     缓存无底洞:FaceBook添加更多memcached节点发现性能更差,由于如mget可能须要访问n多个节点(hash到不一样节点)

     更多的节点不表明更高的性能。

     解决:客户端记住能够在哪一个节点(其实hash一下就行),对每一个节点的key打包好请求,而后多线程从各个节点mget或pipline

  14.优化:

      1. tcp-backlog

      2. swappiness

 

 

 

   京东订单的Redis实践:

     1. 先更新数据库,再更新缓存

     2. 数据一致性保证:循环5次直到成功,解决网络抖动形成失败的几率

                                     还不成功则启动线程扫描库,与缓存比较,更新缓存/或发送一条消息到mq,去更新

   网易的Redis技术分享:

      遍历时间事件链表中找到即将触发的时间,根据这个值去select里阻塞

相关文章
相关标签/搜索