概述

简介

本规范主要针对键值数据库高速缓存Redis的应用,结合PaaS服务产品部微服务架构实际场景,制定包含设计,安全,开发和维护四大类规范。

本规范重点说明高速缓存数据库Redis和RedisCluster相关规范,总共约40+条规则/建议。

术语约定

本规范采用以下的术语描述:

★ 规则:编程时强制必须遵守的原则。

★ 建议:编程时必须加以考虑的原则。

★ 说明:对此规则或建议进行必要的解释。

★ 示例:对此规则或建议进行正、反两个方面的举例。

适用范围

本规范主要面向设计人员、开发人员和DBA。适用于美宜佳信息系统内所使用的Redis缓存数据库。

设计规范

规则:只缓存热点数据到Redis

缓存是宝贵的资源,不是所有数据都要缓存到Redis,应该只缓存热点数据,对吞吐率要求高的场景。

规则:杜绝内存泄露,要设计缓存淘汰机制

Redis是内存数据库,随着保存数据越来越多,占用会越来越大。

1、注意垃圾回收, 不常使用的数据要定期清理,或设置超时淘汰掉。

2、基于Redis特性设定key的过期时间。

 规则:需要保证Redis缓存和持久化数据的最终一致性

建议:合理控制数据库规模和数量

 控制Redis单实例内存,最大不超过5G。

 控制Redis单实例连接数,最大不超过500。

 Redis单实例并发读写吞吐能力5w-10w/s。

 RedisCluster并发读写吞吐能力: 5w/s*N实例数。三节点RedisCluster在实体机可达到100w/s。

规则:数据库缺省值使用一个

(对应redis.conf的databases) Redis虽然支持通过编号区分不同的库。但是为了避免应用用错,只用缺省的即可。

规则:禁止在Redis中存储图片、文件等大数据

规则:Redis最佳使用方式是Cache非持久化模式

Redis原生持久化能力较弱。Redis支持三种模式:

1、cache 非持久化 。

2、aof模式:基于事务日志,优点:文件过大自动重建,缺点:文件破坏需要修复

3、snapshot快照模式:RDB数据快照,优点:启动快,缺点:fork消耗资源,数据可能丢失。

规则:客户端必须使用连接池功能(长连接和自动重连)

 每次连接的建立和释放比较消耗资源。

 考虑到Redis重启等场景,网络闪断或Redis重启后,应用客户端连接要支持自动重连。

 官方推荐的Java客户端jedis.JedisPool提供连接池功能。也可以使用PaaS服务产品部平台封装的接口。

规则:缓存要做异常保护和容错设计

非持久化模式下,Redis启等异常场景缓存可能丢失或部分丢失,应用需要进行数据容错处理。

 关键操作进行重试保护。

 缓存数据重新加载。

 设置数据超期,定期数据进行一致性校验。

 事件重新订阅。

 防止缓存雪崩。

规则:大数据量缓存预热要控制初始化时间,提高可用性。

一方面可以用Lazy方式加载,另外在加字段时候可以优化:

 用批量命令,事务等提高写入效率。

 多线程并发初始化。

 建议:根据业务场景选择合适的数据结构

Redis数据结构丰富。KV的Value可以是string,hash,list,set,sorted sets等类型。

建议:尽量不要使用Lua脚本。

Lua脚本在服务端运行, 存在安全隐患,如果写的不好,会影响整个服务器性能。

建议:从高可用和安全性角度,Redis和关系数据库分开部署

Redis定位是高速缓存,而关系数据库定位是持久化存储,为避免相互影响,从高可用和安全性角度,有条件的化,建议分开部署。

对于查询类操作,单点故障不影响功能,Redis和关系数据库其中一个挂了尽量不影响功能。

建议: 服务无状态设计,状态可以外置到数据库

安全规范

规则:禁止在Redis中保存敏感信息

说明:Redis原生通信协议和持久化格式都是文本协议。

规则:禁止不安全的客户端访问方式

在命令行输入密码,会被ps出来。

反例: /opt/redis/bin/redis-cli -h 10.67.147.112 -p 32035 -a abc

规则:禁止直接使用官方原生的未经过安全加固整改的 Redis

原生版本多项不满足公司安全要求,应该使用加固后的版本。

规则:规划好Key前缀作为命名空间,避免冲突

Key-Value第一级的Key值前缀要全局规范好,避免冲突导致相互覆盖。

Key前缀建议在程序中支持全局配置。

规则:Key前缀不要使用魔鬼数字, 防止硬编码

Key前缀命名应该清晰明了,容易理解。

规则:Key不要含有空格符,命名不要过长

含有空格容易导致输入错误。命名太长浪费内存空间。

建议:Key命名建议统一用":"分隔域,用"."作为单词间的连接

很多展示工具,如phpRedisAdmin缺省也是以冒号来分组(折叠和展开Key)。举例:active.db:1 active.db:2等key会分成一组

使用规范

规则:合理规划内存占用,养成节约内存的习惯

1、受系统最大内存限制。

一般应用建议单实例缓存控制在5G以内。

2、大数据下内存占用应该接近实际存储容量,但还要实测分析内存占用是否合理。 (参见典型案例)

示例:5000个Hash,每个Hash15个field,每个Value 占30K,内存占用估算:2.35G

3、预留一定的内存空间,一般Redis只使用机器内存的一半。

内存其实分为两部分:

  1. 缓存数据占用的内存。对应redis.conf配置 Maxmemory
  2. 处理高并发请求分配的临时内存。并发请求越多,临时内存越多

规则:Key的数量越小越好

减少key数量可以降低对内存的开销。可以改用其他如hash结构。

假如一个key-value单元需要最小占用100字节,即使只存一个字节也占了100字节。

