REDIS


1、redis是基于键值对的非关系型数据库。工作在内存当中

  • 字符串数据类型(string)
  • 哈希表数据类型(hash)
  • 列表数据类型(list)
  • 集合数据类型(set)
  • 有序集合数据类型(zset)

位图bitmaps,hyperlooglogs,GEO(地理位置定位),持久化,发布订阅,流水线,哨兵,键过期,lua脚本,LRU收回,事务

redis优点:

1、速度快,读写速度可以达到10万次/秒

  • 工作在内存中
  • C语言编写的内容,距离操作系统更近,执行速度相对较快
  • redis属于单线程架构,避免多线程争抢资源(单线程缺点:害怕阻塞)

2、基于键值对的数据结构服务器

  • Remote Dictionary Server   (远程字典服务器)

3、功能丰富

4、简单稳定

  • 代码量少,方便开发,redis不需要依赖系统类库。

5、客户端语言多

java、python、c、c++、php、...

6、持久化

7、支持主从复制

8、高可用和分布式

redis使用场景

1、缓存

2、排行榜

3、计数器

4、社交活动

5、消息队列

redis-server:启动redis服务器端

redis-cli:启动redis客户端

redis-check-aof:持久化的检查工具

redis-check-rdb:持久化的检查工具

redis-benchmark:测试工具

redis的编译安装

1.下载redis的压缩包(就不用多说了~找度娘233)

2.解包并切换到解压目录

[root@shuai ~]# tar -zxvf redis-4.0.6.tar.gz -C /usr/src/
[root@shuai ~]# cd /usr/src/redis-4.0.6/

3.编译安装

[root@shuai ~]# make -j4 && make install

4.启动redis服务端

[root@shuai ~]# redis-server

启动客户端

[root@shuai ~]# redis-cli

5.启动redis服务端后会出现4个warning

首先先解决第一个warning(在后面加上redis.conf就好了)

[root@shuai redis-4.0.6]# redis-server redis.conf

然后再来解决第二个warning (注意:需要强制写入。不能直接vim修改,会同步失败)

[root@shuai redis-4.0.6]# echo 511 > /proc/sys/net/core/somaxconn
[root@shuai redis-4.0.6]# cat /proc/sys/net/core/somaxconn
511

继续解决第三个warning (vim /etc/sysctl.conf 打开配置文件在最后一行添加vm.overcommit_memory = 1,保存)

[root@shuai redis-4.0.6]# vim /etc/sysctl.conf 
[root@shuai redis-4.0.6]# sysctl -p
net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
error: "net.bridge.bridge-nf-call-ip6tables" is an unknown key
error: "net.bridge.bridge-nf-call-iptables" is an unknown key
error: "net.bridge.bridge-nf-call-arptables" is an unknown key
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
vm.overcommit_memory = 1            //在这里可以看见刚刚添加的内容

解决最后一个warning

[root@shuai redis-4.0.6]# echo never > /sys/kernel/mm/transparent_hugepage/enabled
//注意:这样修改是一次性生效,重启后需要再次输入这条命令。
如果想要永久生效,可以把这条命令加入开机自启
[root@shuai 桌面]# vim /etc/rc.local 
//然后在最后面一行加入下面这条命令:
echo never > /sys/kernel/mm/transparent_hugepage/enabled

看到下图的样子才算是成功了

最后切换到另一个终端,启动客户端来执行ping测试(返回PONG为成功)

[root@shuai redis-4.0.6]# redis-cli 
127.0.0.1:6379> ping
PONG

redis配置文件:redis.conf

  • port:6379                端口号
  • bind:127.0.0.1        绑定地址
  • daemonize:            是否允许后台运行

基本语法:

创建键值对

127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> KEYS *
1) "hello"
127.0.0.1:6379> dbsize
(integer) 1

查看键值对个数

127.0.0.1:6379> DBSIZE
(integer) 2

创建列表

127.0.0.1:6379> RPUSH mylist a b c d e f g
(integer) 7
127.0.0.1:6379> KEYS *
1) "hello"
2) "mylist"

 

删除键值对

127.0.0.1:6379> DEL hello mylist
(integer) 2
127.0.0.1:6379> KEYS *
(empty list or set)

exists 键名 检测键是否存在,存在返回1,不存在返回0,如果检测键是多个的时候,返回存在键的个数

键过期

expire key seconds 给某个键设置过期时间,当超过过期时间,键会自动删除

ttl:查询键的剩余过期时间

