Redis开发规范
一、总体情况介绍:
- redis实例总共3780个,140个集群(cluster 模式)主要为cluster模式
- 最大的集群广告集群,双机房部署,lg机房17台服务器,25个分片,共50个实例 600G已用423G
- 架构 主推 redis-cluster ,辅助m-s架构
-
Redis Cluster简介
- 是Redis官方3.0版本开始提供的分布式数据库方案,集群通过分片(sharding)来进行数据共享,并提供复制和故障转移功能。 整个集群是无中心化结构,把集群的键空间(KeySpace)划分为16384个slots(槽)。集群中每个分片(shard)负责处理部分slots,每个redis节点都会保留集群slots分布的元数据信息。smart clients(如jedis)首次构建线程池会获取cluster slots分布的元数据,client在处理请求命令,通过对被操作的key, 进行CRC16(key)/16384公式计算出key的数据槽号,通过槽号归属于一个节点,这样Redis集群就知道请求最终发向正确的节点。
-
架构细节:
- (1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
- (2)节点的fail是通过集群中超过半数的master节点检测失效时才生效. gossip 协议
- (3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- (4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key
-
分配图:
- cluster ---> 16384 个slots (分配到多个分片)---> key
-
名词解释 分片和节点
- 一个Redis集群包含固定的16384个数据槽(slot),这些数据槽通常分布到多个分片(sharding),每个分片有且有一个主节点(master node),每个主节点可能有0个或多个副本(replica)。Redis集群理论上最多能支持16384个主节点(每个node负责1个slot),但官方建议目前版本节点不要超1000个。 从最佳实践来看不超过100个。
-
数据槽(slots)
- Redis cluster 将存储空间分为16384(0-16383)个slots,当所有slots分配完毕,集群就可以写入数据对外提供服务。一般slots的分配,采用平均分配的原则,假如有10个分片,则每个分片有:16384/10个slots。
-
复制和副本
- Redis集群虽是无中心节点,且任意节点间两两互联,通过gossip协议(流言协议)进行通信和配置更新;但并不像Cassandra采用对等结构(P2P)分布式模型。因为集群中的节点分为主节点和从节点两种角色。
- Redis集群内部支持复制,每个主节点可设置0~多个从节点,通过Redis的原生异步复制同步数据。当某个主节点挂掉或网络无法连接,集群通过投票判定主节点故障(Fail)后,会选择它的一个从节点进行顶替。
-
故障检测和故障转移
- 1 选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.
-
2 什么时候整个集群不可用(
cluster_state:fail
)?
- a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成时进入fail状态. 如果cluster-require-full-coverage参数打开,那么集群兼容部分失败,默认是打开。
- b:如果集群超过半数以上master挂掉,无论是否有slave集群进入fail状态. ps:当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误
三、当前redis使用过程遇到的问题
- 1、使用的版本?
- 2、当前的redis架构?
- 3、缓存还是存储?数据完整性要求?极端情况下是否容许丢数据。
四、运维支持
- 监控 http://falcon.xae.xiaomi.com/template/view/246
-
备份还原
http://dba.n.xiaomi.com/redisbackup/log
-
存储类型的,cluster架构,一般情况下正常切换,不丢数据
- 极端情况下1 :主机down机,从库也down机并且无法启动,只能恢复到当天凌晨3点
- 极端情况下2 :主机down机,从库也down机但是可以启动,可恢复到down机前。doing.
-
存储类型的,cluster架构,一般情况下正常切换,不丢数据
-
扩容:
- 1、支持横向扩容,通过划分更多的分片,实现扩容。添加机器,reblance slots分布。
- 2、支持纵向扩容,通过调整单个实例的容量,和failover 机制扩容。
- 前提:不要使用一些包装的命令,例如pipline。
-
Redis的慢查询分析
- slowlog只存储在内存中,最老的慢查询淘汰后,就没法找回。现在通过slowlog len命令取得慢查询列表中的个数。
- 慢查询扩大问题,由于Redis是单线程的,因此出现一个慢查询,比如get操作执行500ms,导致这500ms内的请求都会堵住,但是慢查询日志只会记录一条。
五、 cluster 的使用限制
- 1、不支持pipline 操作
- 2、不支持多key操作,例如keys、mget、hmget
- 3、单个key过大,QPS过高,可能网络会成为瓶颈,需要业务优化
六、常见问题
-
1、 Java 异常Too many Cluster redirections
- 可能的原因:
- 1. 超时比较多,默认超时时间是2秒。 - (1). 网络原因:比如是否存在跨机房、网络割接等等。 - (2). 慢查询,因为redis是单线程,如果有慢查询的话,会阻塞住之后的操作。 - (3). value值过大? - (4). aof 重写/rdb fork发生?
- 2. 节点之间关系发生变化,会发生JedisMovedDataException
- 3. 数据在节点之间迁移,会发生JedisAskDataException
- 参考: http://carlosfu.iteye.com/blog/2251034
- 参考: https://cachecloud.github.io/2016/11/17/Redis%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%B8%B8%E8%A7%81%E5%BC%82%E5%B8%B8%E5%88%86%E6%9E%90/
-
2、双机房问题
- 1、目前双机房,采用业务双写的策略。如果是java ,可以使用 广告组开发的公共包。其他语言,暂时没有。
- 2、双机房的高可用问题,采用的策略是机房自治策略,单个机房出现问题时,业务降级,将流量从A机房迁移到B机房。
七、开发规范
-
生产环境严禁使用的危险命令(请误在生产环境尝试)
- keys * : 导致Redis实例堵死,甚于触发故障切换,导致整个集群出现大面积故障
- flushall: 导致Redis堵死,同时丢失所有数据
- flushdb: 丢失当前database的所有数据,出现堵死现象
- save: 导致Redis堵死
- bgsave: 导致Redis卡顿,FORK引起COW内存消耗,有导致大面积OOM的风险
- config set: 严禁开发同学修改生产配置,错误配置会导致数据丢失和OOM的风险
- shutdown: 导致Redis关闭、数据丢失和故障转移
- debug : 导致Redis Crash、堵死和集群故障转移等
- 慎用时间复杂度为O(N)的命令方法, 详细分析见本节后文”程序架构规范"。
-
Keyspace设计
-
只使用database 0,通过key前缀划分命令空间
- 多个database用select切换时,更消耗CPU资源
- 更易自动化运维管理,如scan/dbsize命令只用于当database
-
只使用database 0,通过key前缀划分命令空间
-
Key的设计规范:高可读性、区分性和尽量简洁
- 按业务功能命名key前缀,防止key冲突覆盖,同时方便运维管理。
- Key的长度小于30个字符,Key内容本身分占用1到多份内存容量。
- Key名字本身是String对象,最大长度512MB
- 建议Key使用":"字符进行分层。
- Redis缓存场景,建议Key都设置TTL值,保证不使用的Key能被及时清理或淘汰,使内存复用。
- 有业务60%的Key 100天都未访问过一次,或已废弃。
-
程序架构规范
- Cluster模式中,热点Key和大容量Key尽量设计"打散”;避免集群不均,导致某个分片QPS“过载“和容量过大。
- 避免使用时间复杂度为O(N)的访问模式或命令;对元素比较多的集群key使用时间复杂度为O(N)命令,往往。
- redis是single-threaded server,如果命令耗时过长,命令独占server,其间不能响应其他命令,导致服务超时。如果执行时间比较长,甚于导致判断节点为下线状态,触发集群故障转移。
- 查看命令时间复杂度,官方文档Commands,每个都对应有Time complexity属性;如HGETALL命令Time complexity: O(N) where N is the size of the hash.时间复杂度为O(N)的常见命令: keys mget mset hgetall
-
容量规划
- 可以通过工具计算出需要的容量
--------EOF---------
微信分享/微信扫码阅读
微信分享/微信扫码阅读