Skip to content

Redis6

一、Nosql与Redis概述

1、Nosql的优势

(1)使用nosql解决cpu与内存压力

(2)使用nosql解决I/O压力

2、Nosql数据库的概述

(1)NoSql= Not Only SQL

(2)采用key-value模式存储

(3)不遵循SQL标准

(4)性能远超过SQL

3、使用场景

(1)数据的高并发读写

(2)海量数据读写

(3)数据可扩展性

4、不适用场景

需要事务的支持

基于sql的结构化查询存储,需要即席查询

5、 Redis概述

(1)开源的key-value系统

(2)支持String、List、Set、zset、hash等数据类型

(3)数据库支持push/pop/add/remove操作

(3)支持不同方式的排序

(4)可写入内存也可以持久化

(5)主从同步功能

二、Redis6安装与使用

1、官网下载:放入liunx对应目录内

<https://redis.io/&gt;

2、安装gcc编译环境

bash
yum install centos-release-scl scl-utils-build

yum install -y devtoolset-8-toolchain

scl enable devtoolset-8 bash

测试gcc版本

bash
gcc -version

1625619349410-c974859c-58eb-4353-83d7-a5e6552d5d57.webp

3、解压缩:

bash
tar zxvf redis-6.2.4.tar.gz

1625619349446-7b213793-7c70-4a6f-b070-c8b5367dac6b.webp

4、进入redis-6.2.4目录执行make命令

1625619349499-1c34d1eb-5cc2-4440-9057-901acc25f00c.webp

5、执行安装make install

1625619349442-c9861263-f17d-42f7-996a-99c529c894cb.png

6、验证安装成

bash
cd /usr/local/bin

ll

1625619349528-93c6a71b-fb0d-44c1-989f-bd53e842d04b.webp

7、相关软件介绍:

redis-benchmar:性能测试工具

redis-check-aof:修改有问题的AOF

redis-check-rdb:修改有问题的rdb文件

redis-sentinel:Redis的集群使用

redis-server:Redis服务器集群使用

redis-cli:客户端,操作入口

8、前台启动(不推荐)

1625619349494-6ad9ffd0-aa86-4f95-83ee-0eaf35c59cb8.webp

9、后台启动

(1) 复制配置文件

bash
cp -r redis.conf /opt/

(2)修改参数配置,将daemonize no改为daemonize yes,让服务支持在后台启动

bash
[root@localhost redis-6.2.4]# cd /opt/
[root@localhost opt]# vi redis.conf

1625619349506-7756b040-da47-4817-a341-c92a4c60c158.webp

(3)启动redis

bash
[root@localhost bin]# cd /usr/local/bin/
[root@localhost bin]# redis-server /opt/redis.conf 
[root@localhost bin]# ps -ef|grep redis

(4)使用redis-cli测试

10、redis关闭

(1)redis-cli shutdown(进入终端shutdown也可以)

(2)kill -9 xxx(进程)

三、常用五大数据类型

1、Redis key操作

(1)查看所有key:keys *

bash
127.0.0.1:6379> keys *
(empty array)

(2)添加 key value:set

bash
127.0.0.1:6379> set k1 lucy
OK
127.0.0.1:6379> set k2 mary
OK
127.0.0.1:6379> set k3 jack
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"

(3)判断key是否存在 exists

bash
127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> exists k4
(integer) 0

(4)查看key的类型:type

bash
127.0.0.1:6379> type k1
string

(5)删除key数据:del

bash
127.0.0.1:6379> del k1
(integer) 1
bash
127.0.0.1:6379> unlink k2
(integer) 1

(7)设置key的过期时间(秒):expire

bash
127.0.0.1:6379> expire k3 10
(integer) 1

(9)查看ttl过期时间(秒):ttl(-1永久不过期,-2已经过期)

bash
127.0.0.1:6379> ttl k3
(integer) -2

(10)切换数据库:select

bash
127.0.0.1:6379[1]> select 0
OK

(11)查看当前数据库的key数量:dbsize

bash
127.0.0.1:6379> dbsize
(integer) 1

(12)清空当前库内数据(慎用)

bash
127.0.0.1:6379> flushdb
OK

(13)通杀所有库内数据(慎用)

bash
127.0.0.1:6379> flushall
OK

2、Redis字符串(String)

(1)简介:字符串,一个key对应一个value,是二进制安全的,是Redis最基本数据类型,value最多512M,底层为动态字符串,ArrayList

(2)设置值,相同key值覆盖:set

bash
set k1 v100

(3)获取值:get

bash
get k1

1625619349501-28038223-e7ce-4add-8f58-6f597d413e9d.webp

(4)追加值:append,返回总长度

bash
append k1 abcd

1625619349619-13e3e291-5e5e-4e41-9000-eca07a67fb0b.webp

(5)获取值的长度:strlen

bash
strlen k1

1625619349570-79236b2a-ee70-4198-a6e3-074977420712.webp

(6)当key存在时操作:setnx,设置成功返回1,设置失败返回0

1setnx k1 v1

1625619349616-087acb89-af1d-4c6d-885c-00acf26cb8e4.webp

(7)将数字类型值+1/-1:incr/decr,原子性操作,不受多线程机制打断。

bash
incr k3
decr k3

1625619349596-9eea92a3-ca97-4e27-8f83-2ae676bd1419.webp

(8)将key存储的数字值递增x/递减x:incrby/decrby

bash
incrby k3 10
decrby k3 5
bash
msetnx k11 v11 k12 v12 k13 v13
msetnx k1 v11 k4 v4

(9)同时设置一个或多个key-value键值对:mset

bash
mset k1 v1 k2 v2 k3 v3

1625619349537-2ce0f4c4-3b97-4fbe-acee-4e3d209122d4.webp

(10)同时获取一个或多个value:mget

bash
mget k1 k2 k3

1625619349571-d2c6fd48-19c2-4e84-8f2b-d933bc40c5bc.webp

(11)设置多个key-value(当key都不存在时设置成功):msetnx

bash
127.0.0.1:6379> msetnx k11 v11 k12 v12 k13 v13
(integer) 1
127.0.0.1:6379> msetnx k1 v11 k4 v4
(integer) 0

1625619349616-1b1aa7cc-741a-40aa-9b46-6e7b5ec4dad6.webp

(12)获取范围的值(开始-结束):getrange

bash
127.0.0.1:6379> getrange name 0 3
"luck"

1625619349574-4f057805-b4ea-4b1b-8e75-0652f1de4baf.webp

(13)设置范围的值(开始位置-覆盖):setrange,返回总长度

bash
127.0.0.1:6379> setrange name 3 abc
(integer) 8

1625619349625-cdf14f97-a4da-49d1-9f31-2c3b53f3862b.webp

(14)设置key的同时设置过期时间:setex

bash
127.0.0.1:6379> setex age 20 value30
OK

1625619349562-d105b884-7a8f-4ed9-b60e-0d82fd7ae0dd.webp

(15)以新值换旧值(显示旧值):getset

bash
127.0.0.1:6379> getset name jack
"lucabcry"

1625619349559-ff6a94f5-e8aa-4267-a809-2f4c952661c8.webp

3、Redis列表(List)

(1)简介:单键多值的字符串列表,可以按照插入顺序排序,底层为双向链表(zipList(数据少时)->quickList(数据多时))

(2)从左边/右边插入一个或多个值:lpush/rpush,返回数组长度

bash
127.0.0.1:6379> lpush k1 v1 v2 v3
(integer) 3
127.0.0.1:6379> rpush k1 v7 v8 v9
(integer) 6

1625619349652-2e4b9766-16ae-4f14-9568-6099f015698f.webp

(3)按照索引下标(范围)获取元素,从左到右(0表示左边第一个,-1表示右边第一个):lrange

bash
127.0.0.1:6379> lrange k1 0 -1
1) "v3"
2) "v2"
3) "v1"
4) "v7"
5) "v8"
6) "v9"

1625619349604-4bf10725-c1c7-42ba-99b9-8cecc838aa20.webp

(4)从左边或右边取出一个值:lpop/rpop

bash
127.0.0.1:6379> lpop k1
"v3"
127.0.0.1:6379> rpop k1
"v9"