规则:尽量使用value为纯数字,可以节省内存

1、字符串会转化成int类型减少内存的使用

示例::“true”/“false”可以用1/0表示

2、配置在REDIS_SHARED_INTEGERS范围内的数字会采用共享存储。

如果value数字小于宏REDIS_SHARED_INTEGERS(默认10000),则这个redisObject也都节省了,使用redis Server启动时的share Object.

规则:尽量使用Hash结构,而不是用get/set方式

1、可以考虑将数据分段,每一段使用一个Hash结构存储,由于Hash结构会在单个Hash元素在不足一定数量时进行压缩存储,所以可以大量节约内存。

2、可以使用hmget获取部分数据。

规则:优先使用批量接口获取批量数据。

1、交互越多越耗时,另外原子性也得不到保证。

2、Redis基本命令都是原子命令,其中批量接口命令主要有:

SET/GET -> MSET/MGET

HGET/HSET→HMGET/HMSET

HDEL/HGETALL/HKEYS

GETSET

LSET→LPUSH/RPUSH

LINDEX→LRANG

3、其次才是事务:multi exec

建议:集合操作为主的业务考虑使用set数据结构

set有丰富的取交集,并集,差集等命令,简单高效,保证了事务。

事务规范

规则:要保证操作的事务的原子性

Redis是单线程操作,单个请求就是事务,但是如果请求分开两个操作就会破坏原子性。

正例: set key value expiretime

反例: set key value

expire key expiretime

建议:如果配置AOF持久化,建议不要使用事务

当使用 AOF 方式做持久化的时候, Redis 会使用单个 write(2) 命令将事务写入到磁盘中,如果 Redis 服务器因为某些原因被管理员杀死,或者遇上某种硬件故障,那么可能只有部分事务命令会被成功写入到磁盘中。需要使用修复工具redis-check-aof

建议:Redis只支持简单事务,部分成功不会回滚

1、MULTI 、 EXEC 、 DISCARD 和 WATCH 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

2、Redis 在事务失败时不进行回滚,而是继续执行余下的命令。

它不保证原子性——所有指令同时成功或同时失败,只有决定是否开始执行全部指令的能力,没有执行到一半进行回滚的能力。

3、在redis里失败分两种:

  1. 明显的指令错误,比如指令名拼错,指令参数个数不对。
  2. 隐含的错误:比如在事务里,第一句是SET foo bar, 第二句是LLEN foo,对第一句产生的String类型的key执行LLEN会失败,但这种错误只有在指令运行后才能发现,这时候第一句成功,第二句失败。

4、如果事务执行到一半redis被KILL,已经执行的指令同样也不会被回滚。

性能规范

规则:尽可能减少和Redis的交互次数

1、交互越多越耗时,另外原子性也得不到保证

2、尽量使用批量命令(MSET/MGET)或可变参数命令

3、使用multi,pipeline等功能减少交互次数

4、如果可以尽量使用pipeline而不是序列的往返命令。

5、服务器端虽然支持lua脚本,但考虑到维护成本和安全性,默认不推荐使用。

规则:Redis单实例不适合作为海量数据存储方案.

Redis 适合在数据规模较小, 性能要求较高的条件下应用

为什么不建议Redis大量数据持久化

1.持久化的大小不能超过内存大小。

2.redis加载2G文件大概需要1分钟,比较耗时。

3.如果持久化:Redis rewrite aof和save rdb时,将会带来非常大且长的系统压力,并占用额外内存,很可能导致系统内存不足等严重影响性能的线上故障。

4.如果持久化,要考虑好备份和恢复,升级,数据安全等场景。

建议:注意可能引起性能问题的调优参数。

通过调整set-max-intset-entries参数,从默认512改为1024。小等于该边界:采用紧凑存储:一维存储,缺点是O(n)的时间复杂度。大于这个边界采用HashMap,优势就是查找和操作的时间复杂度都是O(1),缺点是内存占用会增加。

RedisCluster规范

规则:RedisCluster部署节点数量建议为1,3,5

如果节点个数为2,会出现脑裂的情况,无法选主而导致集群不可用。

规则:禁止在RedisCluster和客户端之间挂载Proxy中间服务

RedisCluster客户端具有SmartClient,会缓存服务端分片的IP和Port的映射关系,因此不能再在中间挂载DBProxy之类的组件。

规则:客户端连接RedisCluster必须指定所有分片地址

因为SmartClient的缘故,正常场景,虽然应用只连接其中一个分片也能感知到其他分片,但是考虑到可用性角度,可能存在部分分片失效,如果只连接部分分片可能导致不可用。

原则:对分片数进行Key覆盖性测试,避免某些分片可能出现的热点数据,尽量避免数据迁移

RedisCluster的分片算法是固定的,为尽量避免出现热点数据而迁移数据。

数据迁移可能出现数据丢失。

建议:合理利用RedisCluster的hashtag功能,让数据可预期分布

通过hashtag机制可以让预期的一类数据固定分配到一个实例中。

维护规范/行为规范

规则:线上Redis高危操作必须要经过数据部和运维部共同审批

Redis高危操作影响
keys *当keys数量比较大,比较消耗资源,应该用scan
FLUSHALLFLUSHDB 清空数据
shutdown实例退出命令

管理类命令,

如save,bgsave,bgrewriteaof,

monitor,slaveof,debug,config

管理类命令要慎重

规则:访问数据库账号保持权限最小原则

Redis目前支持三类用户。

分类说明

只读用户

readdbuser

健康检查/监控类操作缺省使用

定位问题时原则缺省使用

普通用户

ossdbuser

应用的读写

迫不得已涉及修改规避才用应用缺省账号

超户

dbuser

数据库管理类操作


  • 无标签
写评论...