一、什么是redis数据库?
redis数据库是一种非关系型数据库,全称(Remote Dctionary Server)远程字典服务。是基于内存的,支持持久化,支持网络的高速缓存数据库。
redis数据库是以键值对方式存储,key值为字符串,value值类型包含字符串(String),哈希(Hash),列表(List),集合(Set),有序集合(Zset)五种基本数据类型,地理位置(Geo),基数统计(Hyperloglog),位图(Bitmap)三种特殊数据类型。
二、redis入门命令
下面实验环境基于windows版本redis。
1.基础命令
启动redis服务端
E:\redis>redis-server.exe redis.windows.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.100 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 76804
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[76804] 14 Jan 10:58:12.918 # Server started, Redis version 3.2.100
[76804] 14 Jan 10:58:12.922 * DB loaded from disk: 0.001 seconds
[76804] 14 Jan 10:58:12.922 * The server is now ready to accept connections on port 6379
使用客户端进行一些基本操作
E:\redis>redis-cli.exe -h 127.0.0.1 -p 6379 -a yinkeqi /* 使用客户端连接redis服务端,-h指定ip,-p指定端口,-a指定密码 */
127.0.0.1:6379> ping /* ping检查连接是否正常 */
PONG
127.0.0.1:6379> select 1 /* 切换redis库,默认为0号库,切换为1号库 */
OK
127.0.0.1:6379[1]> dbsize /* 查看当前库的大小 */
(integer) 0
127.0.0.1:6379[1]> set a 1 /* 设置一个键值 */
OK
127.0.0.1:6379[1]> dbsize /* 查询当前库的大小 */
(integer) 1
127.0.0.1:6379[1]> flushdb /* 清空当前库 */
OK
127.0.0.1:6379[1]> dbsize
(integer) 0
127.0.0.1:6379[1]> flushall /* 清空所有库 */
OK
127.0.0.1:6379[1]> shutdown /* 客户端关闭redis服务 */
not connected>
2.键命令
127.0.0.1:6379[1]> set language english /* 设置键值 */
OK
127.0.0.1:6379[1]> get language /* 获取键值 */
"english"
127.0.0.1:6379[1]> del language /* 删除键值 */
(integer) 1
127.0.0.1:6379[1]> set language english
OK
127.0.0.1:6379[1]> set user yinkeqi
OK
127.0.0.1:6379[1]> keys *u* /* 查询符合正则key */
1) "user"
2) "language"
127.0.0.1:6379[1]> exists user /* 判断key是否存在 */
(integer) 1
127.0.0.1:6379[1]> ttl user /* 获取key的失效时间,不会失效返回-1,已经失效返回0,返回正数表示还有多少秒失效 */
(integer) -1
127.0.0.1:6379[1]> expire user 10 /* 设置key的失效时间 */
(integer) 1
127.0.0.1:6379[1]> ttl user
(integer) 5
127.0.0.1:6379[1]> ttl user
(integer) 0
127.0.0.1:6379[1]> rename user username
(error) ERR no such key
127.0.0.1:6379[1]> set user yinkeqi
OK
127.0.0.1:6379[1]> rename user username /* 修改key值名称 */
OK
127.0.0.1:6379[1]> keys user
(empty list or set)
127.0.0.1:6379[1]> keys user*
1) "username"
三、redis五大基本类型
1.String类型
String类型是最常用的redis数据结构,类似java的字符串和数值类型。包含对字符串的设置、获取、拼接、长度获取、截取、批量设置、批量获取。数值类型的自增、自减、加、减。还有setnx(不存在时设置,存在不设置)、setex(设置字符串同时设置失效时间)。
127.0.0.1:6379[1]> set user yinkeqi /* 设置字符串类型的值 */
OK
127.0.0.1:6379[1]> get user /* 获取字符串类型的值 */
"yinkeqi"
127.0.0.1:6379[1]> append user yyds /* 拼接字符串 */
(integer) 11
127.0.0.1:6379[1]> get user
"yinkeqiyyds"
127.0.0.1:6379[1]> strlen user /* 获取字符串长度 */
(integer) 11
127.0.0.1:6379[1]> substr user 1 3 /* 截取字符串,返回截取后的字符串,原redis存储的字符串不变 */
"ink"
127.0.0.1:6379[1]> substr user 3 6
"keqi"
127.0.0.1:6379[1]> incr user
(error) ERR value is not an integer or out of range
127.0.0.1:6379[1]> set age 18
OK
127.0.0.1:6379[1]> incr age /* 数值类型自增 */
(integer) 19
127.0.0.1:6379[1]> decr age /* 数值类型自减 */
(integer) 18
127.0.0.1:6379[1]> incrby age 8 /* 数值类型加值 */
(integer) 26
127.0.0.1:6379[1]> decrby age 6 /* 数值类型减值 */
(integer) 20
127.0.0.1:6379[1]> mset name yinkeqi age 18 sex y /* 批量设置字符串 */
OK
127.0.0.1:6379[1]> mget name age sex /* 批量获取字符串 */
1) "yinkeqi"
2) "18"
3) "y"
127.0.0.1:6379[1]> setnx name zhangsan /* 如果不存在就设置字符串,返回1;如果存在就不设置字符串,返回0 */
(integer) 0
127.0.0.1:6379[1]> setnx money 10000
(integer) 1
127.0.0.1:6379[1]> setex girlfriend 10 lisi /* 设置字符串并设置失效时间 */
OK
127.0.0.1:6379[1]> ttl girlfriend
(integer) 2
127.0.0.1:6379[1]> ttl girlfriend
(integer) -2
127.0.0.1:6379[1]> get girlfriend
(nil)
2.Hash类型
Hash类型类似java的map数据结构,以键值对方式存在。命令主要以h开头,包括对键值对的设置、删除、获取、批量设置、长度获取、是否存在、获取所有键值对、获取所有key、获取所有value。
127.0.0.1:6379[1]> hset family sister lisi /* 设置hash类型的值 */
(integer) 1
127.0.0.1:6379[1]> hget family sister /* 获取hash类型的值 */
"lisi"
127.0.0.1:6379[1]> hmset family brother zhangsan father wangwu mother zhaoliu /* 批量设置hash类型的值 */
OK
127.0.0.1:6379[1]> hmget family father mother brother sister /* 批量获取hash类型的值 */
1) "wangwu"
2) "zhaoliu"
3) "zhangsan"
4) "lisi"
127.0.0.1:6379[1]> hgetall family /* 获取hash类型的所有值 */
1) "brother"
2) "zhangsan"
3) "sister"
4) "lisi"
5) "father"
6) "wangwu"
7) "mother"
8) "zhaoliu"
127.0.0.1:6379[1]> hdel family sister /* 删除hash类型的值 */
(integer) 1
127.0.0.1:6379[1]> hgetall family
1) "brother"
2) "zhangsan"
3) "father"
4) "wangwu"
5) "mother"
6) "zhaoliu"
127.0.0.1:6379[1]> hlen family /* 获取hash类型的大小 */
(integer) 3
127.0.0.1:6379[1]> hexists family sister /* 判断hash类型是否存在 */
(integer) 0
127.0.0.1:6379[1]> hexists family brother
(integer) 1
127.0.0.1:6379[1]> hkeys family /* 获取hash类型的所有key值 */
1) "brother"
2) "father"
3) "mother"
127.0.0.1:6379[1]> hvals family /* 获取hash类型的所有value值 */
1) "zhangsan"
2) "wangwu"
3) "zhaoliu"
3.List类型
List类型类似java的双端队列,可以从两端插入和弹出。命令主要以l和r开头,表示从左端操作队列,从右端操作队列。包含从左插入、从右插入、从左弹出、从右弹出、移除某元素、插入某元素、长度获取。
127.0.0.1:6379[1]> lpush num 1 2 3 4 5 6 7 8 9 10 /* 从list左侧依次插入数据 */
(integer) 10
127.0.0.1:6379[1]> rpush num 11 12 13 14 15 /* 从list右侧依次插入数据 */
(integer) 15
127.0.0.1:6379[1]> lrange num 0 -1 /* 获取list的列表 */
1) "10"
2) "9"
3) "8"
4) "7"
5) "6"
6) "5"
7) "4"
8) "3"
9) "2"
10) "1"
11) "11"
12) "12"
13) "13"
14) "14"
15) "15"
127.0.0.1:6379[1]> lpop num /* 从list左侧弹出数据 */
"10"
127.0.0.1:6379[1]> lpop num
"9"
127.0.0.1:6379[1]> rpop num /* 从list右侧弹出数据 */
"15"
127.0.0.1:6379[1]> rpop num
"14"
127.0.0.1:6379[1]> rpop num
"13"
127.0.0.1:6379[1]> llen num /* 获取list长度 */
(integer) 10
127.0.0.1:6379[1]> linsert num before 8 7 /* list中插入数据 */
(integer) 11
127.0.0.1:6379[1]> lrange num 0 -1
1) "7"
2) "8"
3) "7"
4) "6"
5) "5"
6) "4"
7) "3"
8) "2"
9) "1"
10) "11"
11) "12"
127.0.0.1:6379[1]> lrem num 2 7 /* 移除list中的数值 */
(integer) 2
127.0.0.1:6379[1]> lrange num 0 -1
1) "8"
2) "6"
3) "5"
4) "4"
5) "3"
6) "2"
7) "1"
8) "11"
9) "12"
127.0.0.1:6379[1]> ltrim num 0 3 /* 截取list的特定长度 */
OK
127.0.0.1:6379[1]> lrange num 0 -1
1) "8"
2) "6"
3) "5"
4) "4"
4.Set类型
set与java的set类似,都是不包含相同元素。命令以s开头,包含对集合的添加、删除、查询、是否存在、大小获取、并集、差集、合集运算。
127.0.0.1:6379[1]> sadd set 1 2 3 4 5 6 7 8 9 0 /* set中添加元素 */
(integer) 10
127.0.0.1:6379[1]> sadd set 1 2 3 4 5 /* set已有元素不会重复添加 */
(integer) 0
127.0.0.1:6379[1]> srem set 1 2 3 10 /* 移除set存在的元素 */
(integer) 3
127.0.0.1:6379[1]> scard set /* 查询set的大小 */
(integer) 7
127.0.0.1:6379[1]> smembers set /* 查询set中的元素 */
1) "0"
2) "4"
3) "5"
4) "6"
5) "7"
6) "8"
7) "9"
127.0.0.1:6379[1]> sismember set 1 /* 判断set中是否包含某元素 */
(integer) 0
127.0.0.1:6379[1]> sismember set 0
(integer) 1
127.0.0.1:6379[1]> spop set 1 /**/
1) "6"
127.0.0.1:6379[1]> scard set
(integer) 6
127.0.0.1:6379[1]> sadd set2 1 2 3 4 5 6 7 8 9 0
(integer) 10
127.0.0.1:6379[1]> sdiff set set2
(empty list or set)
127.0.0.1:6379[1]> sinter set set2
1) "0"
2) "4"
3) "5"
4) "7"
5) "8"
6) "9"
127.0.0.1:6379[1]> sunion set set2
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
7) "6"
8) "7"
9) "8"
10) "9"
5.Zset类型
Zset是带权重的set,不允许有相同的元素,每个元素都带有对应权重。命令以z开头,包含元素添加,删除、查询、大小获取、权重查询。
127.0.0.1:6379> zadd performance 36 zhangsan 60 li 75 wangwu 88 zhaoliu /* 有序集合添加元素 */
(integer) 4
127.0.0.1:6379> zrange performance 0 -1 /* 以下标位置,查询所有元素 */
1) "zhangsan"
2) "li"
3) "wangwu"
4) "zhaoliu"
127.0.0.1:6379> zcount performance 0 -1 /* 以score查询元素数量 */
(integer) 0
127.0.0.1:6379> zcount performance 0 100
(integer) 4
127.0.0.1:6379> zrangebyscore performance 0 100 /* 以score,查询元素 */
1) "zhangsan"
2) "li"
3) "wangwu"
4) "zhaoliu"
127.0.0.1:6379> zrangebyscore performance 60 100
1) "li"
2) "wangwu"
3) "zhaoliu"
127.0.0.1:6379> zrem performance zhaoliu /* 有序集合移除元素 */
(integer) 1
127.0.0.1:6379> zrange performance 0 100
1) "zhangsan"
2) "li"
3) "wangwu"
127.0.0.1:6379> zcard performance /* 查询总数 */
(integer) 3
127.0.0.1:6379> zscore performance zhangsan /* 查询某元素的分数 */
"36"
127.0.0.1:6379> zincrby performance 24 zhangsan /* 增加某元素的分数 */
"60"
127.0.0.1:6379> zscore performance zhangsan
"60"
127.0.0.1:6379> zincrby performance -24 zhangsan /* 减少某元素的分数 */
"36"
四、redis三种特殊类型
1.Geo类型
坐标类型。命令以geo开头,也可使用zset的部分命令。包含地理坐标的添加、删除、数量查询、地址的坐标查询、地址间距离查询、坐标附近的地址查询。
127.0.0.1:6379> geoadd china 116.41667 39.91667 beijing 121.43333 34.50000 shanghai
(integer) 2
127.0.0.1:6379> geoadd china 113.23333 23.16667 guangzhou 114.06667 22.61667 shenzhen
(integer) 2
127.0.0.1:6379> geoadd china 111 11 hubei /* geo添加地理坐标 */
(integer) 1
127.0.0.1:6379> zrem china hubei /* geo使用zset的命令移除坐标地址*/
(integer) 1
127.0.0.1:6379> zcard china /* 查询geo地理坐标总数 */
(integer) 4
127.0.0.1:6379> geodist china beijing shanghai km /* 查询两坐标的距离 */
"748.3469"
127.0.0.1:6379> geopos china beijing /* 查询某地址的坐标 */
1) 1) "116.41667157411575"
2) "39.916670952735892"
127.0.0.1:6379> zrange china 0 -1 /* 查询所有坐标 */
1) "guangzhou"
2) "shenzhen"
3) "shanghai"
4) "beijing"
127.0.0.1:6379> georadius china 110 23 1000 km withcoord /* 查询某坐标1000公里内的城市 */
1) 1) "guangzhou"
2) 1) "113.23332935571671"
2) "23.166670823726726"
2) 1) "shenzhen"
2) 1) "114.06667023897171"
2) "22.616669283525248"
127.0.0.1:6379> georadius china 110 23 1000 km withcoord withdist
1) 1) "guangzhou"
2) "331.3496"
3) 1) "113.23332935571671"
2) "23.166670823726726"
2) 1) "shenzhen"
2) "419.1123"
3) 1) "114.06667023897171"
2) "22.616669283525248"
127.0.0.1:6379> georadiusbymember china beijing 1000 km withcoord withdist /* 查询某城市1000公里内的城市 */
1) 1) "shanghai"
2) "748.3469"
3) 1) "121.43333047628403"
2) "34.499999717161309"
2) 1) "beijing"
2) "0.0000"
3) 1) "116.41667157411575"
2) "39.916670952735892"
2.Hyperloglogs类型
基数统计类型,适用于set类型的特殊场景。命令以pf开头,包含元素的添加、数量统计、合并。
127.0.0.1:6379> pfadd over10 11 12 13 14 15 16 17 18 19 20 /* 基数统计添加元素 */
(integer) 1
127.0.0.1:6379> pfadd lower15 15 14 13 12 11 10 9 8 7 6 5
(integer) 1
127.0.0.1:6379> pfcount over10 /* 统计数量 */
(integer) 10
127.0.0.1:6379> pfcount lower15
(integer) 11
127.0.0.1:6379> pfmerge over10 lower15 /* 合并后一个统计到前一个统计中 */
OK
127.0.0.1:6379> pfcount over10
(integer) 16
127.0.0.1:6379> pfcount lower15
(integer) 11
127.0.0.1:6379>
3.Bitmap类型
bitmap类型类似布尔值,,只能设置为0或1。命令包含bit,有设置、获取、数量获取。
127.0.0.1:6379> setbit gotowork 1 1 /* 设置周一有去上班 */
(integer) 0
127.0.0.1:6379> setbit gotowork 2 1 /* 设置周二有去上班 */
(integer) 0
127.0.0.1:6379> setbit gotowork 3 1 /* 设置周三有去上班 */
(integer) 0
127.0.0.1:6379> setbit gotowork 4 1 /* 设置周四有去上班 */
(integer) 0
127.0.0.1:6379> setbit gotowork 5 1 /* 设置周五有去上班 */
(integer) 0
127.0.0.1:6379> setbit gotowork 6 0 /* 设置周六没有去上班 */
(integer) 0
127.0.0.1:6379> setbit gotowork 7 0 /* 设置周日没有去上班 */
(integer) 0
127.0.0.1:6379> getbit gotowork 1 /* 查看周一是否去上班 */
(integer) 1
127.0.0.1:6379> getbit gotowork 7
(integer) 0
127.0.0.1:6379> bitcount gotowork 0 -1 /* 查看去上班的总数 */
(integer) 5
五、redis事务与乐观锁
1.事务
redis事务,使用multi命令表示开启事务,后面的命令进入队列,执行exec命令,则执行队列中的命令,执行discard命令,则取消执行队列中的命令。redis事务只是将命令放入到队列中,通过批量执行或取消执行,并不具备关系型数据库事务的特征。
127.0.0.1:6379> multi /* 开启事务 */
OK
127.0.0.1:6379> set a 1 /* 命令一进入队列 */
QUEUED
127.0.0.1:6379> set b 2 /* 命令二进入队列 */
QUEUED
127.0.0.1:6379> set c 3 /* 命令三进入队列 */
QUEUED
127.0.0.1:6379> exec /* 执行命令 */
1) OK
2) OK
3) OK
127.0.0.1:6379> multi /* 开启事务 */
OK
127.0.0.1:6379> set d 4 /* 命令一进入队列 */
QUEUED
127.0.0.1:6379> set e 5 /* 命令二进入队列 */
QUEUED
127.0.0.1:6379> set f 6 /* 命令三进入队列 */
QUEUED
127.0.0.1:6379> discard /* 回滚命令 */
OK
127.0.0.1:6379> get d
(nil)
127.0.0.1:6379> get a
"1"
2.乐观锁
redis乐观锁命令watch。先使用watch命令开始观察元素是否发生改变,然后使用multi开启事务,当观察的元素发生改变时,事务中的命令不执行,当观察的元素没发生改变时,事务中的命令执行。即使事务中操作的元素不包含被观察的元素,依然遵循上述规则。
127.0.0.1:6379> watch test /* 观察元素 */
OK
127.0.0.1:6379> multi /* 开启事务 */
OK
127.0.0.1:6379> set test 123 /* 命令一进入队列 */
QUEUED
127.0.0.1:6379> set test 234 /* 命令二进入队列 */
QUEUED
127.0.0.1:6379> exec /* 执行命令,返回nil,元素发生了改变,事务中的命令未执行 */
(nil)
127.0.0.1:6379> get test
"345"
127.0.0.1:6379> unwatch /* 释放观察 */
OK
127.0.0.1:6379> watch test
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a 1
QUEUED
127.0.0.1:6379> set b 2
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> unwatch
OK
六、redis发布与订阅
redis的发布和订阅类似微信公众号的推文。订阅了公众号的人都会受到推文。包含subscribe订阅,publish推送消息,unsubscribe退订。redis的发布与订阅不能进行持久化,因此在5.0版本引入了stream
下面分别演示订阅了qqchannel和wxchannel推送消息。
1.订阅wxchannel
127.0.0.1:6379> subscribe wxchannel /* 订阅微信渠道wxchannel */
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "wxchannel"
3) (integer) 1
1) "message"
2) "wxchannel"
3) "i am ykq"
2.订阅qqchannel
127.0.0.1:6379> subscribe qqchannel /* 订阅qq渠道qqchannel */
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "qqchannel"
3) (integer) 1
1) "message"
2) "qqchannel"
3) "i am 18 years old"
3.推送消息
127.0.0.1:6379> publish wxchannel "i am ykq" /* 推送给微信渠道消息 */
(integer) 1
127.0.0.1:6379> publish qqchannel "i am 18 years old" /* 推送给qq渠道消息 */
(integer) 1
七、主从复制
使用两个端口启动两个redis-server,使用slaveof命令即可实现本次启动的两个服务实现主从。不过这种只是短暂的,本次生效,不是永久的。
1.启动服务6379
E:\redis>redis-server.exe redis.windows.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.100 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 8828
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[8828] 19 Jan 13:45:35.875 # Server started, Redis version 3.2.100
[8828] 19 Jan 13:45:35.876 * DB loaded from disk: 0.001 seconds
[8828] 19 Jan 13:45:35.876 * The server is now ready to accept connections on port 6379
2.复制redis.windows.conf
此处只安装一个redis,通过两个配置文件来启动两个服务,复制redis.windows.conf,命名为redis.windows1.conf
修改配置文件配置
port 6380 ### 修改端口为6380
slaveof 127.0.0.1 6379 ### 修改6380服务从属于6379服务
masterauth yinkeqi ### 修改主机验证的密码,主机有密码情况下,不配置将会复制失败
3.启动服务6380
E:\redis>redis-server.exe redis.windows1.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.100 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6380
| `-._ `._ / _.-' | PID: 2720
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[2720] 19 Jan 14:06:38.591 # Server started, Redis version 3.2.100
[2720] 19 Jan 14:06:38.593 * DB loaded from disk: 0.001 seconds
[2720] 19 Jan 14:06:38.593 * The server is now ready to accept connections on port 6380
[2720] 19 Jan 14:06:38.593 * Connecting to MASTER 127.0.0.1:6379
[2720] 19 Jan 14:06:38.663 * MASTER <-> SLAVE sync started
[2720] 19 Jan 14:06:38.663 * Non blocking connect for SYNC fired the event.
[2720] 19 Jan 14:06:38.664 * Master replied to PING, replication can continue...
[2720] 19 Jan 14:06:38.664 * Partial resynchronization not possible (no cached master)
[2720] 19 Jan 14:06:38.720 * Full resync from master: 75a8bfd22d1551a3c28b72cfd44ee3ff40859341:1
[2720] 19 Jan 14:06:39.418 * MASTER <-> SLAVE sync: receiving 763 bytes from master
[2720] 19 Jan 14:06:39.424 * MASTER <-> SLAVE sync: Flushing old data
[2720] 19 Jan 14:06:39.425 * MASTER <-> SLAVE sync: Loading DB in memory
[2720] 19 Jan 14:06:39.427 * MASTER <-> SLAVE sync: Finished with success
4.客户端连接6379进行写操作
可以看到主机是可以进行读写的。
E:\redis>redis-cli.exe -p 6379 -a yinkeqi
127.0.0.1:6379> set name yinkeqi
OK
127.0.0.1:6379> get name
"yinkeqi"
5.客户端连接6380进行读操作
从机只能进行读操作,不能进行写操作。
E:\redis>redis-cli.exe -p 6380 -a yinkeqi
127.0.0.1:6380> get name
"yinkeqi"
127.0.0.1:6380> set name zhangsan
(error) READONLY You can't write against a read only slave.
八、哨兵模式
1.复制redis.windows.conf
哨兵模式需要三个节点演示,一个主节点A,两个从节点B、C。当主节点A下线了,其中一个从节点B升级为主节点,另一个从节点C的主机变为节点B。
因此需要再复制一个配置文件,命名为redis.windows2.conf
port 6381 ### 修改端口为6381
slaveof 127.0.0.1 6379 ### 修改6381服务从属于6379服务
masterauth yinkeqi ### 修改主机验证的密码,主机有密码情况下,不配置将会复制失败
2.配置三个sentinel.conf
配置三个哨兵,当有两个哨兵认为主机下线,则选举其中一个从机为主机
(1)sentinel.conf
port 9736 ### 指定当前哨兵的端口
sentinel monitor mymaster 127.0.0.1 6379 2 ### 指定当前哨兵监控的主机ip和端口,以及判定主机下线条件
sentinel down-after-milliseconds mymaster 3000 ### 当主机3秒无响应,当前哨兵认为主机下线
sentinel auth-pass mymaster yinkeqi ### 当主机有密码时,需要设置连接主机的密码
(2)sentinel1.conf
port 9737
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 3000
sentinel auth-pass mymaster yinkeqi
(3)sentinel2.conf
port 9738
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 3000
sentinel auth-pass mymaster yinkeqi
3.启动三个redis服务
(1)6379服务
E:\redis>redis-server.exe redis.windows.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.100 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 13876
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[13876] 20 Jan 09:50:21.655 # Server started, Redis version 3.2.100
[13876] 20 Jan 09:50:21.657 * DB loaded from disk: 0.001 seconds
[13876] 20 Jan 09:50:21.657 * The server is now ready to accept connections on port 6379
[13876] 20 Jan 09:50:52.531 * Slave 127.0.0.1:6380 asks for synchronization
[13876] 20 Jan 09:50:52.531 * Full resync requested by slave 127.0.0.1:6380
[13876] 20 Jan 09:50:52.532 * Starting BGSAVE for SYNC with target: disk
[13876] 20 Jan 09:50:52.580 * Background saving started by pid 22388
[13876] 20 Jan 09:50:54.257 # fork operation complete
[13876] 20 Jan 09:50:54.258 * Background saving terminated with success
[13876] 20 Jan 09:50:54.266 * Synchronization with slave 127.0.0.1:6380 succeeded
[13876] 20 Jan 09:51:22.617 * Slave 127.0.0.1:6381 asks for synchronization
[13876] 20 Jan 09:51:22.617 * Full resync requested by slave 127.0.0.1:6381
[13876] 20 Jan 09:51:22.618 * Starting BGSAVE for SYNC with target: disk
[13876] 20 Jan 09:51:22.662 * Background saving started by pid 25956
[13876] 20 Jan 09:51:23.313 # fork operation complete
[13876] 20 Jan 09:51:23.314 * Background saving terminated with success
[13876] 20 Jan 09:51:23.319 * Synchronization with slave 127.0.0.1:6381 succeeded
(2)6380服务
E:\redis>redis-server.exe redis.windows1.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.100 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6380
| `-._ `._ / _.-' | PID: 28308
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[28308] 20 Jan 09:50:52.458 # Server started, Redis version 3.2.100
[28308] 20 Jan 09:50:52.459 * DB loaded from disk: 0.001 seconds
[28308] 20 Jan 09:50:52.460 * The server is now ready to accept connections on port 6380
[28308] 20 Jan 09:50:52.460 * Connecting to MASTER 127.0.0.1:6379
[28308] 20 Jan 09:50:52.529 * MASTER <-> SLAVE sync started
[28308] 20 Jan 09:50:52.529 * Non blocking connect for SYNC fired the event.
[28308] 20 Jan 09:50:52.530 * Master replied to PING, replication can continue...
[28308] 20 Jan 09:50:52.531 * Partial resynchronization not possible (no cached master)
[28308] 20 Jan 09:50:52.581 * Full resync from master: 1e31e28f3f28670ed40f8dd165fc451ef6ee324e:1
[28308] 20 Jan 09:50:54.264 * MASTER <-> SLAVE sync: receiving 75 bytes from master
[28308] 20 Jan 09:50:54.268 * MASTER <-> SLAVE sync: Flushing old data
[28308] 20 Jan 09:50:54.268 * MASTER <-> SLAVE sync: Loading DB in memory
[28308] 20 Jan 09:50:54.272 * MASTER <-> SLAVE sync: Finished with success
(3)6381服务
E:\redis>redis-server.exe redis.windows2.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.100 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6381
| `-._ `._ / _.-' | PID: 16380
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[16380] 20 Jan 09:51:22.542 # Server started, Redis version 3.2.100
[16380] 20 Jan 09:51:22.543 * DB loaded from disk: 0.001 seconds
[16380] 20 Jan 09:51:22.544 * The server is now ready to accept connections on port 6381
[16380] 20 Jan 09:51:22.544 * Connecting to MASTER 127.0.0.1:6379
[16380] 20 Jan 09:51:22.615 * MASTER <-> SLAVE sync started
[16380] 20 Jan 09:51:22.615 * Non blocking connect for SYNC fired the event.
[16380] 20 Jan 09:51:22.616 * Master replied to PING, replication can continue...
[16380] 20 Jan 09:51:22.617 * Partial resynchronization not possible (no cached master)
[16380] 20 Jan 09:51:22.663 * Full resync from master: 1e31e28f3f28670ed40f8dd165fc451ef6ee324e:43
[16380] 20 Jan 09:51:23.318 * MASTER <-> SLAVE sync: receiving 75 bytes from master
[16380] 20 Jan 09:51:23.322 * MASTER <-> SLAVE sync: Flushing old data
[16380] 20 Jan 09:51:23.324 * MASTER <-> SLAVE sync: Loading DB in memory
[16380] 20 Jan 09:51:23.326 * MASTER <-> SLAVE sync: Finished with success
4.启动三个哨兵
(1)9736哨兵
E:\redis>redis-server.exe sentinel.conf --sentinel
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.100 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 9736
| `-._ `._ / _.-' | PID: 30480
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[30480] 21 Jan 16:28:11.895 # Sentinel ID is beb9b509fefd0bfcd0d7a58a9956b094cef12503
[30480] 21 Jan 16:28:11.895 # +monitor master mymaster 127.0.0.1 6379 quorum 2
[30480] 21 Jan 16:28:11.898 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
[30480] 21 Jan 16:28:11.901 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
[30480] 21 Jan 16:28:52.969 * +sentinel sentinel e6f45d87cc07b47c280c21d7676a360df2b220f8 127.0.0.1 9737 @ mymaster 127.0.0.1 6379
[30480] 21 Jan 16:29:19.947 * +sentinel sentinel 4f1ced8a0d327b1002a98b5614ec253bedd17a24 127.0.0.1 9738 @ mymaster 127.0.0.1 6379
[30480] 21 Jan 16:29:19.955 # +tilt #tilt mode entered
(2)9737哨兵
E:\redis>redis-server.exe sentinel1.conf --sentinel
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.100 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 9737
| `-._ `._ / _.-' | PID: 21708
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[21708] 21 Jan 16:28:50.898 # Sentinel ID is e6f45d87cc07b47c280c21d7676a360df2b220f8
[21708] 21 Jan 16:28:50.899 # +monitor master mymaster 127.0.0.1 6379 quorum 2
[21708] 21 Jan 16:28:50.903 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
[21708] 21 Jan 16:28:50.905 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
[21708] 21 Jan 16:28:52.780 * +sentinel sentinel beb9b509fefd0bfcd0d7a58a9956b094cef12503 127.0.0.1 9736 @ mymaster 127.0.0.1 6379
[21708] 21 Jan 16:28:56.922 # +sdown sentinel beb9b509fefd0bfcd0d7a58a9956b094cef12503 127.0.0.1 9736 @ mymaster 127.0.0.1 6379
[21708] 21 Jan 16:29:17.265 * +sentinel sentinel 4f1ced8a0d327b1002a98b5614ec253bedd17a24 127.0.0.1 9738 @ mymaster 127.0.0.1 6379
[21708] 21 Jan 16:29:20.041 # -sdown sentinel beb9b509fefd0bfcd0d7a58a9956b094cef12503 127.0.0.1 9736 @ mymaster 127.0.0.1 6379
[21708] 21 Jan 16:29:53.289 # +sdown sentinel beb9b509fefd0bfcd0d7a58a9956b094cef12503 127.0.0.1 9736 @ mymaster 127.0.0.1 6379
(3)9738哨兵
E:\redis>redis-server.exe sentinel2.conf --sentinel
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.100 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 9738
| `-._ `._ / _.-' | PID: 17728
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[17728] 21 Jan 16:29:15.183 # Sentinel ID is 4f1ced8a0d327b1002a98b5614ec253bedd17a24
[17728] 21 Jan 16:29:15.184 # +monitor master mymaster 127.0.0.1 6379 quorum 2
[17728] 21 Jan 16:29:15.187 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
[17728] 21 Jan 16:29:15.189 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
[17728] 21 Jan 16:29:15.557 * +sentinel sentinel e6f45d87cc07b47c280c21d7676a360df2b220f8 127.0.0.1 9737 @ mymaster 127.0.0.1 6379
[17728] 21 Jan 16:29:20.088 * +sentinel sentinel beb9b509fefd0bfcd0d7a58a9956b094cef12503 127.0.0.1 9736 @ mymaster 127.0.0.1 6379
[17728] 21 Jan 16:29:53.408 # +sdown sentinel beb9b509fefd0bfcd0d7a58a9956b094cef12503 127.0.0.1 9736 @ mymaster 127.0.0.1 6379
5.客户端操作
(1)关闭6379服务
E:\redis>redis-cli.exe -p 6379 -a yinkeqi
127.0.0.1:6379> shutdown
(2)查看6380服务主从信息
6380服务被选举为主机
E:\redis>redis-cli.exe -p 6380 -a yinkeqi
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=13232,lag=0
master_repl_offset:13232
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:13231
(3)查看6381服务主从信息
6381服务的主机切换为了6380
E:\redis>redis-cli.exe -p 6381 -a yinkeqi
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:21896
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
九、redis配置文件详解
###################### 网络配置 ######################
bind 127.0.0.1 ### 绑定本机ip,只允许本地连接
requirepass yinkeqi ### 设置当前redis服务的密码
protected-mode yes ### 启动保护模式,校验bind的ip以及密码,关闭则不校验
port 6379 ### 设置服务端口
###################### 主从配置 ######################
databases 16 ### 设置数据库的数量,默认为0数据库
slaveof 127.0.0.1 6379 ### 设置本机为6379服务的从机
masterauth yinkeqi ### 当设置slaveof后,如果主机有密码必须设置主机密码,否则无法复制
daemonize yes ### windows不支持,指定该服务为后台守护进程,必须kill才能关闭,关闭服务窗口不会关闭服务
pidfile /var/run/redis.pid ### windows不支持,指定保存redis的进程id的文件
###################### rdb存储 ######################
dir ./ ### 指定rdb保存目录
dbfilename dump.rdb ### 指定rdb方式持久化的文件名
rdbcompression yes ### rdb持久化时,是否进行压缩处理
save 900 1 ### 每900秒有一次更新就保存
save 300 10 ### 每300秒有10次更新就保存
save 60 10000 ### 每60秒有10000次更新就保存
###################### aof存储 ######################
appendonly yes ### 开启aof存储模式
appendfilename "appendonly.aof" ### 设置aof存储的文件名
appendfsync everysec ### 每秒进行一次持久化
# appendfsync no ### 不进行持久化,仅在系统需要时持久化
# appendfsync always ### 每次操作都进行持久化
###################### 限制配置 ######################
maxclients 10000 ### 最大的客户端连接数
maxmemory <bytes> ### 最大的内存容量
maxmemory-policy noeviction ### 达到最大内存时的删除策略
# volatile-lru -> 使用lru算法(最近最少使用算法)删除有过期时间的键
# allkeys-lru -> 使用lru算法删除任何键(包含设置了过期时间和没设置过期时间的键)
# volatile-random -> 随机删除带有过期时间的的键
# allkeys-random -> 随机删除任意键
# volatile-ttl -> 删除过期时间最近的键
# noeviction -> 不删除键,返回错误,提示无法写入