1625619349621-8ca2c70c-0256-4fc7-bdca-26682284057f.webp

(5)从k1列表右边吐出一个值,插入到v2列表的左边:rpoplpush

bash
127.0.0.1:6379> rpoplpush k1 k2
"v1"

1625619349622-535f838d-5650-452f-98e2-90c1f2d7ba40.webp

(6)按照索引下标(单值)获取元素(从左到右):lindex

bash
127.0.0.1:6379> lindex k2 0
"v1"

1625619349676-1effd86e-ecdc-4319-a41e-31adcdcfce6f.webp

(7)获取列表的长度:llen

bash
llen k1

1625619349690-99cba5e4-6734-45b9-913e-0950109b6940.webp

(8)在key对应的value前面/后面插入new value:linset before/after

bash
127.0.0.1:6379> linsert k1 before "v3" "v31"
(integer) 3
127.0.0.1:6379> linsert k1 after "v2" "v21"
(integer) 4

(9)从左边删除n个对应的value:lrem

bash
127.0.0.1:6379> lrem k1 2 "new11"
(integer) 2

1625619349715-5ac2f017-0ca9-477b-8b51-dadb7bb18fc3.webp

(10)将列表key下标为index的值替换成value:lset

bash
127.0.0.1:6379> lset k1 1 "new31"
OK

1625619349668-49c7739e-0092-4a0b-b6fa-ea9c82319c3c.webp

4、Redis集合(Set)

(1)Redis Set是String类型的无序集合,它的底层其实是一个value为null的hash表,value自动排重且无序

(2)将一个或多个元素加入到集合key中:sadd,已经存在元素将忽略

bash
127.0.0.1:6379> sadd k1 v1 v2 v3
(integer) 3

1625619349661-7f4779c8-9875-40b1-a3f9-e343ba8466f5.webp

(3)取出集合中的所有值:smembers

bash
127.0.0.1:6379> smembers k1
1) "v3"
2) "v2"
3) "v1"

1625619349733-1e798160-e0d1-4aab-9d48-3ca593d621df.webp

(4)判断key集合中是否包含对应的value:sismember,1有0无

bash
127.0.0.1:6379> sismember k1 v1
(integer) 1

1625619349758-d09a42f9-c78d-4c0d-a5f0-6f5e853272b5.webp

(5)返回集合中元素个数:scard

bash
127.0.0.1:6379> scard k1
(integer) 3

1625619349694-cce4614e-7fb3-400b-9da5-b01da819b4fb.webp

(6)从集合中删除某一个或多个元素:srem

bash
127.0.0.1:6379> srem k1 v1
(integer) 1

1625619349792-9ef4f518-5192-4883-b930-95f02d4c7182.webp

(7)随机从该集合吐出一个元素:spop

bash
127.0.0.1:6379> spop k1
"v3"

1625619349669-da26961b-acfb-4c2f-9d7a-e0322406c08a.webp

(8)随机从集合中取出n个值,不会从集合中删除:srandmember

bash
127.0.0.1:6379> srandmember k1 2
1) "v1"
2) "v2"

1625619349733-622d9431-3807-497d-a65c-df6f08cdee0a.webp

(9)把集合中的一个值从一个集合移动到另一个集合:smove

bash
127.0.0.1:6379> smove k1 k2 v3
(integer) 1

(10)取两个集合的交集/并集/差集(key1中存在,key2中不存在):sinter/sunoin/sdiff

bash
127.0.0.1:6379> sinter k2 k3
1) "v4"
127.0.0.1:6379> sunion k2 k3
1) "v3"
2) "v5"
3) "v4"
4) "v7"
5) "v6"
127.0.0.1:6379> sdiff k2 k3
1) "v3"
2) "v5"

1625619349740-b0c1b521-f49e-4921-98f0-caa9df9bdd43.webp

5、Redis哈希(Hash)

(1)简介:是一个String类型的field和value的映射表,hash适合用来存储对象。类似java中Map&lt;String,Object>,底层为zipList(数据量少)或hashtable(数据量较多)

(2)向hash内添加数据(key-field-value):hset

bash
127.0.0.1:6379> hset user:1001 id 1
(integer) 1
127.0.0.1:6379> hset user:1001 name zhangsan
(integer) 1

1625619349733-de022536-a45b-4bcf-a7a5-16afb7a233cd.webp

(3)从集合中取出数据(key-field):hget

bash
127.0.0.1:6379> hget user:1001 id
"1"
127.0.0.1:6379> hget user:1001 name
"zhangsan"

1625619349729-0b1870f9-051f-4a4a-ba16-efb669159898.webp

(4)批量添加数据:hmet

bash
127.0.0.1:6379> hmset user:1002 id 2 name lisi age 30
OK

1625619349712-8a9a43d7-46f8-4504-993a-4edf8258e2b5.webp

(5)判断哈希表key中,field是否存在:hexists,1有0无

bash
127.0.0.1:6379> hexists user:1002 id
(integer) 1
127.0.0.1:6379> hexists user:1002 name
(integer) 1
127.0.0.1:6379> hexists user:1002 gender
(integer) 0

1625619349842-94b46648-fecb-4524-99c0-8e4aab37eb34.webp

(6)查看哈希表中所有field:hkeys

bash
127.0.0.1:6379> hkeys user:1002
1) "id"
2) "name"
3) "age"

1625619349820-6c211690-5f2a-4f97-8194-ef4454b951f0.webp

(7)查看哈希表内所有value:hvals

bash
127.0.0.1:6379> hvals user:1002
1) "2"
2) "lisi"
3) "30"

1625619349712-fa6ee33a-e225-4e6b-9364-d7b2122bc33a.webp

(8)对应的key、field的值增量+1:hincrby

bash
127.0.0.1:6379> hincrby user:1002 age 2
(integer) 32

1625619349841-917bc8bf-a0dd-43d7-81ec-0c3254b0803d.webp

(9)添加数据,仅当field不存在时:hsetnx

bash
127.0.0.1:6379> hsetnx user:1002 age 40
(integer) 0
127.0.0.1:6379> hsetnx user:1002 gender 1
(integer) 1

1625619349804-783e908a-5906-4a6a-8484-8ab0f83870a3.webp

6、Redis有序集合(Zset)

(1)简介:有序的,类似set,没有重复元素,关联了score并可以进行排序,底层架构类似Map&lt;String,value>,Zset底层为hash以及跳跃表

(2)将一个或多个元素以及score加入到有序集合key中:zadd

bash
127.0.0.1:6379> clear
127.0.0.1:6379> zadd topn 200 java 300 c++ 400 mysql 500 php
(integer) 4

1625619349871-5fee9fbc-15af-46b3-ab4c-faaeb6e8ca51.webp

(3)取出返回有序集合key中,下标在之间:zrange,自动按照score排序,[withscores]可以返回评分

bash
127.0.0.1:6379> zrange topn 0 -1
1) "java"
2) "c++"
3) "mysql"
4) "php"
127.0.0.1:6379> zrange topn 0 -1 withscores
1) "java"
2) "200"
3) "c++"
4) "300"
5) "mysql"
6) "400"
7) "php"
8) "500"

1625619349813-e75a1803-c9d0-4330-a69b-1b183f2dbbc5.webp

(4)取出score值介于min和max之间的成员,按照score从小到大排序:zrangebyscore [withscores][limit offset count]

bash
127.0.0.1:6379> zrangebyscore  topn 300 500  withscores 
1) "c++"
2) "300"
3) "mysql"
4) "400"
5) "php"
6) "500"

1625619349820-099bdc81-ac79-4d37-8409-7597dd29d292.webp

(5)zrevngebyscore [withscores][limit offset count]

bash
127.0.0.1:6379> zrevrangebyscore  topn 500 300  withscores 
1) "php"
2) "500"
3) "mysql"
4) "400"
5) "c++"
6) "300"

1625619349828-b7aa568d-93cf-4db2-9ac2-318cda383c8a.webp

(6)为元素score加上增量:zincrby

bash
127.0.0.1:6379> zincrby topn 50 java
"250"