-2:键不存在
-1:键没有设置过期时间

127.0.0.1:6379> EXPIRE hello 30
(integer) 1
127.0.0.1:6379> ttl hello
(integer) 28
127.0.0.1:6379> ttl hello
(integer) 27
127.0.0.1:6379> ttl hello
(integer) 26

type:查看数据类型

127.0.0.1:6379> TYPE hello
string
127.0.0.1:6379> RPUSH mylist a b c d e
(integer) 5
127.0.0.1:6379> TYPE mylist
list

内部编码

每一种数据结构都由内部编码实现

string         raw      int       embstr

hash         hashtable         ziplist

list         linkedlist        ziplist

set          hashtable         intset

zset         skiplist          ziplist

object encoding 键名     //查询内部编码

内部编码的好处

  1. 改进内部编码,对数据结构和命令没有任何影响
  2. 多种内部编码可以适用于不同地场景

redis使用单线程架构和I/O多路复用模型实现高性能服务

  1. redis将所有数据放在内存上,内存响应时间约为100纳秒
  2. 非阻塞I/O线程,redis使用epoll作为I/O多路复用技术的基础,减少时间消耗
  3. 单线程避免了多线程争抢资源问题

字符串数据类型

SET key value [ex seconds] [px milliiseconds] [nx|xx]
  • ex seconds 设置秒级别过期时间
  • px milliseconds 设置毫秒级过期时间
  • nx:键必须不存在才能设置成功(用于创建)
  • xx:键必须存在才能设置成功(用于更新)
setnx [set if no exists]

批量设置键值对

mset key1 value1 key2 value2...
127.0.0.1:6379> mset a b c d e f g h
OK
127.0.0.1:6379> KEYS *
1) "redis"
2) "c"
3) "g"
4) "a"
5) "mylist"
6) "e"
127.0.0.1:6379> mget a c e g              //批量查询
1) "b"
2) "d"
3) "f"
4) "h"
127.0.0.1:6379>

计数

incr key

  1. 只能对数字进行增加
  2. 每次以1增加,返回的值为加过之后的结果
127.0.0.1:6379> set shu 1
OK
127.0.0.1:6379> incr shu
(integer) 2
127.0.0.1:6379> get shu
"2"
127.0.0.1:6379> incr shu
(integer) 3
  • incrby  key    增加的数字

decr key          减少

decrby key      减少的数字

带有小数点的数字进行增加(自增浮点数)

incrbyfloat key 带小数的数字

 

追加值

append key value

计算字符串长度

strlen

显示中文(将汉字正常的显示)

[root@shuai 桌面]# redis-cli --raw
127.0.0.1:6379> 
127.0.0.1:6379> get hello
世界

设置并返回原值

getset key value

127.0.0.1:6379> GETSET hello world
世界
127.0.0.1:6379> GET hello
world

设置指定位置的字符

setrange key 数字位置 value

2^29-1,储存的字符串长度 (偏移量)

2^29-1=536870911

如果给定的key比偏移量小。原来字符和偏移量之间将用零字节表示(\x00)

获取部分字符串

getrange key 开启位置 结束位置(-1:获取所有字符串)

127.0.0.1:6379> GETRANGE hello 0 -1
world
127.0.0.1:6379> GETRANGE hello 0 1
wo

字符串内部编码

INT       8字节的长度字符串         2^63-1      9223372036954775807
embstr    小于45个字节的字符串
raw       大于45个字节的字符串

哈希

键 field(字段) 值

储存字段和值的映射。哈希不支持嵌套其他数据类型。比如说哈希散列中有集合是不允许的

设置值

hset key 字段(field) value

获取值

hget key 字段(field)

计算field个数

hlen key

删除field

hdel key field [field...]

127.0.0.1:6379> HSET user1 name tom
1
127.0.0.1:6379> HGET user1 name
tom
127.0.0.1:6379> HSET user1 sex m
1
127.0.0.1:6379> HGET user1 sex
m
127.0.0.1:6379> HDEL user1 sex
1
127.0.0.1:6379> HGET user1 sex

批量设置获取字段和值

hmset key field value [field...]

hmget key field [field...]

127.0.0.1:6379> HMSET user1 name sjk age 20 city beijing
OK

判断字段是否存在(存在返回1,不存在返回0)

hexists key 字段 (field)

直接获取所有值

hvals key

直接获取所有字段

hkeys key

直接获取所有的字段和值

hgetall key

增加哈希数据类型中的数值

hincrbyfloat  key 字段(field) 增加的数

