Redis and redis-py
2019年9月3日大约 4 分钟
Abstract
Redis(Remote Dictionary Server) server 的启动:
redis-server.exe redis.windows.conf
安装 redis-py:
pip install redis
redis 提供两个类 Redis 和 StrictRedis 用于实现 Redis 的命令,StrictRedis 用于实现大部分官方的命令,并使用官方的语法和命令,Redis 是 StrictRedis 的子类,用于向后兼容旧版本的 redis-py。
可以使用 Redis 可视化工具 RDM(redis deaktop manager)
Redis 简述
什么是 Redis?有什么优缺点?
- Redis本质上是一个 key-value 类型的内存数据库,整个数据库都在内存中加载,通过异步操作可以持久化到磁盘中
- Redis的性能十分出色,是已知的性能最快的 key-value DB(每秒大概处理10W次IO操作)
- Redis 拥有丰富的数据结构(5 种,分别是 string, list, hash, set, zset)
- Redis 丰富的数据结构给了它很多的应用,如 celery 就可以维护一个高性能的消息队列(list)
- 不同于 memcached, redis 的单个 value 可以保存的最大数据限制是 1GB(memcached 是 1M)
- 缺点在于 redis 的数据存储受到物理内存的限制,不能做海量的数据场景
Redis 原理
数据淘汰策略
当达到内存最大限制的时候,Redis 会采用一些策略(maxmemory-policy配置), 来进行数据淘汰:
- noeviction:默认策略,不淘汰,达到最大的内存限制的时候,如果再请求更多的数据,直接报错
- allkeys-lru:LRU 策略,删除最近最少使用的 key, 针对于所有的key
- volatile-lru:设置的 expire 的key使用 LRU
- allkeys-random:随机删除一部分key
- volatile-random:对设置的 expire 的key随机删除
- volatile-ttl:对设置 expire 的key使用,优先删除剩余时间短的key
对于这六种数据淘汰策略的使用场景可以归纳为:
- 如果分为热数据和冷数据的场景(所有key中有一部分经常被读写),使用 LRU 方法
- 如果是循环读所有的 key, 那么就使用 allkeys-random 策略
Redis 生产适用场景
- session cache 会话缓存 一般业界使用 memcached, 但是 redis 多了持久化功能,可以维护严格要求一致性的缓存
- FPC 全页缓存
- redis queues 如 celery 队列可以使用 redis作为broker
- 排行榜、计数器 使用了 redis 中的递增和递减操作
- 原子操作、事务操作 事务是一个单独的隔离操作,事务中的所有命令都会序列化、按顺序地执行; 事务在执行的过程中不会被其他客户端发送过来的命令打断; 事务是一个原子操作,事务中的所有命令要么全部被执行,要么全部不执行。 事务相关的命令:
MULTI, EXEC, DISCARD, WATCH
Redis 优化
设置key的过期时间 使用
expire
命令,如果想要永久有效,那么就使用presist
.使用散列表 比如说有一个场景,需要存储用户的账户、密码等信息,尽量不给每一个字段去设置单独的key, 而是将他们一起存储于一张散列表里面。
Redis 分布式锁
分布式锁
分布式的流行使得原单机部署情况下的并发控制策略失效。
分布式锁大致分为三种:
- 数据库乐观锁
- 基于 redis 的分布式锁
- 基于 ZooKeeper 的分布式锁
分布式锁的实现条件:
- 互斥性,任何时候只能有一个客户端持有锁
- 可靠性,尽量避免死锁
- 一致性,锁只能由加锁人解锁,不能产生A的加锁被B用户解锁的情况
Redis 分布式集群
目前已知的可以通过 proxy 来实现
Redis 分布式锁
基本上实现如下,主要使用三个命令:
# SETNX
SETNX key val
# EXPIRE
expire key timeout
# DELETE
delete key
redis 锁的实现思路基本上是:
- setnx加锁,并设置超时时间,这时候锁的 value 值就是一个随机生成的 UUID
- 获取锁和超时时间
- 释放锁的时候根据 UUID 判断,而后 DELETE 删除(注意这里要注意原子性)
Redis Cluster 槽
redis-py
StrictRedis()
初始化 Redis:
from redis import StrictRedis
def create_redis_client():
redis_client = StrictRedis(
host='localhost',
port=6379,
password=None)
return redis_client
也可以使用 Redis()
类初始化,如果遇到了向后兼容的问题。
append()
redis_client.append(key, value)
如果 key 不存在则创建。