redis使用的经验

版权所有,禁止匿名转载;禁止商业使用。

去年下半年,在公司和同事一起做了并上线一个基于redis的的分布式cache系统,来统一替换公司历史上使用的各种各样的缓存系统。redis提供了高并发能力和丰富的数据结构供业务使用。系统中使用redis不做持久化,只当作cache使用,是经典的DB+cache结构,cache miss会由db加载,redis掉电后cache数据就丢失了,分布式算法采用一致性hash,节点的信息放在zookeeper上。

系统的整体结构类似于twitter开源的tmemproxy,不过没有中间的proxy层,客户端直连redis,逻辑主要实现在客户端,优点是直连redis可以提高效率,缺点是逻辑分散在各个客户端而不是中间的proxy层,难于统一更改。

目前redis在公司内部的使用规模是:50+台96G内存机器,200+ redis server实例,2T左右的总数据量。
对redis的使用会遇到很多各种各样的问题,业界很多其他公司都做过一个分享,这里结合自己在公司内部的使用经验,做一些总结。

一.代码
redis的代码量并不大,刚开始接触redis的时候,总代码量一共2w多行(现在已经到4w多行了),结构也比较清晰,过一遍代码实现还是比较容易的。

二.内存
redis需要将全部数据放在内存才能提供高性能的server表现,redis自身的vm内存管理用处不大,新版中已经去掉。因此,需要仔细注意redis的内存使用情况。
redis并没有使用特别的内存管理机制,只是简单包装了一下malloc,因此可能会有比较多的内存碎片。不过redis可以编入jemalloc或tcmalloc等优秀的开源内存管理库来管理内存。
要注意的是配置文件中的maxmemory 21000000000限制的并不是redis进程本身占用的内存,而是数据占用的内存,由于内存碎片的存在,redis进程本身占用的内存可能要大于这个值。
当内存占满之后,可以配置逐出机制,不过redis的lru机制和memcache并不相同,redis是随机采样一批key,在这批采样的key中进行lru。
另外,redis删除过期的key采用的是惰性删除,过期的key并不是过期后实时删除,而是在过期后的下次访问会被删除。每隔100ms,从eventloop醒来,还会随机采样一批key,删除采样到过期的key。如果采用出的key中过期的太多,高于一定比例,就会循环随机采样,删除采样采样到过期的key。
在bgsave或者bgrewriteaof会让redis fork一个子进程出来,这时占用内存会翻一倍。

三.单线程的redis
redis主要工作都是在一个线程内完成的。作者对此的解释是网卡内存才是瓶颈,而cpu并不是瓶颈。但实际使用中,还是会发现redis在某些情况下会阻塞住。例如如果pipeline地使用hgetall,就会观察到redis会慢。redis提供了slowslog的功能可以查看哪些命令执行的时间比较长。不过slowlog只能观察到单条命令的执行时间。一次eventloop可能会执行很多条命令(例如在大量使用pipeline的情况下),除了处理事件,redis还需要完成其他的一些工作,比如上面提到的删除过期key,如果每次采样,过期key都超过了一定比例,随机采样的循环可能要持续很久,也可能会阻塞redis。redis被短暂阻塞的原因非常多。除了slowlog之后,我们还可一使用strace观察redis的系统调用结合源码来猜测redis当时在执行什么。
官网上有一篇文章讲redis的延迟问题:http://redis.io/topics/latency

四.持久化

我们的系统中并没有开启redis的持久化,所以关于这方面的经验不是特别多。不过网上也有很多讲解这方面经验的资料。这里也稍提及一些。
首先,必读的是redis作者讲述持久化的一篇blog:http://oldblog.antirez.com/post/redis-persistence-demystified.html,讲解了redis持久化的机制和持久化安全性。
redis虽然会利用后台线程进行持久化,但仍有可能会引起阻塞。例如:在开了aof的Redis server上, 当执行bgrewriteaof对aof进行归并,按理,bgrewriteaof是在后台进行操作, 不应该影响Redis的正常服务。不过redis服务默认设置appendfsync everysec, 主进程每秒钟会调用fsync(), 但由于子进程同时也在写硬盘, 从而导致主进程磁盘io操作被阻塞。
http://blog.nosqlfan.com/html/4077.html 这里还提到了一些其他的持久化中的问题

五.分布式

redis目前版本没有官方的分布式支持。官方的主从目前也有比较大的问题,主从连接断开后重新连上需要重传所有数据而不是续传增量数据。
twitter开源的tmemproxy是一个比较流行的redis分布式方案。https://github.com/twitter/twemproxy
redis官方说会在3.0版本推出官方的分布式方案RedisClient,目前的官方代码中提供了redis-sentinel来管理redis instance 

另外,如果自己调用redis的客户端从分布式redis集群来批量取一批key时,也会遇到类似memcache muliget hole的问题,这时,需要自己在客户端来实现并行化从各个redis server并发的调用mget,而不是依次从每台redis server调用mget。


0 0