计算value的字符长度

hstrlen key field(字段)

哈希的内部编码

ziplist(压缩列表):当哈希元素个数小于hash-max-ziplist-entries配置(默认512个),同时所有的值都小于hash-max-ziplist-value配置(默认64字节),redis使用ziplist作为hash的内部编码
hashtable:不满足ziplist的情况使用hashtable

list列表

列表是用来存储多个有序的字符串。一个列表中最多可以储存2个32次方-1个元素。

列表中的元素都是有顺序的,通过索引下标获取某个元素或者某个范围内的元素列表

列表中的元素允许重复

命令        操作

增          rpush       lpush      linsert
查          lrange      lindex     llen
删          lpop        rpop       ltrim
改          lset
阻塞        blpop       brpop

127.0.0.1:6379> RPUSH mylist a b c d e 
(integer) 5
127.0.0.1:6379> LPUSH mylist a b c 
(integer) 8
127.0.0.1:6379> LRANGE mylist 0 -1
1) "c"
2) "b"
3) "a"
4) "a"
5) "b"
6) "c"
7) "d"
8) "e"

向某个元素前或者后插入元素(顺序插入)

linset key before | after 已经存在的值(pivot)  value

127.0.0.1:6379> LINSERT mylist before a redis
(integer) 10
127.0.0.1:6379> LRANGE mylist 0 -1
1) "c"
2) "b"
3) "redis"
4) "a"
5) "a"
6) "b"
7) "c"
8) "d"
9) "e"
10) "a"

查看指定范围的元素

lrange key start stop

127.0.0.1:6379> LRANGE mylist 0 -1
1) "c"
2) "b"
3) "redis"
4) "a"
5) "a"
6) "b"
7) "c"
8) "d"
9) "e"
10) "a"

查看列表中指定索引下标的元素

lindex key 索引下标

127.0.0.1:6379> LINDEX mylist 2
"redis"

获取列表的长度

llen key

127.0.0.1:6379> LLEN mylist
(integer) 10

左删除

lpop

127.0.0.1:6379> lpop mylist
"c"

右删除

rpop127.0.0.1:6379> rpop mylist
"a"

删除指定元素

lrem key count value

count大于0,从左往右删,删除count个元素。如果没有这个元素,则不删

count小于0,从右往左删,删除count个元素。如果没有这个元素,则不删

count等于0,删除所有指定元素

127.0.0.1:6379> LREM mylist 1 a
(integer) 1
127.0.0.1:6379> LRANGE mylist 0 -1
1) "b"
2) "redis"
3) "a"
4) "b"
5) "c"
6) "d"
7) "e"
127.0.0.1:6379> LREM mylist -1 b
(integer) 1
127.0.0.1:6379> LRANGE mylist 0 -1
1) "b"
2) "redis"
3) "a"
4) "c"
5) "d"
6) "e"

删除指定范围内的所有元素

ltrim key start  stop

127.0.0.1:6379> LRANGE mylist 0 -1
1) "b"
2) "redis"
3) "a"
4) "c"
5) "d"
6) "e"
<strong><span style="color: #ff0000;">127.0.0.1:6379> LTRIM mylist 0 1</span></strong>
OK
127.0.0.1:6379> LRANGE mylist 0 -1
1) "b"
2) "redis"

修改

lset key index newvalue

127.0.0.1:6379> LSET mylist 6 hello
OK
127.0.0.1:6379> LRANGE mylist 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
5) "b"
6) "redis"
7) "hello"
8) "b"
9) "c"
10) "d"
11) "e"

阻塞。(当并发过大时,用来缓解压力)

blpop key [key...] timeout(超时时间)                        从左往右

brpop key [key...] timeout(超时时间)                       从右往左

如果所有key都不存在或者包含空列表,那么blpop将会阻塞。知道超时0代表永久阻塞

内部编码

ziplist 压缩列表:当列表的元素个数小于list-max-ziplist-entries 512个,同时列表中的每个元素值都小于list-max-ziplist-value 64字节
redis使用ziplist方式作为内部编码

linkedlist(quicklist):当满足ziplist的方式,就使用linkedlist

集合(set)

集合也可以用来存储多个元素,集合中不允许有重复的的元素,并且集合中元素是无序的,一个集合中最多允许2的32次方-1个元素
集合可以求交、并、差集

创建集合

sadd key 元素

删除元素

srem key 元素

计算元素的个数

scard key

判断元素是否在集合中

sismeber key 元素