1625619349819-9130a484-bcaf-46f9-bfc3-2be3a89b8b9e.webp

(7)删除该集合中下,指定元素的值:zrem

bash
127.0.0.1:6379> zrem topn php
(integer) 1

(8)统计该集合,分数区间内的元素个数:zcount

bash
127.0.0.1:6379> zcount topn 200 300
(integer) 2

1625619349854-2c233b77-6b3d-4197-a5b6-c954ff7003e8.webp

(9)返回该值在集合中的排名,从0开始:zrank

bash
127.0.0.1:6379> zrank topn c++
(integer) 1

1625619349919-6c2c3451-2135-48ed-b98c-37759e317f65.webp

四、Redis6配置文件详解

1、units单位:

只支持bytes,支持bit,不区分大小写

1625619349946-f0734f95-60d2-4356-94b0-07d574ef712c.webp

2、INCLUDES:

包含其他的配置文件

1625619349888-a9789494-3293-4be0-af74-81e2a5df4386.webp

3、NETWORK:网络相关配置

(1)bind:限定是否只能本机连接等

1625619349900-39d934e5-de46-407f-899f-e236137c81b1.png

(2)protected-mode:是否开启本机保护模式,只可本机访问

1625619349928-4b3ef344-541c-4189-b60e-6563aa4e6200.webp

(3)port:默认端口号6379

1625619349857-0ca8897f-c499-45d6-83e9-21c05038bcb5.webp

(4)tcp-backlog:正在进行三次握手的队列总和默认值为511

1625619349884-2f640619-3091-4e90-8751-e0c0bbd3af98.webp

(5)timeout:超时时间默认0,永不超时

1625619349914-1bf4c74c-9d5c-4e11-b074-0c7351a0c0f9.webp

(6)tcp-keepalive:检测心跳时间默认300秒

1625620819892-0117b3cb-617d-4a6f-9d01-a53c8c38cbc5.webp

(7)daemonize:是否支持后台启动

1625619349924-cb51d8dd-c677-44b2-8be2-26d4794086b2.webp

(8)pidfile:保存对应的进程号文件

1625619349931-1aab8819-fd86-40ad-a758-13a19a205556.webp

(9)loglevel:保存日志的级别

1625619350032-f515e03f-c845-4deb-bf55-9b6478c2dc73.webp

(10)logfile:设置日志的路径

1625619350032-648867d8-46fe-47f9-990e-d69e90ceebb1.webp

(11)databases:默认使用16个库

1625619349993-7ee2be2e-8649-479b-a134-c47094cc73f9.webp

(12)Security密码设置:

foobared 取消注释,设置对应的密码信息

1625619349985-badf394d-ff30-44a0-979b-bf8973316322.webp

(13)LIMITS限制:

maxclients:最大连接数,默认10000

1625619349926-ff739641-2cec-47bd-8086-de8d0ce3ae8e.webp

(14)maxmemory:内存上限:

1625619349993-dc4c0456-c964-4905-9555-7b5d1ef46586.webp

五、Redis6的发布和订阅

1、发布与订阅:

(1)发送者:pub发送消息

(2)订阅者:sub接受消息

redis客户端可以订阅任意数量的频道

2、发布订阅流程

(1)客户端可以订阅频道

(2)当这个频道发布消息后,消息就会发送给订阅的客户端

3、发布订阅的命令行实现

(1)打开一个客户端订阅channel1

bash
127.0.0.1:6379> subscribe channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1

1625619350016-c9ea5c74-621f-4047-8ab5-605898a3fdf4.webp

(2)打开另一个客户端,给channel1发布消息hello

go
127.0.0.1:6379> publish channel1 hello
(integer) 1

1625619349954-5bfd721c-a206-41dc-9f1b-8819fa59e909.webp

(3)打开第一个客户端,可以看到发送的消息

bash
127.0.0.1:6379> subscribe channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message"
2) "channel1"
3) "hello"

1625619349963-12f7bde2-6b1a-48c2-9fb1-d56ca4753e4b.webp

六、Redis6新数据类型

1、Bitmaps

(1)简介:实现对字符串的位的操作的字符串。是一个以位位单元的数组,数组每个单元只能存储0与1,下标与偏移量,与set相比节省gongjinaq

(2)设置Bitmaps中某个偏移量的值(0或1):setbit

bash
127.0.0.1:6379> setbit users:20210101 1 1
(integer) 0
127.0.0.1:6379> setbit users:20210101 6 1
(integer) 0
127.0.0.1:6379> setbit users:20210101 11 1
(integer) 0
127.0.0.1:6379> setbit users:20210101 15 1
(integer) 0
127.0.0.1:6379> setbit users:20210101 19 1
(integer) 0

1625619349968-f75635fe-9752-4eca-bd82-39f8e06935b6.webp

(3)获取Bitmaps中某个偏移量的值:getbit

bash
127.0.0.1:6379> getbit users:20210101 1
(integer) 1

1625619350034-6d1667b1-44e7-4fe5-9c93-313c0dc4d075.webp

(4)统计字符串被设置位1的bit数量:bitcount[begin][end]

bash
127.0.0.1:6379> bitcount users:20210101
(integer) 5
127.0.0.1:6379> bitcount users:20210101 1 5
(integer) 3

1625619350042-399f2873-69db-4950-b3c8-7afbf0d621e3.webp

(5)复合操作(交集/并集/非/异或):bitop and/or/not/xor

设置初始数据:

bash
127.0.0.1:6379> setbit unique:users:20201104 1 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201104 2 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201104 5 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201104 9 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201103 0 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201103 1 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201103 4 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201103 9 1
(integer) 0

计算出两天都访问过网站的用户数量:(1与9号用户两天都访问了)

bash
127.0.0.1:6379> bitop and unique:users:and:20201104_03 unique:users:20201103 unique:users:20201104
(integer) 2127.0.0.1:6379> bitcount unique:users:and:20201104_03
(integer) 2

计算出任意一天都访问过网站的用户数量

bash
127.0.0.1:6379> bitop or unique:users:or:20201104_03 unique:users:20201103 unique:users:20201104
(integer) 2
127.0.0.1:6379> bitcount unique:users:or:20201104_03
(integer) 6

1625619350069-4a5bb18a-75c1-4999-9422-2ee45c3fd685.webp

2、HyperLogLog

(1)简介:

适用于独立IP数、搜索记录等需要去重和计数时。

(2)添加指定元素到HyperLogLog:pdadd[element],1成功0失败

bash
127.0.0.1:6379> pfadd program "java"
(integer) 1
127.0.0.1:6379> pfadd program "php"
(integer) 1
127.0.0.1:6379> pfadd program "java"
(integer) 0
127.0.0.1:6379> pfadd program "c++" "mysql"
(integer) 1

1625619350009-d8738cac-1ea8-45cc-b3fb-b61c85e5599f.webp

(3)统计HLL的pfcount

bash
127.0.0.1:6379> pfcount program
(integer) 4

(4)将一个或多个HLL合并的结果存储在另一个HLL:pfmeger

bash
127.0.0.1:6379> pfmerge k100 k1 program
OK

3、Geospatial

(1)简介:redis3.2后增加GEO类型,即地理信息的缩写,提供了经纬度的设置、查询、范围查询、举例查询、经纬度hash等

(2)加地理位置(经度、纬度、名称):geoadd[]...

有效经纬度:-180°-180°,纬度:-85.05112878°-85.05112878°

bash
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing
(integer) 3

1625619350094-83e80291-d6b9-4a33-b3cd-c51e5b4fa196.webp

(3)获取指定地区的坐标值:geoos[member]...

bash
127.0.0.1:6379> geopos china:city shanghai
1) 1) "121.47000163793563843"
   2) "31.22999903975783553"
127.0.0.1:6379> geopos china:city beijing
1) 1) "116.38000041246414185"
   2) "39.90000009167092543"

1625619350075-69f2c3bc-f12e-487e-99ad-f8faefdbc4f7.webp

(4)获取两个位置之间的直线距离:geodist<单位>

bash
127.0.0.1:6379> geodist china:city beijing shanghai km
"1068.1535"

