角色
当用作 主存 和 缓存 时,redis 的配置和用法有明显区别。最好在配置时创建两套实例,应用不同的配置并在程序中做明显的区分使用。
用作主存的 redis,可靠性应该和其他数据库一样高,可以独立存储数据。这样的实例挂掉后会导致数据访问不可用。另外除非业务需要,一般不设置超时。
而用作缓存的 redis,不会独立存储数据,且都应默认配置为:取不到数据时,自动去找原数据,并在找到后尝试再次缓存。这样的 redis 挂掉后,会拖慢数据层的性能,但功能是完整的。因为缓存实例的可靠性、优先级都不高,这些 key 一般都设置超时,并且只使用 string
类型和 get/set
方法。刷新靠 del key 实现。
本文一些论断都是基于以上约束得出的。
为什么缓存只使用 string 类型
因为对于 key 存在与否的判断不可靠。
本文通用的一个例子是:
假设我要缓存一个 set,主要逻辑是判断一个 value 是否为其元素。
redis 的一个特性是,在使用 sismember(key, value)
时,即使 key 不存在,也会正常返回一个 False。
另一个特性是,redis 不会保存一个空的 set。(这个特性在 hash 上也成立)这会导致一个结果就是,假设我需要缓存的 set 本来就是 空的,那么每次我尝试缓存它时,都会得到一个调用异常——sadd 的参数不足,导致调用失败。或者 srem
掉了最后一个元素,这个 key 就被 redis 自动释放了,下次又会触发缓存流程。
和其他使用 hash index 的数据库的区别
当用作主存时,不可避免的要使用持久化配置。那么问题便是,这时的 redis,和使用了 hash index
的 MySQL 或者 MongoDB 有何区别呢?在功能相对弱势的情况下,还有什么性能上的优势吗?
- 全内存支持
这依然是最重要的。
- 单线程连接
redis 使用单线程的异步连接服务器,而不是像 MySQL 一样每个连接一个线程。因此在连接数极大,或频繁新建、断开连接的情景下性能不会明显下降。MySQL 企业版或其他第三方分支(如 AliSQL)可以提供线程池来处理这个问题。或者一个反向代理也可以处理这种问题。
糖
replace
3.0 以前,直接替换一个 set 的方法是使用事务,先删后加。3.0 后则有了 restore
+ replace
参数的替代方法。其中序列化值需要通过第三方模块来生成。这种方式避免了事务的使用,以 sadd(key, list(range(10)))
为例速度可以快一倍(没算生成序列化值的时间)。
内建方法
Python 的 RestictRedis 对象支持一些字典的内建方法:
__delitem____getitem____setitem__
这使得其可以像字典一样被使用。但需注意,仅支持 String 类型或不存在的 key,因为它实际是调用的 GET
、SET
等方法。
PipeLine 对象则支持以下方法:
__enter____exit____len__
可以用于使用 with
语句和检查已经进入管道的命令的数量。