redis简介 redis是什么?
Redis(Re mote Di ctionary S erver ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
免费和开源!是当下最热门的NoSql技术之一!也被人们称为结构化数据库!
redis能干嘛?
内存存储、持久化,内存是断电即失的,所以需要持久化(RDB、AOF)
高效率、用于高速缓冲
发布订阅系统
地图信息分析
计时器、计数器(eg:浏览量)
redis特性?
多样的数据类型
持久化
集群
事务
redis是单线程的,redis是基于内存操作的,cpu不是redis的性能瓶颈,redis的瓶颈是根据机器的内存和网络宽带,既然可以使用单线程来实现,就使用单线程了
linux安装 下载地址:https://redis.io/
下载:redis-6.2.10.tar.gz
[root@quan quan]# cd /opt [root@quan opt]# ls -l -rw-r--r-- 1 root root 2490833 2月 12 18:22 redis-6.2.10.tar.gz [root@quan opt]# tar -zxvf redis-6.2.10.tar.gz [root@quan opt]# cd redis-6.2.1 [root@quan redis-6.2.1]# yum install gcc-c++ [root@quan redis-6.2.1]# make [root@quan redis-6.2.1]# make isntall [root@quan redis-6.2.1]# cd /usr/local/bin [root@quan bin]# mkdir myconfig [root@quan bin]# cp /opt/redis-6.2.10/redis.conf /usr/local/bin/myconfig/ [root@quan bin]# cd myconfig/ [root@quan myconfig]# vim redis.conf daemonize yes [root@quan myconfig]# cd .. [root@quan bin]# redis-server myconfig/redis.conf [root@quan bin]# redis-cli -p 6379 127.0.0.1:6379> ping PONG 127.0.0.1:6379> [root@quan ~]# ps -ef|grep redis polkitd 3324 3304 0 16:26 ? 00:00:27 redis-server *:6379 root 3387 1460 0 16:26 pts/1 00:00:00 docker exec -it ae5139dfe541 redis-cli root 3403 3304 0 16:26 pts/0 00:00:00 redis-cli root 12600 3647 0 21:20 pts/0 00:00:00 redis-cli -p 6379 root 12621 12603 0 21:21 pts/2 00:00:00 grep --color=auto redis [root@quan bin]# 127.0.0.1:6379> shutdown (0.51s) not connected> exit
测试性能 redis-benchmark:Redis官方提供的性能测试工具
[root@quan ~]# cd /usr/local/bin/ [root@quan bin]# ls dump.rdb myconfig redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server [root@quan bin]# redis-benchmark -h localhost -p 6379 -c 100 -n 100000
Redis命令 select
语法
说明
select index
切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值。
[root@quan myconfig]# cd /usr/local/bin/myconfig/ [root@quan myconfig]# vim redis.conf databases 16 [root@quan bin]# redis-cli -p 6379 127.0.0.1:6379> set db_number 0 OK 127.0.0.1:6379> select 1 OK 127.0.0.1:6379[1]> get db_number (nil) 127.0.0.1:6379[1]> select 3 OK 127.0.0.1:6379[3]>
keys
语法
说明
keys pattern
查找所有符合给定模式 pattern 的 key
127.0.0.1:6379> set runoob1 redis OK 127.0.0.1:6379> set runoob2 mysql OK 127.0.0.1:6379> set runoob3 mongodb OK 127.0.0.1:6379> keys runoob* 1) "runoob3" 2) "runoob2" 3) "runoob1" 127.0.0.1:6379> keys * 1) "counter:__rand_int__" 2) "runoob1" 3) "myhash" 4) "runoob3" 5) "key:__rand_int__" 6) "k1" 7) "runoob2" 8) "mylist"
flushdb
语法
说明
flushdb
清空当前数据库中的所有 key。
127.0.0.1:6379> flushdb OK
flushall
语法
说明
flushall
清空整个 Redis 服务器的数据(删除所有数据库的所有 key )。
127.0.0.1:6379[1]> flushall OK
Redis键(key) exists
语法
说明
exists key
检查给定 key 是否存在
127.0.0.1:6379> exists k1 (integer ) 0 127.0.0.1:6379> set k1 v1 OK 127.0.0.1:6379> exists k1 (integer ) 1
move
语法
说明
move key db
将当前数据库的 key 移动到给定的数据库 db 当中。
127.0.0.1:6379> get k1 "v1" 127.0.0.1:6379> move k1 1 (integer ) 1 127.0.0.1:6379> exists k1 (integer ) 0 127.0.0.1:6379> select 1 OK 127.0.0.1:6379[1]> exists k1 (integer ) 1
expire
语法
说明
expire key time
设置 key 的过期时间,key 过期后将不再可用。单位以秒计
127.0.0.1:6379> set name redis OK 127.0.0.1:6379> expire name 60 (integer ) 1
ttl
语法
说明
ttl
以秒为单位返回 key 的剩余过期时间
127.0.0.1:6379> set name redis OK 127.0.0.1:6379> expire name 10 (integer ) 1 127.0.0.1:6379> ttl name (integer ) 8 127.0.0.1:6379> ttl name (integer ) -2 127.0.0.1:6379> set name redis OK 127.0.0.1:6379> ttl name (integer ) -1
type
语法
说明
type key
返回 key 所储存的值的类型。
常见数据类型有:
none (key不存在)
string (字符串)
list (列表)
set (集合)
zset (有序集合)
hash (哈希表)
127.0.0.1:6379> set weather "sunny" OK 127.0.0.1:6379> type weather string
Redis字符串(String) set
语法
说明
set key
设置给定 key 的值。如果 key 已经存储其他值, set 就覆写旧值,且无视类型
127.0.0.1:6379> set key "value" OK 127.0.0.1:6379> get key "value"
get
语法
说明
get key
获取指定 key 的值。如果 key 不存在,返回 nil 。如果key 储存的值不是字符串类型,返回一个错误。
127.0.0.1:6379> get db (nil) 127.0.0.1:6379> get name "redis" 127.0.0.1:6379> lpush db redis mongodb mysql (integer ) 3 127.0.0.1:6379> get db (error) WRONGTYPE Operation against a key holding the wrong kind of value
append
语法
说明
append key value
为指定的 key 追加值
127.0.0.1:6379> append myphone "iphone" (integer ) 6 127.0.0.1:6379> append myphone " - 1110" (integer ) 13 127.0.0.1:6379> get myphone "iphone - 1110"
strlen
语法
说明
strlen key
获取指定 key 所储存的字符串值的长度。当 key 储存的不是字符串值时,返回一个错误。
127.0.0.1:6379> get myphone "iphone - 1110" 127.0.0.1:6379> strlen myphone (integer ) 13 127.0.0.1:6379> strlen nonno (integer ) 0
incr
语法
说明
incr key
将 key 中储存的数字值增一
127.0.0.1:6379> set page_view 20 OK 127.0.0.1:6379> incr page_view (integer ) 21 127.0.0.1:6379> incr page_view (integer ) 22 127.0.0.1:6379> get page_view "22"
decr
语法
说明
decr key
将 key 中储存的数字值减一
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
127.0.0.1:6379> set failure_times 10 OK 127.0.0.1:6379> decr failure_times (integer ) 9 127.0.0.1:6379> decr cou (integer ) -1 127.0.0.1:6379> set commany YOUR_CODE_SUCKS.LLC OK 127.0.0.1:6379> decr commany (error) ERR value is not an integer or out of range
incrby
语法
说明
incrby key amount
将 key 中储存的数字加上指定的增量值。
127.0 .0.1 :6379 > set rank 50 OK 127.0 .0.1 :6379 > incrby rank 20 (integer) 70
decrby
语法
说明
decrby key amount
将 key 所储存的值减去指定的减量值
127.0 .0.1 :6379 > set count 50 OK 127.0 .0.1 :6379 > decrby count 20 (integer) 30
getrange
语法
说明
getrange key start end
获取存储在指定 key 中字符串的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。
127.0 .0.1 :6379 > set mykey "This is my test key" OK 127.0 .0.1 :6379 > getrange mykey 0 3 "This" 127.0 .0.1 :6379 > getrange mykey 0 -1 "This is my test key"
setrange
语法
说明
getrange key offset value
用指定的字符串覆盖给定 key 所储存的字符串值,覆盖的位置从偏移量 offset 开始。
127.0 .0.1 :6379 > set key1 "Hello World" OK 127.0 .0.1 :6379 > setrange key1 6 "Redis" (integer) 11 127.0 .0.1 :6379 > get key1"Hello Redis"
setnx
语法
说明
setnx key value
在指定的 key 不存在时,为 key 设置指定的值。set if not exists
127.0 .0.1 :6379 > exists job (integer) 0 127.0 .0.1 :6379 > setnx job "programer" (integer) 1 127.0 .0.1 :6379 > setnx job "code-farmer" (integer) 0 127.0 .0.1 :6379 > get job "programer"
setex
语法
说明
setex key timout value
为指定的 key 设置值及其过期时间。如果 key 已经存在,setex 命令将会替换旧的值
127.0 .0.1 :6379 > setex mykey 60 redisOK 127.0 .0.1 :6379 > ttl mykey(integer) 57 127.0 .0.1 :6379 > get mykey"redis" 127.0 .0.1 :6379 > ttl mykey(integer) -2 127.0 .0.1 :6379 > get mykey(nil)
mset
语法
说明
mset key1 val1 key2 val3…
同时设置一个或多个 key-value 对
127.0 .0.1 :6379 > mset key1 "Hello" key2 "World" OK 127.0 .0.1 :6379 > get key1"Hello" 127.0 .0.1 :6379 > get key2"World"
mget
语法
说明
mget key1 key2 …
返回所有(一个或多个)给定 key 的值。 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil
127.0 .0.1 :6379 > mget key1 key2 key31 ) "Hello" 2 ) "World" 3 ) (nil)
msetnx
语法
说明
msetnx key1 val1 key2 val3…
所有给定 key 都不存在时,同时设置一个或多个 key-value 对。
127.0 .0.1 :6379 > msetnx rmdbs "Mysql" nosql "Mongodb" key-value-store "redis" (integer) 1 127.0 .0.1 :6379 > mget rmdbs nosql key-value-store 1 ) "Mysql" 2 ) "Mongodb" 3 ) "redis" 127.0 .0.1 :6379 > msetnx key1 val1 key2 val2 (integer) 0
getset
语法
说明
getset key value
设置指定 key 的值,并返回 key 的旧值。
127.0 .0.1 :6379 > getset key1 redis (nil) 127.0 .0.1 :6379 > get key1"redis" 127.0 .0.1 :6379 > getset key1 haha "redis" 127.0 .0.1 :6379 > get key1"haha"
Redis列表(List) Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 4294967295个元素, 每个列表超过40亿个元素。
lpush
语法
说明
lpush key val1 val2…
将一个或多个值插入到列表头部(左)
如果 key 不存在,一个空列表会被创建并执行 lpush 操作。 当 key 存在但不是列表类型时,返回一个错误。
127.0 .0.1 :6379 > lpush list "one" (integer) 1 127.0 .0.1 :6379 > lpush list "two" (integer) 2 127.0 .0.1 :6379 > lpush list "three" (integer) 3 127.0 .0.1 :6379 > lrange list 0 -1 1 ) "three" 2 ) "two" 3 ) "one"
lrange
语法
说明
lrange key start end
返回列表中指定区间内的元素,区间以偏移量 start 和 end 指定
其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
127.0 .0.1 :6379 > lrange list 0 -1 1 ) "three" 2 ) "two" 3 ) "one" 127.0 .0.1 :6379 > lrange list 0 1 1 ) "three" 2 ) "two"
rpush
语法
说明
rpush key val1 val2…
将一个或多个值插入到列表的尾部(最右边)
如果列表不存在,一个空列表会被创建并执行 rpush 操作。 当列表存在但不是列表类型时,返回一个错误。
127.0 .0.1 :6379 > rpush mylist "hello" (integer) 1 127.0 .0.1 :6379 > rpush mylist "foo" (integer) 2 127.0 .0.1 :6379 > rpush mylist "bar" (integer) 3 127.0 .0.1 :6379 > lrange mylist 0 -1 1 ) "hello" 2 ) "foo" 3 ) "bar"
lpop
语法
说明
lpop key
移除并返回列表的第一个元素
127.0 .0.1 :6379 > lrange mylist 0 -1 1 ) "hello" 2 ) "foo" 3 ) "bar" 127.0 .0.1 :6379 > lpop mylist "hello"
rpop
语法
说明
rpop key
移除列表的最后一个元素,返回值为移除的元素
127.0 .0.1 :6379 > lrange mylist 0 -1 1 ) "hello" 2 ) "foo" 3 ) "bar" 127.0 .0.1 :6379 > rpop mylist "bar"
lindex
语法
说明
lindex key index
通过索引获取列表中的元素
你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
127.0 .0.1 :6379 > lrange list 0 -1 1 ) "three" 2 ) "two" 3 ) "one" 127.0 .0.1 :6379 > lindex list 0 "three" 127.0 .0.1 :6379 > lindex list 2 "one" 127.0 .0.1 :6379 > lindex list 3 (nil) 127.0 .0.1 :6379 > lindex list -1 "one"
llen
如果列表 key 不存在,则 key 被解释为一个空列表,返回 0 。 如果 key 不是列表类型,返回一个错误
127.0 .0.1 :6379 > lrange list 0 -1 1 ) "three" 2 ) "two" 3 ) "one" 127.0 .0.1 :6379 > llen list(integer) 3
lrem
语法
说明
llrem key count value
根据参数 count 的值,移除列表中与参数 value 相等的元素
count 的值可以是以下几种:
count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
count = 0 : 移除表中所有与 value 相等的值。
127.0 .0.1 :6379 > lrange list 0 -1 1 ) "five" 2 ) "four" 3 ) "three" 4 ) "two" 5 ) "one" 127.0 .0.1 :6379 > lrem list 1 one(integer) 1 127.0 .0.1 :6379 > lrange list 0 -1 1 ) "five" 2 ) "four" 3 ) "three" 4 ) "two" 127.0 .0.1 :6379 > lpush list five(integer) 5 127.0 .0.1 :6379 > lrange list 0 -1 1 ) "five" 2 ) "five" 3 ) "four" 4 ) "three" 5 ) "two" 127.0 .0.1 :6379 > lrem list 2 five(integer) 2 127.0 .0.1 :6379 > lrange list 0 -1 1 ) "four" 2 ) "three" 3 ) "two"
ltrim
语法
说明
ltrim key start stop
对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
下标 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
127.0 .0.1 :6379 > lrange list 0 -1 1 ) "four" 2 ) "three" 3 ) "two" 127.0 .0.1 :6379 > ltrim list 1 -1 OK 127.0 .0.1 :6379 > lrange list 0 -1 1 ) "three" 2 ) "two"
rpoplpush
语法
说明
rpoplpush source destination
移除列表的最后一个元素,并将该元素添加到另一个列表并返回
127.0 .0.1 :6379 > lrange list 0 -1 1 ) "three" 2 ) "two" 3 ) "one" 127.0 .0.1 :6379 > rpoplpush list otherlist"one" 127.0 .0.1 :6379 > lrange list 0 -1 1 ) "three" 2 ) "two" 127.0 .0.1 :6379 > lrange otherlist 0 -1 1 ) "one"
lset
语法
说明
lset key index element
通过索引来设置元素的值。当索引参数超出范围,或对一个空列表进行 LSET 时,返回一个错误。
127.0 .0.1 :6379 > lrange mylist 0 -1 1 ) "hello" 2 ) "foo" 3 ) "this" 4 ) "world" 127.0 .0.1 :6379 > lset mylist 0 barOK 127.0 .0.1 :6379 > lrange mylist 0 -1 1 ) "bar" 2 ) "foo" 3 ) "this" 4 ) "world" 127.0 .0.1 :6379 > lset oother 1 other (error) ERR no such key
linsert
语法
说明
linsert key before|after pivot element
在列表的元素前或者后插入元素。当指定元素不存在于列表中时,不执行任何操作
列表不存在时,被视为空列表,不执行任何操作。
如果 key 不是列表类型,返回一个错误。
将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
127.0 .0.1 :6379 > lrange mylist 0 -1 1 ) "bar" 2 ) "foo" 3 ) "this" 4 ) "world" 127.0 .0.1 :6379 > linsert mylist before this three (integer) 5 127.0 .0.1 :6379 > lrange mylist 0 -1 1 ) "bar" 2 ) "foo" 3 ) "three" 4 ) "this" 5 ) "world"
Redis集合(Set) Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为 4294967295, 每个集合可存储40多亿个成员。
sadd
语法
说明
sadd key member [member …]
将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略
假如集合 key 不存在,则创建一个只包含添加的元素作成员的集合。
当集合 key 不是集合类型时,返回一个错误。
127.0 .0.1 :6379 > sadd myset "hello" (integer) 1 127.0 .0.1 :6379 > sadd myset "foo" (integer) 1 127.0 .0.1 :6379 > sadd myset "hello" (integer) 0 127.0 .0.1 :6379 > smembers myset1 ) "hello" 2 ) "foo"
smembers
语法
说明
smembers key
返回集合中的所有的成员。 不存在的集合 key 被视为空集合
127.0 .0.1 :6379 > smembers myset1 ) "hello" 2 ) "foo"
sismember
语法
说明
sismember key member
判断成员元素是否是集合的成员
127.0 .0.1 :6379 > smembers myset1 ) "hello" 2 ) "foo" 127.0 .0.1 :6379 > sismember myset "hello" (integer) 1 127.0 .0.1 :6379 > sismember myset "hellossss" (integer) 0
scard
语法
说明
scard key
返回集合中元素的数量
127.0 .0.1 :6379 > smembers myset1 ) "hello" 2 ) "foo" 127.0 .0.1 :6379 > scard myset(integer) 2
srem
语法
说明
srem key member [member …]
移除集合中的一个或多个成员元素,不存在的成员元素会被忽略
127.0 .0.1 :6379 > smembers myset1 ) "hello" 2 ) "world" 3 ) "foo" 127.0 .0.1 :6379 > srem myset world(integer) 1 127.0 .0.1 :6379 > smembers myset1 ) "hello" 2 ) "foo" 127.0 .0.1 :6379 > srem myset hello foo(integer) 2 127.0 .0.1 :6379 > smembers myset(empty array)
srandmember
语法
说明
srandmember key [count]
返回集合中的一个随机元素
可选的 count 参数:
如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。
如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。
该操作和 SPOP 相似,但 SPOP 将随机元素从集合中移除并返回,而 Srandmember 则仅仅返回随机元素,而不对集合进行任何改动。
127.0 .0.1 :6379 > smembers myset1 ) "nihao" 2 ) "hello" 3 ) "world" 127.0 .0.1 :6379 > srandmember myset"nihao" 127.0 .0.1 :6379 > srandmember myset"world" 127.0 .0.1 :6379 > srandmember myset"nihao" 127.0 .0.1 :6379 > srandmember myset 2 1 ) "hello" 2 ) "world" 127.0 .0.1 :6379 > srandmember myset -2 1 ) "world" 2 ) "world" 127.0 .0.1 :6379 > srandmember myset -3 1 ) "hello" 2 ) "nihao" 3 ) "hello"
spop
语法
说明
spop key [count]
移除集合中的指定 key 的一个或多个随机元素,移除后会返回移除的元素
该命令类似 srandmember 命令,但 SPOP 将随机元素从集合中移除并返回,而 srandmember 则仅仅返回随机元素,而不对集合进行任何改动。
127.0 .0.1 :6379 > smembers myset1 ) "haha" 2 ) "shi" 3 ) "world" 4 ) "nihao" 5 ) "ni" 6 ) "de" 127.0 .0.1 :6379 > spop myset"haha" 127.0 .0.1 :6379 > spop myset 2 1 ) "de" 2 ) "nihao" 127.0 .0.1 :6379 > smembers myset1 ) "shi" 2 ) "ni" 3 ) "world"
smove
语法
说明
smove source destination member
将指定成员 member 元素从 source 集合移动到 destination 集合
SMOVE 是原子性操作。
如果 source 集合不存在或不包含指定的 member 元素,则 SMOVE 命令不执行任何操作,仅返回 0 。否则, member 元素从 source 集合中被移除,并添加到 destination 集合中去。
当 destination 集合已经包含 member 元素时, SMOVE 命令只是简单地将 source 集合中的 member 元素删除。
当 source 或 destination 不是集合类型时,返回一个错误。
127.0 .0.1 :6379 > smembers myset1 ) "ni" 2 ) "hello" 3 ) "hao" 4 ) "world" 5 ) "ya" 127.0 .0.1 :6379 > smembers myset21 ) "zhe" 127.0 .0.1 :6379 > smove myset myset2 "hello" (integer) 1 127.0 .0.1 :6379 > smembers myset1 ) "hao" 2 ) "world" 3 ) "ni" 4 ) "ya" 127.0 .0.1 :6379 > smembers myset21 ) "hello" 2 ) "zhe"
sdiff
语法
说明
sdiff key [key …]
返回第一个集合与其他集合之间的差集,也可以认为说第一个集合中独有的元素
不存在的集合 key 将视为空集
差集的结果来自前面的 first_key,而不是后面的 other_key1,也不是整个 first_key other_key1..other_kenn 的差集
key1 = {a,b,c,d} key2 = {c} key3 = {a,c,e} sdiff key1 key2 key3 = {b,d}
127.0 .0.1 :6379 > smembers myset 1 ) "b" 2 ) "d" 3 ) "a" 4 ) "c" 127.0 .0.1 :6379 > smembers myset2 1 ) "e" 2 ) "d" 3 ) "f" 4 ) "c" 127.0 .0.1 :6379 > sdiff myset myset21 ) "b" 2 ) "a"
sinter
语法
说明
sinter key [key …]
返回给定所有给定集合的交集
不存在的集合 key 将视为空集。当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。
127.0 .0.1 :6379 > smembers myset 1 ) "b" 2 ) "d" 3 ) "a" 4 ) "c" 127.0 .0.1 :6379 > smembers myset2 1 ) "e" 2 ) "d" 3 ) "f" 4 ) "c" 127.0 .0.1 :6379 > sinter myset myset21 ) "d" 2 ) "c"
sunion
语法
说明
sunion key [key …]
返回给定集合的并集。不存在的集合 key 被视为空集。
127.0 .0.1 :6379 > smembers myset 1 ) "b" 2 ) "d" 3 ) "a" 4 ) "c" 127.0 .0.1 :6379 > smembers myset2 1 ) "e" 2 ) "d" 3 ) "f" 4 ) "c" 127.0 .0.1 :6379 > sunion myset myset21 ) "c" 2 ) "b" 3 ) "f" 4 ) "e" 5 ) "d" 6 ) "a"
Redis哈希(Hash) Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。
Redis 中每个 hash 可以存储 40多亿键值对。
hset
语法
说明
hset key field value [field value …]
为哈希表中的字段赋值
如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作。
如果字段已经存在于哈希表中,旧值将被覆盖。
127.0 .0.1 :6379 > hset myhash fidle1 "foo" (integer) 1 127.0 .0.1 :6379 > hset website google "www.g.cn" (integer) 1 127.0 .0.1 :6379 > hset website google "www.google.com" (integer) 0
hget
语法
说明
hget key field
返回哈希表中指定字段的值
127.0 .0.1 :6379 > hget myhash fidle1"foo" 127.0 .0.1 :6379 > hget website google"www.google.com"
hmset
语法
说明
hmset key field value [field value …]
同时将多个 field-value (字段-值)对设置到哈希表中
此命令会覆盖哈希表中已存在的字段。
如果哈希表不存在,会创建一个空哈希表,并执行 HMSET 操作。
127.0 .0.1 :6379 > hmset myhash field1 "hello" field2 "world" OK 127.0 .0.1 :6379 > hget myhash field1"hello" 127.0 .0.1 :6379 > hget myhash field2"world"
hmget
语法
说明
hmget key field [field …]
返回哈希表中,一个或多个给定字段的值
如果指定的字段不存在于哈希表,那么返回一个 nil 值。
127.0 .0.1 :6379 > hmget myhash field1 field21 ) "hello" 2 ) "world"
hgetall
语法
说明
hgetall key
返回哈希表中,所有的字段和值
在返回值里,紧跟每个字段名(field name)之后是字段的值(value),所以返回值的长度是哈希表大小的两倍。
127.0 .0.1 :6379 > hgetall myhash1 ) "field1" 2 ) "hello" 3 ) "field2" 4 ) "world"
hdel
语法
说明
hdel key field [field …]
删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略
127.0 .0.1 :6379 > hgetall myhash1 ) "field1" 2 ) "hello" 3 ) "field2" 4 ) "world" 127.0 .0.1 :6379 > hdel myhash field1(integer) 1 127.0 .0.1 :6379 > hgetall myhash1 ) "field2" 2 ) "world"
hlen
语法
说明
hlen key
获取哈希表中字段的数量
127.0 .0.1 :6379 > hgetall myhash1 ) "field2" 2 ) "world" 3 ) "field" 4 ) "hello" 127.0 .0.1 :6379 > hlen myhash(integer) 2
hexists
语法
说明
hexists key filed
查看哈希表的指定字段是否存在
127.0 .0.1 :6379 > hgetall myhash1 ) "field2" 2 ) "world" 3 ) "field" 4 ) "hello" 127.0 .0.1 :6379 > hexists myhash field(integer) 1
hkeys
语法
说明
hkeys key
获取哈希表中的所有域(field)
127.0 .0.1 :6379 > hgetall myhash1 ) "field2" 2 ) "world" 3 ) "field" 4 ) "hello" 127.0 .0.1 :6379 > hkeys myhash1 ) "field2" 2 ) "field"
hvals
语法
说明
hvals key
返回哈希表所有域(field)的值
127.0 .0.1 :6379 > hgetall myhash1 ) "field2" 2 ) "world" 3 ) "field" 4 ) "hello" 127.0 .0.1 :6379 > hvals myhash1 ) "world" 2 ) "hello"
hincrby
语法
说明
hincrby key field increment
为哈希表中的字段值加上指定增量值
127.0 .0.1 :6379 > hset myhash field 5 (integer) 0 127.0 .0.1 :6379 > hincrby myhash field 1 (integer) 6 127.0 .0.1 :6379 > hincrby myhash field -1 (integer) 5 127.0 .0.1 :6379 > hincrby myhash field -10 (integer) -5
hsetnx
语法
说明
hsetnx key field value
为哈希表中不存在的的字段赋值
127.0 .0.1 :6379 > hsetnx myhash field1 "foo" (integer) 1 127.0 .0.1 :6379 > hsetnx myhash field1 "bar" (integer) 0 127.0 .0.1 :6379 > hget myhash field1 "foo"
Redis有序集合(ZSet) Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为 4294967295, 每个集合可存储40多亿个成员。
zadd
语法
说明
zadd key sorce member [score member …]
将一个或多个成员元素及其分数值加入到有序集当中
如果某个成员已经是有序集的成员,那么更新这个成员的分数值,并通过重新插入这个成员元素,来保证该成员在正确的位置上。
分数值可以是整数值或双精度浮点数。
如果有序集合 key 不存在,则创建一个空的有序集并执行 ZADD 操作。
当 key 存在但不是有序集类型时,返回一个错误。
127.0 .0.1 :6379 > zadd myzset 1 "one" (integer) 1 127.0 .0.1 :6379 > zadd myzset 1 "uno" (integer) 1 127.0 .0.1 :6379 > zadd myzset 2 "two" 3 "three" (integer) 2 127.0 .0.1 :6379 > zrange myzset 0 -1 withscores1 ) "one" 2 ) "1" 3 ) "uno" 4 ) "1" 5 ) "two" 6 ) "2" 7 ) "three" 8 ) "3"
zrange
语法
说明
zrange key min max [withscores]
返回有序集中,指定区间内的成员
其中成员的位置按分数值递增(从小到大)来排序。具有相同分数值的成员按字典序(lexicographical order )来排列。
如果你需要成员按值递减(从大到小)来排列,请使用 zrevrange 命令。
下标参数 min 和 max都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。
你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
127.0 .0.1 :6379 > zrange salary 0 -1 withscores 1 ) "jack" 2 ) "3500" 3 ) "tom" 4 ) "5000" 5 ) "boss" 6 ) "10086" 127.0 .0.1 :6379 > zrange salary 1 2 withscores 1 ) "tom" 2 ) "5000" 3 ) "boss" 4 ) "10086" 127.0 .0.1 :6379 > zrange salary 0 200000 withscores 1 ) "jack" 2 ) "3500" 3 ) "tom" 4 ) "5000" 5 ) "boss" 6 ) "10086" 127.0 .0.1 :6379 > zrange salary 200000 3000000 withscores (empty array)
zrangebyscore
语法
说明
zrangebyscore key min max [withscores] [limit offset count]
返回有序集合中指定分数区间的成员列表
zrangebyscore zset (1 5 返回所有符合条件 1 < score <= 5 的成员 zrangebyscore zset (5 (10 返回所有符合条件 5 < score < 10 的成员
127.0 .0.1 :6379 > zrangebyscore salary -inf +inf 1 ) "jack" 2 ) "tom" 3 ) "boss" 127.0 .0.1 :6379 > zrangebyscore salary -inf +inf withscores 1 ) "jack" 2 ) "3500" 3 ) "tom" 4 ) "5000" 5 ) "boss" 6 ) "10086" 127.0 .0.1 :6379 > zrangebyscore salary -inf 5000 withscores 1 ) "jack" 2 ) "3500" 3 ) "tom" 4 ) "5000" 127.0 .0.1 :6379 > zrangebyscore salary (5000 (400000 1 ) "boss"
zrem
语法
说明
zrem key member [member …]
移除有序集中的一个或多个成员,不存在的成员将被忽略
当 key 存在但不是有序集类型时,返回一个错误。
127.0 .0.1 :6379 > zrange salary 0 -1 withscores1 ) "jack" 2 ) "3500" 3 ) "tom" 4 ) "5000" 5 ) "boss" 6 ) "10086" 127.0 .0.1 :6379 > zrem salary jack (integer) 1 127.0 .0.1 :6379 > zrange salary 0 -1 withscores1 ) "tom" 2 ) "5000" 3 ) "boss" 4 ) "10086" 127.0 .0.1 :6379 > zrem salary tom boss (integer) 2 127.0 .0.1 :6379 > zrange salary 0 -1 withscores(empty array)
zcard
语法
说明
zcard key
计算集合中元素的数量
127.0 .0.1 :6379 > zrange salary 0 -1 1 ) "tom" 2 ) "jack" 3 ) "boss" 127.0 .0.1 :6379 > zcard salary(integer) 3
zrevrange
语法
说明
zrevrange ksy start stop [withscores]
返回有序集中,指定区间内的成员
127.0 .0.1 :6379 > zrange salary 0 -1 withscores 1 ) "tom" 2 ) "2500" 3 ) "jack" 4 ) "3000" 5 ) "boss" 6 ) "6000" 127.0 .0.1 :6379 > zrevrange salary 0 -1 withscores 1 ) "boss" 2 ) "6000" 3 ) "jack" 4 ) "3000" 5 ) "tom" 6 ) "2500"
zcount
语法
说明
zcount key min max
计算有序集合中指定分数区间的成员数量
127.0 .0.1 :6379 > zrange salary 0 -1 withscores1 ) "tom" 2 ) "2500" 3 ) "jack" 4 ) "3000" 5 ) "boss" 6 ) "6000" 127.0 .0.1 :6379 > zcount salary 2000 3500 (integer) 2
geospatial地理空间 geoadd
语法
说明
geoadd key longitude latitude member [longitude latitude member …]
添加一个或多个地理位置元素到一个key中
有效的经度是 -180度到180度
有效的纬度是-85.05112878度到85.05112878度
经度(longitude) 纬度(latitude)
上海市经纬度 经度:121.48941 维度:31.40527
北京市经纬度 经度:116.23128 维度:40.22077
广州市经纬度 经度:113.27324 维度:23.15792
深圳市经纬度 经度:113.88308 维度:22.55329
127.0 .0.1 :6379 > geoadd china:city 121.48941 31.40527 shanghai(integer) 1 127.0 .0.1 :6379 > geoadd china:city 116.23128 40.22077 beijing(integer) 1 127.0 .0.1 :6379 > geoadd china:city 113.27324 23.15792 guangzhou(integer) 1 127.0 .0.1 :6379 > geoadd china:city 113.88308 22.55329 shenzhen(integer) 1
geopos
语法
说明
geopos key member [member …]
返回一个或多个位置的经纬度信息
127.0 .0.1 :6379 > geopos china:city shanghai1 ) 1 ) "121.48941010236740112" 2 ) "31.40526993848380499" 127.0 .0.1 :6379 > geopos china:city beijing shenzhen1 ) 1 ) "116.23128265142440796" 2 ) "40.22076905438526495" 2 ) 1 ) "113.88307839632034302" 2 ) "22.55329111565713873"
geodist
语法
说明
geodist key member1 member2 [m|km|ft|mi]
返回一个key中指定两个位置之间的距离
m 表示单位为米。
km表示单位为千米。
mi 表示单位为英里。
ft 表示单位为英尺。
127.0 .0.1 :6379 > geodist china:city beijing shanghai"1088644.3544" 127.0 .0.1 :6379 > geodist china:city beijing shanghai km "1088.6444" 127.0 .0.1 :6379 > geodist china:city shenzhen guangzhou km "91.8118"
georadius
语法
说明
georadius key longitude latitude radius m|km|ft|mi [withcoord] [withdist] [withhash] [count count]
以给定位置为中心,半径不超过给定半径的附近所有位置
127.0 .0.1 :6379 > georadius china:city 110 30 1000 km 1 ) "shenzhen" 2 ) "guangzhou" 127.0 .0.1 :6379 > georadius china:city 110 30 1000 km withcoord 1 ) 1 ) "shenzhen" 2 ) 1 ) "113.88307839632034302" 2 ) "22.55329111565713873" 2 ) 1 ) "guangzhou" 2 ) 1 ) "113.27324062585830688" 2 ) "23.1579209662846921" 127.0 .0.1 :6379 > georadius china:city 110 30 1000 km withdist 1 ) 1 ) "shenzhen" 2 ) "914.1294" 2 ) 1 ) "guangzhou" 2 ) "827.6084" 127.0 .0.1 :6379 > georadius china:city 110 30 1000 km withhash1 ) 1 ) "shenzhen" 2 ) (integer) 4046340107163728 2 ) 1 ) "guangzhou" 2 ) (integer) 4046534010880445 127.0 .0.1 :6379 > georadius china:city 110 30 1000 km withcoord count 1 1 ) 1 ) "guangzhou" 2 ) 1 ) "113.27324062585830688" 2 ) "23.1579209662846921"
georadiusbymember
语法
说明
georadiusbymember key member radius m|km|ft|mi [withdist] [withhash] [count count]
使用输入的经度和纬度来决定中心点,找出位于指定范围内的元素
127.0 .0.1 :6379 > georadiusbymember china:city beijing 1000 km 1 ) "beijing"
geohash
语法
说明
geohash key member [member…]
返回一个或多个位置元素的 Geohash表示
127.0 .0.1 :6379 > geohash china:city beijing shanghai1 ) "wx4sucvncn0" 2 ) "wtw6st1uuq0"
geo底层的实现原理其实就是Zset,我们可以使用Zset命令来操作geo
127.0 .0.1 :6379 > zrange china:city 0 -1 1 ) "shenzhen" 2 ) "guangzhou" 3 ) "shanghai" 4 ) "beijing" 127.0 .0.1 :6379 > zrem china:city beijing(integer) 1 127.0 .0.1 :6379 > zrange china:city 0 -1 1 ) "shenzhen" 2 ) "guangzhou" 3 ) "shanghai"
Hyperloglog Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
A={1,3,5,7,8,7,8}
B={1,3,5,8}
A与B的基数是5,基数就是不重复元素,基数估计就是在误差可接受的范围内,快速计算基数
pfadd
语法
说明
pfadd key element [element …]
将所有元素参数添加到 HyperLogLog 数据结构中
127.0 .0.1 :6379 > pfadd mykey a b b c d e f g h i j(integer) 1
pfcount
语法
说明
pfcount key [key …]
返回给定 HyperLogLog 的基数估算值
127.0 .0.1 :6379 > pfadd mykey a b b c d e f g h i j(integer) 1 127.0 .0.1 :6379 > pfcount mykey (integer) 10
pfmerge
语法
说明
pfmerge destkey sourcekey [sourcekey …]
将多个 HyperLogLog 合并为一个 HyperLogLog
合并后的 HyperLogLog 的基数估算值是通过对所有 给定 HyperLogLog 进行并集计算得出的。
127.0 .0.1 :6379 > pfadd mykey a b c d e(integer) 1 127.0 .0.1 :6379 > pfadd mykey2 e f g h i j k(integer) 1 127.0 .0.1 :6379 > pfmerge mykey3 mykey mykey2OK 127.0 .0.1 :6379 > pfcount mykey3(integer) 11
Bitmap Redis提供的Bitmaps这个“数据结构”可以实现对位的操作。Bitmaps本身不是一种数据结构,实际上就是字符串,但是它可以对字符串的位进行操作。
可以把Bitmaps想象成一个以位为单位数组,数组中的每个单元只能存0或者1,数组的下标在bitmaps中叫做偏移量。单个bitmaps的最大长度是512MB,即2^32个比特位。
统计用户信息,例如统计活跃、不活跃!登录、未登录!打卡、未打卡!两个状态的,都可以使用Bitmps
Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!
setbit
语法
说明
setbit key offset value
对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit),返回指定偏移量原来储存的位
例如使用Bitmaps来记录周一到周日的打卡记录
127.0 .0.1 :6379 > setbit sign 0 1 (integer) 0 127.0 .0.1 :6379 > setbit sign 1 0 (integer) 0 127.0 .0.1 :6379 > setbit sign 2 0 (integer) 0 127.0 .0.1 :6379 > setbit sign 3 1 (integer) 0 127.0 .0.1 :6379 > setbit sign 4 1 (integer) 0 127.0 .0.1 :6379 > setbit sign 5 1 (integer) 0 127.0 .0.1 :6379 > setbit sign 6 0 (integer) 0
getbit
语法
说明
getbit key offset
对 key 所储存的字符串值,获取指定偏移量上的位(bit)
查看某一天是否打卡
127.0 .0.1 :6379 > getbit sign 0 (integer) 1 127.0 .0.1 :6379 > getbit sign 1 (integer) 0 127.0 .0.1 :6379 > getbit sign 3 (integer) 1
bitcount
语法
说明
bitcount key [start end]
计算给定字符串中,被设置为 1的比特位的数量
127.0 .0.1 :6379 > bitcount sign (integer) 4
Redis事务 Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
批量操作在发送 EXEC 命令前被放入队列缓存。
收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
一个事务从开始到执行会经历以下三个阶段:
开始事务(multi)
命令入队(一系列命令)
执行事务(exec)
Redis单条命令是保证原子性的,但是redis事务是不保证原子性的。
redis事务的本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行。
一次性、顺序性、排他性!执行一系列的命令。
Redis的事务没有隔离级别的概念!所有命令在事务中,并没有被直接执行!只有发起执行命令exec时候才会执行!
Redis可以实现乐观锁!
multi
exec
127.0 .0.1 :6379 > multi OK 127.0 .0.1 :6379 (TX)> set k1 v1 QUEUED 127.0 .0.1 :6379 (TX)> set k2 v2 QUEUED 127.0 .0.1 :6379 (TX)> get k2 QUEUED 127.0 .0.1 :6379 (TX)> set k3 v3 QUEUED 127.0 .0.1 :6379 (TX)> exec 1 ) OK 2 ) OK 3 ) "v2" 4 ) OK
编译型异常(代码有问题!命令有错!),事务中的所有命令都不会被执行!
127.0 .0.1 :6379 > multi OK 127.0 .0.1 :6379 (TX)> set k1 v1 QUEUED 127.0 .0.1 :6379 (TX)> set k2 v2 QUEUED 127.0 .0.1 :6379 (TX)> set k3 v3 QUEUED 127.0 .0.1 :6379 (TX)> getset k2 (error) ERR wrong number of arguments for 'getset' command 127.0 .0.1 :6379 (TX)> set k4 v4 QUEUED 127.0 .0.1 :6379 (TX)> exec (error) EXECABORT Transaction discarded because of previous errors. 127.0 .0.1 :6379 > get k4 (nil)
运行时异常(比如1除以0 1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的!错误命令抛出异常
127.0 .0.1 :6379 > set k1 "v1" OK 127.0 .0.1 :6379 > multi OK 127.0 .0.1 :6379 (TX)> incr k1 QUEUED 127.0 .0.1 :6379 (TX)> set k2 v2 QUEUED 127.0 .0.1 :6379 (TX)> set k3 v3 QUEUED 127.0 .0.1 :6379 (TX)> get k3 QUEUED 127.0 .0.1 :6379 (TX)> exec 1 ) (error) ERR value is not an integer or out of range2 ) OK3 ) OK4 ) "v3" 127.0 .0.1 :6379 > get k2 "v2" 127.0 .0.1 :6379 > get k3 "v3"
discard
语法
说明
discard
用于取消事务,放弃执行事务块内的所有命令。
127.0 .0.1 :6379 > multi OK 127.0 .0.1 :6379 (TX)> set k1 v1 QUEUED 127.0 .0.1 :6379 (TX)> set k2 v2 QUEUED 127.0 .0.1 :6379 (TX)> set k4 v4 QUEUED 127.0 .0.1 :6379 (TX)> discard OK 127.0 .0.1 :6379 > get k4 (nil)
watch
语法
说明
watch
用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
悲观锁:顾名思义,很悲观,什么时候都会出问题,无论做什么都加锁!
乐观锁:顾名思义,很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据。一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会+1。当线程A要更新数据值时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。
127.0 .0.1 :6379 > set money 100 OK 127.0 .0.1 :6379 > set out 0 OK 127.0 .0.1 :6379 > watch money OK 127.0 .0.1 :6379 > multi OK 127.0 .0.1 :6379 (TX)> decrby money 20 QUEUED 127.0 .0.1 :6379 (TX)> incrby out 20 QUEUED 127.0 .0.1 :6379 (TX)> exec 1 ) (integer) 80 2 ) (integer) 20
127.0 .0.1 :6379 > watch money OK 127.0 .0.1 :6379 > multi OK 127.0 .0.1 :6379 (TX)> decrby money 10 QUEUED 127.0 .0.1 :6379 (TX)> incrby out 10 QUEUED 127.0 .0.1 :6379 (TX)> 127.0 .0.1 :6379 (TX)> exec (nil) 127.0 .0.1 :6379 > get money "80" 127.0 .0.1 :6379 > set money 1000 OK
unwatch
语法
说明
unwatch
取消 WATCH 命令对所有 key 的监视
127.0 .0.1 :6379 > unwatch OK 127.0 .0.1 :6379 > watch money OK 127.0 .0.1 :6379 > multiOK 127.0 .0.1 :6379 (TX)> decrby money 20 QUEUED 127.0 .0.1 :6379 (TX)> incrby out 20 QUEUED 127.0 .0.1 :6379 (TX)> exec 1 ) (integer) 80 2 ) (integer) 20
Jedis jedis是redis的java版本的客户端实现
导入对应的依赖
<dependency > <groupId > redis.clients</groupId > <artifactId > jedis</artifactId > <version > 3.2.0</version > </dependency >
编码测试
public static void main (String[] args) { Jedis jedis=new Jedis ("127.0.0.1" ,6379 ); System.out.println(jedis.ping()); jedis.set("name" ,"zhangsan" ); System.out.println(jedis.get("name" )); System.out.println(jedis.exists("name" )); }
通过jedis理解事务
public static void main (String[] args) { Jedis jedis=new Jedis ("127.0.0.1" ,6379 ); Transaction multi = jedis.multi(); try { multi.set("name" ,"lisi" ); multi.set("age" ,"20" ); multi.exec(); } catch (Exception e) { multi.discard(); e.printStackTrace(); } finally { System.out.println(jedis.get("name" )); System.out.println(jedis.get("age" )); jedis.close(); } }
Redis.cong详解 Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf
[root @quan ~] [root @quan myconfig ] redis.conf [root @quan myconfig ]
config get
语法
说明
config get name
查看或设置配置项
127.0 .0.1 :6379 > config get loglevel1 ) "loglevel" 2 ) "notice"
使用 ***** 号获取所有配置项
127.0 .0.1 :6379 > config get * 1 ) "rdbchecksum" 2 ) "yes" 3 ) "daemonize" 4 ) "yes" 5 ) "io-threads-do-reads" 6 ) "no" 7 ) "lua-replicate-commands" 8 ) "yes" 9 ) "always-show-logo" 10 ) "no" 11 ) "protected-mode" 12 ) "yes" 13 ) "rdbcompression" 14 ) "yes" 15 ) "rdb-del-sync-files" 16 ) "no" 17 ) "activerehashing" 18 ) "yes" 19 ) "stop-writes-on-bgsave-error" 20 ) "yes" 21 ) "set-proc-title" 22 ) "yes" 23 ) "dynamic-hz" 24 ) "yes" 25 ) "lazyfree-lazy-eviction" 26 ) "no" 27 ) "lazyfree-lazy-expire" 28 ) "no" 29 ) "lazyfree-lazy-server-del" 30 ) "no" 31 ) "lazyfree-lazy-user-del" 32 ) "no" 33 ) "lazyfree-lazy-user-flush" 34 ) "no" 35 ) "repl-disable-tcp-nodelay" 36 ) "no" 37 ) "repl-diskless-sync" 38 ) "no" 39 ) "gopher-enabled" 40 ) "no" 41 ) "aof-rewrite-incremental-fsync" 42 ) "yes" 43 ) "no-appendfsync-on-rewrite" 44 ) "no" 45 ) "cluster-require-full-coverage" 46 ) "yes" 47 ) "rdb-save-incremental-fsync" 48 ) "yes" 49 ) "aof-load-truncated" 50 ) "yes" 51 ) "aof-use-rdb-preamble" 52 ) "yes" 53 ) "cluster-replica-no-failover" 54 ) "no" 55 ) "cluster-slave-no-failover" 56 ) "no" 57 ) "replica-lazy-flush" 58 ) "no" 59 ) "slave-lazy-flush" 60 ) "no" 61 ) "replica-serve-stale-data" 62 ) "yes" 63 ) "slave-serve-stale-data" 64 ) "yes" 65 ) "replica-read-only" 66 ) "yes" 67 ) "slave-read-only" 68 ) "yes" 69 ) "replica-ignore-maxmemory" 70 ) "yes" 71 ) "slave-ignore-maxmemory" 72 ) "yes" 73 ) "jemalloc-bg-thread" 74 ) "yes" 75 ) "activedefrag" 76 ) "no" 77 ) "syslog-enabled" 78 ) "no" 79 ) "cluster-enabled" 80 ) "no" 81 ) "appendonly" 82 ) "no" 83 ) "cluster-allow-reads-when-down" 84 ) "no" 85 ) "crash-log-enabled" 86 ) "yes" 87 ) "crash-memcheck-enabled" 88 ) "yes" 89 ) "use-exit-on-panic" 90 ) "no" 91 ) "disable-thp" 92 ) "yes" 93 ) "aclfile" 94 ) "" 95 ) "unixsocket" 96 ) "" 97 ) "pidfile" 98 ) "/var/run/redis_6379.pid" 99 ) "replica-announce-ip" 100 ) "" 101 ) "slave-announce-ip" 102 ) "" 103 ) "masteruser" 104 ) "" 105 ) "cluster-announce-ip" 106 ) "" 107 ) "syslog-ident" 108 ) "redis" 109 ) "dbfilename" 110 ) "dump.rdb" 111 ) "appendfilename" 112 ) "appendonly.aof" 113 ) "server_cpulist" 114 ) "" 115 ) "bio_cpulist" 116 ) "" 117 ) "aof_rewrite_cpulist" 118 ) "" 119 ) "bgsave_cpulist" 120 ) "" 121 ) "ignore-warnings" 122 ) "" 123 ) "proc-title-template" 124 ) "{title} {listen-addr} {server-mode}" 125 ) "masterauth" 126 ) "" 127 ) "requirepass" 128 ) "" 129 ) "supervised" 130 ) "no" 131 ) "syslog-facility" 132 ) "local0" 133 ) "repl-diskless-load" 134 ) "disabled" 135 ) "loglevel" 136 ) "notice" 137 ) "maxmemory-policy" 138 ) "noeviction" 139 ) "appendfsync" 140 ) "everysec" 141 ) "oom-score-adj" 142 ) "no" 143 ) "acl-pubsub-default" 144 ) "allchannels" 145 ) "sanitize-dump-payload" 146 ) "no" 147 ) "databases" 148 ) "16" 149 ) "port" 150 ) "6379" 151 ) "io-threads" 152 ) "1" 153 ) "auto-aof-rewrite-percentage" 154 ) "100" 155 ) "cluster-replica-validity-factor" 156 ) "10" 157 ) "cluster-slave-validity-factor" 158 ) "10" 159 ) "list-max-ziplist-size" 160 ) "-2" 161 ) "tcp-keepalive" 162 ) "300" 163 ) "cluster-migration-barrier" 164 ) "1" 165 ) "active-defrag-cycle-min" 166 ) "1" 167 ) "active-defrag-cycle-max" 168 ) "25" 169 ) "active-defrag-threshold-lower" 170 ) "10" 171 ) "active-defrag-threshold-upper" 172 ) "100" 173 ) "lfu-log-factor" 174 ) "10" 175 ) "lfu-decay-time" 176 ) "1" 177 ) "replica-priority" 178 ) "100" 179 ) "slave-priority" 180 ) "100" 181 ) "repl-diskless-sync-delay" 182 ) "5" 183 ) "maxmemory-samples" 184 ) "5" 185 ) "maxmemory-eviction-tenacity" 186 ) "10" 187 ) "timeout" 188 ) "0" 189 ) "replica-announce-port" 190 ) "0" 191 ) "slave-announce-port" 192 ) "0" 193 ) "tcp-backlog" 194 ) "511" 195 ) "cluster-announce-bus-port" 196 ) "0" 197 ) "cluster-announce-port" 198 ) "0" 199 ) "repl-timeout" 200 ) "60" 201 ) "repl-ping-replica-period" 202 ) "10" 203 ) "repl-ping-slave-period" 204 ) "10" 205 ) "list-compress-depth" 206 ) "0" 207 ) "rdb-key-save-delay" 208 ) "0" 209 ) "key-load-delay" 210 ) "0" 211 ) "active-expire-effort" 212 ) "1" 213 ) "hz" 214 ) "10" 215 ) "min-replicas-to-write" 216 ) "0" 217 ) "min-slaves-to-write" 218 ) "0" 219 ) "min-replicas-max-lag" 220 ) "10" 221 ) "min-slaves-max-lag" 222 ) "10" 223 ) "maxclients" 224 ) "10000" 225 ) "active-defrag-max-scan-fields" 226 ) "1000" 227 ) "slowlog-max-len" 228 ) "128" 229 ) "acllog-max-len" 230 ) "128" 231 ) "lua-time-limit" 232 ) "5000" 233 ) "cluster-node-timeout" 234 ) "15000" 235 ) "slowlog-log-slower-than" 236 ) "10000" 237 ) "latency-monitor-threshold" 238 ) "0" 239 ) "proto-max-bulk-len" 240 ) "536870912" 241 ) "stream-node-max-entries" 242 ) "100" 243 ) "repl-backlog-size" 244 ) "1048576" 245 ) "maxmemory" 246 ) "0" 247 ) "hash-max-ziplist-entries" 248 ) "512" 249 ) "set-max-intset-entries" 250 ) "512" 251 ) "zset-max-ziplist-entries" 252 ) "128" 253 ) "active-defrag-ignore-bytes" 254 ) "104857600" 255 ) "hash-max-ziplist-value" 256 ) "64" 257 ) "stream-node-max-bytes" 258 ) "4096" 259 ) "zset-max-ziplist-value" 260 ) "64" 261 ) "hll-sparse-max-bytes" 262 ) "3000" 263 ) "tracking-table-max-keys" 264 ) "1000000" 265 ) "client-query-buffer-limit" 266 ) "1073741824" 267 ) "repl-backlog-ttl" 268 ) "3600" 269 ) "auto-aof-rewrite-min-size" 270 ) "67108864" 271 ) "logfile" 272 ) "" 273 ) "watchdog-period" 274 ) "0" 275 ) "dir" 276 ) "/root" 277 ) "save" 278 ) "3600 1 300 100 60 10000" 279 ) "client-output-buffer-limit" 280 ) "normal 0 0 0 slave 268435456 67108864 60 pubsub 33554432 8388608 60" 281 ) "unixsocketperm" 282 ) "0" 283 ) "slaveof" 284 ) "" 285 ) "notify-keyspace-events" 286 ) "" 287 ) "bind" 288 ) "127.0.0.1 -::1" 289 ) "oom-score-adj-values" 290 ) "0 200 800"
config set
语法
说明
config set name value
修改配置
127.0 .0.1 :6379 > config set loglevel "notice" OK 127.0 .0.1 :6379 > config get loglevel1 ) "loglevel" 2 ) "notice"
启动的时候,就是通过配置文件来启动!
单位,配置文件 unit 单位大小写不敏感
INCLUDES 包含
NETWORK 网络
bind 127.0 .0.1 -::1 protected-mode yes port 6379
GENERAL 通用
daemonize yes pidfile /var/run/redis_6379.pid loglevel notice logfile "" databases 16 always-show-logo no
SNAPSHOTTING 快照
持久化,在规定的时间内,执行了多少次操作,则会持久化到文件 .rdb .aof,redis是内存数据库,如果没有持久化,那么数据断电即失!
save 900 1 save 300 10 save 60 10000 stop-writes -on-bgsave-error yes rdbcompression yes rdbchecksum yes dir ./
SECURITY 安全
可以在这里设置redis的密码,默认是没有密码的!
127.0 .0.1 :6379 > config get requirepass 1 ) "requirepass" 2 ) "" 127.0 .0.1 :6379 > config set requirepass "123456" OK 127.0 .0.1 :6379 > auth 123456 OK 127.0 .0.1 :6379 > config get requirepass1 ) "requirepass" 2 ) "123456"
CLIENTS 限制
MEMORY MANAGEMENT
maxmemory <bytes> maxmemory-policy noeviction
APPEND ONLY MODE 模式 aof 配置
appendonly no appendfilename "appendonly.aof" appendfsync everysec
RDB持久化 RDB持久化 RDB全称Redis DataBase
redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所以redis提供了持久化功能。
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的 Snapshot 快照,它恢复时是将快照文件直接读到内存里。 Redis 会单独创建( fork )一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的。这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。 RDB 的缺点是最后一次持久化后的数据可能丢失。
我们默认就是RDB,一般情况下不需要修改这个配置。rdb保存的文件是 dump.rdb。
在配置文件redis.conf配置
save 60 5 dbfilename dump.rdb
[root @quan ~] [root @quan myconfig ] save 60 5 [root @quan myconfig ] [root @quan bin ] dump.rdb redis-benchmark redis-check-rdb redis-sentinel myconfig redis-check-aof redis-cli redis-server [root @quan bin ] 127.0 .0.1 :6379 > set k1 v1OK 127.0 .0.1 :6379 > set k2 v2OK 127.0 .0.1 :6379 > set k3 v3OK 127.0 .0.1 :6379 > set k4 v4OK 127.0 .0.1 :6379 > set k5 v5 OK [root @quan bin ] [root @quan myconfig ] dump.rdb redis.conf [root @quan myconfig ] appendonly.aof dump.rdb yum.log
rdb文件触发机制,备份就会自动生成一个dump.rdb
save的规则满足的情况下,会触发rdb规则
执行flushall命令,也会触发rdb规则
退出redis,也会产生rdb文件
怎么恢复rdb文件?
只需要将rdb文件放在redis启动目录即可,redis启动的时候会自动检查dump.rdb,恢复其中的数据。
127.0 .0.1 :6379 > config get dir 1 ) "dir" 2 ) "/usr/local/bin/myconfig"
优点
适合大规模数据恢复
对数据的完整性要求不高
缺点
需要一定的时间间隔进行操作,如果redis意外宕机了,这个最后一次修改的数据就没有了
fork进程的时候,会占用一定的内存空间
AOF持久化 AOF全称 Append Only File
将我们所有的命令都记录下来,恢复的时候就会把这个文件全部执行一遍!
以日志的形式来记录每个写操作,将redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
aof保存的文件是 appendonly.aof
aof文件默认就是文件的无限追加,文件会越来越大!
redis.conf
appendonly no appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64 mb aof-load-truncated yes aof-use-rdb-preamble yes
[root @quan ~] [root @quan myconfig ] appendonly yes 127.0 .0.1 :6379 > shutdown not connected> exit [root @quan ~] root 25039 24860 0 14 :05 pts/0 00 :00 :00 grep --color =auto redis [root @quan ~] [root @quan ~] 127.0 .0.1 :6379 > pingPONG 127.0 .0.1 :6379 > config get appendonly1 ) "appendonly" 2 ) "yes" [root @quan myconfig ] /root/appendonly.aof [root @quan myconfig ] *2 $6 SELECT $1 0 *3 $3 set $2 k1 $2 v1 *3 $3 set $2 k2 $2 v2 *2 $6 SELECT $1 0 *3 $3 [root @quan ~] [root @quan ~] Could not connect to Redis at 127.0 .0.1 :6379 : Connection refused
如果aof文件有错,这时候redis是启动不起来的,我们需要修复这个aof文件
redis给我们提供看一个工具redis-check-aof --fix来修复
[root @quan bin ] myconfig redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server [root @quan bin ] 'x 7d: Expected prefix ' $ ', got: ' AOF analyzed: size=159 , ok_up_to=104 , diff =55 This will shrink the AOF from 159 bytes, with 55 bytes, to 104 bytes Continue ? [y /N ]: ySuccessfully truncated AOF [root @quan ~] [root @quan ~] 127.0 .0.1 :6379 > ping PONG
优点
每一次修改都同步,文件的完整会更好
每秒同步一次数据,可能会丢失一秒的数据
从不同步,效率最高的
缺点
相对于数据文件来说,aof文件远远大于rdb,修复的速度也比rdb慢
aof的运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化
Redis发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
redis客户端可以定义任意数量的频道。
订阅/发布消息图:
第一个:消息发送者 第二个:频道 第三个:消息订阅者
下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
subscribe
语法
说明
subscribe channel [channel …]
订阅给定的一个或多个频道的信息
127.0 .0.1 :6379 > subscribe myChannel Reading messages... (press Ctrl-C to quit) 1 ) "subscribe" 2 ) "myChannel" 3 ) (integer) 1 1 ) "message" 2 ) "myChannel" 3 ) "hello,world,nihao" 1 ) "message" 2 ) "myChannel" 3 ) "hello,redis"
publish
语法
说明
publish channel message
用于将信息发送到指定的频道
127.0 .0.1 :6379 > publish myChannel "hello,world,nihao" (integer) 1 127.0 .0.1 :6379 > publish myChannel "hello,redis" (integer) 1
Redis主从复制 主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower), 数据的复制是单向的!只能由主节点复制到从节点(主节点以写为主、从节点以读为主)。
默认情况下,每台Redis服务器都是主节点,一个主节点可以有0个或者多个从节点,但每个从节点只能有一个主节点。
主从复制的作用主要包括:
数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余的方式。
故障恢复:当主节点故障时,从节点可以暂时替代主节点提供服务,是一种服务冗余的方式
负载均衡:在主从复制的基础上,配合读写分离,由主节点进行写操作,从节点进行读操作(即写redis数据时应用连接主节点,读redis数据时应用连接从节点),分担服务器的负载;尤其是写少读多的场景下,通过多个从节点分担负载,可以大大提高redis服务器的并发量。
高可用(集群)基石:除上述作用意外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是redis高可用的基础。
一般来说,要将 Redis 运用于工程项目中,只使用一台 Redis 是万万不能的(宕机),原因如下:
从结构上,单个 Redis 服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大;
从容量上,单个 Redis 服务器内存容量有限,就算一台 Redis 服务器内存容量为 256G ,也不能将所有内存用作 Redis 存储内存。一般来说,单台 Redis 最大使用内存不应该超过 20G 。
电商网站上的商品,一般都是一次上传,无数次浏览的,说专业点也就是”多读少写”。
对于这种场景,我们可以使如下这种架构:
主从复制,读写分离,80%的情况下都是在进行读操作!减缓服务器压力,架构中经常使用。一主二从。
只要在公司中,主从复制就是必须要使用的,因为在真实的项目中不可能单机使用 Redis
为什么使用集群
单台服务器难以负载大量的请求
单台服务器故障率高,系统崩坏概率大
单台服务器内存容量有限
[root @quan ~] [root @quan ~] 127.0 .0.1 :6379 > info replication role:master connected_slaves:0 master_failover_state:no-failover master_replid:169 fe236d591291c56ec23d87b251305a04c6868 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
集群搭建 因为只有一台服务器,所以需要编写3个配置文件,通过3个不同的配置文件来启动服务,搭建一个伪集群。
默认情况下,每台redis服务器都是主节点;我们一般情况下只用配置从机就好了;找老大!一主(79)二从(80,81)
从机配置:slave of
只配置从库,不用配置主库。
[root @quan ~] [root @quan myconfig ] redis.conf [root @quan myconfig ] [root @quan myconfig ] [root @quan myconfig ] [root @quan myconfig ] redis79.conf redis80.conf redis81.conf redis.conf
第一个redis窗口:主机(redis79.conf)
[root @quan ~] [root @quan myconfig ] port 6379 daemonize yes pidfile /var/run/redis_6379.pid logfile "6379.log" dbfilename dump6379.rdb [root @quan myconfig ] [root @quan myconfig ] 127.0 .0.1 :6379 > pingPONG 127.0 .0.1 :6379 > info replicationrole:master connected_slaves:0 master_failover_state:no-failover master_replid:46 c717d739570dbd04aa91d28abe424500068e19 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 127.0 .0.1 :6379 > info replicationrole:master connected_slaves:2 slave0:ip=127.0 .0.1 ,port=6380 ,state=online,offset=378 ,lag=0 slave1:ip=127.0 .0.1 ,port=6381 ,state=online,offset=378 ,lag=0 master_failover_state:no-failover master_replid:e60babaf15a4dada473a82d261008f1e2c5309e1 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:378 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:378 127.0 .0.1 :6379 > set k1 v1 OK 127.0 .0.1 :6379 > get k1"v1
第二个redis窗口:从机(redis80.conf)
[root @quan ~] [root @quan myconfig ] port 6380 daemonize yes pidfile /var/run/redis_6380.pid logfile "6380.log" dbfilename dump6380.rdb [root @quan myconfig ] [root @quan myconfig ] 127.0 .0.1 :6380 > pingPONG 127.0 .0.1 :6380 > info replicationrole:master connected_slaves:0 master_failover_state:no-failover master_replid:0 e411f26920fdc8e1c626e02acc36477ae85f9e4 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 127.0 .0.1 :6380 > slaveof 127.0 .0.1 6379 OK 127.0 .0.1 :6380 > info replicationrole:slave master_host:127.0 .0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:2 master_sync_in_progress:0 slave_repl_offset:14 slave_priority:100 slave_read_only:1 connected_slaves:0 master_failover_state:no-failover master_replid:e60babaf15a4dada473a82d261008f1e2c5309e1 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:14 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:14 127.0 .0.1 :6380 > get k1 "v1" 127.0 .0.1 :6380 > set k2 v2 (error) READONLY You can't write against a read only replica. 127.0.0.1:6380> set k2 v2 # 从机只能读取内容,不能写 (error) READONLY You can' t write against a read only replica.
第三个redis窗口:从机(redis81.conf)
[root @quan ~] [root @quan myconfig ] port 6381 daemonize yes pidfile /var/run/redis_6381.pid logfile "6381.log" dbfilename dump6381.rdb [root @quan myconfig ] [root @quan myconfig ] 127.0 .0.1 :6381 > pingPONG 127.0 .0.1 :6381 > info replicationrole:master connected_slaves:0 master_failover_state:no-failover master_replid:7486 ac9fe45463bae0299d42294294628bea2572 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 127.0 .0.1 :6381 > slaveof 127.0 .0.1 6379 OK 127.0 .0.1 :6381 > info replicationrole:slave master_host:127.0 .0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:5 master_sync_in_progress:0 slave_repl_offset:308 slave_priority:100 slave_read_only:1 connected_slaves:0 master_failover_state:no-failover master_replid:e60babaf15a4dada473a82d261008f1e2c5309e1 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:308 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:309 repl_backlog_histlen:0 127.0 .0.1 :6380 > get k1 "v1" 127.0 .0.1 :6380 > set k2 v2 (error) READONLY You can't write against a read only replica.
第四个redis窗口:测试
[root @quan ~] root 16831 1 0 20 :46 ? 00 :00 :00 redis-server 127.0 .0.1 :6379 root 16844 15792 0 20 :46 pts/0 00 :00 :00 redis-cli -p 6379 root 16871 1 0 20 :47 ? 00 :00 :00 redis-server 127.0 .0.1 :6380 root 16885 16501 0 20 :47 pts/1 00 :00 :00 redis-cli -p 6380 root 16903 1 0 20 :48 ? 00 :00 :00 redis-server 127.0 .0.1 :6381 root 16913 16674 0 20 :48 pts/2 00 :00 :00 redis-cli -p 6381 root 16992 16960 0 20 :49 pts/3 00 :00 :00 grep --color =auto redis
注意:
主机断开连接(shutdown),从机依旧连接到主机的,但是没有写操作,这个时候,如果主机回来了,从机依旧可以读取到主机写的信息。
如果是使用命令行来配置的主从,这个时候如果从机断开连接后,就会变成主机!此时只要变为从机,立马就会从主机中获取值。
复制原理
slave 启动成功连接到 master 后会发送一个 sync 同步命令
Master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后, master 将传送整个数据文件到 slave ,并完成一次完全同步。
全量复制 :而 slave 服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制 : Master 继续将新的所有收集到的修改命令依次传给slave ,完成同步
但是只要是重新连接 master ,一次完全同步(全量复制)将被自动执行!我们的数据一定可以在从机中看到
真实的主从配置应该是在配置文件中配置,这样的话是永久的,我们这里使用的是命令,暂时的
配置redis.cofig配置位置如下:
replicaof <masterip> <masterport>
宕机后手动配置主机 上一个主节点连接下一个从节点
如果主机断开连接,我们可以使用slave of one 让自己变成主机!其他的节点就可以手动连接到最新的这个主节点(手动)
如果这个时候老大修复了,那就重新连接!
第一个redis窗口:主机(redis79.conf)
[root @quan myconfig ] [root @quan myconfig ] 127.0 .0.1 :6379 > info replicationrole:master connected_slaves:2 slave0:ip=127.0 .0.1 ,port=6380 ,state=online,offset=111226 ,lag=1 slave1:ip=127.0 .0.1 ,port=6381 ,state=online,offset=111226 ,lag=1 127.0 .0.1 :6379 > info replicationrole:master connected_slaves:1 slave0:ip=127.0 .0.1 ,port=6380 ,state=online,offset=111660 ,lag=0 127.0 .0.1 :6379 > set k6 v6OK 127.0 .0.1 :6379 > shutdown not connected> exit [root @quan ~] [root @quan ~] 127.0 .0.1 :6379 > info replication role:master connected_slaves:0
第二个redis窗口:从机(redis80.conf)
[root @quan myconfig ] [root @quan myconfig ] 127.0 .0.1 :6380 > info replicationrole:slave master_host:127.0 .0.1 master_port:6379 127.0 .0.1 :6380 > info replicationrole:slave master_host:127.0 .0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:7 master_sync_in_progress:0 slave_repl_offset:111590 slave_priority:100 slave_read_only:1 connected_slaves:1 slave0:ip=127.0 .0.1 ,port=6381 ,state=online,offset=111590 ,lag=1 127.0 .0.1 :6380 > get k6"v6" 127.0 .0.1 :6380 > set k7 v7(error) READONLY You can't write against a read only replica. 127.0.0.1:6380> slaveof no one # 6380自己当老大了 OK 127.0.0.1:6380> info replication # Replication role:master connected_slaves:1 slave0:ip=127.0.0.1,port=6381,state=online,offset=112305,lag=1
第三个redis窗口:从机(redis81.conf)
[root @quan myconfig ] [root @quan myconfig ] 127.0 .0.1 :6381 > info replicationrole:slave master_host:127.0 .0.1 master_port:6379 127.0 .0.1 :6381 > slaveof 127.0 .0.1 6380 OK 127.0 .0.1 :6381 > info replicationrole:slave master_host:127.0 .0.1 master_port:6380 127.0 .0.1 :6381 > get k6"v6" 127.0 .0.1 :6381 > set k7 v7(error) READONLY You can't write against a read only replica. ################################### # 如果此时6379挂了,没有老大了,这个时候能不能选一个老大出来呢?手动!滑稽 127.0.0.1:6381> slaveof no one # 对一个从属服务器执行命令 SLAVEOF NO ONE 将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃。 OK 127.0.0.1:6381> info replication # 6379挂了,老大没了,要自己当老大了 # Replication role:master connected_slaves:0 127.0.0.1:6381> slaveof 127.0.0.1 6380 # 继续指定主机为6380,6380此时是6379的从机,6380即是主机也是从机 OK 127.0.0.1:6381> info replication # Replication role:slave master_host:127.0.0.1 master_port:6380
哨兵模式 主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。
自动选举老大,能够监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。
哨兵模式是一种特殊的模式,首先redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,他会独立运行,其原理是哨兵通过发送命令,等待redis服务器响应,从而监控运行的多个redis实例。
然而一个哨兵对redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控,各个哨兵之间还会进行监控,这样就形成了多哨兵模式。
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行 failover 过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象称为主观下线 .当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行 failover[故障转移]操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线 .
哨兵的作用:
通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式 通知其他的从服务器,修改配置文件,让它们切换主机。
我们目前的状态是一主二从
配置哨兵配置文件 sentinel.conf
sentinel monitor myredis 127.0 .0.1 6379 1
后面的这个数字1代表主机挂了,slave投票看让谁接替成为主机,票数最多的,就会成为主机
启动哨兵
如果master节点断开了,这个时候就会从从机中随机选择一个服务器!(投票算法)
如果主机此时回来了,只能归并袄新的主机下,当做从机,这就是哨兵模式的规则。
哨兵模式的优点
哨兵集群,基于主从复制模式,所有主从配置的优点,它都有
主从可以切换,故障可以转移,系统的可用性更好
哨兵模式是主从模式的升级,手动到自动,更加健壮
哨兵模式的缺点
Redis不好在线扩容,集群容量一旦达到上限,在线扩容就十分麻烦
实现哨兵模式的配置其实是很麻烦的,里面有很多配置项
哨兵模式的全部配置
完整的哨兵模式配置文件 sentinel.conf
port 26379 dir /tmp sentinel monitor mymaster 127.0 .0.1 6379 2 sentinel auth-pass mymaster MySUPER--secret-0123passw0rd sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000 sentinel notification-script mymaster /var/redis/notify.sh sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
第一个redis窗口:主机(redis79.conf)
[root @quan myconfig ] [root @quan myconfig ] 127.0 .0.1 :6379 > info replicationrole:master connected_slaves:2 slave0:ip=127.0 .0.1 ,port=6380 ,state=online,offset=111226 ,lag=1 slave1:ip=127.0 .0.1 ,port=6381 ,state=online,offset=111226 ,lag=1 127.0 .0.1 :6379 > set k1 v1OK 127.0 .0.1 :6379 > shutdown not connected> exit [root @quan ~] [root @quan ~] 127.0 .0.1 :6379 > info replication role:slave master_host:127.0 .0.1 master_port:6380
第二个redis窗口:从机(redis80.conf)
[root @quan myconfig ] [root @quan myconfig ] 127.0 .0.1 :6380 > info replicationrole:slave master_host:127.0 .0.1 master_port:6379 127.0 .0.1 :6380 > info replicationrole:master connected_slaves:1 slave0:ip=127.0 .0.1 ,port=6381 ,state=online,offset=19485 ,lag=1
第三个redis窗口:从机(redis81.conf)
[root @quan myconfig ] [root @quan myconfig ] 127.0 .0.1 :6381 > info replicationrole:slave master_host:127.0 .0.1 master_port:6379 127.0 .0.1 :6381 > info replicationrole:slave master_host:127.0 .0.1 master_port:6380
第三个redis窗口:测试
[root @quan ~] [root @quan myconfig ] sentinel monitor myredis 127.0 .0.1 6379 1 [root @quan myconfig ] total 636 -rw-r--r-- 1 root root 4064 Apr 13 19 :14 6379 .log-rw-r--r-- 1 root root 141078 Apr 13 19 :28 6380 .log-rw-r--r-- 1 root root 92207 Apr 13 19 :28 6381 .log-rw-r--r-- 1 root root 111 Apr 13 19 :28 appendonly.aof-rw-r--r-- 1 root root 197 Apr 13 19 :14 dump6379.rdb-rw-r--r-- 1 root root 194 Apr 13 19 :28 dump6380.rdb-rw-r--r-- 1 root root 194 Apr 13 19 :28 dump6381.rdb-rw-r--r-- 1 root root 92 Apr 11 14 :05 dump.rdb-rw-r--r-- 1 root root 92232 Apr 12 20 :40 redis79.conf-rw-r--r-- 1 root root 92232 Apr 12 20 :43 redis80.conf-rw-r--r-- 1 root root 92232 Apr 12 20 :45 redis81.conf-rw-r--r-- 1 root root 92220 Apr 11 14 :03 redis.conf-rw-r--r-- 1 root root 42 Apr 13 19 :50 sentinel.conf[root @quan myconfig ] [root @quan bin ] myconfig redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server [root @quan bin ] 20268 :X 13 Apr 2021 19 :55 :57.598 20268 :X 13 Apr 2021 19 :55 :57.598 20268 :X 13 Apr 2021 19 :55 :57.598 20268 :X 13 Apr 2021 19 :55 :57.599 * monotonic clock: POSIX clock_gettime _._ _.-``__ '' -._ _.-`` `. `_. '' -._ Redis 6.2 .1 (00000000 /0 ) 64 bit .-`` .-```. ```\/ _.,_ '' -._ ( ' , .-` | `, ) Running in sentinel mode |`-._`-...-` __...-.``-._|' ` _.-'| Port: 26379 | `-._ `._ / _.-' | PID: 20268 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-' _.-'| | `-._`-._ _.-' _.-' | http://redis.io `-._ `-._`-.__.-' _.-' _.-' |`-._`-._ `-.__.-' _.-' _.-'| | `-._`-._ _.-' _.-' | `-._ `-._`-.__.-' _.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' 20268 :X 13 Apr 2021 19 :55 :57.599 20268 :X 13 Apr 2021 19 :55 :57.604 20268 :X 13 Apr 2021 19 :55 :57.604 20268 :X 13 Apr 2021 19 :55 :57.605 * +slave slave 127.0 .0.1 :6380 127.0 .0.1 6380 @ myredis 127.0 .0.1 6379 20268 :X 13 Apr 2021 19 :55 :57.610 * +slave slave 127.0 .0.1 :6381 127.0 .0.1 6381 @ myredis 127.0 .0.1 6379 20268 :X 13 Apr 2021 19 :58 :01.811 20268 :X 13 Apr 2021 19 :58 :01.811 20268 :X 13 Apr 2021 19 :58 :01.811 20268 :X 13 Apr 2021 19 :58 :01.811 20268 :X 13 Apr 2021 19 :58 :01.817 20268 :X 13 Apr 2021 19 :58 :01.817 20268 :X 13 Apr 2021 19 :58 :01.817 20268 :X 13 Apr 2021 19 :58 :01.883 20268 :X 13 Apr 2021 19 :58 :01.883 * +failover-state-send-slaveof-noone slave 127.0 .0.1 :6380 127.0 .0.1 6380 @ myredis 127.0 .0.1 6379 20268 :X 13 Apr 2021 19 :58 :01.983 * +failover-state-wait-promotion slave 127.0 .0.1 :6380 127.0 .0.1 6380 @ myredis 127.0 .0.1 6379 20268 :X 13 Apr 2021 19 :58 :02.041 20268 :X 13 Apr 2021 19 :58 :02.041 20268 :X 13 Apr 2021 19 :58 :02.112 * +slave-reconf-sent slave 127.0 .0.1 :6381 127.0 .0.1 6381 @ myredis 127.0 .0.1 6379 20268 :X 13 Apr 2021 19 :58 :03.056 * +slave-reconf-inprog slave 127.0 .0.1 :6381 127.0 .0.1 6381 @ myredis 127.0 .0.1 6379 20268 :X 13 Apr 2021 19 :58 :03.056 * +slave-reconf-done slave 127.0 .0.1 :6381 127.0 .0.1 6381 @ myredis 127.0 .0.1 6379 20268 :X 13 Apr 2021 19 :58 :03.111 20268 :X 13 Apr 2021 19 :58 :03.111 20268 :X 13 Apr 2021 19 :58 :03.111 * +slave slave 127.0 .0.1 :6381 127.0 .0.1 6381 @ myredis 127.0 .0.1 6380 20268 :X 13 Apr 2021 19 :58 :03.111 * +slave slave 127.0 .0.1 :6379 127.0 .0.1 6379 @ myredis 127.0 .0.1 6380 20268 :X 13 Apr 2021 19 :58 :33.123
缓存穿透和雪崩 Redis 缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面.但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解。如果对数据的一致性要求很高,那么就不能使用缓存。另外的一些典型问题就是,缓存穿透、缓存雪崩和缓存击穿。目前,业界也都有比较流行的解决方案。
缓存穿透
概念
缓存穿透的概念很简单,用户想要查询一个数据,发现 redis 内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。查不到数据 !
解决方案
布隆过滤器 对所有可能查询的参数以Hash的形式存储,以便快速确定是否存在这个值,在控制层先进行拦截校验,校验不通过直接打回,减轻了存储系统的压力。
缓存空对象 当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源!
但是这种方法会存在两个问题:
如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
缓存击穿
概述
这里需要注意和缓存击穿的区别,缓存击穿,是指一个 key 非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key 在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
当某个 key 在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存,会导使数据库瞬间压力过大。量太大,缓存过期!
解决方案
设置热点数据永不过期 从缓存层面来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。
加互斥锁 分布式锁:使用分布式锁,保证对于每个 key 同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。
缓存雪崩
概念
缓存雪崩,是指在某一个时间段,缓存集中过期失效。
产生雪崩的原因之一,比如在写本文的时候,马上就要到双十一零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。
其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。
解决方案
redis高可用 这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。
限流降级 这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
数据预热 数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key ,设置不同的过期时间,让缓存失效的时间点尽量均匀。