- 创建者: 管理员,上次更新者: 虚拟的现实,更新时间:9月 28, 2023 需要 2 分钟阅读时间
概述
简介
本规范主要针对键值数据库高速缓存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只使用机器内存的一半。
内存其实分为两部分:
- 缓存数据占用的内存。对应redis.conf配置 Maxmemory
- 处理高并发请求分配的临时内存。并发请求越多,临时内存越多
规则: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里失败分两种:
- 明显的指令错误,比如指令名拼错,指令参数个数不对。
- 隐含的错误:比如在事务里,第一句是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 |
FLUSHALL | FLUSHDB 清空数据 |
shutdown | 实例退出命令 |
管理类命令, 如save,bgsave,bgrewriteaof, monitor,slaveof,debug,config | 管理类命令要慎重 |
规则:访问数据库账号保持权限最小原则
Redis目前支持三类用户。
分类 | 说明 |
---|---|
只读用户 readdbuser | 健康检查/监控类操作缺省使用 定位问题时原则缺省使用 |
普通用户 ossdbuser | 应用的读写 迫不得已涉及修改规避才用应用缺省账号 |
超户 dbuser | 数据库管理类操作 |
- 无标签
添加评论