1625619350177-2e8a6144-fd10-44d1-a632-902e82d25480.webp

(5)以给定的经纬度为中心,找出某一半径内的元素:georadiusradius m|km|ft|mi

bash
127.0.0.1:6379> georadius china:city 110 30 1000 km
1) "chongqing"
2) "shenzhen"

七、Jedis操作Redis6

1、idea建立maven工程

1625619350070-1c2e8479-2796-4133-86f2-13eb60f009c1.webp

2、引入相关依赖:

bash
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>

3、jedis连接redis测试(Maven)

bash
package com.testbk.jedis;
import redis.clients.jedis.Jedis;

public class jedisDemo1 {
    public static void main(String[] args) {
        //创建Jedis对象,需要修改redis.conf的bind(注释)与protected-mode(no)配置
        Jedis jedis =new Jedis("192.168.37.8",6379);
        //测试
        String value = jedis.ping();
        System.out.println(value);
    }
}

显示结果如下:

bash
PONG

4、Jedis-API:操作key

bash
//操作key
    @Test
    public void demo1(){
        //创建Jedis对象,需要修改redis.conf的bind(注释)与protected-mode(no)配置
        Jedis jedis =new Jedis("192.168.37.8",6379);
        //清空redis
        jedis.flushDB();
        //添加数据
        jedis.set("k1","v1");
        jedis.set("k2","v2");
        jedis.set("k3","v3");
        //查询所有key值
        Set<String> keys = jedis.keys("*");
        for(String key:keys){
            System.out.println(key);
        }
        //根据key获取value
        String value = jedis.get("k1");
        System.out.println("k1对应的value为:"+value);
    }

查看运行结果:

bash
k3
k1
k2
k1对应的value为:v1

5、Jedis-API:操作String

bash
//操作String
    @Test
    public void demo2(){
        //创建Jedis对象,需要修改redis.conf的bind(注释)与protected-mode(no)配置
        Jedis jedis =new Jedis("192.168.37.8",6379);
        //清空redis
        jedis.flushDB();
        //添加多个数据
        jedis.mset("str1","v1","str2","v2","str3","v3");
        //查询所有key值
        System.out.println(jedis.mget("str1","str2","str3"));
    }

查看运行结果:

bash
[v1, v2, v3]

6、Jedis-API:操作List

bash
//操作List
    @Test
    public void demo3(){
        //创建Jedis对象,需要修改redis.conf的bind(注释)与protected-mode(no)配置
        Jedis jedis =new Jedis("192.168.37.8",6379);
        //清空redis
        jedis.flushDB();
        //添加数据
        jedis.lpush("k1","lucy","mary","jack");
        //查询数据
        List<String> value = jedis.lrange("k1", 0, -1);
        System.out.println(value);
    }

查看运行结果:

bash
[jack, mary, lucy]

7、Jedis-API:操作set

bash
//操作set
    @Test
    public void demo4(){
        //创建Jedis对象,需要修改redis.conf的bind(注释)与protected-mode(no)配置
        Jedis jedis =new Jedis("192.168.37.8",6379);
        //清空redis
        jedis.flushDB();
        //添加数据
        jedis.sadd("name","luck","mary","jack");
        //查询数据
        Set<String> names = jedis.smembers("name");
        System.out.println(names);
    }

查看运行结果:

bash
[jack, mary, luck]

8、Jedis-API:操作set

bash
//操作set
    @Test
    public void demo4(){
        //创建Jedis对象,需要修改redis.conf的bind(注释)与protected-mode(no)配置
        Jedis jedis =new Jedis("192.168.37.8",6379);
        //清空redis
        jedis.flushDB();
        //添加数据
        jedis.sadd("orders","order1");
        jedis.sadd("orders","order2");
        jedis.sadd("orders","order3");
        jedis.sadd("orders","order4");
        //查询数据
        Set<String> orders1 = jedis.smembers("orders");
        System.out.println(orders1);
        //删除后再查询
        jedis.srem("orders","order1");
        Set<String> orders2 = jedis.smembers("orders");
        System.out.println(orders2);
    }

查看运行结果:

bash
[order3, order4, order1, order2]
[order3, order4, order2]

9、Jedis-API:操作Hash

bash
//操作Hash
    @Test
    public void demo5(){
        //创建Jedis对象,需要修改redis.conf的bind(注释)与protected-mode(no)配置
        Jedis jedis =new Jedis("192.168.37.8",6379);
        //清空redis
        jedis.flushDB();
        //添加数据
        jedis.hset("users","age","20");
        //查询数据
        String hget = jedis.hget("users", "age");
        System.out.println(hget);
    }

查看运行结果:

bash
20

10、Jedis-API:操作Zset

bash
//操作Zset
    @Test
    public void demo6(){
        //创建Jedis对象,需要修改redis.conf的bind(注释)与protected-mode(no)配置
        Jedis jedis =new Jedis("192.168.37.8",6379);
        //清空redis
        jedis.flushDB();
        //添加数据
        jedis.zadd("china",100d,"shanghai");
        //查询数据
        Set<String> china = jedis.zrange("china", 0, -1);
        System.out.println(china);
    }

查看运行结果:

bash
[shanghai]

八、Redis6与Spring Boot整合

1、idea创建springboot工程

1625625108645-e853c20b-e647-4f35-bfe9-14a3c2d68ba9.webp

2、pom文件引入springboot-redis的两个依赖

bash

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>

3、springboot配置文件中配置redis相关内容

文件位置为resources下面的application.properties

bash
# Redis服务器地址
spring.redis.host=192.168.37.8
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# Redis数据库索引(默认为0)
spring.redis.database=0
# 连接超时时间(毫秒)
spring.redis.timeout=1800000
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=20
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0

4、创建redis配置类:

bash
package com.testbk.redis_springboot.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setConnectionFactory(factory);
        //key序列化方式
        template.setKeySerializer(redisSerializer);
        //value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //value hashmap序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

5、编写RedisTestControll添加测试方法:

bash
package com.testbk.redis_springboot.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
    @Autowired
    private RedisTemplate redisTemplate;
    @GetMapping
    public String testRedis(){
        //设置值到redis
        redisTemplate.opsForValue().set("name","lucy");
        //从redis获取值
        String name = (String)redisTemplate.opsForValue().get("name");
        return  name;
    }
}

6、启动类启动Springboot类:RedisSpringbootApplication

显示运行结果:

bash
.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.1)

浏览器访问验证:http://localhost:8080/redisTest,显示结果:

bash
lucy

九、Redis6的事务操作

1、Redis事务定义

Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序的执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

Redis事务的主要作用就是串联多个命令防止别的命令插队

2、Multi、Exec、discard

(1)基本概念

输入Multi命令开始:输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。

组队的过程中可以通过discard来放弃组队

正常场景:

1625625157386-c7b24ce6-5d7c-4980-bade-b30e9057ae47.webp

异常场景2种:

1625625190305-b35fce19-93b1-4598-b4ca-eebc60701046.webp

1625625204411-9dbbdd49-4a2f-4140-ade0-a969d26d298e.webp

3、事务命令演示

(1)组队-执行案例

bash
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set key1 value1 
QUEUED
127.0.0.1:6379(TX)> set key2 value2
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK

1625625237115-cb9951b4-1fde-4563-8514-a4eff2336a5b.webp

(2)组队-取消案例

bash
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set a1 v1
QUEUED
127.0.0.1:6379(TX)> set a2 v2
QUEUED
127.0.0.1:6379(TX)> discard
OK

1625625337762-a6f57a4d-d5b2-4c81-8181-05be4b250a04.webp

(3)组队-错误处理

bash
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set b1 v1
QUEUED
127.0.0.1:6379(TX)> set b2 v2
QUEUED
127.0.0.1:6379(TX)> set b3 
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.

1625625326218-b9a584ff-d9ca-49da-a4c6-cb4414022a62.webp

(4)组队-执行-错误处理

bash
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set c1 v1
QUEUED
127.0.0.1:6379(TX)> incr c1
QUEUED
127.0.0.1:6379(TX)> set c2 v2
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK

1625625355655-b3399241-5b0d-4e5d-8232-2b5bec2d379c.webp