随机从集合中返回指定个数的元素

srandmember key [count]

从集合中随机删除元素

spop key [count]

查看集合内所有元素

smembers key

求集合间的交集

sinter key key [key...]

127.0.0.1:6379> SADD user1 music sports sing computer
(integer) 4
127.0.0.1:6379> SADD user2 eat sleep sing dance
(integer) 4
127.0.0.1:6379> SINTER user1 user2

求集合间的并集

sunion key key [key...]

127.0.0.1:6379> SUNION user1 user2
1) "sleep"
2) "sing"
3) "sports"
4) "eat"
5) "dance"
6) "computer"
7) "music"

求集合间的差集

sdiff key key [key...]

127.0.0.1:6379> SDIFF user1 user2
1) "sports"
2) "music"
3) "computer"
127.0.0.1:6379> SDIFF user2 user1
1) "sleep"
2) "eat"
3) "dance"

交并差集的保存

sinterstore destination                 保存交集
sunionstore destination               保存并集
sdiffstore destination                   保存差集

127.0.0.1:6379> SINTERSTORE user1:2j user1 user2
(integer) 1
127.0.0.1:6379> SMEMBERS user1:2j
1) "sing"
127.0.0.1:6379> SUNIONSTORE user1:2b user1 user2
(integer) 7
127.0.0.1:6379> SMEMBERS user1:2b
1) "sleep"
2) "sing"
3) "sports"
4) "eat"
5) "dance"
6) "computer"
7) "music"
127.0.0.1:6379> SDIFFSTORE user1:2c user1 user2
(integer) 3
127.0.0.1:6379> SMEMBERS user1:2c
1) "sports"
2) "music"
3) "computer"
127.0.0.1:6379> SDIFFSTORE user1:2c user2 user1
(integer) 3
127.0.0.1:6379> SMEMBERS user1:2c
1) "sleep"
2) "eat"
3) "dance"

内部编码

intset 当集合中的元素都是整数而且元素个数小于set-max-intset-entries(512个)使用intset

 

有序集合(zset)

  1. 有序集合元素是由顺序的,排序由分数(score)决定
  2. 不能有重复的元素
数据结构        是否允许重复      是否有序       有序实现方式       应用场景
列表               是              是            索引下标         消息列队
集合               否              否              无            标签,社交
有序集合           否              是              分数           排行榜,社交环境

zset是在集合基础上,加上score分数。每个值都会一个分值。元素不能重复,但是分数可以重复。分数必须是一个数字

zadd key score member [score member]

CH此次操作完成后,有序集合元素和分数发生变化的个数
incr:对score进行增加

127.0.0.1:6379> zadd userranking ch 251 tom
(integer) 1
127.0.0.1:6379> zadd userranking 1 kris 91 mike 200 frank 220 tim 250 martin
(integer) 5
127.0.0.1:6379> ZRANGE userranking 0 -1 
1) "kris"
2) "mike"
3) "frank"
4) "tim"
5) "martin"
6) "tom"
127.0.0.1:6379> ZADD userranking 255 tom
(integer) 0
127.0.0.1:6379> 
127.0.0.1:6379> ZRANGE userranking 0 -1 withscores
1) "kris"
2) "1"
3) "mike"
4) "91"
5) "frank"
6) "200"
7) "tim"
8) "220"
9) "martin"
10) "250"
11) "tom"
12) "255"

查看成员的个数

zcard key

127.0.0.1:6379> ZCARD userranking
(integer) 6

查看指定成员的分数

zscore key member

127.0.0.1:6379> ZSCORE userranking tom
"255"

求成员的排名

zrank key member                               //从低到高查看排名
zrevrank key member                         //从高到低查看排名

删除某个成员

zrem key member [member...]

127.0.0.1:6379> ZREM userranking kris tom
(integer) 2

增加某个成员的分数

zincrby key increment member

127.0.0.1:6379> ZINCRBY userranking 100 mike
"191"

指定排名范围的成员

zrange key start stop [withscores]                 由低到高进行排列
zrevrange key start end [withscores]            由高到低进行排列

求指定分数范围内的成员

zrangebyscore key min max [withscores] [limit offset count]                   由低到高进行排列
zrevrangebyscore key max mix [withscores] [limit offset count]              由高到低进行排列

127.0.0.1:6379> ZRANGEBYSCORE userranking 1 200 withscores       //由低到高排列
1) "mike"
2) "191"
3) "frank"
4) "200"
127.0.0.1:6379> ZREVRANGEBYSCORE userranking 200 50 withscores     //由高到低排列
1) "frank"
2) "200"
3) "mike"
4) "191"

