Redis复习——事务持久化主从高可用集群
Posted 胖虎是只mao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis复习——事务持久化主从高可用集群相关的知识,希望对你有一定的参考价值。
一、数据类型
- 字符串
set get incr incrby incrby a -1
- hash {}
hset hmset hget hgetall
- list []
lpush rpush lpop rpop
- set 集合
sadd smembers sismember
- zset (sorted set) 有序集合
zadd zscore zrange
redis中的value,可以有多种数据类型,但是每种数据类型不允许嵌套,也就是不能多层使用。每种数据类型中,只能是字符串。只是对单一的字符串进行了一次封装,组成了多种类型
{
'a': 'xxx',
'b': {"foo": "100", "":"", xx},
'c': ["", "","" ], 有序 可以重复
'd': set(), 无序 不重复
'e': zset() 有序 值不重复 分数可以相同
值:权重 分数score
"itcast": 19 "python":100 "tbd39": 100
"itcast": 0 "python":0 "tbd39": 0 相同为0 排序按值的字符顺序,—————字母的先后顺序
}
zset (sorted set)
redis 会按照权重(分数),由小到大进行排列
只对数据记录级别设置有效期 不对内部的具体元素设置。只能让记录过期
setex 只对字符串类型生效
expires 对所有类型通用
二、redis 事务
基本事务指令
Redis提供了一定的事务支持,可以保证一组操作原子执行不被打断,但是如果执行中出现错误,事务不能回滚,Redis未提供回滚支持。
multi
开启事务exec
执行事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a 100
QUEUED // 表示被添加到队列中,其实并没有执行
127.0.0.1:6379> set b 200
QUEUED
127.0.0.1:6379> get a
QUEUED
127.0.0.1:6379> get b
QUEUED
127.0.0.1:6379> exec // 开始执行
1) OK
2) OK
3) "100"
4) "200"
使用multi开启事务后,操作的指令并未立即执行,而是被redis记录在队列中,等待一起执行。当执行exec命令后,开始执行事务指令,最终得到每条指令的结果。
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set c 300
QUEUED
127.0.0.1:6379> hgetall a
QUEUED
127.0.0.1:6379> set d 400
QUEUED
127.0.0.1:6379> get d
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
4) "400"
127.0.0.1:6379>
如果事务中出现了错误,事务并不会终止执行,而是只会记录下这条错误的信息,并继续执行后面的指令。所以事务中出错不会影响后续指令的执行。
三、Python客户端操作
在Redis的Python 客户端库redis-py中,提供了pipeline (称为流水线 或 管道),该工具的作用是:
- 在客户端统一收集操作指令
- 补充上multi和exec指令,当作一个事务发送到redis服务器执行
from redis import StrictRedis
r = StrictRedis.from_url('redis://127.0.0.1:6381/0') // 链接对象
pl = r.pipeline() // 事务已经包含在内
pl.set('a', 100) // 将这些指令放入管道
pl.set('b', 200)
pl.get('a')
pl.get('b')
ret = pl.execute() // 指令一次性执行
print(ret) # [True, True, b'100', b'200']
watch监视
exec执行前,提前发现错误语句,进行终止。跟乐观锁的作用一样
若在构建的redis事务在执行时依赖某些值,可以使用watch对数据值进行监视。
127.0.0.1:6379> set stock 100
OK
127.0.0.1:6379> watch stock // 监视stock
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby stock -1
QUEUED
127.0.0.1:6379> incr sales
QUEUED
127.0.0.1:6379> exec
1) (integer) 99
2) (integer) 1
事务开始到exec执行前,没有任何人对stock值进行改变
事务exec执行前被监视的stock值未变化,事务正确执行。
127.0.0.1:6379> set stock 100
OK
127.0.0.1:6379> watch stock // 进行监视
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby stock -1
QUEUED
127.0.0.1:6379> incr sales
QUEUED
并发情况下,此时在另一个客户端修改stock的值,执行
127.0.0.1:6379> incrby stock -2
(integer) 98
当第一个客户端再执行exec时
127.0.0.1:6379> exec
(nil)
表明事务需要监视的stock值发生了变化,事务不能执行了。
注意:Redis Cluster 集群不支持事务,multi和exec、watch指令只能在单机的方式里用
四、 Redis持久化
redis可以将数据写入到磁盘中,在停机或宕机后,再次启动redis时,将磁盘中的备份数据加载到内存中恢复使用。这是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 //在900s 之内 如果进行了至少一次写操作,那么就会执行一次快照操作,会将内存数据刷到磁盘中
save 300 10
save 60 10000
save 900 1
在多少s 只内,至少执行多少次改变操作后,触发一次快照持久化操作
-
BGSAVE 手动执行命令
执行
BGSAVE
命令,手动触发RDB持久化
-
SHUTDOWN
关闭redis时触发
AOF 追加文件持久化(append only file)
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 每秒写入,则最坏仅会丢失一秒内的数据。
应用场景:
redis保存数据时,如果不保存业务数据,仅仅当作缓存使用,可以关闭全部的持久化方式,性能可以提升
如果需要保存业务数据,就需要开启持久化。
五、 redis 主从
redis本身自带,配置即可
redis 只能是一主多从,不能有多主,但是就下面从,也可以作为主,类似于树
① slaveof
可以自动使某台机器变成从
② 配置文件中声明
查看当前机器是主还是从的信息:info Replication
六、redis 高可用
为了保证redis最大程度上能够使用,redis提供了主从同步+Sentinel
哨兵机制。
redis原生提供高可用,依赖于哨兵机制
哨兵只是一段程序
哨兵文件:
redis 哨兵的作用是 帮助看护主从机器,能够做自动切换
Sentinel 哨兵 (类似于keepalived)
https://redis.io/topics/sentinel
redis提供的哨兵是用来看护redis实例进程的,可以自动进行故障转移,其功能如下:
- 监控。Sentinel 会不断检查您的主实例和副本实例是否按预期工作。
- 通知。Sentinel 可以通过 API 通知系统管理员或其他计算机程序,其中一个受监控的 Redis 实例出现问题。
- 自动故障转移。如果 master 没有按预期工作,Sentinel 可以启动一个故障转移过程,其中一个副本被提升为 master,其他额外的副本被重新配置为使用新的 master,并且使用 Redis 服务器的应用程序会被告知要使用的新地址连接时。
- 配置提供程序。Sentinel 充当客户端服务发现的权威来源:客户端连接到 Sentinel 以请求负责给定服务的当前 Redis 主节点的地址。如果发生故障转移,Sentinels 将报告新地址。
在redis安装后,会自带sentinel哨兵程序,修改sentinel.conf
配置文件
开启哨兵服务之后,python程序对接redis,直接跟哨兵对接,而不再是redis了。哨兵会告知,主从信息
bind 127.0.0.1 //哨兵IP端口
port 26380
daemonize yes // 以后台守护进程的方式一直运行
logfile /var/log/redis-sentinel.log // 日志
sentinel monitor mymaster 127.0.0.1 6380 2 // 哨兵守护该IP机器,
sentinel down-after-milliseconds mymaster 30000 // 心跳的频率 超过3w 毫秒
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000 // 缓冲时间,时间过后若还未恢复,进行故障转移
sentinel monitor mymaster 127.0.0.1 6380 2
说明
mymaster 为sentinel监护的redis主从集群起名
127.0.0.1 6300 为主从中任一台机器地址
2 表示有两台以上的sentinel认为某一台redis宕机后,才会进行自动故障转移,防止因为哨兵自身问题,导致自动故障转移,需要多数哨兵认为才行。
启动方式:
redis-sentinel sentinel.conf
master对外通讯用6379 端口,但是对内,和哨兵通讯时用其他端口,如:16379
slave1 -> master 6379 16379->sentinel1 心跳机制
|
sentienl2 slave2 master->slave (sentinel3)
|
slave3 slave4
高可用方案注意事项
- 至少三个sentinel以上
- sentinel要分散运行在不同的机器上。保证哨兵不会全部崩溃
Python客户端使用
# redis 哨兵
REDIS_SENTINELS = [
('127.0.0.1', '26380'),
('127.0.0.1', '26381'),
('127.0.0.1', '26382'),
]
REDIS_SENTINEL_SERVICE_NAME = 'mymaster'
from redis.sentinel import Sentinel
_sentinel = Sentinel(REDIS_SENTINELS) // 直接操作sentinel 哨兵即可,可以直接从上面三太机器中,创建 主 从机器。具体主从分配方式,由redsi自身决定
redis_master = _sentinel.master_for(REDIS_SENTINEL_SERVICE_NAME) // 获取redis 客户端 从该集群中拿出主
redis_slave = _sentinel.slave_for(REDIS_SENTINEL_SERVICE_NAME) //// 获取redis 客户端 从该集群中拿出从
使用示例
写数据,只能在master里写,不能在slave中写
# 读数据,master读不到去slave读
try:
real_code = redis_master.get(key)
except ConnectionError as e:
real_code = redis_slave.get(key)
# 写数据,只能在master里写
try:
current_app.redis_master.delete(key)
except ConnectionError as e:
logger.error(e)
七、 redis集群
https://redis.io/topics/partitioning
Reids Cluster集群方案,内部已经集成了sentinel机制来做到高可用。
数据分片的逻辑:客户端数据存放到主服务器上时,不需要指定哪台,redis自身会根据传入数据的 hash
和槽位 进行数学计算,
开启redis实例之后,执行redis-trib.rb
文件,可以将多台redis实例,组成一个集群。具体,如何组成,有redis自身内部进行决定
redis-cluster-py
python redis集群扩展包
pip install redis-cluster-py
Python客户端
# redis 集群
REDIS_CLUSTER = [
{'host': '127.0.0.1', 'port': '7000'},
{'host': '127.0.0.1', 'port': '7001'},
{'host': '127.0.0.1', 'port': '7002'},
]
# 将开启的机器随机配置几台,放到这边即可,redis会根据这几台机器,找到其他开启的全部机器,并区分主从
from rediscluster import StrictRedisCluster
redis_cluster = StrictRedisCluster(startup_nodes=REDIS_CLUSTER)
# 可以将redis_cluster就当作普通的redis客户端使用
redis_master.delete(key)
链接集群的方式和存储数据的槽位
注意:
- redis cluster 不支持事务
- redis cluster 不支持多键操作,如mset
5 用途
- 缓存
- 持久存储
数据库的统计冗余字段 放到 redis中保存
以上是关于Redis复习——事务持久化主从高可用集群的主要内容,如果未能解决你的问题,请参考以下文章
浅谈小白如何读懂Redis高速缓存与持久化并存及主从高可用集群
浅谈小白如何读懂Redis高速缓存与持久化并存及主从高可用集群