【Redis笔记】基础
Redis为什么有多个库?
Redis默认有16个库,使用select命令切换,Redis中的库和关系型数据库不一样,Redis中的库可以理解为“命名空间”,且不支持独立密码。Redis多数据库目的是为了对数据隔离,防止key冲突。
Redis为什么速度快?
1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。
2、类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);
3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
4、使用多路I/O复用模型,非阻塞IO;
Redis为什么是单线程的?
官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了
降低了复杂度,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗,同时保证了线程安全
注意:这里我们一直在强调的单线程,只是在处理我们的网络请求的时候只有一个线程来处理,一个正式的Redis Server运行的时候肯定是不止一个线程的,这里需要大家明确的注意一下!例如Redis进行持久化的时候会以子进程或者子线程的方式执行
最佳实践
key设计
Redis的key允许有多个单词形成层级结构,“:”分隔,如:业务名称:数据名:id
。
set login:user:1 value # 登录业务保存用户信息
set like:user:1 value # 收藏业务保存用户信息
优点:
- 可读性强
- 避免key冲突
- 方便管理
拒绝bigkey,防止慢查询
- string类型控制在10k以内
- hash、lish、set、zset元素个数不要超过1000
bigkey的危害:
- 网络阻塞
对BigKey执行读请求时,少量的QPS就可能导致贷款被占满,导致请求变慢 - 数据倾斜
BigKey所在的Redis实例内存使用率远超其他实例,无法使数据分片的内存资源达到均衡 - Redis阻塞
对元素较多的hash、list、set、zset等做运算会耗时久,使主线程被阻塞 - CPU压力
对BigKey的数据序列化和反序列化会导致CPU使用率飙升
如何发现bigkey:
redis-cli --bigkeys
scan扫描
第三方工具,如Redis-Rdb-Tools
网络监控
控制key的声明周期:
建议使用expire设置过期时间,尽量打散过期时间,不要集中过期
禁用命令:
禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐进式处理。因为redis是单线程执行,容易导致线上不可用.
scan命令是通过游标分步进行,不会阻塞线程,提供count参数,不是结果数量,是Redis单次遍历字典数量,同keys一样也提供模式匹配功能。
scan 0 match user_token* count 5 #从0开始遍历,返回新游标,下次查询从新游标开始遍历
合理使用select:
redis的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线程处理,会有干扰
尽量使用批量操作提高效率:
原生命令:例如mget、mset;非原生命令:可以使用pipeline提高效率。
但要注意控制一次批量操作的元素个数(例如500以内,实际也和元素字节数有关)。
通用命令
help
查看命令的帮助文档
help keys --查看keys命令的帮助文档
keys
查看符合模式的所有key
*
代表多个字符,?
代表单个字符
keys * --查询所有key
keys list* --查询list开头的key
KEYS *name* --查询包含name的所有key
KEYS a?? --查询包含a开头、共3个字符的所有key
DEL
删除缓存
del key1 key2 key3
exists
查看指定key的缓存是否存在
exists a
type
查询键对应的value类型
type key1
expire
设置缓存时间,到期自动删除,单位秒
expire key 10
ttl
查看剩余过期时间(-2表示已过期)
ttl key
其他命令
flushall --清空全部库数据
flushdb --清空当前库数据
set a aaa [EX seconds] [PX milliseconds] --设置过期时间EX表示秒 PX表示毫秒
move a 1 --移除a,1代表当前库