求指定分数的范围查看成员的个数

zcount key min max

删除指定排名内的升序元素

zremrangebyrank key start end

有序集合间的操作 交集

zinterstore destination numkeys key [key...] [weight weight] [aggregate sum|min|max]

aggregate:成员求完交集之后,按照sum|min|max进行汇总

并集

zunionstore destination numkeys key [key...] [weight weight] [aggregate sum|min|max]

有序集合内部编码
ziplist:当有序集合元素个数小于zset-maax-ziplist-entries(默认128个),同时每个元素值都小于zset-max-ziplist-value(默认64字节)。redis使用ziplist作为内部编码

skiplist(跳跃表):当不满足ziplist条件,使用skiplist

 

对键进行重命名

rename key newname

127.0.0.1:6379> set a aaa
OK
127.0.0.1:6379> RENAME a z
OK
127.0.0.1:6379> get z
"aaa"

键过期

expireat key 时间戳

迁移键

move key db

dump+restore

dump key
restore key ttl value

  1. 在源redis上,使用dump进行序列化备份,格式rdb
  2. 在目标redis上,使用restore将备份号的数据写入进行还原
  • ttl:过期时间,0表示永不过期
  • 整个迁移过程中不具备原子性
127.0.0.1:6379> DUMP user1
"\x02\x04\x06sports\x04sing\x05music\bcomputer\b\x00twH'a\x8e\x9f."             //复制这个16进制的代码
//切换到另一个端口的终端
127.0.0.1:6380> restore hello 0 "\x02\x04\x06sports\x04sing\x05music\bcomputer\b\x00twH'a\x8e\x9f."           //在这粘贴
OK

migrate

迁移过程中具有(原子性):要么都成功,要么都失败

migrate host port key | '' destination-db timeout [copy] [replace] [keys key [key...]]
host :主机
port:端口
key | ''  :键
destination-db:多少号数据库
timeout:超时时间
copy:不删除源数据
replace:直接迁移源数据
127.0.0.1:6379> MIGRATE 127.0.0.1 6380 '' 15 0 copy keys z redis
//切换到另一个端口的终端
127.0.0.1:6380> select 15
OK
127.0.0.1:6380[15]> keys *
1) "redis"
2) "z"

渐进式遍历键

首先从0开始进行遍历,当游标再一次变成0时,遍历完全部键

scan cursor [match pattern] [count number]

cursor:游标
match pattern:用作模式的匹配

  1.       *    匹配任意字符
  2.       ?  匹配一个字符
  3.       []   匹配部分字符

count number:表示每次都要遍历的键的个数

默认情况下,每次scan遍历出来的键默认为10个

优点:防止使用keys *阻塞数据库
缺点:无法一次性遍历完所有数据,无法一次性查到想要的键
当我们遍历时,对数据进行多次的键的增删,将会导致遍历出来的结果不完全,或者说可能出现某些键没有遍历到或者出现重复遍历一个键

慢查询

慢查询日志记录的命令执行前后的耗时,如果超过预设阈值,将会把这条命令记录下来

进入redis配置文件:redis.conf
slowlog-log-slower-than 10000:慢查询记录的时间(微秒)
slowlog-max-len 128:最大能记录的条数

  1. 获取慢查询日志 slowlog get
  2. 获取man查询日志条目 slowlog len
  3. 重置 slowlog reset

慢查询由:标识id,发生时间戳,命令耗时,执行命令的参数组成

 

redis shell

[redis-cli]

-r:将命令执行多次
-i:表示每隔几秒执行一次

[root@shuai 桌面]# redis-cli -r 3 -i 1 ping
PONG
PONG
PONG
-x:从标准输入读取数据作为redis-cli的参数
[root@shuai 桌面]# echo 'world' | redis-cli -x set hello
OK

-c:连接集群节点时需要使用的参数,防止moved和ask异常

-a:不需要手动输入密码

127.0.0.1:6379> config set requirepass '123.com'            //临时生效
OK
127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 123.com
OK
127.0.0.1:6379> keys *
1) "redis"
2) "myset"
3) "user1:2b"
4) "request"
5) "user2"

127.0.0.1:6379> CONFIG rewrite //永久生效(将上面的操作写入配置文件,每次进入都需要指定密码进行登陆)
OK

requirepass "123.com"    //可在redis配置文件最后一行看到

--scan:用于扫描指定模式的键

