- redis笔记
redis是什么,是一种非关系型数据库,统称nosql。
- 1、redis受益于“持久化”可以做存储(storge),memcached只能做缓存(cache)
- 2、redis有多种数据结构,memcached只有一种类型
字符串(string)
安装最新稳定版
# 源码安装redis-4.0
# 下载
wget http://download.redis.io/releases/redis-4.0.1.tar.gz
# 解压
tar zxvf redis-4.0.1.tar.gz
cd redis-4.0.1
# 编译
make && make install
/usr/local/bin/redis-server -v
- redis-benchmark redis性能测试工具
- redis-check-aof 检查aof日志的工具
- redis-check-rdb 检查rdb日志的工具
- redis-cli 连接用的客户端
- redis-server 服务进程
# 地址
bind 0.0.0.0
# 保护模式
protected-mode no
# 端口
port 6380
tcp-backlog 511
timeout 0
tcp-keepalive 300
# 守护进程模式
daemonize yes
supervised no
# 进程id文件
pidfile /usr/local/redis/run/redis.pid
# 日志等级
loglevel notice
# 日志位置
logfile /usr/local/redis/logs/redis.log
# 数据个数
databases 16
always-show-logo yes
# 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
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
# rdb开启
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
# 主从
# +------------------+ +---------------+
# | Master | ---> | Replica |
# | (receive writes) | | (exact copy) |
# +------------------+ +---------------+
acllog-max-len 128
# 密码
requirepass omgzui
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
oom-score-adj no
oom-score-adj-values 0 200 800
# aof
appendonly yes
appendfilename "appendonly.aof"
# appendfsync always
appendfsync everysec
# appendfsync no
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
# 从服务器
# cluster-announce-ip 10.1.1.5
# cluster-announce-port 6379
# cluster-announce-bus-port 6380
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
- keys 查询
在redis里,允许模糊查询key
有3个通配符 - ? []
-: 通配任意多个字符
?: 通配单个字符
[]: 通配括号内的某1个字符
- keys 查询
- del 删除
- rename 重命名
- move 移到另外一个库
- randomkey 随机
- exists 存在
- type 类型
- ttl 剩余生命周期
- expire 设置生命周期
- persist 永久有效
- flushdb 清空
-
set
- set name shengj -> OK
-
get
- get name -> "shengj"
-
del
- del name -> (integer) 1
- get name -> (nil)
-
mset
- mset name shengj age 23 sex male -> OK
-
mget
-
mget age sex
1) "23" 2) "male"
-
-
setrange
- setrange sex 2 1 将sex的第3个字符改成1 -> (integer) 4
- get sex -> "ma1e"
-
append
- append name GG -> (integer) 8
- get name -> "shengjGG"
-
getrange
- getrange name 1 2 -> "he"
-
incr 自增
-
incrby 自增一个量级
-
incrbyfloat 自增一个浮点数
-
decr 递减
-
decrby 递减一个量级
-
decrbyfloat 递减一个浮点数
-
setbit 设置二进制位数
-
getbit 获取二进制表示
-
bitop 位操作
-
rpush 右边插入
- rpush list item1 -> (integer) 1
- rpush list item2 -> (integer) 2
- rpush list item3 -> (integer) 3
-
lrange 列出链表值
-
lrange list 0 -1
1) "item1" 2) "item2" 3) "item3"
-
-
lindex
- lindex list 1 -> "item2"
-
lpop
-
lpop list -> "item1"
-
lrange list 0 -1
1) "item2" 2) "item3"
-
-
ltrim
- ltrim list 3 0 -> OK
- lrange list 0 -1 -> (empty list or set)
-
lpush 左边插入
-
rpop 右边删除
-
lrem
-
sadd 增加
- sadd set item1 -> (integer) 1
- sadd set item2 -> (integer) 1
- sadd set item3 -> (integer) 1
- sadd set item1 -> (integer) 0 已存在
-
smembers 所有集合元素
-
smembers set
1) "item3" 2) "item2" 3) "item1"
-
-
sismember 存不存在
- sismember set item1 -> (integer) 1
- sismember set item -> (integer) 0 不存在
-
srem 移除元素
-
srem set item1 -> (integer) 1
-
smembers set
1) "item3" 2) "item2"
-
-
spop 随机删除一个元素
-
srandmember 随机获取一个元素 -> 抽奖
-
scard 多少个元素
-
smove 移动
-
sinter 交集
-
sinterstore 交集并赋值
-
suion 并集
-
sdiff 差集
-
hset 设置一个
- hset hash key1 value1 -> (integer) 1
- hset hash key2 value2 -> (integer) 1
- hset hash key3 value3 -> (integer) 1
- hset hash key1 value1 -> (integer) 0 已存在
-
hgetall 获取全部
-
hgetall hash
1) "key1" 2) "value1" 3) "key2" 4) "value2" 5) "key3" 6) "value3"
-
-
hget 获取一个
- hget hash key1 -> "value1"
-
hdel 删除
-
hdel hash key1 -> (integer) 1
-
hgetall hash
1) "key2" 2) "value2" 3) "key3" 4) "value3"
-
-
hmset 设置多个
-
hmget 获取多个
-
hlen 个数
-
hexists 是否存在增长
-
hinrby 增长
-
hkeys 所有的key
-
hvals 所有的值
-
zadd 增加
- zadd zset 100 item1 -> (integer) 1
- zadd zset 200 item2 -> (integer) 1
- zadd zset 300 item3 -> (integer) 1
- zadd zset 100 item1 -> (integer) 0 已存在
-
zrange 按分值排序
-
zrange zset 0 -1 withscores
1) "item1" 2) "100" 3) "item2" 4) "200" 5) "item3" 6) "300"
-
-
zrangebyscore 按分值的一部分排序
-
zrangebyscore zset 0 200 withscores
1) "item1" 2) "100" 3) "item2" 4) "200"
-
-
zrem 删除
-
zrem zset item1 -> (integer) 1
-
zrange zset 0 -1 withscores
1) "item2" 2) "200" 3) "item3" 4) "300"
-
-
zrank 排名升序
-
zremrangebyscore 按分值删除一部分
-
zremrangebyrank 按排名删除一部分
-
zcard 个数
首先,来看一下 Redis 的核心数据类型。Redis 有 8 种核心数据类型,分别是 :
- string 字符串类型;
- list 列表类型;
- set 集合类型;
- sorted set 有序集合类型;
- hash 类型;
- bitmap 位图类型;
- geo 地理位置类型;
- HyperLogLog 基数统计类型。
string 是 Redis 的最基本数据类型。可以把它理解为 Mc 中 key 对应的 value 类型。string 类型是二进制安全的,即 string 中可以包含任何数据。 Redis 中的普通 string 采用 raw encoding 即原始编码方式,该编码方式会动态扩容,并通过提前预分配冗余空间,来减少内存频繁分配的开销。 在字符串长度小于 1MB 时,按所需长度的 2 倍来分配,超过 1MB,则按照每次额外增加 1MB 的容量来预分配。 Redis 中的数字也存为 string 类型,但编码方式跟普通 string 不同,数字采用整型编码,字符串内容直接设为整数值的二进制字节序列。 在存储普通字符串,序列化对象,以及计数器等场景时,都可以使用 Redis 的字符串类型,字符串数据类型对应使用的指令包括 set、get、mset、incr、decr 等。
Redis 的 list 列表,是一个快速双向链表,存储了一系列的 string 类型的字串值。list 中的元素按照插入顺序排列。插入元素的方式,可以通过 lpush 将一个或多个元素插入到列表的头部,也可以通过 rpush 将一个或多个元素插入到队列尾部,还可以通过 lset、linsert 将元素插入到指定位置或指定元素的前后。 list 列表的获取,可以通过 lpop、rpop 从对头或队尾弹出元素,如果队列为空,则返回 nil。还可以通过 Blpop、Brpop 从队头/队尾阻塞式弹出元素,如果 list 列表为空,没有元素可供弹出,则持续阻塞,直到有其他 client 插入新的元素。这里阻塞弹出元素,可以设置过期时间,避免无限期等待。最后,list 列表还可以通过 LrangeR 获取队列内指定范围内的所有元素。Redis 中,list 列表的偏移位置都是基于 0 的下标,即列表第一个元素的下标是 0,第二个是 1。偏移量也可以是负数,倒数第一个是 -1,倒数第二个是 -2,依次类推。 list 列表,对于常规的 pop、push 元素,性能很高,时间复杂度为 O(1),因为是列表直接追加或弹出。但对于通过随机插入、随机删除,以及随机范围获取,需要轮询列表确定位置,性能就比较低下了。 feed timeline 存储时,由于 feed id 一般是递增的,可以直接存为 list,用户发表新 feed,就直接追加到队尾。另外消息队列、热门 feed 等业务场景,都可以使用 list 数据结构。 操作 list 列表时,可以用 lpush、lpop、rpush、rpop、lrange 来进行常规的队列进出及范围获取操作,在某些特殊场景下,也可以用 lset、linsert 进行随机插入操作,用 lrem 进行指定元素删除操作;最后,在消息列表的消费时,还可以用 Blpop、Brpop 进行阻塞式获取,从而在列表暂时没有元素时,可以安静的等待新元素的插入,而不需要额外持续的查询。
set 是 string 类型的无序集合,set 中的元素是唯一的,即 set 中不会出现重复的元素。Redis 中的集合一般是通过 dict 哈希表实现的,所以插入、删除,以及查询元素,可以根据元素 hash 值直接定位,时间复杂度为 O(1)。 对 set 类型数据的操作,除了常规的添加、删除、查找元素外,还可以用以下指令对 set 进行操作。 sismember 指令判断该 key 对应的 set 数据结构中,是否存在某个元素,如果存在返回 1,否则返回 0; sdiff 指令来对多个 set 集合执行差集; sinter 指令对多个集合执行交集; sunion 指令对多个集合执行并集; spop 指令弹出一个随机元素; srandmember 指令返回一个或多个随机元素。 set 集合的特点是查找、插入、删除特别高效,时间复杂度为 O(1),所以在社交系统中,可以用于存储关注的好友列表,用来判断是否关注,还可以用来做好友推荐使用。另外,还可以利用 set 的唯一性,来对服务的来源业务、来源 IP 进行精确统计。
Redis 中的 sorted set 有序集合也称为 zset,有序集合同 set 集合类似,也是 string 类型元素的集合,且所有元素不允许重复。 但有序集合中,每个元素都会关联一个 double 类型的 score 分数值。有序集合通过这个 score 值进行由小到大的排序。有序集合中,元素不允许重复,但 score 分数值却允许重复。 有序集合除了常规的添加、删除、查找元素外,还可以通过以下指令对 sorted set 进行操作。 zscan 指令:按顺序获取有序集合中的元素; zscore 指令:获取元素的 score 值; zrange指令:通过指定 score 返回指定 score 范围内的元素; 在某个元素的 score 值发生变更时,还可以通过 zincrby 指令对该元素的 score 值进行加减。 通过 zinterstore、zunionstore 指令对多个有序集合进行取交集和并集,然后将新的有序集合存到一个新的 key 中,如果有重复元素,重复元素的 score 进行相加,然后作为新集合中该元素的 score 值。 sorted set 有序集合的特点是: 所有元素按 score 排序,而且不重复; 查找、插入、删除非常高效,时间复杂度为 O(1)。 因此,可以用有序集合来统计排行榜,实时刷新榜单,还可以用来记录学生成绩,从而轻松获取某个成绩范围内的学生名单,还可以用来对系统统计增加权重值,从而在 dashboard 实时展示。
Redis 中的哈希实际是 field 和 value 的一个映射表。 hash 数据结构的特点是在单个 key 对应的哈希结构内部,可以记录多个键值对,即 field 和 value 对,value 可以是任何字符串。而且这些键值对查询和修改很高效。 所以可以用 hash 来存储具有多个元素的复杂对象,然后分别修改或获取这些元素。hash 结构中的一些重要指令,包括:hmset、hmget、hexists、hgetall、hincrby 等。 hmset 指令批量插入多个 field、value 映射; hmget 指令获取多个 field 对应的 value 值; hexists 指令判断某个 field 是否存在; 如果 field 对应的 value 是整数,还可以用 hincrby 来对该 value 进行修改。
Redis 中的 bitmap 位图是一串连续的二进制数字,底层实际是基于 string 进行封装存储的,按 bit 位进行指令操作的。bitmap 中每一 bit 位所在的位置就是 offset 偏移,可以用 setbit、bitfield 对 bitmap 中每个 bit 进行置 0 或置 1 操作,也可以用 bitcount 来统计 bitmap 中的被置 1 的 bit 数,还可以用 bitop 来对多个 bitmap 进行求与、或、异或等操作。 bitmap 位图的特点是按位设置、求与、求或等操作很高效,而且存储成本非常低,用来存对象标签属性的话,一个 bit 即可存一个标签。可以用 bitmap,存用户最近 N 天的登录情况,每天用 1 bit,登录则置 1。个性推荐在社交应用中非常重要,可以对新闻、feed 设置一系列标签,如军事、娱乐、视频、图片、文字等,用 bitmap 来存储这些标签,在对应标签 bit 位上置 1。对用户,也可以采用类似方式,记录用户的多种属性,并可以很方便的根据标签来进行多维度统计。bitmap 位图的重要指令包括:setbit、 getbit、bitcount、bitfield、 bitop、bitpos 等。
在移动社交时代,LBS 应用越来越多,比如微信、陌陌中附近的人,美团、大众点评中附近的美食、电影院,滴滴、优步中附近的专车等。要实现这些功能,就得使用地理位置信息进行搜索。地球的地理位置是使用二维的经纬度进行表示的,我们只要确定一个点的经纬度,就可以确认它在地球的位置。 Redis 在 3.2 版本之后增加了对 GEO 地理位置的处理功能。Redis 的 GEO 地理位置本质上是基于 sorted set 封装实现的。在存储分类 key 下的地理位置信息时,需要对该分类 key 构建一个 sorted set 作为内部存储结构,用于存储一系列位置点。 在存储某个位置点时,首先利用 Geohash 算法,将该位置二维的经纬度,映射编码成一维的 52 位整数值,将位置名称、经纬度编码 score 作为键值对,存储到分类 key 对应的 sorted set 中。 需要计算某个位置点 A 附近的人时,首先以指定位置 A 为中心点,以距离作为半径,算出 GEO 哈希 8 个方位的范围, 然后依次轮询方位范围内的所有位置点,只要这些位置点到中心位置 A 的距离在要求距离范围内,就是目标位置点。轮询完所有范围内的位置点后,重新排序即得到位置点 A 附近的所有目标。 使用 geoadd,将位置名称(如人、车辆、店名)与对应的地理位置信息添加到指定的位置分类 key 中; 使用 geopos 方便地查询某个名称所在的位置信息; 使用 georadius 获取指定位置附近,不超过指定距离的所有元素; 使用 geodist 来获取指定的两个位置之间的距离。 这样,是不是就可以实现,找到附近的餐厅,算出当前位置到对应餐厅的距离,这样的功能了? Redis GEO 地理位置,利用 Geohash 将大量的二维经纬度转一维的整数值,这样可以方便的对地理位置进行查询、距离测量、范围搜索。但由于地理位置点非常多,一个地理分类 key 下可能会有大量元素,在 GEO 设计时,需要提前进行规划,避免单 key 过度膨胀。 Redis 的 GEO 地理位置数据结构,应用场景很多,比如查询某个地方的具体位置,查当前位置到目的地的距离,查附近的人、餐厅、电影院等。GEO 地理位置数据结构中,重要指令包括 geoadd、geopos、geodist、georadius、georadiusbymember 等。
Redis 的 hyperLogLog 是用来做基数统计的数据类型,当输入巨大数量的元素做统计时,只需要很小的内存即可完成。HyperLogLog 不保存元数据,只记录待统计元素的估算数量,这个估算数量是一个带有 0.81% 标准差的近似值,在大多数业务场景,对海量数据,不足 1% 的误差是可以接受的。 Redis 的 HyperLogLog 在统计时,如果计数数量不大,采用稀疏矩阵存储,随着计数的增加,稀疏矩阵占用的空间也会逐渐增加,当超过阀值后,则改为稠密矩阵,稠密矩阵占用的空间是固定的,约为12KB字节。 通过 hyperLoglog 数据类型,你可以利用 pfadd 向基数统计中增加新的元素,可以用 pfcount 获得 hyperLogLog 结构中存储的近似基数数量,还可以用 hypermerge 将多个 hyperLogLog 合并为一个 hyperLogLog 结构,从而可以方便的获取合并后的基数数量。 hyperLogLog 的特点是统计过程不记录独立元素,占用内存非常少,非常适合统计海量数据。在大中型系统中,统计每日、每月的 UV 即独立访客数,或者统计海量用户搜索的独立词条数,都可以用 hyperLogLog 数据类型来进行处理。
比较 | mysql | redis |
---|---|---|
开启 | start transaction | multi |
语句 | 普通sql语句 | 普通redis命令 |
失败 | rollback | discard |
成功 | commit | exec |
如果已经成功执行了2条语句, 第3条语句出错.
rollback后,前2条的语句影响消失.
discard只是结束本次事务,前2条语句造成的影响仍然还在
我正在买票ticket -1 , money -100
而票只有1张, 如果在我multi之后,和exec之前, 票被别人买了,即ticket变成0了.我该如何观察这种情景,并不再提交
悲观的想法:
世界充满危险,肯定有人和我抢, 给 ticket上锁, 只有我能操作. [悲观锁]
乐观的想法:
没有那么人和我抢,因此,我只需要注意, --有没有人更改ticket的值就可以了 [乐观锁]
Redis的事务中,启用的是乐观锁,只负责监测key没有被改动
具体的命令---- watch命令
redis 127.0.0.1:6379> watch ticket
OK
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> decr ticket
QUEUED
redis 127.0.0.1:6379> decrby money 100
QUEUED
redis 127.0.0.1:6379> exec
(nil) // 返回nil,说明监视的ticket已经改变了,事务就取消了.
redis 127.0.0.1:6379> get ticket
"0"
redis 127.0.0.1:6379> get money
"200"
watch key1 key2 ... keyN
作用:监听key1 key2..keyN有没有变化,如果有变, 则事务取消
unwatch
作用: 取消所有watch监听
订阅端: subscribe 频道名称
发布端: publish 频道名称 发布内容
有限制,还是容易数据丢失,恢复快
save 900 1 # 900内,有1条写入,则产生快照
save 300 1000 # 如果300秒内有1000次写入,则产生快照
save 60 10000 # 如果60秒内有10000次写入,则产生快照
(这3个选项都屏蔽,则rdb禁用)
stop-writes-on-bgsave-error yes # 后台备份进程出错时,主进程停不停止写入?
rdbcompression yes # 导出的rdb文件是否压缩
Rdbchecksum yes # 导入rbd恢复时数据时,要不要检验rdb的完整性
dbfilename dump.rdb # 导出来的rdb文件名
dir ./ //rdb的放置路径
appendonly no # 是否打开 aof日志功能
appendfsync always # 每1个命令,都立即同步到aof. 安全,速度慢
appendfsync everysec # 折衷方案,每秒写1次
appendfsync no # 写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到aof. 同步频率低,速度快,
no-appendfsync-on-rewrite yes: # 正在导出rdb快照的过程中,要不要停止同步aof
auto-aof-rewrite-percentage 100 #aof文件大小比起上次重写时的大小,增长率100%时,重写
auto-aof-rewrite-min-size 64mb #aof文件,至少超过64M时,重写
注: 在dump rdb过程中,aof如果停止同步,会不会丢失? 答: 不会,所有的操作缓存在内存的队列里, dump完成后,统一操作.
注: aof重写是指什么? 答: aof重写是指把内存中的数据,逆化成命令,写入到.aof日志里.以解决 aof日志过大的问题.
问: 如果rdb文件,和aof文件都存在,优先用谁来恢复数据? 答: aof
问: 2种是否可以同时用? 答: 可以,而且推荐这么做
问: 恢复时rdb和aof哪个恢复的快 答: rdb快,因为其是数据的内存映射,直 接载入到内存,而aof是命令,需要逐条执行
Master配置:
1:关闭rdb快照(备份工作交给slave)
2:可以开启aof
slave配置:
1: 声明slave-of
2: 配置密码[如果master有密码]
3: [某1个]slave打开 rdb快照功能
4: 配置是否只读[slave-read-only]
主键表
列名 | 操作 | 备注 |
---|---|---|
global:user_id | incr | 全局user_id |
global:post_id | incr | 全局post_id |
mysql用户表
列名 | 操作 | 备注 | |
---|---|---|---|
user_id | user_name | password | authsecret |
1 | shengj | 123456 | ,./!@# |
redis用户表
列名 | 操作 | 备注 | |
---|---|---|---|
user:user_id | user:user_id:*:user_name | user:user_id:*:password | user:user_id:*:authsecret |
1 | shengj | 123456 | ,./!@# |
mysql发送表
列名 | 操作 | 备注 | ||
---|---|---|---|---|
post_id | user_id | user_name | time | content |
1 | 1 | shengj | 1370987654 | 测试内容 |
redis发送表
列名 | 操作 | 备注 | ||
---|---|---|---|---|
post:post_id | post:post_id:*:user_id | post:post_id:*:user_name | post:post_id:*:time | post:post_id:*:content |
1 | 1 | shengj | 1370987654 | 测试内容 |
关注表:following -> set user_id
粉丝表:follower -> set user_id
推送表:receivepost -> list user_ids
拉取表:pullpost -> zset user_ids
问题:当我们的缓存失效或者redis挂了,那么这个时候的请求都会直接走数据库,就会给数据库造成极大的压力,导致数据库也挂了
解决:
- 对缓存设置不同的过期时间,这样就不会导致缓存同时失效
- 建立redis集群,保证服务的可靠性
问题:当有大量用户不走我们设置的键值,就会直接走数据库,就会给数据库造成极大的压力,导致数据库也挂了
解决:
- 参数过滤和提醒,引导用户走我们的设置的键值
- 对不合法的参数进行空对象缓存,并设置较短的过期时间
问题:如果一直是读的话,是没问题的,但是更新操作会导致数据库已经更新了,缓存还是旧的数据
解决:
并发下解决数据库与缓存不一致的思路:将删除缓存、修改数据库、读取缓存等的操作积压到队列里边,实现串行化。
- 先删除缓存,再更新数据库
在高并发下表现不如意,在原子性被破坏时表现优异
- 先更新数据库,再删除缓存(Cache Aside Pattern设计模式)
在高并发下表现优异,在原子性被破坏时表现不如意
# 拉取redis
docker pull redis
# 主
docker run -v $(pwd)/master/redis.conf:/usr/local/etc/redis/redis.conf --name redis-master redis redis-server /usr/local/etc/redis/redis.conf
# 从1 --link redis-master:master master是别名
docker run -v $(pwd)/slave1/redis.conf:/usr/local/etc/redis/redis.conf --name redis-slave1 --link redis-master:master redis redis-server /usr/local/etc/redis/redis.conf
# 从2
docker run -v $(pwd)/slave2/redis.conf:/usr/local/etc/redis/redis.conf --name redis-slave2 --link redis-master:master redis redis-server /usr/local/etc/redis/redis.conf
# 拉取redis
docker pull redis
# 目录
├── docker-compose.yml
├── master
│ ├── Dockerfile
│ └── redis.conf
├── redis.conf
├── slave1
│ ├── Dockerfile
│ └── redis.conf
└── slave2
├── Dockerfile
└── redis.conf
# 启动
docker-compose up -d master slave1 slave2
# 查看主容器
docker-compose exec master bash
root@cab5db8d544b:/data# redis-cli
127.0.0.1:6379> info Replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.23.0.3,port=6379,state=online,offset=1043,lag=0
slave1:ip=172.23.0.4,port=6379,state=online,offset=1043,lag=0
master_replid:995257c6b5ac62f7908cc2c7bb770f2f17b60401
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1043
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1043