
一、简介
- redis是一个基于网络的、高性能的key-value内存数据库
- redis跟memcached类似,不过数据可以持久化,支持的数据类型丰富
- redis有以下几个特点
二、应用场景
- 取最新N个数据的操作,例如博客网站获取最近的文章
- 排行榜取TOP N,上面得需求以时间为权重,这里取TOP N以条件为权重
- 设置精确过期时间得应用,如用户会话信息
- 计数器应用,比如记录用户访问网站次数
- 缓存,如缓存系统中经常访问的数据
- 发布/订阅功能
- 手机验证码,使用expire设置过期时间
二、业务流程
2.1 redis架构
- 无中心自组织的架构,节点之间使用Gossip协议来交换节点状态信息
- 各节点维护key->server得映射关系
- Client节点可以向任意节点发起请求,节点不会转发请求,只是重定向client
- 如果client在第一次请求和重定向之间,cluster拓扑发生变化,则第二次重定向将被再次重定向,直到找到正确的server
如下图所示,在第一次请求时,如果请求的数据不在节点中,redis会要求客户端重定向到正确节点,如果在请求和重定向之间,cluster拓扑发生了变化就会在重复做一次重定向

2.2 redis读写流程
- client链接server,发起发送cluster nodes请求;
- server返回集群拓扑,主要包括集群节点及槽位跟节点之间得映射关系,客户端在内存中缓存集群拓扑
- 客户端读写数据时,根据hash(key)%16384计算得到key归属得槽位,再查询槽位跟节点得映射,进一步得到key归属的节点server2,直接访问节点进行读写
- server2收到客户端的请求,检查自身是否为key归属的节点;若不是则响应告知客户端client重定向到server3;若是则直接返回业务操作结果;
- 客户端收到重定向响应,重新向server3发起读写请求
- server3收到请求,重复第4步操作