[root@shuai 桌面]# redis-cli --scan --pattern 'he*'
hello

--slave:把当前的客户端模拟成redis节点的从节点,获取redis节点的更新(实时获取主节点的操作)

SYNC with master, discarding 692 bytes of bulk transfer...
SYNC done. Logging commands from master.
"PING"
"PING"

--pipe:执行流水线,将命令封装成redis的通信协议定义的数据格式,批量发送给redis进行执行

  • -r:光标移动至行首且不换行 -n:换行光标移动至行首

--rdb:拍摄快照,备份,请求redis实例生成rdb持久化文件,保存在本地

[root@shuai ~]# redis-cli --rdb /root/test/dump.rdb
SYNC sent to master, writing 692 bytes to '/root/test/dump.rdb'
Transfer finished with success.

--eval:执行指定的lua脚本

查询延迟
--latency:可以测试客户端到目标redis的网络延迟,只会输出一条结果。cli将一直运行,向redis服务端发送ping命令,测量得到答复的时间,每秒发送100次ping命令

[root@shuai ~]# redis-cli --latency
min: 0, max: 2, avg: 0.25 (3770 samples)

--latency-history:每隔15秒返回一次延迟信息

--stat:可以实时获取redis的统计信息

[root@shuai ~]# redis-cli --latency-history
min: 0, max: 2, avg: 0.23 (1404 samples) -- 15.00 seconds range
min: 0, max: 50, avg: 0.30 (1400 samples) -- 15.01 seconds range

--latency-dist:使用统计图形式从控制台输出延迟信息

--redis-server

--test-memory:检测是否有内存问题造成的内存崩溃。用来检测当前操作系统是否稳定的分配制定内存给redis

redis-benchmark:作为redis的基准测试工具。用来给开发和运维提供测试数据

  • -c:设置客户端并发量 -n:设置客户端请求总量 -q:仅显示结果 -r:在一个空的redis上执行redis-benchmark。并向redis插入更多随机键 -p:每个请求pipe流线的数量,默认1 -k:代表客户端是否使用keeplive,1作为使用,0没使用
[root@shuai ~]# redis-benchmark -c 100 -n 30000
====== PING_INLINE ======

流水线

把指令批量发送给服务端进行处理

RTT(round-tryy time)往返时间

 

事务

为了保证多条命令的原子性,redis事务相较于mysql比较简单

mutil:开启事务
exec:提交事务
discard:放弃事务

当开启事务的时候,每个事务都是独立的。在不开启事务的过程中可以对数据进行操作

 

bitmaps位图

使用二进制存储数据,1字节=8位

ASCII

setbit key offset value          //设置对应二进制位的数据
getbot:查看对应二进制位的数据

位图之间的运算

bitop op destkey key [key...]

and:交集
or:并集
not:非
xor:异或

hyperloglog

通过字符串数据类型开发。可以利用很小的内存完成总数的统计,可以统计IP、EMAIL、ID等等

pfadd 向hyperloglog添加元素
pfadd key element [element...]
pfcount 计算独立用户数
pfcount key [key...]
pfmerge:合并,将多个hyperloglog结果赋值给新的key
pfmerge destkey sourcekey [sourcekey...]

127.0.0.1:6379> PFADD 20181107 user1 user2 user3
(integer) 1
127.0.0.1:6379> PFADD 20181106 user4 user5 user6
(integer) 1
127.0.0.1:6379> PFCOUNT 20181107 20181106
(integer) 6
127.0.0.1:6379> PFMERGE 201811 20181107 20181106
OK
127.0.0.1:6379> PFCOUNT 201811
(integer) 6

发布订阅 

redis基于发布订阅模式的消息机制

发布者和订阅者不进行直接的消息交流,频道

发布消息

publish channel message

127.0.0.1:6379> PUBLISH redisChat 'Redis is a great caching technique'
(integer) 0

订阅消息

subscribe channel [channel...]

127.0.0.1:6379> SUBSCRIBE redisChat

取消订阅

unsubscribe [channel [channel1]]

按照模式进行订阅和取消订阅

psubscride [pattern [pattern...]]

127.0.0.1:6379> PSUBSCRIBE re*              //订阅由re开头的所有频道
psubscribe
re*
1
pmessage
re*
redisChat

取消订阅

punsubscribe [pattern[pattern...]]

查看订阅

