Redis功能强大,数据类型丰富,再快的系统,也经不住疯狂的滥用。通过禁用部分高风险功能,并挂上开发的枷锁,业务更能够以简洁、通用的思想去考虑问题,而不是绑定在某种实现上。
Redis 根据不同的用途,会有不同的持久化策略和逐出策略,所以,在使用和申请 Redis 集群前,请明确是用来做缓存还是存储。redis 的集群有主从和 cluster 两种模式,各有优缺点。以下规范不区分集群模式,我们分别从使用场景和操作限制两方面说明。
基础功能介绍
默认16个数据库,类似数组下标从零开始,初始默认使用零号库
在redis.conf配置文件定义了数据库的个数
# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
Select命令切换数据库
127.0.0.1:6379> keys *
1) "mylist"
2) "counter:__rand_int__"
3) "key:__rand_int__"
4) "dhx"
127.0.0.1:6379> SELECT 1 #切换到1号数据库
OK
127.0.0.1:6379[1]> keys *
(empty list or set)
127.0.0.1:6379[1]>
Dbsize查看当前数据库的key的数量
127.0.0.1:6379> keys *
1) "mylist"
2) "counter:__rand_int__"
3) "key:__rand_int__"
4) "dhx"
127.0.0.1:6379> DBSIZE
(integer) 4
127.0.0.1:6379>
FLUSHDB和FLUSHALL
- FLUSHDB:会清楚当前数据库所有数据
- FLUSHALL:会清楚所有库的数据
127.0.0.1:6379> keys *
1) "mylist"
2) "counter:__rand_int__"
3) "key:__rand_int__"
4) "dhx"
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> keys *
(empty list or set)
统一密码管理,16库都是同样的密码,要么都ok,要么都链接不上。
keys
keys *
返回满足的所有键,可以模糊匹配,比如keys abc*
代表adc开头的key
127.0.0.1:6379> keys *
1) "name2"
2) "num"
3) "name"
ttl key
ttl key
查看剩余时间,当key不存在时,返回-2,存在但没有设置剩余生存时间时返回-1,否则,以秒为单位,返回key的剩余生存时间。
127.0.0.1:6379> ttl num
(integer) -1
move key dbindex
move key dbindex
将当前的key转移到其他数据库
exists key :是否存在指定的key,存在返回1,不存在返回0
expire key second :设置某个key的过期时间,时间为秒
del key :删除某个key
type key :查看你的key是什么类型
info 查看数据库信息
127.0.0.1:6379> info
# Server
redis_version:3.2.100
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:dd26f1f93c5130ee
redis_mode:standalone
os:Windows
arch_bits:64
multiplexing_api:WinSock_IOCP
process_id:20316
run_id:17eadfb924151b926dd9bc121f6895f8049c7946
tcp_port:6379
uptime_in_seconds:9441
uptime_in_days:0
hz:10
lru_clock:4956482
executable:D:\install\redis\Redis-x64-3.2.100\redis-server.exe
config_file:
# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
# Memory
used_memory:689368
used_memory_human:673.21K
used_memory_rss:651592
used_memory_rss_human:636.32K
used_memory_peak:6405296
used_memory_peak_human:6.11M
total_system_memory:0
total_system_memory_human:0B
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:0.95
mem_allocator:jemalloc-3.6.0
# Persistence
loading:0
rdb_changes_since_last_save:12
rdb_bgsave_in_progress:0
rdb_last_save_time:1699453239
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
# Stats
total_connections_received:201
total_commands_processed:300044
instantaneous_ops_per_sec:0
total_net_input_bytes:11701255
total_net_output_bytes:8153480
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:1
evicted_keys:0
keyspace_hits:200021
keyspace_misses:3
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:3496
migrate_cached_sockets:0
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:4.09
used_cpu_user:0.83
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
# Cluster
cluster_enabled:0
# Keyspace
db0:keys=3,expires=0,avg_ttl=0
使用规范
冷热数据区分
虽然 Redis支持持久化,但将所有数据存储在 Redis 中,成本非常昂贵。建议将热数据 (如 QPS超过 5k) 的数据加载到 Redis 中。低频数据可存储在 Mysql、 ElasticSearch中。
业务数据分离
不要将不相关的数据业务都放到一个 Redis中。一方面避免业务相互影响,另一方面避免单实例膨胀,并能在故障时降低影响面,快速恢复。
消息大小限制
由于 Redis 是单线程服务,消息过大会阻塞并拖慢其他操作。保持消息内容在 1KB 以下是个好的习惯。严禁超过 50KB 的单条记录。消息过大还会引起网络带宽的高占用,持久化到磁盘时的 IO 问题。
连接数限制
连接的频繁创建和销毁,会浪费大量的系统资源,极限情况会造成宿主机宕机。请确保使用了正确的 Redis 客户端连接池配置。
缓存 Key 设置失效时间
作为缓存使用的 Key,必须要设置失效时间。失效时间并不是越长越好,请根据业务性质进行设置。注意,失效时间的单位有的是秒,有的是毫秒,这个很多同学不注意容易搞错。
缓存不能有中间态
缓存应该仅作缓存用,去掉后业务逻辑不应发生改变,万不可切入到业务里。第一,缓存的高可用会影响业务;第二,产生深耦合会发生无法预料的效果;第三,会对维护行产生肤效果。
扩展方式首选客户端 hash
小应用就算了
如单 redis 集群并不能为你的数据服务,不要着急扩大你的 redis 集群(包括 M/S 和 Cluster),集群越大,在状态同步和持久化方面的性能越差。 优先使用客户端 hash 进行集群拆分。如:根据用户 id 分 10 个集群,用户尾号为 0 的落在第一个集群。
操作限制
严禁使用 Keys
Keys 命令效率极低,属于 O(N)操作,会阻塞其他正常命令,在 cluster 上,会是灾难性的操作。严禁使用,DBA 应该 rename 此命令,从根源禁用。
严禁使用 Flush
flush 命令会清空所有数据,属于高危操作。严禁使用,DBA 应该 rename 此命令,从根源禁用,仅 DBA 可操作。
严禁作为消息队列使用
如没有非常特殊的需求,严禁将 Redis 当作消息队列使用。Redis 当作消息队列使用,会有容量、网络、效率、功能方面的多种问题。如需要消息队列,可使用高吞吐的 Kafka 或者高可靠的 RocketMQ。
严禁不设置范围的批量操作
redis 那么快,慢查询除了网络延迟,就属于这些批量操作函数。大多数线上问题都是由于这些函数引起。
- [zset] 严禁对 zset 的不设范围操作
ZRANGE、 ZRANGEBYSCORE等多个操作 ZSET 的函数,严禁使用 ZRANGE myzset 0 -1 等这种不设置范围的操作。请指定范围,如 ZRANGE myzset 0 100。如不确定长度,可使用 ZCARD 判断长度
- [hash] 严禁对大数据量 Key 使用 HGETALL
HGETALL会取出相关 HASH 的所有数据,如果数据条数过大,同样会引起阻塞,请确保业务可控。如不确定长度,可使用 HLEN 先判断长度
- [key] Redis Cluster 集群的 mget 操作
Redis Cluster 的 MGET 操作,会到各分片取数据聚合,相比传统的 M/S架构,性能会下降很多,请提前压测和评估
- [其他] 严禁使用 sunion, sinter, sdiff等一些聚合操作
禁用 select 函数
select函数用来切换 database,对于使用方来说,这是很容易发生问题的地方,cluster 模式也不支持多个 database,且没有任何收益,禁用。
禁用事务
redis 本身已经很快了,如无大的必要,建议捕获异常进行回滚,不要使用事务函数,很少有人这么干。
禁用 lua 脚本扩展
lua 脚本虽然能做很多看起来很 cool 的事情,但它就像是 SQL 的存储过程,会引入性能和一些难以维护的问题,禁用。
禁止长时间 monitor
monitor函数可以快速看到当前 redis 正在执行的数据流,但是当心,高峰期长时间阻塞在 monitor 命令上,会严重影响 redis 的性能。此命令不禁止使用,但使用一定要特别特别注意。
Key 规范
Redis 的 Key 一定要规范,这样在遇到问题时,能够进行方便的定位。Redis 属于无 scheme 的 KV 数据库,所以,我们靠约定来建立其 scheme 语义。其好处:
- 能够根据某类 key 进行数据清理
- 能够根据某类 key 进行数据更新
- 能够方面了解到某类 key 的归属方和应用场景
- 为统一化、平台化做准备,减少技术变更
一般,一个 key 需要带以下维度:业务、key 用途、变量等,各个维度使用 :
进行分隔,以下是几个 key 的实例:
user:sex 用户 10002232 的性别 msg:achi 201712 的用户发言数量排行榜
End
适当的约束是架构成熟的必要条件,通过约定能达到规范是集体开发的最高境界。Redis用的多,也要用的稳,给点约束、立点规矩,生活将变的美好。通过二次封装redis客户端,直接阻断,效果更佳。