Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。(B/S架构)
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
-
下载压缩包
github:https://github.com/tporadowski/redis/releases
-
解压缩
-
配置环境变量
添加REDIS_HOME系统变量:
再配置环境变量path(即在path中添加):
-
试运行
尝试在任何地方使用cmd运行如下命令:
redis-server
如果出现如下内容则证明redis安装成功并且环境变量配置成功:
Redis服务端 服务端启动Redis服务Redis默认端口号:6379
-
前台启动
redis-server
-
后台启动
redis-server &
-
指定配置文件启动
redis-server
[&] (是否后台启动)
redis-cli shutdownRedis客户端
Redis分为客户端和服务端。客户端用于连接Redis服务,并且向Redis服务端发送命令。
启动cli客户端使用以下命令即可启动redis的客户端程序
redis-cli #默认连接127.0.0.1:6379的redis服务 [-p port] #指定端口号 [-h hostname] #指定主机地址退出cli客户端
exit [quit]Redis基本知识 服务端测试Redis性能
redis-benchmark客户端查看Redis服务是否正常运行
127.0.0.1:6379>ping PONG #返回PONG说明Redis服务正常运行客户端查看Redis服务的统计信息
127.0.0.1:6379>info #返回redis服务的所有相关信息 [section] #查看具体某一指定端的信息Redis数据库实例
Redis的数据库实例只能由Redis服务来创建和维护,开发人员不能修改和自行创建数据库实例。默认情况下,Redis会自动创建16个数据库实例,并且这些数据库实例由编号来区别,由0—15来使用。Redis的数据库实例本身占用的存储空间很少。Redis客户端默认连接的是编号为0的数据库实例。
客户端切换数据库实例127.0.0.1:6379>select [index] #根据编号切换数据库实例客户端查看数据库实例记录数(key的数量)
127.0.0.1:6379>dbsize (integer) 2 #返回key的数量客户端查看当前数据库实例所有key
127.0.0.1:6379>keys [pattern] [*] # * 所有 1) "key:__rand_int__" 2) "k1" #返回有哪些key客户端清空当前数据库实例
127.0.0.1:6379>flushdb客户端清空所有数据库实例
127.0.0.1:6379>flushall客户端查看当前Redis服务的配置信息
127.0.0.1:6379>config get [param] [*]Redis的五种数据结构
Redis支持五种数据类型:string(字符串),list(列表),hash(哈希),set(集合)及zset(sorted set:有序集合)。
string(字符串)string是redis最基本的类型,一个key对应一个value,是二进制安全的。可以包含任何数据,比如jpg图片或者序列化的对象。
最大能存储512MB
cli> set key value 127.0.0.1:6379> SET runoob "菜鸟教程" 127.0.0.1:6379> GET runoob "菜鸟教程"list(列表)
简单的字符串列表,按照插入顺序排序,可以添加元素到头部或者尾部
列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。
cli> lpush key member cli> lrange key start end #从start到end遍历key列表 127.0.0.1:6379> lpush runoob redis 127.0.0.1:6379> lpush runoob mongodb redis 127.0.0.1:6379> lrange runoob 0 10 1) "mongodb" 2) "redis"set(集合)
字符串的无序集合(基于哈希表实现,故不能插入重复的value)。
cli> sadd key member #成功返回1,失败返回0(如重复) cli> smembers key #遍历key集合 127.0.0.1:6379> sadd runoob redis 127.0.0.1:6379> sadd runoob mongodb 127.0.0.1:6379> smembers runoob 1) "redis" 2) "mongodb"hash(哈希)
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
每个 hash 可以存储 232 -1 键值对(40多亿)。
#存入key对象,其中属性field1的值为value1,属性filed2的值为value2 cli> HMSET key field1 value1 field2 value2 #获取key对象中属性为filed的值value cli> HGET key filed 127.0.0.1:6379> HMSET runoob field1 "Hello" field2 "World" "OK" 127.0.0.1:6379> HGET runoob field1 "Hello" 127.0.0.1:6379> HGET runoob field2 "World"zset(有序集合)
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数(score)。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
cli> zadd key score member cli> zrangebyscore key start end #根据具体分数(score必须在start和end范围内)排序 cli> zrange key start end #排序(根据分数) redis 127.0.0.1:6379> zadd runoob 0 redis (integer) 1 redis 127.0.0.1:6379> zadd runoob 0 mongodb (integer) 1 redis 127.0.0.1:6379> zadd runoob 0 rabbitmq (integer) 1 redis 127.0.0.1:6379> zadd runoob 0 rabbitmq (integer) 0 redis 127.0.0.1:6379> ZRANGEBYSCORE runoob 0 1000 1) "mongodb" 2) "rabbitmq" 3) "redis"Redis命令的基本语法
cli> COMMAND KEY_NAME
COMMAND是命令,KEY_NAME是键
如
127.0.0.1:6379> DEL runoobkey
DEL是删除命令,runoobkey是一个键,该命令的目的是删除runoobkey
Redis关于key的命令 查询key的命令(keys)基本语法格式
cli> keys [pattern] #pattern是匹配规则 [*] #匹配0个或者多个字符 [?] #只匹配1个字符 [[]] #只匹配[]中的1个字符 [a*] #以'a'字符开始的key [a*b] #以'a'开始,'b'结尾的key
如
127.0.0.1:6379> keys * #查看所有key 1) "ageZset" 2) "name" 3) "osList" 4) "citySet" 5) "key:__rand_int__" 6) "k1" 127.0.0.1:6379> keys k* #查看以'k'字符开头的key 1) "key:__rand_int__" 2) "k1" 127.0.0.1:6379> keys a*t #查看以'a'开头,t结尾的key 1) "ageZset" 127.0.0.1:6379> keys n?me #查看第1个字符为n,第34字符为me的key 1) "name" 127.0.0.1:6379> keys n[abc]me #查看第1个字符为n,第2个字符为[abc]其中一个,第34字符为me的key 1) "name"判断key是否存在(exists)
cli> exists key [key key key...] #判断key是否存在 #存在返回1(或存在的数量),否则返回0
如
127.0.0.1:6379> exists name (integer) 1 127.0.0.1:6379> exists name osList ageZset citySet (integer) 4 127.0.0.1:6379> exists name osList ageZset citySet test (integer) 4移动key到指定的数据库实例(move)
cli> move key index #移动key到index数据库实例查看key剩余生存时间(ttl)
单位是秒。(TTL:time to live)
cli> ttl key #查看key的剩余生存时间 #返回-1,永不过期(默认) #返回-2,key不存在设置定key的生存时间(expire)
cli> expire key seconds #给key设置生存时间seconds秒(超出即被删除)查看key的数据类型(type)
cli> type key #查看key的数据类型重命名key(rename)
cli> rename key newkey删除key(del)
cli> del key [key key key...] #返回成功删除key的条数总结
- 增
- 删
- del:删除key
- 改
- move:移动key
- expire:设置key的生存时间
- rename:重命名
- 查
- keys:查询key
- exists:判断key是否存在
- ttl:查询key的剩余生存时间
- type:查看key的数据类型
单key——单value
存string类型数据(set)cli> set key value #如果key已经存在,会发生覆盖取string类型数据(get)
cli> get key追加字符串(append)
cli> append key value #往key中追加字符串value #返回值是追加后字符串长度 #如果key不存在,相当于set获取字符串长度(strlen)
cli> strlen key #返回key的字符串长度将字符串数值进行加1运算(incr)
cli> incr key #key的value+1并且返回
将字符串数值进行减1运算(decr)Tips:
- 如果key不存在,则先创建该key-value,value初始化为0然后+1
- key的value必须是数值,否则报错
cli>decr key
与incr同理
将字符串数值进行加offset(指定数值)运算(incrby)cli>incrby key offset #key的vaule+offset并且返回将字符串数值进行减offset(指定数值)运算(decrby)
cli>decrby key offset #key的vaule-offset并且返回获取字符串中字符串(getrange)
cli>getrange key startIndex endIndex #截取key中value从startIndex到endIndex设置字符串中字符串(setrange)
会改变数据库中的值
cli>setrange key startIndex value #用value覆盖从下标为startIndex开始的字符串设置字符串的同时设置生命周期(setex)
cli>setex key seconds value #给key-value设置seconds秒后过期 cli> setex k1 30 v1 OK cli> ttl k1 (integer) 27设置字符串数据当key不存在才设置,key存在则不设置(setnx)
cli>setnx key value批量设置字符串数据(mset)
cli>mset key1 value1 key2 value2 key3 value3 ...批量获取字符串数据(mget)
cli>mget key1 key2 key3 ...总结
Redis操作string类型
- 增
- set:最基本的存储string类型数据的方式(如果存在则会覆盖)
- setex:存储数据的同时设置生命周期
- setnx:如果存在则不存储
- mset:批量存储
- 删
- 改
- set:修改string类型的数据(如果存在则会覆盖,也就是修改)
- append:在原有的基础上追加数据
- incr:数值字符串增加
- decr:数值字符串减少
- setrange:修改字符串中指定下标的数据
- 查
- get:获得数据
- mget:批量获得数据
- getrange:获得字符串中子串
- strlen:字符串长度
单key——多有序value。顺序跟插入元素的顺序有关
从左侧起存list类型数据(lpush)依次往左侧(头部)添加元素
cli>lpush key value [value value...] cli> lpush list1 1 2 3 4 (integer) 4 cli> lrange list1 0 4 1) "4" 2) "3" 3) "2" 4) "1" #可以看到lpush的顺序后插入的元素在列表中越靠前从右侧起存list类型数据(rpush)
依次从右侧(尾部)添加元素
cli>rpush key value [value value...]获取指定列表中指定下标区间的元素(lrange)
cli>lrange key startIndex endIndex #获取key列表中startIndex到endIndex的元素 cli> lrange list1 0 4 1) "4" 2) "3" 3) "2" 4) "1" cli> lrange list1 0 -1 #获取从头到尾的全部元素,-1表示倒数第一个,即尾部 1) "4" 2) "3" 3) "2" 4) "1"从指定列表中移除并返回表头(左侧)元素(lpop)
cli> lpop key从指定列表中移除并返回表尾(右侧)元素(rpop)
cli> rpop key获取列表中指定下标的元素(lindex)
cli> lindex key index获取指定列表的长度(元素个数)(llen)
cli> llen key移除指定列表中数据(lrem)
cli>lrem key count value #移除key列表count个中值为value的元素 # count > 0 从左侧起移除 # count < 0 从右侧起移除 # count = 0 移除所有总结
Redis操作list类型
- 增
- lpush:从左边添加元素
- rpush:从右边添加元素
- 删
- lpop:从左边弹出元素
- rpop:从右边弹出元素
- lrem:移除指定元素
- 改
- 查
- lrange:遍历
- lindex:指定下标的元素
- llen:长度
单key——多无序且不可重复value
将一个或多个元素添加到指定集合中(sadd)cli> sadd key value [value value ...] #若元素重复,则忽略 cli> sadd set1 a b c a (integer) 3 #成功添加元素的个数 #只添加成功三个获取指定集合中的元素(smembers)
cli> smembers key cli> smembers set1 1) "c" 2) "b" 3) "a"判断元素在集合中是否存在(sismember)
cli> sismember key member (integer) 1 #返回1则存在 (integer) 0 #返回0则不存在获取集合的长度(scard)
cli> scard key移除集合中1个或者多个元素(srem)
cli> srem key member [member ...] #返回成功移除的元素的个数随机获取集合中的一个或多个元素(srandmember)
cli> srandmember key [count] #count>0 随机获取的元素不会重复 #count<0 随机获取的元素可能重复随机移除集合中的一个或多个元素(spop)
cli> spop key [count]将集合中的元素移动到另一集合(smove)
cli> smove source dest member #将source集合中的member移动到dest集合获取集合的差集(sdiff)
即一个集合中有,但是其他集合中没有的元素
cli> sdiff key1 key2 [key3 ...] #即key1集合中有,其他集合中没有的元素 cli> smembers set1 1) "f" 2) "c" 3) "e" 4) "g" 5) "a" 6) "b" cli> smembers set2 1) "d" 2) "c" 3) "g" 4) "f" 5) "e" 6) "i" 7) "b" 8) "a" 9) "h" cli> sdiff set2 set1 #set2中有hid,但是set1中没有 1) "i" 2) "d" 3) "h"获取集合的交集(sinter)
即指定集合中都有的元素
cli> sinter key key [key key...] 127.0.0.1:6379> smembers set1 1) "f" 2) "c" 3) "e" 4) "g" 5) "a" 6) "b" 127.0.0.1:6379> smembers set2 1) "d" 2) "c" 3) "g" 4) "f" 5) "e" 6) "i" 7) "b" 8) "a" 9) "h" 127.0.0.1:6379> sinter set1 set2 1) "f" 2) "c" 3) "e" 4) "g" 5) "a" 6) "b" #set1和set2中都有abcefg获取集合的并集(sunion)
即指定集合中的所有元素
cli> sunion key key [key key...]总结
Redis操作set类型
- 增
- sadd:新增元素到集合中
- 删
- srem:移除元素
- spop:弹出元素
- smove:移动过元素到另一集合
- 改
- sadd:新增元素到集合中,如果value已经存在则会覆盖
- 查
- smembers:遍历集合元素
- sismember:判断元素是否存在
- scard:集合长度
- srandmember:随机获取集合元素
- sdiff:差集
- sinter:交集
- sunion:并集
单key——field-value
field-value
field-value
适合存储对象
将一个或多个field-value(属性—值)对存入hash表,会覆盖(hset)如果key中的filed之前是存在的,则会强制覆盖(使用hsetnx不会强制覆盖)
cli> hset key field1 value1 [field2 value2 ...] cli> hset student1 name wqk age 20 (integer) 2获取指定hash表中指定field值(hget)
cli> hget key field #获取key哈希表中field的值 cli> hget student1 name "wqk"批量获取指定hash表中field的值(hmget)
cli> hmget key field1 [field2 field3 ...] cli> hmget student1 name age 1) "wqk" 2) "20"获取hash表中所有的field和value(hgetall)
cli> hgetall key cli> hgetall student1 1) "name" 2) "wqk" 3) "age" 4) "20"移除hash表中指定一个或者多个field(hdel)
cli> hdel key field1 [field2 field3 ...]统计hash表中field数量(hlen)
cli> hlen key判断hash表中是否存在某field(hexists)
cli> hexists key field #返回0表示不存在,1表示存在获取hash表中所有的field列表(hkeys)
cli> hkeys key cli> hkeys student2 1) "id" 2) "name" 3) "age"获取hash表中所有的value(hvals)
cli> hvals key cli> hvals student2 1) "10001" 2) "test" 3) "18"对hash表中指定field的value进行整数加法运算(hincrby)
cli> hincrby key field incrment #对key哈希表中的field属性的值进行加incrment值运算 cli> hget student2 age "18" cli> hincrby student2 age 2 (integer) 20对hash表中指定field的value进行浮点数加法运算(hincrbyfloat)
cli> hincrbyfloat key field incrment cli> hset student2 score 85 (integer) 1 cli> hincrbyfloat student2 score 1.5 "86.5"将一个或多个field-value(属性—值)对存入hash表,不会覆盖(hsetnx)
如果key的field已经存在则放弃设置
cli> hsetnx key filed1 value1 [field2 value2]总结
Redis操作hash类型
- 增
- hset:存入hash类型数据
- hsetnx:存入数据,如果存在则不存入
- 删
- hdel:删除hash表中field及其value
- 改
- hset:存入hash类型数据,如果field存在则会覆盖
- hincrby:value是数值,则会增加
- 查
- hget:获取hash表中指定field的value
- hmget:批量获取hash表中指定field的value
- hgetall:获取hash表中所有field及其value
- hlen:获取hash表中field的数量
- hexists:判断hash表中该field是否存在
- hkeys:获取hash表中所有field
- hvals:获取hash表中所有value
有序集合。顺序跟score有关
将一个或多个member及其score值加入有序集合(zadd)score必须是数值。如果member已经存在,则会覆盖
cli> zadd key score member [score member] cli> zadd zset1 95 wqk 90 lk 98 zp (integer) 3获取有序集合中指定下标区间的元素(zrange)
cli> zrange key startIndex endIndex [withscores] #获取key集合startIndex到endIndex区间的元素(是否显示分数)获取有序集合中指定分数区间(闭区间)的元素(zrangebyscore)
cli> zrangebyscore key min max [withscores] #获取key集合min到max分数区间的元素(是否显示分数)删除有序集合中一个或者多个元素(zrem)
cli> zrem key member [member]获取有序集合中元素个数(zcard)
cli> zcard key获取有序集合中分数在指定区间的元素个数(zcount)
cli> zcount key min max #获取key有序集合中min到max区间的元素个数获取有序集合中指定元素的排名(升序)(zrank)
cli> zrank key member获取有序集合中指定元素的排名(降序)(zrevrank)
cli> zrevrank key member获取有序集合指定元素的分数(zscore)
cli> zscore key member总结
Redis操作zset类型
- 增
- zadd:往集合中存入元素
- 删
- zrem:移除集合中的元素
- 改
- 查
- zrange:遍历集合元素
- zrangebyscore:根据score遍历集合元素
- zcard:集合元素个数
- zcount:指定分数区间元素个数
- zrank:元素的排名(正序)
- zrevrank:元素的排名(倒序)
- zscore:元素的分数
Redis根目录下有个默认的配置文件:.redis.conf,里面有一些redis默认的配置参数
cli> redis-server [config_name] #默认使用默认的配置的文件网络配置
-
port
指定redis服务所使用的端口号,默认6379
-
bind
指定客户端连接redis服务时,所能使用的主机地址,默认是redis服务所在主机名,一般情况下都需要指定主机名
-
tcp-keeplive
TCP连接保活策略,单位是秒。指的是Redis服务端会在指定秒内向连接他的客户端发送一次ACK请求,以确保连接有效。默认是60秒
如果以上配置在配置文件中生效,则在客户端中连接需使用:
redis-cli -h bind -p 6380常规配置
-
loglevel
配置日志级别,分为四个级别:debug、verbose、notice、warning。默认是notice
-
logfile
日志文件持久化存储的地方。默认不会持久化,只会输出到终端
-
databases
配置Redis服务默认创建的数据库实例个数。默认是16个。
-
requirepass
配置Redis客户端访问Redis服务时的密码,需要protected-mode = yes时生效
如配置了requirepass,则在客户端连接中需使用:
redis-cli [-h hostname] [-p port] [-a pwd]Redis数据持久化
Redis提供持久化策略,可以在适当的时机采用适当的手段把内存中的数据持久化的磁盘。
RDB策略(Redis默认启用的持久化策略)RDB(Redis Database)策略是指,在指定时间间隔内,Redis服务执行指定次数的写操作,会自动触发一次持久化操作。如需修改可以在redis的配置文件中修改RDB相关的配置(dbfilename持久化数据的文件名,默认是dump.rdb,dir持久化数据的目录,默认是./,即根目录)。
AOF策略记录每一次Redis服务的完整写操作进入日志,每次Redis服务启动时,都会重新执行一遍完整的操作日志以便恢复数据。效率不高,默认不开启AOF(appendonly配置是否开启AOF策略,appendfilename配置操作日志文件)。
Redis事务数据库事务:一组对数据库的操作一起执行,保证操作的原子性,要么同时成功,要么同时失败。
Redis事务:允许一组Redis命令放在一起,将命令序列化,然后按队列执行,保证部分原子性。
multi标记一个Redis事务的开始(与exec成对存在)。
exec标记一个Redis事务的结束(与multi成对存在),即立即开始执行上述事务。
一个完整的Redis事务的输入格式应该是如下
cli> multi #标识事务开始了 cli> set k1 v1 #操作1 cli> set k2 v2 #操作2 cli> exec #标识事务结束了(即立即开始执行)
cli> multi OK #事务开启 cli> set str1 value1 QUEUED #操作1加入队列 cli> set str2 value2 QUEUED #操作2加入队列 cli> exec 1) OK #操作1执行结果 2) OK #操作2执行结果
discardTips:
Redis事务不是脚本命令。而是在cli执行multi后接着一行一行输入操作的命令(操作会插入队列),最后执行exec才会按队列执行上述操作。为保证事务的部分原子性,Redis事务遵循以下两则规则:
输入事务操作过程中如果发生错误,则事务输入失败,即事务无法被创建。即multi和exec中间操作语句有错误则事务无法被创建。
cli> multi cli> set k1 v1 cli> seta k2 v2 #操作2:命令错误 cli> exec #该事务无法被创建:操作的命令错误如果上述规则没有发生错误,则在最后执行操作队列时,即使其中一项操作执行异常仍会继续执行其余操作。
cli> multi cli> set k1 v1 cli> incr k1 cli> exec #事务会被创建,即使incr的执行结果异常
清除已经存在于操作队列中的命令
cli> multi OK cli> set k5 v5 QUEUED cli> set k6 v6 QUEUED cli> discard #清空上述操作队列 OK cli> exec (error) ERR EXEC without MULTI #exec执行失败的原因是操作命令的队列被清空watch
在事务开启前(multi)监控某一个键,在事务执行的过程中监控的键的值发生变化,则此次事务放弃执行;否则正常执行。
用以下事务来模拟一个场景:钱包A余额50,钱包B余额50,钱包B向钱包A转账50,那么最后钱包B余额0,钱包A余额100。并发情况下假如多个钱包需要向钱包B转账,那么就会发生错误。所以需要监控该次事务执行前的version是否还是该version。
cli> set balanceA 50 OK cli> set balanceB 50 OK cli> set verison 1 OK cli> watch version #监控version的值 OK cli> multi OK cli> incrby balanceA 50 QUEUED cli> decrby balanceB 50 QUEUED cli> incr version QUEUED cli> exec 1) (integer) 100 2) (integer) 0 3) (integer) 2
unwatchTips
watch就是类似于乐观锁,A事务执行前查询一个键(该键会在其他事务进行该事务后发生改变,即标识此次事务执行成功),如果该键在A事务执行过程中发生了改变(说明其他事务对数据进行了操作),即A事务应该不执行,如果该键没有发生改变,则A事务正常执行。
放弃监控的所有键。
Redis消息的发布与订阅(了解)Redis客户端订阅频道,订阅了同一频道的客户端可以发送或者收到来自同一频道的消息。(消息中间件)
subscribe订阅频道(以便接收消息)
cli> subscribe channel [channel ...] #可以订阅多个频道
client1:
订阅了ch1频道
cli> subscribe ch1 Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "ch1" 3) (integer) 1
client2:
订阅了ch1频道
cli> subscribe ch1 Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "ch1" 3) (integer) 1
此时client1和client2都订阅了ch1频道,如果有客户端往ch1频道发送消息,那么client1和client2都会收到
psubscribe订阅频道(支持通配符)
cli> psubscribe pattern [pattern ...] cli> psubscribe news* #订阅以news开头的频道publish
往频道上发布消息
cli> publish channel message #往channel频道发送message消息
client3向ch1频道发送消息:
cli> publish ch1 Hello,Redis! (integer) 2
此时client1和client2就会收到来自client3的消息:
1) "message" 2) "ch1" 3) "Hello,Redis!"Redis主从复制 搭建一主二从的Redis集群并启动
实际开发中应分别在三台不同的服务器上部署三个Redis服务,这里为了方便演示选择在同一台服务器启动三个配置文件不同的Redis服务来模拟,三个Redis服务端口号分别是6379、6380、6381,三份配置文件名命名为:redis_6379.conf、redis_6380.conf、redis_6381.conf。
redis_6379.conf:
port 6379 #修改端口号 logfile "redis_6379.log" #修改生成的日志文件名 dbfilename redis_6379.rdb #修改持久化的文件名
同理,redis_6380.conf和redis_6381.conf也需要修改以上配置
Tips
需要修改日志和持久化文件的文件名,不然可能会造成数据冲突。
接下来使用redis-server
redis-server redis_6379.conf redis-server redis_6380.conf redis-server redis_6381.conf使用cli分别连接三台Redis服务
redis-cli -p 6379 redis-cli -p 6380 redis-cli -p 6381查看Redis服务的主从信息
cli> info replication # Replication role:master #角色:主机 connected_slaves:0 #已连接的从机数量:0 master_replid:91792be1189896bfa47e7a99aae23b8702c8c93b master_replid2:0000000000000000000000000000000000000000 master_repl_offset:0 second_repl_offset:-1 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0
初始化的Redis服务的角色都是主机,即role:master。
设置从机从属于主机(slaveof)命令格式如下:
cli> slaveof host port #设置当前连接的服务从属于host:port的redis服务
在已连接从机服务的客户端上执行:slaveof 127.0.0.1 6379,即
127.0.0.1:6380> slaveof 127.0.0.1 6379 OK 127.0.0.1:6380> info replication # Replication role:slave #角色:从机 master_host:127.0.0.1 #主机host地址 master_port:6379 #主机port端口号 master_link_status:up #与主机连接状态:up(已连接) ...
127.0.0.1:6381> slaveof 127.0.0.1 6379 OK 127.0.0.1:6381> info replication # Replication role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up ...全量复制
一旦主从关系确定,主库会将所有数据立马同步到从库。
增量复制在主库上写的数据,会同步到从库。
读写分离,主写从读主机既能读也能写(尽量写),从机只能读不能写。
主机宕机,从机原地待命主机宕机后,从机仍然可以读数据,可以从info replication中看到与主机的连接状态变为down
127.0.0.1:6380> info replication # Replication role:slave #角色仍是从机 master_host:127.0.0.1 master_port:6379 master_link_status:down #与主机的连接状态变为down(未连接)主机恢复,恢复原样
主机恢复后,恢复到原样,从机与主机继续建立连接
127.0.0.1:6380> info replication # Replication role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up #与主机的连接状态变为up(已连接)从机宕机
从机宕机后,主机少一台从机,其余从机不受影响
从机恢复从机恢复后,会初始化到最初的状态(即变为role:master),需要重新设置从属主机,然后主机的数据会全量复制到从机上。
主机宕机,从机上位主机宕机后,如果主机灾害程度无法短时间恢复则可以使用从机进行上位(即取代主机)。
-
选择一个从机取消其原本的从属关系,成为新的主机
127.0.0.1:6380> slaveof no one #取消从属关系(成为主机) OK 127.0.0.1:6380> info replication #查看复制关系 # Replication role:master #角色:主机(新的主机) connected_slaves:0 ...
此时6380从机成为了新的主机,并且仍保留原有的数据
-
其余从机重新从属于新的主机
127.0.0.1:6381> slaveof 127.0.0.1 6380 #6381从机从属于6380 OK 127.0.0.1:6381> info replication # Replication role:slave master_host:127.0.0.1 master_port:6380 master_link_status:up
Redis哨兵模式Tips
主机可读可写,从机只能读,不能写。
Redis的哨兵模式会在某一Redis服务发生故障(如宕机)时,自动执行从机上位(按照一定规则),并且主机恢复后会从属于新的主机。流程如下:
-
配置哨兵的配置文件
redis_sentinel.conf:(配置文件名称自定义)
#该哨兵的名称是sentinel-redis。作用是monitor(监控)主机127.0.0.1的6379(端口)上的Redis服务 sentinel monitor sentinel-redis 127.0.0.1 6379 1
-
启动哨兵
cmd> redis-server redis_sentinel.conf --sentinel
出现以下内容则启动成功:
cmd>redis-server.exe redis_sentinel.conf --sentinel [16228] 07 Oct 21:58:19.446 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo [16228] 07 Oct 21:58:19.446 # Redis version=5.0.10, bits=64, commit=1c047b68, modified=0, pid=16228, just started [16228] 07 Oct 21:58:19.446 # Configuration loaded _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 5.0.10 (1c047b68/0) 64 bit .-`` .-```. ```/ _.,_ ''-._ ( ' , .-` | `, ) Running in sentinel mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 26379 | `-._ `._ / _.-' | PID: 16228 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' [16228] 07 Oct 21:58:19.452 # Sentinel ID is 192b87ae0be76565fefed74ead2f28454a49f746 [16228] 07 Oct 21:58:19.452 # +monitor master sentinel-redis 127.0.0.1 6379 quorum 1 [16228] 07 Oct 21:58:19.456 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ sentinel-redis 127.0.0.1 6379 [16228] 07 Oct 21:58:19.457 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ sentinel-redis 127.0.0.1 6379 -
监控的主机宕机,从机会在短时间后上位(变为新的主机,其余从机从属于该新主机)
(此时6379宕机)
6381成为新的主机:
127.0.0.1:6381> info replication # Replication role:master connected_slaves:1 slave0:ip=127.0.0.1,port=6380,state=online,offset=22068,lag=0 ...
6380从属于6381:
127.0.0.1:6380> info replication # Replication role:slave master_host:127.0.0.1 master_port:6381 master_link_status:up ...
-
旧主机恢复,变为新主机的从机
(此时6379恢复)
6379从属于6381:
127.0.0.1:6379> info replication # Replication role:slave master_host:127.0.0.1 master_port:6381 master_link_status:up ...
总结Tips
哨兵并不会在主机宕机的一瞬间就将从机上位,而是在一定间隔时间内扫描,扫描到主机宕机了再让从机上位,旧主机恢复时,哨兵将其变为新主机的从机时同理(并不会立马执行,而是在一定时间间隔内)。
-
查看Redis服务的主从关系
cli> info replication
-
设置Redis服务之间的从属关系
cli> slaveof host port #执行命令的当前主机从属于host:port上的Redis服务
-
开启哨兵模式
cmd> redis-sentinel
#以sentinel_config配置文件执行哨兵
Jedis的使用Tips
- 主从复制原则:先全量复制,再增量复制
- 哨兵三大任务:监控、提醒、自动故障迁移
Jedis是在Java上使用Redis的客户端,封装了一些命令和操作。类似jdbc,同时Spring官方还提供Spring Data Redis
引入Jedis依赖采用Maven项目进行演示,需要引入Jedis依赖
配置主机和端口号redis.clients jedis 2.9.0
创建Jedis的连接
JedisConnection.java
public class JedisConnection {
//host
public static final String REDIS_HOST = "127.0.0.1";
//port
public static final int REDIS_PORT = 6379;
public static Jedis getJedis(){
return new Jedis(REDIS_HOST,REDIS_PORT);
}
}
操作key
具体命令参考Redis操作key
public class JedisKeys {
public static void main(String[] args) {
//获得Jedis对象
Jedis jedis = JedisConnection.getJedis();
//是否能连接上redis服务
String ping = jedis.ping();
//查询keys
Set keys = jedis.keys("*");
//k1是否存在
Boolean existsK1 = jedis.exists("k1");
//k1的生存时间
Long ttlK1 = jedis.ttl("k1");
//k1的类型
String typeK1 = jedis.type("k1");
// ...
}
}
操作string
具体命令参考Redis操作string类型
public class JedisString {
public static void main(String[] args) {
//获得Jedis对象
Jedis jedis = JedisConnection.getJedis();
//存储string数据
String setResult = jedis.set("k3", "v3");
//批量存储string数据
String msetResult = jedis.mset("k4", "v4", "k5", "v5");
//获得k3的value
String getK3 = jedis.get("k3");
//存储k10并且自加
jedis.set("k10","5");
jedis.incr("k10");
//存储k11并且自加50
jedis.set("k11","100");
jedis.incrBy("k11", 50);
//获得k3的字符串长度
jedis.strlen("k3");
//...
}
}
操作list
具体命令参考Redis操作list类型
public class JedisList {
public static void main(String[] args) {
Jedis jedis = JedisConnection.getJedis();
//从左边添加元素
jedis.lpush("list1","v1","v2","v3");
//移除左边的元素
jedis.lpop("list1");
//遍历list1
List list1 = jedis.lrange("list1", 0, -1);
list1.forEach(System.out::println);
//返回list1长度
jedis.llen("list1");
//从右边添加元素
jedis.rpush("list2","v1","v2","v3");
//从右边移除元素
jedis.rpop("list2");
//遍历list2
List list2 = jedis.lrange("list2", 0, -1);
list2.forEach(System.out::println);
//返回list2长度
jedis.llen("list2");
//...
}
}
操作set
具体命令参考Redis操作set类型
public class JedisSet {
public static void main(String[] args) {
Jedis jedis = JedisConnection.getJedis();
//添加元素
jedis.sadd("set1","v1","v2","v3");
//判断元素是否存在
jedis.sismember("set1","v1");
//(随机)弹出元素
jedis.spop("set1",1);
//移除v1,v2元素
jedis.srem("set1","v1","v2");
//遍历set1
Set smembers = jedis.smembers("set1");
smembers.forEach(System.out::println);
//set1长度
jedis.scard("set1");
//...
}
}
操作hash
具体命令参考Redis操作hash类型
public class JedisHash {
public static void main(String[] args) {
Jedis jedis = JedisConnection.getJedis();
//存入对象student1
jedis.hset("student1","name","wqk");
HashMap map = new HashMap<>();
map.put("age","18");
map.put("score","98");
//批量存入student1
jedis.hmset("student1",map);
//获取student1对象的name值
jedis.hget("student1","name");
//批量获取student1对象的name、age、score
jedis.hmget("student1","name","age","score");
//获取student1对象的所有field-value
jedis.hgetAll("student1");
//...
}
}
操作zset
具体命令参考Redis操作zset类型
public class JedisZset {
public static void main(String[] args) {
Jedis jedis = JedisConnection.getJedis();
//向zset1添加v1,v2,v3
jedis.zadd("zset1",500,"v1");
jedis.zadd("zset1",1000,"v2");
jedis.zadd("zset1",100,"v3");
//按照下标遍历zset1
Set zset1 = jedis.zrange("zset1", 0, -1);
zset1.forEach(System.out::println);
//按照分数遍历zset1
Set zset11 = jedis.zrangeByScore("zset1", 0, 1000);
zset11.forEach(System.out::println);
//zset1长度
jedis.zcard("zset1");
//...
}
}
Redis事务
public class JedisTransaction {
public static void main(String[] args) {
Jedis jedis = JedisConnection.getJedis();
//获取Redis的事务对象
Transaction transaction = jedis.multi();
// start
transaction.set("k6","v6");
transaction.set("k7","v7");
// end
transaction.exec(); //执行事务
}
}
Redis客户端可视化
一个开源的Redis客户端可视化工具Redis-Desktop-Manager