pubsub channels [argumet [argument[argument...]]

127.0.0.1:6379> PUBSUB channels redisChat
redisChat

查看频道订阅数

pubsub numsub [argument [argument...]]

127.0.0.1:6379> PUBSUB numsub redisChat
redisChat
1

查看模式订阅数

pubsub numpat

127.0.0.1:6379> PUBSUB numpat
1

GEO地理信息定位

3.2版本之后开启的功能,Ardb

把某个位置的经纬度添加到指定的key,数据被保存后可以通过GEO提供的特殊指令查看到。通过有序集合实现

有效的经度:-180度 到 180度
有效的维度:-85.05112878 到 85.05112878

添加地理位置信息

geoadd key longitude latitude member [longitude latitude member...]

127.0.0.1:6379> GEOADD citis:locations 116.28 39.55 beijing 117.12 39.08 tianjin 114.29 38.02 shijiazhuang 118.01 39.38 tangshan 115.29 38.51 baoding
5

获取地理位置信息

geopos key member1 [member2...]

127.0.0.1:6379> GEOPOS citis:locations beijing
116.28000229597091675
39.5500007245470826

获取两个地理位置的距离

geodist key member1 member2 [unit] m,km,mi,ft

127.0.0.1:6379> GEODIST citis:locations beijing tianjin m
89206.0576
127.0.0.1:6379> GEODIST citis:locations beijing tianjin km
89.2061
127.0.0.1:6379> GEODIST citis:locations beijing tianjin mi
55.4302
127.0.0.1:6379> GEODIST citis:locations beijing tianjin ft
292670.7926

获取指定位置范围内的地理信息位置集合

georadius key longitude latiude randius m|ft|mi|km [withcoord] [withdist] [wothhash] [COUNT count] [asc|desc|] [store key] [storedist key]
  • withcoord:返回的结果中包含经纬度
  • withdist:返回的结果中包含里中心节点位置的距离
  • withhash:获取geohash,将二维维度转换为一维字符串
  • COUNT count指定返回的数量
  • store key storedist key:将结果保存到某个键中
127.0.0.1:6379> GEORADIUS citis:locations 117.38 38.90 100 km withcoord withdist
1) 1) "tianjin"
2) "30.1008"
3) 1) "117.12000042200088501"
2) "39.0800000535766543"
2) 1) "tangshan"
2) "76.1844"
3) 1) "118.01000028848648071"
2) "39.37999951111137165"

通过成员名来返回信息

georadiusbymember key member m|ft|mi|km  [withcoord] [withdist] [wothhash] [COUNT count] [asc|desc|] [store key] [storedist key]

搜索附近150km内有什么地点

127.0.0.1:6379> GEORADIUSBYMEMBER citis:locations beijing 150 km store key storedist weizhi
(integer) 4
127.0.0.1:6379> ZRANGE weizhi 0 -1 withscores
1) "beijing"
2) "0"
3) "tianjin"
4) "89.206057589342976"
5) "baoding"
6) "143.86456236399633"
7) "tangshan"
8) "149.74786840070465"
<span style="color: #ff00ff;">获取geohash</span>

将二维的经纬度转换成一维的字符串

geohash key member [member...]

GEOHASH长度       精度(km)

1                 2500
2                 630 
3                 78
4                 20
5                 2.4 
6                 0.61
7                 0.076
8                 0.019
9                 0.002

字符串越相近表示距离越近

持久化

RDB
rdb把当前进程数据生成快照保存到硬盘当中

打开redis配置文件

1.手动触发

save:阻塞当前redis,直到rdb过程完成

bgsave:redis进行fork操作创建子进程,rdb持久化由子进程负责,持久化完毕,子进程消失。检测到有子进程在执行持久化,直接返回

2.自动触发

  • 表示m秒内存在n次修改会自动触发bgsave
  • 如果从节点执行全量复制,主节点自动执行bgsave,然后把rdb文件发送给从节点
  • 执行debug reload 命令重新加载redis时,自动触发save操作
  • 执行shutdown时,如果没有开启AOF持久化,自动触发bgsave

在redis中设置持久化文件的保存路径

config set dir newdir

127.0.0.1:6379> CONFIG set dir /var/redis
OK
127.0.0.1:6379> BGSAVE
Background saving started

redis使用LZF压缩,压缩后的文件远远小于内存大小,默认开启

config set rdbcompression yes|no

AOF

工作流程:

  • 命令写入-文件同步-文件重写-重启加载