4、事务冲突的问题

场景:多个人同时使用一个账户,参加双十一抢购,购买不同的商品,未加事务会产生冲突。

(1)悲观锁

每次拿数据适都认为别人会修改,所以每次在拿数据适都会上锁,这样别人想拿数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁,读锁,写锁,都是操作前上锁。

1625625375415-5a6cbb67-3e8f-46bd-aa20-6baa5b186420.webp

(2)乐观锁

每次拿数据的适合都认为别人不会修改,所以不会上锁,但是在更新的适合会判断一下在此期间别人有没有取更新这个数据,可以使用版本号等机制,乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用check-and-set机制实现事务的。

1625625384859-af63df2d-9a4d-4d70-9756-cf7e85b2ce9d.webp

(3)WATCH key[key ...]

含义:在执行multi之前,先执行wath key1[key2] 可以监视一个或多个key,如果在事务执行之前这些key被其他命令所改动,那么事务讲被打断。

举例,同时打开两个客户端,都watch 同一个key,然后第一个窗口exec,第二个窗口再执行exec,被乐观锁住:

bash
127.0.0.1:6379> set balance 100
OK
127.0.0.1:6379> keys *
1) "balance"
127.0.0.1:6379> watch balance
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incrby balance 10
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 110
127.0.0.1:6379>
127.0.0.1:6379> keys *
1) "balance"
127.0.0.1:6379> watch balance
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incrby balance 20
QUEUED
127.0.0.1:6379(TX)> exec
(nil)
127.0.0.1:6379>

1625625399596-ea7139f3-4727-4e10-bc2f-c032845c8320.webp

(4)UNWATCH:

取消命令对所有key的监视。

5、Redis事务三特性:

(1)单独的隔离操作:

事务种的所有名历经都会序列化、按顺利执行,事务在执行的过程中,不会被其他客户端发送来的命令所打断

(2)没有隔离级别的概念:

队列中的命令没有提交之前不会实际被执行,因为事务提交前任何执行都不会被实际执行

(3)不保证原子性

事务中如果有一条命令执行失败,其中的命令任然会被执行,没有回滚

十、Reids6持久化

1、简介

两种持久化方式

(1)RDB(Redis DataBase):内存中数据直接写入文件中

(2)AOF(Append Of File):以追加的行为把内容写入文件中

2、RDB:

(1)概念:

指定的时间间隔内讲内存中的数据集快照写入磁盘,它恢复时可以将快照文件直接读到内存里

(2)RDB持久化流程:

Redis会单独创建fork一个子进程来进行持久化,先将数据写入一个临时文件中,待持久化过程结束后,再用这个临时文件替换上次持久化的文件,RDB方式比AOF文件更加高效,缺点是最后一次持久化的数据可能丢失。

1625625574313-ab41846a-552d-4509-84d1-74b8fb2c8e1c.png

(3)Fork:

写时复制技术:新进程的所有数据(变量、环境变量、程序计数器等)数值都有原进程一致。

(4)redis.conf配置内RDB相关配置(SNAPSHOTTING内配置)

rdb文件名:dbfilename dump.rdb

文件产生的路径,默认值(启动程序的位置):dir ./

bash
dbfilename dump.rdb
dir ./

1625625595304-85e3f4dd-119c-4d7f-b141-d53eba205250.png

快照的时间间隔:

bash
# save 3600 1
# save 300 100
# save 60 10000

1625625608129-481b996d-b89c-4069-8605-51c4ebdc162d.webp

设置手动持久化或自动持久化

save Vs bgsave:建议设置自动持久化

bash
# save ""

Redis无法写入磁盘的化,直接关掉Redis的写操作,默认yes

bash
stop-writes-on-bgsave-error yes

是否进行文件压缩:rdbcompre,默认yes

bash
rdbcompression yes

检查数据的完整性:rdbchecksum yes,默认yes

bash
rdbchecksum yes

(5)RDB恢复备份文件

将持久化的备份文件恢复,重新redis,数据恢复

bash
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> shutdown
not connected> exit
[root@localhost bin]# /usr/local/bin/redis-server /opt/redis.conf
[root@localhost bin]# /usr/local/bin/redis-cli
127.0.0.1:6379> keys *
1) "program"
2) "k100"
3) "k1"
4) "china:city"

另一个命令行恢复操作:

bash
[root@localhost bin]# ll
total 18884
-rw-r--r--. 1 root root      92 Jun 14 09:57 dump.rdb
-rw-r--r--. 1 root root     302 Jun 14 09:54 dump.rdb.bak
-rwxr-xr-x. 1 root root 4829592 May 20 06:16 redis-benchmark
lrwxrwxrwx. 1 root root      12 May 20 06:16 redis-check-aof -> redis-server
lrwxrwxrwx. 1 root root      12 May 20 06:16 redis-check-rdb -> redis-server
-rwxr-xr-x. 1 root root 5002840 May 20 06:16 redis-cli
lrwxrwxrwx. 1 root root      12 May 20 06:16 redis-sentinel -> redis-server
-rwxr-xr-x. 1 root root 9486688 May 20 06:16 redis-server
[root@localhost bin]#  
[root@localhost bin]# rm -rf dump.rdb
[root@localhost bin]# mv dump.rdb.bak dump.rdb

1625625667309-6ccca533-948d-4d0f-b457-67228cc09af1.webp

1625625675733-46d8cfa6-f327-448e-8007-7c4d173b63d6.webp

3、AOF:

(1)概念:

以日志形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数。

优点:备份机制更稳健,丢失数据概率更低,通过操作AOF文件可以处理误操作

缺点:比RDB占用更多磁盘,恢复备份速度慢,每次读写都同步的话有性能压力

(2)AOF持久化流程

客户端在请求写命令时会被append追加到AOF缓冲区内

AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中

AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量

Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的

1625625810385-28771021-4f95-4dd7-8a26-4afe0b451a17.webp

(3) redis.conf关于AOF相关配置:

开启AOF默认:,默认不开启no,开启需要修改为yes

bash
appendonly no

1625625823496-439a37c5-60c7-4f19-8c9e-d6e711853c1e.webp

AOF生成文件名:默认为appendonly.aof,生成的路径同RDB

bash
appendfilename "appendonly.aof"

1625625838834-61690152-4acf-4ad5-a30a-90395c6c1e17.webp

保存文件生成,同时开启AOF与RDB时,系统会使用AOF保存数据:

1625625849746-c611acfd-2ab6-4ab0-bf21-16170ad7ddd5.webp

(4)AOF使用与恢复

执行操作命令:appendonly.aof文件追加了内容:

bash
127.0.0.1:6379> set k11 v11
OK
127.0.0.1:6379> set k12 v12
OK
127.0.0.1:6379> set k13 v13
OK
-rw-r--r--. 1 root root       0 Jun 14 11:29 appendonly.aof
-rw-r--r--. 1 root root     302 Jun 14 09:54 dump.rdb
-rwxr-xr-x. 1 root root 4829592 May 20 06:16 redis-benchmark
lrwxrwxrwx. 1 root root      12 May 20 06:16 redis-check-aof -> redis-server
lrwxrwxrwx. 1 root root      12 May 20 06:16 redis-check-rdb -> redis-server
-rwxr-xr-x. 1 root root 5002840 May 20 06:16 redis-cli
lrwxrwxrwx. 1 root root      12 May 20 06:16 redis-sentinel -> redis-server
-rwxr-xr-x. 1 root root 9486688 May 20 06:16 redis-server
[root@localhost bin]# 
[root@localhost bin]# 
[root@localhost bin]# 
[root@localhost bin]# ll
total 18884
-rw-r--r--. 1 root root     116 Jun 14 11:33 appendonly.aof
-rw-r--r--. 1 root root     302 Jun 14 09:54 dump.rdb
-rwxr-xr-x. 1 root root 4829592 May 20 06:16 redis-benchmark
lrwxrwxrwx. 1 root root      12 May 20 06:16 redis-check-aof -> redis-server
lrwxrwxrwx. 1 root root      12 May 20 06:16 redis-check-rdb -> redis-server
-rwxr-xr-x. 1 root root 5002840 May 20 06:16 redis-cli
lrwxrwxrwx. 1 root root      12 May 20 06:16 redis-sentinel -> redis-server
-rwxr-xr-x. 1 root root 9486688 May 20 06:16 redis-server

