redis
1.查看配置文件、命令工具
- cd /usr/local/bin
- redis-server redis 服务器
- redis-cli redis 命令行客户端
- redis-benchmakr 性能测试工具
- redis-check-aof AOF文件修复工具
- redis-check-rdb RDB文件检索工具
- sudo vim /etc/redis/redis.conf 查看配置
- dir /var/lib/redis 数据文件储存路径
- logfile “/var/log/redis/redis-server.log” 日志文件
- 个人习惯
- ps aux |grep redis 查看进程
- sudo kill -9 pid 杀死进程
- sudo redis-server /etc/redis/…conf 指定加载配置文件
- select 10 切换数据库
2.string类型
(1)增
- set key value 设置键值
- setex key seconds value 设置键值及过期时间,以秒为单位
- mset key1 value1 key2 value2 … 设置多个键值
- incr 计数加1
- decr 计数减1
- incrby 计数加n
(2)获取
1 get key
2 mget key
(3)健命令
- keys * 查看所有键
- keys a* 查看名称中包含a的健
- exists key1 判断键是否存在,如果存在返回
1
,不存在返回0
- type key 查看键对应的
value
的类型 - del key1 key2 … 删除键及对应值
- expire key seconds 设置过期时间,以秒为单位
- ttl key 查看有效时间,以秒为单位
3.hash类型
(1)增、修
- hset key field value 设置单个属性
- hset key field1 value1 filed2 value2 … 设置多个属性
(2)获取
- hget key field 获取⼀个属性的值
- hmget key field1 field2 … 获取多个属性的值
(3)删除
- 删除整个hash键及值,使⽤del命令
- hdel key field1 field2 … 删除属性,属性对应的值会被⼀起删除
4.list类型
(1)增加
- lpush key value1 value2 …在左侧插⼊数据
- rpush key value1 value2 …在右侧插⼊数据
- linsert key before 或after b a 在指定元素的前或后插⼊新元素
- lset 从左修改元素
(2)获取
- lrange key start stop 返回列表⾥指定范围内的元素
start
、stop
为元素的下标索引- 索引从左侧开始,第⼀个元素为0
- 索引可以是负数,表示从尾部开始计数,如
-1
表示最后⼀个元素
- lset key index value 设置指定索引位置的元素值
(3)删除
- lrem key count value 删除指定元素
- 将列表中前
count
次出现的值为value
的元素移除 - count > 0: 从头往尾移除
- count < 0: 从尾往头移除
- count = 0: 移除所有
- 将列表中前
- ltrim key start stop 修剪(截取) 在[start stop]区间内的元素,区间外的元素全部删除
- lpop 从左删除元素
- rpop 从右删除元素
5.set类型
- sadd key member1 member2 … 添加元素
- smembers key 返回所有元素
- srem key 删除指定元素
6.zset类型
-
zadd key score1 member1 score2 member2 … 添加
- sorted set,有序集合
- 元素为string类型
- 元素具有唯⼀性,不重复
- 每个元素都会关联⼀个double类型的score,表示权重,通过权重将元素从⼩到⼤排序
- 说明:没有修改操作
- zrange key start stop 返回指定范围索引
- zrevrange 反向变立元素
- zrangebyscore key min max 返回
score
值在min
和max
之间的成员 - zscore key member 返回成员
member
的score
值
- zrem key member1 member2 … 删除指定元素
- zremrangebyscore key min max 删除权重在指定范围的元素
7.redis-py的使用
from redis import StrictRedis # 创建redis实例对象 redis默认会对数据进行utf-8编码 redis_client = StrictRedis(host='127.0.0.1', port=6379, db=0, decode_responses=True) # 操作语法和官方命令一样 redis_client.set('name', 'zs', ex=10) print(redis_client.get('name')) # 多值操作 redis_client.hmset('user:1', {'name': 'zs', 'age': 20}) print(redis_client.hmget('user:1', ['name', 'age']))
8.redis事务
基本语法
- multi
- 开启事务, 后续的命令会被加入到同一个事务中
- 事务中的操作会发给服务端, 但是不会立即执行, 而是放到了该事务的对应的一个队列中, 服务端返回QUEUED
- exec
- 执行EXEC后, 事务中的命令才会被执行
- 事务中的命令出现错误时, 不会回滚也不会停止事务, 而是继续执行
- discard
- 取消事务, 事务队列会清空, 客户端退出事务状态
ACID
- 原子性
- 不支持
- 不会回滚并且继续执行
- 隔离性
- 支持
- 事务中命令顺序执行, 并且不会被其他客户端打断 (先EXEC的先执行)
- 单机redis读写操作使用 单进程单线程
- 持久性
- 支持, 但相比Mysql, redis数据易丢失
- 一致性
- 不支持
from redis import StrictRedis # 创建redis客户端 redis_client = StrictRedis() # 创建管道对象 默认会开启事务 pipe = redis_client.pipeline() # pipe的后续操作会被放入事务中 不会立即执行 a = pipe.set('name', 'zhangsan') b = pipe.get('name') # 提交事务 提交才会执行事务中的命令 c = pipe.execute() print(a) print(b) print(c)
注意点:
- 创建管道后, 默认会开启事务
- 放入事务中的命令在执行
execute
方法后才会执行
9.redis乐观锁
基本语法
- watch
- redis实现的乐观锁
- 机制
- 事务开启前, 设置对数据的监听, EXEC时, 如果发现数据发生过修改, 事务会自动取消(DISCARD)
- 事务EXEC后, 无论成败, 监听会被移除
watch mykey #设置监视值 multi #开启事务 set mykey 10 exec #如果mykey的值在执行exec之前发生过改变, 则该事务会取消(客户端可以在发生碰撞后不断重试)
应用场景
- 避免并发引起的资源抢夺问题
# 需求: 使用redis实现秒杀功能 (防止超卖) from redis import StrictRedis, WatchError # 1.创建客户端对象 redis_cli = StrictRedis(decode_responses=True) # 2.创建管道对象 pipeline = redis_cli.pipeline() # 监听的key key = "count" while True: # 3.使用watch命令监视键值对数据 pipeline.watch(key) # 4.获取库存 count = redis_cli.get(key) try: if int(count) > 0: # 5.手动开启事务 # 注意:使用了watch命令,管道对象就不会自动开启事务,需要手动开启 pipeline.multi() # 6.在事务内部修改数据【减库存】 pipeline.decr(key) # 7.提交事务 pipeline.execute() print("下单成功") else: print("库存不足") # 移除监视 pipeline.reset() break except WatchError as e: print("库存不足: {}".format(e)) continue
10.redis悲观锁
基本语法
- SETNX命令
- 键不存在才会设置成功
- 多个客户端抢夺, 只有一个可以设置成功(获取锁, 获取操作数据的权限)
setnx lock1 1 # 键不存在,才会设置成功
1
setnx lock1 1 # 键存在, 无法设置, 返回0
0
# 需求:使用redis悲观锁解决超卖问题
from redis import StrictRedis
# 1.创建redis客户端对象
redis_cli = StrictRedis(decode_responses=True)
# 2.设置锁的键
key = "user:lock"
while True:
# 3.争夺锁资源
lock = redis_cli.setnx(key, 66)
if lock:
# 给锁设置有效期,防止忘记移除锁资源,出现死锁
redis_cli.expire(key, 5)
# 4.获取库存
count = redis_cli.get("count")
if int(count) > 0:
# 5.修改库存
redis_cli.decr("count")
print("下单成功")
else:
print("库存不足")
# 6.移除锁资源
redis_cli.delete(key)
break
11.非事务性管道
- redis的事务和管道可以分离, 可以 不使用事务的情况下单独使用管道
- 管道可以实现 一次发送多条命令给redis服务器, 提高传输效率
from redis import StrictRedis
# 1.创建redis客户端对象
# decode_responses=True 将bytes类型转换成string
redis_cli = StrictRedis(decode_responses=True)
# 2.创建非事务性管道: transaction=False
pipeline = redis_cli.pipeline(transaction=False)
# 3.往管道中添加命令'
a = pipeline.set("user6", "zs")
b = pipeline.get("user6")
# 4.执行管道中的命令
ret = pipeline.execute()
print(a)
print(b)
print(ret)
redis分布式
1.数据库主从
基本介绍
- 作用
- 数据备份
- 读写分离
- 特点
- 只能一主多从 (mysql可以多主多从)
- 从数据库不能写入 (mysql可以写)
配置主
-
查看当前主机的ip地址
-
修改etc/redis/redis.conf文件
sudo vi redis.conf
bind 192.168.26.128 -
重启redis服务
sudo service redis stop
redis-server redis.conf
配置从
-
复制etc/redis/redis.conf文件
sudo cp redis.conf ./slave.conf
-
修改redis/slave.conf文件
sudo vi slave.conf
-
编辑内容
bind 192.168.26.128
slaveof 192.168.26.128 6379
port 6378 -
redis服务
sudo redis-server slave.conf
-
查看主从关系
redis-cli -h 192.168.26.128 info Replication
2.哨兵模式
1. 基本介绍
- 作用
- 监控redis服务器的运行状态, 可以进行 自动故障转移(failover), 实现高可用
- 与 数据库主从 配合使用的机制
- 特点
- 独立的进程, 每台redis服务器应该至少配置一个哨兵程序
- 监控redis主服务器的运行状态
- 出现故障后可以向管理员/其他程序发出通知
- 针对故障,可以进行自动转移, 并向客户端提供新的访问地址
内部机制 (了解)
- 流言协议
- 当某个哨兵程序ping 发现监视的主服务器下线后(心跳检测), 会向监听该服务器的其他哨兵询问, 是否确认主服务器下线, 当 确认的哨兵数量 达到要求(配置文件中设置)后, 会确认主服务器下线(客观下线), 然后进入投票环节
- 投票协议
- 当确认主服务器客观下线后, 哨兵会通过 投票的方式 来授权其中一个哨兵主导故障转移处理
- 只有在 大多数哨兵都参加投票 的前提下, 才会进行授权, 比如有5个哨兵, 则需要至少3个哨兵投票才可能授权
- 目的是避免出现错误的故障迁移
- 建议最低配置
- 至少在3台服务器上分别启动至少一个哨兵
- 如果只有一台, 则服务器宕机后, 将无法进行故障迁移
- 如果只有两台, 一旦一个哨兵挂掉了, 则投票会失败
2. 相关配置
- 哨兵模式是Redis官方自带的工具, 默认安装
- 哨兵模式的配置模板在Redis的安装包中, 默认名为
sentinel.conf
# 在/etc/redis中创建三个配置文件
# sentinel_26380.conf
port 26380
sentinel monitor mymaster 127.0.0.1 6381 2
sentinel down-after-milliseconds mymaster 30000
daemonize yes
logfile "/var/log/redis-sentinel-26380.log"
- 启动哨兵模式
sudo redis-sentinel sentinel.conf
from redis.sentinel import Sentinel, StrictRedis
# 1.构建哨兵连接信息
SENTINEL_HOSTS = [
("192.168.243.157", 26380),
("192.168.243.157", 26381),
("192.168.243.157", 26382),
]
# 2.创建哨兵客户端对象
sentinel = Sentinel(SENTINEL_HOSTS)
# 3.准备哨兵监视的主服务器别名
# 注意:需要和配置文件中监视的主服务器别名保持一致
master_name = 'mymaster'
# 4.根据监视的服务器别名获取主、从的redis客户端对象
# 主库
master = sentinel.master_for(master_name, decode_responses=True)
# 从库
slave = sentinel.slave_for(master_name, decode_responses=True)
# 写
master.set("name", "curry1")
# 读取
print(slave.get("name"))
3.集群
1. 基本介绍
- 多个节点共同保存数据
- 作用
- 扩展存储空间
- 提高吞吐量, 提高写的性能
- 和单机的不同点
- 不再区分数据库, 只有0号库, 单机默认0-15
- 不支持事务/管道/多值操作
- 特点
- 要求至少 三主三从
- 要求必须开启 AOF持久化
- 自动选择集群节点进行存储
- 默认集成哨兵, 自动故障转移
2. 相关配置
- 在前边课程中已经讲解过Redis集群的配置, 此处以回顾为主
# 每个节点分别配置ip/端口, 注释表示接受所有请求
# bind 127.0.0.1
port 6379
# 集群配置
cluster-enabled yes # 开启集群
cluster-config-file nodes-7000.conf # 节点日志文件
cluster-node-timeout 15000 # 节点超时时长 15秒
# 开启AOF 及相关配置
appendonly yes
创建集群
-
CentOS虚拟机中已经配置好了6个集群节点(三主三从)的配置文件, 存放在
/etc/redis
目录下, 分别是7000.conf
到7005.conf
6个文件 -
redis-trib.rb create --replicas 1 192.168.105.140:7000 192.168.105.140:7001 192.168.105.140:7002 192.168.105.140:7003 192.168.105.140:7004 192.168.105.140:7005
from rediscluster import RedisCluster
# 带卡槽的数据库连接信息
startup_nodes = [
{"host": "192.168.243.157", "port": 7000},
{"host": "192.168.243.157", "port": 7001},
{"host": "192.168.243.157", "port": 7002},
]
# 方案1:通过带卡槽的redis数据库对象,启动集群
# 1.创建集群的客户端对象
cluster = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)
# 方案2:蔓延机制,根据任意一个ip和端口能够获取集群所有的节点
# cluster = RedisCluster(host="192.168.243.157", port=7005, decode_responses=True)
# 2.设置值
cluster.set("user777", "curry")
print(cluster.get("user777"))
redis持久化
redis可以将数据写入到磁盘中,在停机或宕机后,再次启动redis时,将磁盘中的备份数据加载到内存中恢复使用。这是redis的持久化。持久化有如下两种机制。
RDB 快照持久化
redis可以将内存中的数据写入磁盘进行持久化。在进行持久化时,redis会创建子进程来执行。
redis默认开启了快照持久化机制。
进行快照持久化的时机如下
-
定期触发
redis的配置文件
# save # # Will save the DB if both the given number of seconds and the given # number of write operations against the DB occurred. # # In the example below the behaviour will be to save: # after 900 sec (15 min) if at least 1 key changed # after 300 sec (5 min) if at least 10 keys changed # after 60 sec if at least 10000 keys changed # # Note: you can disable saving completely by commenting out all "save" lines. # # It is also possible to remove all the previously configured save # points by adding a save directive with a single empty string argument # like in the following example: # # save "" save 900 1 save 300 10 save 60 10000
-
BGSAVE
执行
BGSAVE
命令,手动触发RDB持久化 -
SHUTDOWN
关闭redis时触发
AOF 追加文件持久化
redis可以将执行的所有指令追加记录到文件中持久化存储,这是redis的另一种持久化机制。
redis默认未开启AOF机制。
redis可以通过配置如下项开启AOF机制
appendonly yes # 是否开启AOF
appendfilename "appendonly.aof" # AOF文件
AOF机制记录操作的时机
# appendfsync always # 每个操作都写到磁盘中
appendfsync everysec # 每秒写一次磁盘,默认
# appendfsync no # 由操作系统决定写入磁盘的时机
使用AOF机制的缺点是随着时间的流逝,AOF文件会变得很大。但redis可以压缩AOF文件。
结合使用
redis允许我们同时使用两种机制,通常情况下我们会设置AOF机制为everysec 每秒写入,则最坏仅会丢失一秒内的数据。