2.3 redis的特性
2.3.1 多数据库
- 每个数据库对外都是以一个从0开始的递增命名数据库,不支持自定义命名
- redis默认支持16个数据库,可以通过调整database参数来修改这个默认值
- redis默认选择的是0号数据库
- SELECT 数字可以切换数据库
- 多个数据库之间不是完全隔离的,比如flushall命令范围是所有数据库
- flushall清空redis实例下所有数据库数据
- flashdb清空当前数据库的数据
2.3.2 redis基础命令
- 获得符合规则的key名称
- 判断一个key是否存在
- 删除key
- 获取键值的数据类型
- 返回值类型(string,hash,list,set,zset)
- redis命令不区分大小写
2.4 redis数据类型
2.4.1 string
字符串类型是redis中最基本的数据类型,它能够存储任何形式的内容。一个字符串类型的值存储的最大容量是1GB
命令 | 作用 |
set | 设置指定键的值 |
get | 获取指定键的值 |
setnx | 将键的值设置为指定的值,如果这个键不存在, 那么SETNX命令将创建这个键并设置其值 |
mset | 一次性设置多个键的值 |
mget | 一次性获取多个键的值 |
incr | 键的值自增1 |
decr | 键的值自减1 |
incrby | 将键的值加上指定的增量值 |
decrby | 将键的值减少指定的增量值 |
incrybyfloat | 键所储存的值加上浮点数增量 |
append | 将指定的字符串追加到键所储存的值的末尾 |
strlen | 获取指定键所储存的字符串值的长度 |
2.4.2 hash
- hash类型的值存储了字段和字段值的映射,字段和字段值只能是字符串,不支持其他数据类型,hash类型的键至多可以存储四个字节的数据
- hash类型适合存储对象
- redis可以为任何键增减字段而不影响其他键
命令 | 作用 |
hset | 将哈希表中的一个字段的值设置为指定的值 |
hget | 获取哈希表中指定字段的值 |
hmset | 设置哈希表的多个字段值 |
hmget | 获取哈希表的多个字段值 |
hgetall | 返回哈希表中所有字段和值 |
hexists | 查看哈希表key中,给定域field是否存在 |
hincreby | 为哈希表中的字段值加上指定增量值,增量可以为负数 |
hdel | 删除指定的哈希表key |
hkeys | 获取哈希表中的所有字段名 |
hvals | 获取哈希表中的所有字段值 |
hlen | 获取哈希表中字段数量 |
2.4.3 list
list是一个有序的字符串列表,列表内部实现是使用双向链表实现的
命令 | 作用 |
lpush | 将一个或多个值插入到列表头部 |
rpush | 将一个或多个值插入到列表尾部 |
lpop | 移除并返回列表的头元素 |
rpop | 移除并返回列表的尾元素 |
llen | 返回列表的长度 |
lrange | 返回列表中指定区间的元素 |
lrem | 删除列表中等于给定值的元素 (lrem key count value) count为要删除的元素个数; count > 0时从表头开始向表尾搜索,移除与value相等的元素,数量为count; count < 0时从表尾开始向表头搜索,移除与value相等的元素,数量为count绝对值; 删除列表中所有与value相等的元素; |
lindex | 通过索引获取列表中的元素 |
lset | 通过索引设置列表中的元素 |
ltrim | 只保留指定区间内的元素,其他元素删除 |
linsert | 在列表的元素前或元素后插入元素 |
rpoplpush | 移除列表最后一个元素并将该元素添加到另一个列表 |
2.4.4 set
set集合中的元素不重复且无序,一个集合可以存储2的32次方-1个元素
命令 | 方法 |
sadd | 将一个或多个元素插入到集合中 |
smembers | 获取集合中所有元素 |
srem | 移除集合中的一个或多个元素 |
sismember | 判断元素是否在集合中 |
sdiff | 求集合的差集 |
sinter | 求集合的交集 |
sunion | 求集合的并集 |
sdiffstore | 求集合的差集并存储在指定集合中 |
sinterstore | 求集合的交集并存储在指定集合中 |
sunionstore | 求集合的并集并存储在指定集合中 |
scard | 返回集合中元素的数量 |
spop | 移除集合中一个或多个随机元素 |
srandmember | 获取返回一个集合中的随机元素,srandmember key count 1、如果count为正数,且小于集合基数,那么返回一个包含count个元素的数组, 数组中的元素各不相同 2、如果count大于等于集合基数,那么返回整个集合 3、如果count为负数,那么返回一个数组,数组中的元素可能会重复出现多次, 而数组的长度为count的绝对值 |
2.4.5 sorted set
有序集合,在集合的基础上为每个集合关联了一个分数以便于获取分数最高的TOP N个元素
命令 | 作用 |
zadd | 将一个或多个成员及其分数插入到有序集合中 |
zscore | 返回有序集合中成员的分数值 |
zrange | 返回有序集中指定范围的成员,成员位置按分数递增 |
zrevrange | 返回有序集中指定范围的成员,成员位置按分数递减 |
zrangebyscore | 返回有序集合中分数值位于指定区间内的成员 |
zincrby | 给有序集合中指定成员的分数值加上指定的增量 |
zcard | 计算集合中的成员个数 |
zcount | 计算有序集合中指定分数区间的内的成员数量 |
zrem | 移除有序集合中一个或多个元素 |
zremrangebyrank | 移除有序集合中指定排名区间内的成员 |
zremrangebyscore | 移除有序集合中,分数在指定区间内的成员 |
2.5 redis中键的生存时间
使用expire命令设置一个键的生存时间,到期后redis会自动删除这个键
命令 | 作用 |
expire | 以秒为单位设置key的过期时间 |
pexpire | 以毫秒为单位设置key的过期时间 |
ttl | 查看key的剩余过期时间,以秒为单位 |
pttl | 查看key的剩余过期时间,以毫秒为单位 |
persist | 移除指定key的过期时间,这样key就永不过期 |
expireat | 设置时间戳(秒)对应的时间为key的过期时间 |
pexpireat | 设置时间戳(毫秒)对应的时间为key的过期时间 |
下面是几个常见应用场景
- 限时的优惠活动信息
- 网站数据缓存(缓存定时更新的数据)
- 限制网站访客访问频率(限制一分钟只能访问十次)
2.6 redis管道
Redis 管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应,管道在客户端使用,redis本身没有管道操作命令
2.7 redis中的数据排序
对列表、集合、有序集合键的值进行排序
- SORT key。默认以数字作为对象,值被解释为双精度浮点数,然后进行比较
- SORT key BY pattern。根据模式进行排序
- SORT key LIMIT start count。限制返回的数量
- SORT key GET pattern。获取排序后的元素
- SORT key ASC|DESC。可指定排序方式为升序或降序
- SORT key ALPHA。将元素解释为字符串进行排序
- SORT key STORE dstkey。将排序后的结果存储到dstkey中
2.8数据持久化
redis支持两种持久化方式
2.8.1 RDB
RDB是redis默认的持久化方式
- RDB通过快照的方式完成持久化,当符合一定条件时,redis会将内存中的所有数据执行快照操作并存储到硬盘,默认存储在dump.rdb文件中
- redis进行快照的时机(可以在redis.conf中)
- save 900 1:表示900s内至少一个键被更改则进行快照
- save 300 10
- save 60 10000
- 手动执行save或者bgsave命令让redis执行快照
- save由主进程执行快照,会阻塞其他请求
- bgsave是由redis执行fork函数复制出一个子进程来执行快照
2.8.2 AOF
- AOF持久化方式通过日志文件的方式实现,通过配置appendonly参数开启
- redis写命令同步的时机
- appendfsync always:每次都会执行
- appendfsync everysec: 默认每一秒执行一次同步操作
- appendsync no:不主动进行同步,由操作系统来做,30s一次
- RDB切换到AOF
- config set appendonly yes
- config set save "" eg:config set save "60 10000"
注意:
- redis启动时,如果同时开启了RDB和AOF,redis会优先使用AOF的方式来恢复数据,因为AOF方式保存的数据完成性较高,如果AOF文件丢失了,则启动后数据库内容为空
- 如果把正在运行的redis持久化方式由RDB修改为AOF,建议先使用动态切换方式,在修改配置文件(如果直接修改文件在重启数据库,数据库就为空了)
- RDB方式故障时,会丢失最后一次快照之后的数据
三、redis优化
- 精简键名和键值
- 键名:尽量精简,但也不能为了节约空间而使用不易理解的键名
- 键值:部分键值考虑使用数字来表示,如男/女
- 当业务场景不需要持久化时,关闭持久化方式会获得更高的性能
- 内部编码优化
- redis为每种数据类型都提供了两种内部编码方式,在不同的情况下redis会自动调整合适的编码方式
- SLOWLOG
- slowlog-log-slower-than 它决定要对执行时间大于多少微妙的命令进行记录
- slowlog-max-len 决定slowlo最多能保存多少条日志
- 修改linux内核内存分配策略
- overcommit_memory是一个 Linux 系统设置,它控制着内核在内存分配方面如何处理失败的内存分配请求。如果系统中的空闲内存不足,内核会尝试分配更多的内存。如果分配失败,内核会根据 overcommit_memory 的设置来决定如何处理
- 0:内核会尝试分配请求的内存,如果分配失败,会返回错误。这是默认值
- 1:内核会尝试分配请求的内存,如果分配失败,它会尝试使用内存清理算法来腾出更多的内存。这通常会成功,但可能会影响到正在运行的进程,因为内存清理算法会结束一些进程以释放内存
- 2:内核会立即返回错误,如果请求的内存无法立即分配。这可以防止系统过度消耗内存
- 向etc/sysctl.conf添加vm.overcommit_memory=1,重启服务器
- 或执行sysctl vm.overcommit_memory立即生效
- 关闭transparent huge pages(THP)
- THP会造成内存锁影响redis性能,建议关闭
- Transparent Huge Pages用来提升内存管理的性能
- Transparent Huge Pages在32位的HEL6中不支持
- 使用root用户执行下面的命令关闭
- echo never > /sys/kernel/mm/transparent_hugepage/enabled
- 把这条命令添加到这个文件/etc/rc.local
- 修改linux中TCP最大连接数
- 此参数确定了TCP链接中已完成队列的长度,此值小于等于linux系统中定义的/proc/sys/net/core/somaxcoon值,redis默认是511,linux默认参数是128,当系统开发量大且客户端速度缓慢的时候,可以将这两个参数一起参考设定
- echo 511 > /proc/sys/net/core/somaxcoon
- 这个参数并不是限制redis的最大连接数,redis最大连接数通过maxclients参数控制,默认的最大连接数是10000
- 限制redis的内存大小
- 通过redis的info命令查看内存使用情况
- 如果不设置maxmemory或设置为0,64位系统不限制内存,32位系统最多使用3GB内存
- 修改配置文件中maxmemoey和maxmemory-policy
- maxmemory:最大内存
- maxmemory-policy: 内存不足时,数据删除策略
- 数据总量不大且内存足够的情况下不需要限制redis的内存大小,如果数据量不可预估且内存有限,尽量限制redis使用的内存大小,这样可以避免redis使用swap分区或出现OOM错误
- 注意:如果不限制内存,当物理内存使用完之后,会使用swap分区,这样性能较低,如果限制了内存,当达到指定内存之后就不添加数据了,否则会报OOM错误,可以设置maxmemory-policy,内存不足时删除数据
- redis是个单线程模型,客户端命令过来后按顺序执行,如果想要一次操作多条数据的时候,可以使用管道或者使用一次可以操作多条数据的命令
参考
redis菜鸟教程
Redis内存数据库_在线课程_华为云开发者学堂_云计算培训-华为云 (huaweicloud.com)