1625625875547-8b63dcbc-4497-4e71-9b8c-53ec1f1130fd.png

AOF备份恢复

bash
127.0.0.1:6379> keys *
1) "k12"
2) "k11"
3) "k13"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> shutdown
not connected> exit
[root@localhost bin]# redis-server /opt/redis.conf 
[root@localhost bin]# redis-cli 
127.0.0.1:6379> keys *
1) "k11"
2) "k13"
3) "k12"
[root@localhost bin]# cp -r appendonly.aof appendonly.aof.bak
[root@localhost bin]# rm -rf appendonly.aof
[root@localhost bin]# mv appendonly.aof.bak appendonly.aof

1625625935633-01ff6e64-28cb-42d9-8872-ca53c75a4b10.webp

异常恢复:

当AOF文件损坏,可通过如下命令执行文件修复:

bash
redis-check-aof --fix appendonly.aof

1625625949617-ba842056-f5e6-41e2-9074-bfa406bd9fa9.webp

(5)AOF同步频率设置

设置始终同步:appendfsync always,性能较差,但是数据完整性好

每秒同步:appendfsync everysec

把同步时机交给操作系统:appendfsync no

bash
# appendfsync always
appendfsync everysec
# appendfsync no

1625625977864-9863ded6-5880-4178-9076-04f1a11bff52.webp

(6)Rewrite压缩

当AOF文件大小超过所设定的阈值时(>=64M*2),Redis会启动AOF的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof开启此功能。

使用fork子进程将原来文件重写,把rdb的快照已二进制形式附在新的aof头部,作为已有的历史数据据,替换原有的流水账操作。

bash
no-appendfsync-on-rewrite no

1625626074082-c33c9698-24f5-4e0b-b9a2-22646b07177b.webp

十一、Redis6的主从复制

1、概念:

主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主

2、优势:

(1)读写分离,性能扩展

(2)容灾快速恢复

3、主从复制的实现:

(1)创建/myredis文件夹

(2)复制redis.conf配置文件到文件夹中

(3)配置一主两从,创建三个配置文件

redis6379.conf

redis6380.conf

redis6381.conf

(4)在三个配置文件中写入内容

配置先关闭AOF或改名,配置redis6379、redis6380、redis6381配置文件

bash
include /myredis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb
include /myredis/redis.conf
pidfile /var/run/redis_6380.pid
port 6380
dbfilename dump6380.rdb
include /myredis/redis.conf
pidfile /var/run/redis_6381.pid
port 6381
dbfilename dump6381.rdb

(5)启动三台redis服务器并查看进程:

bash
[root@localhost myredis]# redis-server redis6379.conf 
[root@localhost myredis]# redis-server redis6380.conf 
[root@localhost myredis]# redis-server redis6381.conf 
[root@localhost myredis]# ps -ef | grep redis
root       3906      1  0 11:53 ?        00:00:08 redis-server *:6379
root       4024      1  0 13:07 ?        00:00:00 redis-server *:6380
root       4030      1  0 13:07 ?        00:00:00 redis-server *:6381
root       4036   3743  0 13:07 pts/3    00:00:00 grep --color=auto redis

1625626166187-83251663-a859-4970-b75c-159bc92875c2.png

(6)查看三个redis主机运行情况

bash
[root@localhost myredis]# redis-cli -p 6379
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:cc2e7d7d4336c03f7e4333a94a56f4bc9fdbf464
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

1625626172580-15b51ee3-454f-4e7d-afe1-646abb45931c.png

(7)配从(库)不配主(库):

slaveof :成为某个实例的从服务器:

在6380与6381上执行

bash
127.0.0.1:6380> slaveof 127.0.0.1 6379

127.0.0.1:6381> slaveof 127.0.0.1 6379

1625626195885-b1b1c93b-1f18-4315-bdc0-d2443f33a099.png

4、test主从测试:

场景:主服务6379做写操作,查看从服务器,且从服务器不能做写操作

1625626214745-5b3acfd8-d729-4937-ad34-e6a9181574d6.png

5、常用三招:

(1)一主两从:

从服务器挂掉后,重启会变成主服务,需要重新加入,数据会从主服务器重新复制一份

主服务器挂掉后,从服务器还是从服务器,主服务器重启后还是主服务器

(2)薪火相传:

从服务器可以配置为别的从服务器的从服务器

1625626250464-67a9defe-b3f1-4c08-b785-4f8601f4d279.png

(3)反客为主:

当一个master宕机后,可以让一台slave升为master,其后面的slave不用做任何修改

bash
slaveof no one

1625626267983-8d6d5478-a5eb-4da9-9208-b27b5251a79e.png

6、主从复制原理

(1)当从服务器连上主服务器之后,从服务器向主服务器发送进行数据同步消息

(2)主服务器接到从服务器发送过来同步消息,把主服务器数据进行持久化,生成RDB文件,把RDB文件发送给从服务器,从服务器拿到RDB进行读取

(3)每次主服务器进行写操作之后,和从服务器进行数同步

7、哨兵模式(sentinel)

(1)含义:

反客为主的自动版,能否后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库

(2)启动哨兵模式:

如一主二从的场景下,在myredis文件夹下建立sentinel.conf,配置哨兵模式,启动哨兵

bash
sentinel monitor mymaster 127.0.0.1 6379 1

mymaster为监控对象别名,1为至少多少个哨兵同意迁移的数量

bash
[root@localhost myredis]# redis-sentinel sentinel.conf

哨兵默认端口为26379

1625626292349-42744ccd-14f6-41eb-8bcb-77a08d11a0fe.png

(3)当主机挂掉,从服务器选举成为主服务器:

1625626308661-11f2f318-7846-45b0-abb4-1fca52b78744.png

1625626319604-a91914c3-5c23-4fef-b933-e3db9f95521d.png

(4)再次启动原来的主服务器,变为从服务器

1625626337166-df898f1b-6469-42ef-a74a-cf5daa7796b7.png

(5)配置哨兵的优先级:

redis.conf配置文件中:slave-priority 100,值越小优先级越高。

1625626345506-3d818b25-fcc0-4737-8ca9-504b582836ef.png

当优先级相同时选举偏移量最大的

当偏移量一样的时选举runid最小的(随机)

十二、Reids集群

1、集群概念:

Redis集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数量的1/N。

Redis集群通过分区(partition)来提供一定程序的可用性(avaliability):即使集群中有一部分节点失效或者无法通讯,集群也可以继续处理命令请求。

Redis集群的优势:实现扩容、分摊压力、无中心配置相对简单

Redis集群的不足:多键操作不被支持、多键事务不支持(lua脚本不支持)、技术出现较晚,已有redis服务迁移到集群复杂度较高

2、redis集群搭建:

(1)清除原备份文件,并将appendonly配置关闭

1625626388169-a362555c-bde3-4a10-9551-e1f56ab60573.png

(2)制作6个实例,6379,6380,6381,6389,6390,6391

bash
[root@localhost myredis]# vi redis6379.conf 

include /myredis/redis.conf
pidfile "/var/run/redis_6379.pid"
port 6379
dbfilename "dump6379.rdb"
#开启集群模式
cluster-enabled yes
#设置节点的名字
cluster-config-file nodes-6379.conf
#超时切换时间
cluster-node-timeout 15000

同样方式复制并修改(VI命令替换操作:%s/6379/6380):

bash
[root@localhost myredis]# cp redis6379.conf redis6380.conf
[root@localhost myredis]# ll
total 104
-rw-r--r--. 1 root root   244 Jun 27 17:42 redis6379.conf
-rw-r--r--. 1 root root   244 Jun 27 17:44 redis6380.conf
-rw-r--r--. 1 root root 93721 Jun 27 17:38 redis.conf
-rw-r--r--. 1 root root   392 Jun 27 15:45 sentinel.conf
[root@localhost myredis]# cp redis6379.conf redis6381.conf
[root@localhost myredis]# cp redis6379.conf redis6389.conf
[root@localhost myredis]# cp redis6379.conf redis6390.conf
[root@localhost myredis]# cp redis6379.conf redis6391.conf
[root@localhost myredis]# vi redis6380.conf 
[root@localhost myredis]# vi redis6381.conf 
[root@localhost myredis]# vi redis6381.conf 
[root@localhost myredis]# vi redis6389.conf 
[root@localhost myredis]# vi redis6390.conf 
[root@localhost myredis]# vi redis6391.conf