三种同步策略

  • always:命令写入缓冲区之后调用系统fsync操作向硬盘进行同步,完成后线程返回。每秒处理消息的次数(TPS)
  • everysec:命令写入缓冲区调用write操作,write完成线程返回,fsync由专门的线程每秒调用一次
  • no:命令写入缓冲区调用write操作,write完成后线程返回,AOF文件不进行同步,同步到硬盘的操作由操作系统负责,通常周期为30秒

为什么要把命令直接写入缓冲区而不进行直接同步

redis属于单线程。如果数据直接同步到硬盘,性能完全取决于硬盘处理速度。浪费时间

为什么采用文本协议格式?

  • 简单易懂
  • 文本协议具有较高的兼容性
  • 文本协议具有可读性质

 

重写机制

rewrite

  1. 进程内已经超时的文件将不再记入aof文件
  2. 重写之前aof文件由很多无效指令,del,hdel,srem,zrem,lpop,重写之后无效指令将被删除
  3. 多条命令合并成一条。以64个元素作为临界点

重写机制流程

  1. 执行bgrewriteeaof,fork子进程替代父进程执行重写,开销和bgsave一样
  2. 主进程继续等待指令,修改的数据通过aof缓冲区执行相应策略向硬盘进行同步
  3. 新写入的指令将写入aof——rewrite-buf缓冲区,防止新的aof文件生成期间丢失数据
  4. 子进程根据快照,按照命令合并数据,然后写入新的aof文件
  5. aof执行完毕子进程告知父进程任务结束,然后结束进程
  6. 父进程把数据写入到新的aof文件
  7. 老的aof文件被覆盖,重写完成

指定redis日志路径,(配置文件里修改)

logfile "/var/redis/redis.log"

手动触发

bgrewriteeaof

自动触发

打开redis配置文件

开启AOF(默认关闭)

打开redis.conf配置文件(把appendonly后面的no改为yes)

会在路径下生成一个appendonly.aof的文件,会以流水线语言显示

RESP(redis serialization protocol)redis序列化协议
简单易懂
能够被机器解析

流水线语言语法:
*<参数数量> CRLF (\r\n)
$<参数1的字节数量> CRLF
<参数1> CRLF

 

主从复制

第一种复制方式

直接修改配置文件
slaveof, master ip,  master port

第二种在redis命令行
slaveof, master ip,master port

第三种在命令
redis-server -slaveof master ip mater port

slave节点保留主节点信息,以异步的方式执行复制

断开复制并且切主流程

  1. 断开与主节点的复制关系
  2. 从节点晋升为主节点 从节点断开连接不会抛弃原有数据
  3. 删除当前所有数据(备份!!!!!!!!!)
  4. 对新的主节点进行复制

安全性

主节点设置密码

config set requirepass 密码 进行设置密码

从节点每次连接时必须进行密码效验

设置masterauth加入主节点的密码,下次复制时直接可以连接主节点

只读

主节点一般不和从节点部署在一个服务器上

通过修改slave-read-only来确认从节点是否能写入数据

延迟

repl-disable-tcpp-nodelay         是否关闭tcp-noddelay

关闭,主节点产生命令数据无论大小全部实施发送给从节点。适合网络条件良好或者同机房部署状态

开启,主节点会合并比较tcp数据,发送时间由内核决定(默认40毫秒),适用于网络不稳定或者带宽紧张的跨机房部署

拓扑

一主一从

一主多从

树状主从

复制的原理

  1. 保存主节点信息
  2. 从节点内部通过每秒执行定时任务来寻找主节点,如果发现主节点,从节点会与主节点建立网络连接。如果从节点无法建立连接,定时任务会无限重复,直到连接成功
  3. 连接成功从节点发送ping命令,如果主节点无法返回PONG从节点断开连接,等待下次定时任务发起连接
  4. 执行密码验证
  5. 同步数据
  6. 继续复制

从节点每秒都会向主节点发送偏移量,主节点也会将偏移量记录下来

全量复制
用于第一次复制场景,主节点把数据一次性发送给从节点,造成主节点过高网络开销,从节点带宽消耗增加

部分复制

  • 用于处理主从复制之间网络闪断原因造成的数据丢失。当从节点在一定条件内上线,当再次连接主节点时,如果主节点允许,主节点将会发送丢失的数据给从节点。
  • 复制偏移量
  • 复制积压缓冲区:是保存在主节点上的固定长度的队列。主节点响应命令,不但会把命令发送给从节点,还会写入复制积压缓冲区(先进先出)
Last modification:July 6th, 2020 at 06:41 pm
如果觉得我的文章对你有用,请随意赞赏