1625626405418-04d8928b-8e5d-4b46-992f-a1049db1f3b3.png

(3)启动6个redis服务

bash
[root@localhost myredis]# redis-server redis6379.conf
[root@localhost myredis]# redis-server redis6380.conf
[root@localhost myredis]# redis-server redis6381.conf
[root@localhost myredis]# redis-server redis6389.conf
[root@localhost myredis]# redis-server redis6390.conf
[root@localhost myredis]# redis-server redis6391.conf
[root@localhost myredis]# ps -ef |grep redis
root       1596      1  0 15:33 ?        00:00:11 redis-server *:6380
root       1603      1  0 15:33 ?        00:00:10 redis-server *:6381
root       1644      1  0 15:42 ?        00:00:18 redis-sentinel *:26379 [sentinel]
root       1661      1  0 15:52 ?        00:00:09 redis-server *:6379
root       1926      1  0 17:53 ?        00:00:00 redis-server *:6389 [cluster]
root       1932      1  0 17:53 ?        00:00:00 redis-server *:6390 [cluster]
root       1938      1  0 17:53 ?        00:00:00 redis-server *:6391 [cluster]

1625626421061-df92bc3d-9bb9-45ea-afd9-94cdc028a200.png

(4)将6个节点合成一个集群

bash
[root@localhost myredis]# cd /opt/redis-6.2.4/src/
[root@localhost src]# redis-cli --cluster create --cluster-replicas 1 192.168.37.8:6379 192.168.37.8:6380 192.168.37.8:6381 192.168.37.8:6389 192.168.37.8:6390 192.168.37.8:6391

1625626434336-5d6a8470-94ac-4ccc-b081-06224b811a56.png

[ERR] Node 192.168.37.8:6379 is not configured as a cluster node. 错误需要将 redis.conf 下的 cluster-enabled yes 的注释打开

1625626442747-84f9bd52-b09e-448c-bb15-7d405476fd92.png

配置6379、6380、6381为master,6389、6390、6391为slaver,yes确认

配置完成:

1625626501826-0fc0918b-7fe6-4d95-9ed9-b656a3524d18.png

(5)连接集群并查看:

bash
[root@localhost src]# redis-cli -c -p 6379
127.0.0.1:6379> cluster nodes

1625626513902-f4c1b3e6-bf19-44ea-84d3-b4414a4df8b2.png

3、redis集群分配原则:

分配原则:尽量保证每个主数据运行在不同的IP地址,每个主库和从库不在一个IP地址上

选项 --cluster-replicas 1表示我们希望为集群中的每个主节点创建一个从节点。

4、slots(插槽):

1625626623734-5eff28a3-36b3-41bd-9afc-1ba6e67ad78a.png

一个Redis集群包含16384个插槽(hash slot),数据库中每个键都属于这16384个插槽的其中之一。

集群使用公式CRC16(key)%16384来计算键key属于哪个槽,其中CRC176(key)语句用于计算键key和CRC16校验和。

集群中的每个节点负责处理一部分插槽。

1625626641151-fb465a95-11fb-4f60-93be-ff0b9019a8d8.webp

添加数据,即往插槽内添加数据

1625626658302-e4e8b421-1db2-4405-bc47-7bff4aaef0f8.webp

添加多个数据时会报错

1625626704714-7eb301cb-5bdb-4574-b2ad-c44839f55cdd.webp

如要插入多条数据,需要分组操作

1625626727542-3dbd47d3-88b1-44fc-b887-50aa8ccfe390.webp

计算key对应的插槽值

bash
cluster keyslot k1

计算对应插槽中的数值数量(只能看到属于自己集群的插槽)

bash
cluster countkeysinslot 12706

返回操作中n个数值

bash
cluster getkeysinslot 449 1

1625626742835-8c36f845-d391-4318-a9a6-a74a119b8d86.webp

5、故障恢复

(1)使6379集群shutdown,6380从机替换变为主机

1625626760333-f77f1015-7c68-4bcd-9505-f681b9da69d4.webp

(2)主-从均挂掉的情况

cluster-require-full-coverage 为yes,那么某一段插槽主从挂掉,整个集群都挂掉

cluster-require-full-coverage为no ,那么某一段插槽主从挂掉,该段集群的插槽不能提供服务,其他插槽依然可以提供服务

1625626789636-6e222758-837e-474f-8951-f33210ef3f7b.webp

6、集群的jedis开发

bash
package com.testbk.jedis;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

/**
 * 演示redis集群操作
 */
public class RedisClusterDemo {
    public static void main(String[] args) {
        //创建对象
        HostAndPort hostAndPort = new HostAndPort("192.168.37.8", 6379);
        JedisCluster jedisCluster = new JedisCluster(hostAndPort);
        //进行操作
        jedisCluster.set("b1","value1");
        String value = jedisCluster.get("b1");
        System.out.println(value);
        //关闭jedis连接
        jedisCluster.close();
    }

}

查看运行结果:

bash
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
value1

十三、Redis6应用问题解决

1、缓存穿透:

1625626823126-3cde4b2f-44cf-43ce-a3a1-8f51c46693b1.webp

(1)现象:

应用服务器压力变大

redis命中率降低

一直查询数据库

(2)造成原因:

redis查询不到数据库

出现很多非正常url访问

(3)解决方案:

对空值进行缓存:缓存空结果null值

设置访问白名单:使用bitmaps类型定义一个可以访问的名单,每次访问时进行拦截

布隆过滤器:(Bloom Filter)1970年布隆提出的,它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。布隆过滤器用于检索一个元素是否在一个集合,但是也存在误识别的情况

进行实时监控:当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,设置黑名单

2、缓存击穿:

1625626861099-f3d5e8a7-4989-43ca-98c4-47eb7833c46b.webp

(1)现象:

数据库的访问压力瞬时增加、redis里面没有出现大量key过期、redis正常运行

(2)造成原因:

redis某个key过期了,大量访问使用这个key

(3)解决方案:

预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis内,加大这些热门数据key的时长

实时调整:现场监控哪些数据热门,实时调整key的过期时长

使用锁的方式:设置排它锁:在根据key获得的value值为空时,先锁上,再从数据库加载,加载完毕,释放锁。若其他线程发现获取锁失败,则睡眠一段时间后重试

3、缓存雪崩:

1625626932745-96fd41f0-ea78-4282-9d03-3cd5efef8208.png

(1)现象:

数据库压力变大、服务器崩溃

(2)造成原因:

在极少的时间段,查询大量key的集中过期情况

(3)解决方案:

构建多级缓存架构:nginx缓存+redis缓存+其他缓存(ehcache等)

使用锁或队列:用加锁或者队列保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量并发请求落到底层存储系统上,不适用于高并发情况

设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台更新实际key的缓存

将缓存失效实际分散开:可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,很难引发集体失效的事件

4、分布式锁:

(1)解决问题:

随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式多线程,多进程并且分布在不同机器上,这将使原单机部署的情况下并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力,为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题。

(2)分布式锁主流的实现方案

基于数据库实现分布式锁

基于缓存Redis等

基于Zookeeper

(3)每一种分布式锁解决方案都有各自的优缺点:

性能:redis最高

可靠性:zookeeper最高

这里介绍的是基于redis实现的分布式锁

(4)实现方案:使用redis实现分布式锁

使用setnx实现分布式锁:

bash
127.0.0.1:6379> setnx users 10

1625626958982-02a612ab-f80b-42d0-8e3c-f7c0c3041577.webp

删除key释放setnx分布式锁:

bash
192.168.37.8:6381> del users

1625626971017-8d64d85d-6366-4e23-b1a2-d13794212a9a.webp

使用setnx设置分布式锁,再设置过期时间,过期后自动解锁

bash
192.168.37.8:6381> setnx users 10
(integer) 1
192.168.37.8:6381> expire users 10
(integer) 1
192.168.37.8:6381> ttl users

1625626982296-6092e9c3-edaf-493e-8402-017ef70793e4.webp

为防止上锁后redis机器故障,使用set nx ex上锁同时设置过期时间:(原子操作)

bash
set users 10 nx ex 12

1625626993098-a69be197-0275-42e3-8067-9d6099365519.webp

(5)java代码实现分布式锁

springboot编写的代码如下:

bash
package com.testbk.redis_springboot.controller;

import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("testLock")
    public void testLock(){
        //1获取锁,sentne,并设置锁的过期时间3s
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock","111",3, TimeUnit.SECONDS);
        //2获取锁成功、查询num的值
        if(lock){
            Object value = redisTemplate.opsForValue().get("num");
            //2.1判断numb为空return
            if(StringUtils.isEmpty(value)){
                return;
            }
            //2.2有值就转成int
            int num = Integer.parseInt(value+"");
            //2.3把redis的num加1
            redisTemplate.opsForValue().set("num",++num);
            //2.4释放锁,del
            redisTemplate.delete("lock");
        }
        else {
            //3获取锁失败,每隔0.1秒再获取
            try{
                Thread.sleep(100);
                testLock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @GetMapping
    public String testRedis(){
        //设置值到redis
        redisTemplate.opsForValue().set("name","lucy");
        //从redis获取值
        String name = (String)redisTemplate.opsForValue().get("name");
        return  name;
    }
}

运行,并在管理台测试,首先建立key->num赋值为0

bash
127.0.0.1:6379> set num "0"
OK
127.0.0.1:6379> get num
"0"

1625627011575-f6f3f34b-c3a4-4aab-9407-710962dc49ac.webp

另一个窗口通过ab压力测试工具进行测试,1000个请求,100个请求并发,并且触发分布式锁

bash
ab -n 1000 -c 100 http://192.168.31.12:8080/redisTest/testLock

1625627030906-5f6d70f2-9c5f-4bba-9537-d62a8a62e84d.webp

查看num,值累加到1000

bash
127.0.0.1:6379> get num
"1000"

(6)解决释放错锁的问题(防误删)

第一步:通过uuid表示不同的操作

bash
set lock uuid nx ex 10

第二部:释放锁时候,首先判断当前uuid和要适当锁uuid是否一样

改造测试代码如下:

bash
package com.testbk.redis_springboot.controller;

import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("testLock")
    public void testLock(){
        String uuid = UUID.randomUUID().toString();
        //1获取锁,sentne,并设置锁的过期时间3s
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock",uuid,3, TimeUnit.SECONDS);
        //2获取锁成功、查询num的值
        if(lock){
            Object value = redisTemplate.opsForValue().get("num");
            //2.1判断numb为空return
            if(StringUtils.isEmpty(value)){
                return;
            }
            //2.2有值就转成int
            int num = Integer.parseInt(value+"");
            //2.3把redis的num加1
            redisTemplate.opsForValue().set("num",++num);
            //2.4释放锁,del
            //判断比较uuid值是否一样
            Object lockUuid = redisTemplate.opsForValue().get("lock");
            if(lockUuid.equals(uuid)){
                redisTemplate.delete("lock");
            }
        }
        else {
            //3获取锁失败,每隔0.1秒再获取
            try{
                Thread.sleep(100);
                testLock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @GetMapping
    public String testRedis(){
        //设置值到redis
        redisTemplate.opsForValue().set("name","lucy");
        //从redis获取值
        String name = (String)redisTemplate.opsForValue().get("name");
        return  name;
    }
}

(7)解决删除操作非原子性问题:

场景:当比较uuid一样,当a删除操作的时候,正要删除还没有删除时,锁到了过期时间自动释放,此时b上了这把锁,会导致a把b的锁删除掉。

可以通过定义lua脚本优化代码

bash
package com.testbk.redis_springboot.controller;

import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("testLock")
    public void testLock(){
        //1声音一个uuid,讲作为一个value放入我们的key对应的值中
        String uuid = UUID.randomUUID().toString();
        //2定义一个锁:lua脚本可以使用同一把锁,来实现删除!
        String skuId = "25";
        String locKey= "lock" + skuId;
        //3取锁,sentne,并设置锁的过期时间3s
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(locKey,uuid,3, TimeUnit.SECONDS);

        //2获取锁成功、查询num的值
        if(lock){
            Object value = redisTemplate.opsForValue().get("num");
            //2.1判断numb为空return
            if(StringUtils.isEmpty(value)){
                return;
            }
            //2.2有值就转成int
            int num = Integer.parseInt(value+"");
            //2.3把redis的num加1
            redisTemplate.opsForValue().set("num",String.valueOf(++num));
            /*使用lua脚本来锁*/
            //定义lua脚本
            String script = "if redis.call('get',KEY[1]) == ARGV[1] then return redis.call('del',KEY[1]) else return 0 end";
            //使用redis执行lua脚本
            DefaultRedisScript<Long> redisScript= new DefaultRedisScript<>();
            redisScript.setScriptText(script);
            //设置一下返回类型为Long
            //因为删除的时候,返回为0,给其封装为数据类型,如果不封装那么默认返回String
            //那么返回字符串与0会发成错误
            redisScript.setResultType(Long.class);
            //第一个要是script脚本,第二个需要判断的key,第三个就是key对应的值
            redisTemplate.execute(redisScript, Arrays.asList(locKey),uuid);
        }
        else {
            //3获取锁失败,每隔0.1秒再获取
            try{
                Thread.sleep(1000);
                testLock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @GetMapping
    public String testRedis(){
        //设置值到redis
        redisTemplate.opsForValue().set("name","lucy");
        //从redis获取值
        String name = (String)redisTemplate.opsForValue().get("name");
        return  name;
    }
}

(8)总结-分布式锁可用性需要同事满足四个条件:

互斥性:在任意时刻,只有一个客户端能持有锁。

不发生死锁:即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。

解铃还须系铃人:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

加锁和解锁必须具有原子性。

十四、Redis6新功能

1、ACL(访问控制列表):

(1)简介

Access Control List:Redis6提供ACL功能对用户进行更细粒度的权限控制。

(2)命令

使用acl list展现用户权限列表

bash
127.0.0.1:6379> acl list

1625627243692-4dd15c2d-8555-48cb-b9a0-f9b1364e3c2a.png

使用acl cat查看添加权限的指令类别

1625627234562-cc826fff-b610-4b32-bdaf-f27adac23f4e.png

查看当前acl用户:

bash
127.0.0.1:6379> acl whoami

1625627220902-8975b46f-96a5-4c78-98bf-d8ccb6e956bc.png

添加acl用户:(可用,包含密码,可操作包含cached的key,只能get命令操作)

bash
127.0.0.1:6379> acl setuser mary on >password ~cached:* +get

1625627179565-a1e38295-ebb4-4add-95d4-61359bcff1df.png

切换用户,进行测试:

bash
127.0.0.1:6379> auth mary password

1625627168334-3001d0ed-e749-4388-8e67-b6c86c0aa0b9.png

2、IO多线程

(1)简介:

Redis6加入了多线程:值得是客户端交互部分的网络IO交互处理模板多线程,而非执行命令多线程,Redis6执行命令依然是单线程的。

(2)原理架构:

Redis的多线程部分只是用户处理网路数据的读写和协议解析,执行命令依然是单线程的,因为是需要控制key、lua、事务。

多线程默认是不开启的,需要配置文件中配置

bash
io-threads 4

1625627261542-503872e2-bb55-48e3-b34a-6198cf29260a.png

3、工具支持cluster

Redis5之前的版本搭建集合需要单独安装ruby环境,Redis5讲redis-trib.rb的功能集成到了redis-cli,另外官方redis-benchmark工具开始支持cluster模式,通过多线程的方式对多个分片进行压测。

1625627277096-07ac4fab-e3e3-486e-8cd3-0bb7fdd80164.png

最近更新