2021-02-12 大数据课程笔记 day23

时间煮雨
@R星校长

redis 概述

为什么使用 redis?

在这里插入图片描述在这里插入图片描述在这里插入图片描述

什么是 Redis?

Redis是用C语言开发的一个开源的高性能键值对(key-value)内存数据库。
它提供六种数据类型来存储值:string 字符串类型、hash 散列类型、list 列表类型、set 集合类型、zset(SortedSet) 有序集合类型、stream 流类型。
它是一种 NoSQL 数据库。

在这里插入图片描述

Redis 历史发展

2008 年,意大利的一家创业公司 Merzia 推出了一款基于 MySQL 的网站实时统计系统 LLOOGG,然而没过多久该公司的创始人 Salvatore Sanfilippo 便 对 MySQL 的性能感到失望,于是他决定亲自为 LLOOGG 量身定做一个数据库,并于2009年开发完成,这个数据库就是 Redis。

不过 Salvatore Sanfilippo 并不满足只将 Redis 用于 LLOOGG 这一款产品,而是希望更多的人使用它,于是在同一年 Salvatore Sanfilippo 将 Redis 开源发布,并开始和 Redis 的另一名主要的代码贡献者 Pieter Noordhuis 一起继续着 Redis 的开发,直到今天。

Salvatore Sanfilippo 自己也没有想到,短短的几年时间,Redis 就拥有了庞大的用户群体。Hacker News 在 2012 年发布了一份数据库的使用情况调查,结果显示有近 12% 的公司在使用 Redis。国内如新浪微博、街旁网、知乎网,国外如 GitHub、Stack Overflow、Flickr 等都是 Redis 的用户。

VMware 公司从 2010 年开始赞助 Redis 的开发, Salvatore Sanfilippo 和 Pieter Noordhuis 也分别在3月和5月加入 VMware,全职开发 Redis。

redis 特点:

  1. 开源的(BSD协议),使用 ANSI C 编写,基于内存的且支持持久化,高性能的 Key-Value 的 NoSQL 数据库
  2. 支持数据结构类型丰富,有字符串(strings),散列(hashes),列表(lists),集合(sets), 有序集合(sorted sets),stream,位图(bitmaps),hyperloglogs 和地理空间(geospatial)索引半径查询。
  3. 支持众多主流语言的客户端,C、C++、Python、Erlang、R、C#、Java、PHP、Objective-C、Perl、Ruby、Scala、Go、JavaScript、Lua

Redis 的应用场景

 内存数据库(登录信息、购物车信息、用户浏览记录等)
 缓存服务器(商品数据、广告数据等等)。(最多使用)
 解决分布式集群架构中的 session 分离问题(session 共享)。
 任务队列。(秒杀、抢购、12306 等等)
 支持发布订阅的消息模式
 应用排行榜。
 网站访问统计,活跃用户、在线人数。
 数据过期处理(可以精确到毫秒)

NoSQL 介绍

 NoSQL,即 Not-Only SQL(不仅仅是 SQL),泛指非关系型的数据库。
 什么是关系型数据库?数据结构是一种有行有列的数据库
 NoSQL 数据库是为了解决高并发、高可用、高可扩展、大数据存储问题而产生的数据库解决方案。
 NoSQL 可以作为关系型数据库的良好补充,但是不能替代关系型数据库。
在这里插入图片描述
http://db-engines.com/en/ranking在这里插入图片描述

Redis 单节点安装

准备环境

英文:http://www.redis.io
中文:http://redis.cn/
下载老版本:http://download.redis.io/releases/
Redis 版本:5.0.5
下载地址:http://download.redis.io/releases/redis-5.0.5.tar.gz
操作系统:CentOS 6.5
2.2 编译安装
 第一步:安装C语言需要的GCC环境和依赖tcl

yum install gcc  tcl  -y

 第二步:将redis安装包上传到 node2/opt/apps 解压缩Redis源码压缩包

tar -zxf redis-5.0.5.tar.gz 

 第三步:编译Redis源码,进入redis-5.0.5目录,执行编译命令

make
make test

 第四步:安装Redis,需要通过PREFIX指定安装路径

make install PREFIX=/opt/redis-5.0

 第五步:配置环境变量,并生效

export REDIS_HOME=/opt/redis-5.0
export PATH=$PATH:$REDIS_HOME/bin

 第六步:准备配置文件

[root@node2 ~]# find / -name redis.conf
/opt/apps/redis-5.0.5/redis.conf
[root@node2 ~]# cd /opt/redis-5.0/
[root@node2 redis-5.0]# pwd
/opt/redis-5.0
[root@node2 redis-5.0]# mkdir conf
[root@node2 redis-5.0]# cd conf
[root@node2 conf]# cp /opt/apps/redis-5.0.5/redis.conf ./
[root@node2 conf]# ls
redis.conf

 第七步:修改配置文件

[root@node2 conf]# vim redis.conf
daemonize yes  #redis后台运行
logfile "/opt/redis-5.0/log/redis_6379.log"
bind 127.0.0.1 192.168.20.72

 第八步:创建日志目录

[root@node2 redis-5.0]# mkdir log

启动与关闭

服务器端

启动:

[root@node2 redis-5.0]# redis-server conf/redis.conf   

检查是否启动好:

[root@node2 redis-5.0]# ps aux|grep redis
root       8235  0.1  0.7 152428  7772 ?        Ssl  14:56   0:00 redis-server 127.0.0.1:6379         

说明启动没有问题。

关闭:
[root@node2 conf]# redis-cli shutdown
[root@node2 conf]# ps aux|grep redis
root       8289  0.0  0.0 103260   876 pts/0    S+   15:16   0:00 grep redis
客户端命令
  1. redis-cli --help 查看帮助
  2. -p 指定端口号,-h 指定服务器名称或地址 --raw 选项让 redis-cli 显示中文
redis-cli -p 6379 -h 127.0.0.1 --raw
[root@node2 conf]# redis-cli  --raw
127.0.0.1:6379> set name 张飞
OK
127.0.0.1:6379> get name
张飞
127.0.0.1:6379> 
[root@node2 conf]# redis-cli 
127.0.0.1:6379> get name
"\xe5\xbc\xa0\xe9\xa3\x9e"
192.168.20.72:6379> 
  1. -n num 指定选择的数据库实例,默认为0表示第一个数据库实例
[root@node2 conf]# redis-cli -n 0
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> 
[root@node2 conf]# redis-cli -n 1
127.0.0.1:6379[1]> keys *
(empty list or set)

登录不同的库

[root@node2 ~]#redis-cli --help
[root@node2 ~]#redis-cli -n 2 #指定进入编号是2的数据库   redis中默认0-15  16个数据库
127.0.0.1:6379> select 2# 切换数据库的命令

清除当前库数据: FLUSHDB
清除所有库中的数据: FLUSHALL

  1. 退出:exit 或 quit
node2:6379>exit
  1. help帮助
    登陆redis获取帮助
    获取help的信息
127.0.0.1:6379> help

提示有哪些帮助

127.0.0.1:6379> help <tab>

查看 set 命令的帮助

127.0.0.1:6379> help set

查看 string 类型的命令帮助

127.0.0.1:6379> help @string

Redis 数据类型在这里插入图片描述

redis 的 key

Redis key 值是二进制安全的,这意味着可以用任何二进制序列作为 key 值,从形如 “foo” 的简单字符串到一个JPEG文件的内容都可以。空字符串也是有效 key 值。
Key 取值原则:

  1. 键值不需要太长,消耗内存,且在数据中查找这类键值的计算成本较高
  2. 键值不宜过短,可读性较差

string 字符串

一种最基本的 Redis 值类型(字节数组)。
Redis 字符串是二进制安全的,一个 Redis 字符串能包含任意类型的数据。例如: 一张 JPEG 格式的图片或者一个序列化的 Ruby 对象。一个字符串类型的值最多能存储 512M 字节的内容

key : string     value: string
赋值
  1. SET key value [EX seconds] [PX milliseconds] [NX|XX]
set key1 value1
  1. (了解)EX 设置过期时间,秒,等同于 SETEX key seconds value
set hello world ex 10
  1. (了解)PX 设置过期时间,毫秒,等同于 PSETEX key milliseconds value
set hello world px 5000
  1. NX 键不存在,才能设置,等同于 SETNX key value
set hello bjsxt nx
  1. XX 键存在时,才能设置
set hello sxt xx
  1. MSET key value [key value …] 设置多个键的字符串值
mset keya valuea keyb valueb keyc valuec keyd valud
  1. MSETNX key value [key value …] 键不存在时,设置字符串值
msetnx a valua b valueb c valuec

注意是原子操作,对多个 kv,要不成功都不成功

字符串类型的内部编码有 3 种:
(1) int:8个字节的长整型。
(2) embstr:小于等于39个字节的字符串。
(3) raw:大于39个字节的字符串。
Redis 会根据当前值的类型和长度决定使用哪种内部编码实现。
object encoding key 获取 value 底层存储的数据结构类型

node2:6379> object encoding hello
raw
node2:6379> set num 1
OK
node2:6379> object encoding num
int
取值
  1. 获取单个 key 的值
    语法:get key
node2:6379> get hello
sxt
node2:6379> get num
1
  1. 获取多个给定的键的值
    语法:mget key [key ...] “multiple get” mget
node2:6379> mget hello num
sxt
1

3.2.3 返回旧值并设置新值
语法:getset key value

node2:6379> getset num 2
1
node2:6379> get num
2
向尾部追加值

APPEND 命令,向键值的末尾追加 value。如果键不存在则将该键的值设置为 value,即相当于 SET key value。返回值是追加后字符串的总长度。

语法:APPEND key value

node2:6379> set name dongfang
OK
node2:6379> append name bubai
13
node2:6379> get name
dongfangbubai

3.2.5 字符串长度
语法:STRLEN key

node2:6379> strlen hello
3
node2:6379> strlen name
13
数值增减

字符串值会被解释成 64 位有符号的十进制整数来操作,结果依然转成字符串。 string 类型的,底层实现是 int,实际上操作的还是数字。
注意实现:
1、 当 value 为整数数据时,才能使用以下命令操作数值的增减。
2、 数值递增都是原子操作。
 递增数字
语法:INCR key

node2:6379> incr id
1
node2:6379> incr id
2
node2:6379> incr id
3

 增加指定的整数
语法:INCRBY key increment

node2:6379> incrby id 2
5
node2:6379> incrby id 2
7

 递减数值
语法:DECR key

node2:6379> set count 100
OK
node2:6379> decr count
99
node2:6379> decr count
98

 减少指定的整数
语法:DECRBY key decrement

node2:6379> decrby count 2
96
node2:6379> decrby count 2
94

 操作浮点数(扩展了解)
语法:INCRBYFLOAT key increment

node2:6379> incrbyfloat mynum -0.5
-0.5
node2:6379> incrbyfloat mynum -0.5
-1
node2:6379> incrbyfloat mynum -0.5
-1.5
node2:6379> set mynum 10
OK
node2:6379> incrbyfloat mynum -0.5
9.5
node2:6379> incrbyfloat mynum -0.5
9
node2:6379> incrbyfloat mynum -0.5
8.5
node2:6379> incrbyfloat mynum 0.5
9
node2:6379> incrbyfloat mynum 0.5
9.5
应用场景之自增主键

 需求:商品编号、订单号采用 INCR 命令生成。
 设计:key 命名要有一定的设计
 实现:定义商品编号 key:product:id

node2:6379> incr product:id
1
node2:6379> incr product:id
2
获取子字符串

语法:GETRANGE key start end
索引值从 0 开始,负数表示从字符串右边向左数起,-1 表示最右一个字符,负号减轻复杂度。

node2:6379> set phone 13412345678
OK
node2:6379> getrange phone 0 2
134
node2:6379> getrange phone 3 6
1234
node2:6379> getrange phone 7 -1
5678
覆盖字符串

语法:SETRANGE key offset value

node2:6379> set phone 13412345678
OK
node2:6379> setrange phone 2 x
11
node2:6379> get phone
13x12345678
node2:6379> setrange phone 3 ****
11
node2:6379> get phone
13x****5678
位图 bitmap【字节数组】 在这里插入图片描述

位图不是真正的数据类型,它是定义在字符串类型中,一个字符串类型的值最多能存储 512M 字节的内容
位上限:2^(9(512)+10(1024)+10(1024)+3(8b=1B))=2^32b
参考网址:https://www.geekmooc.cn/wiki/1346311662075936/1346331696168992

bitmap 基础知识
  1. 设置某一位上的值
    语法:SETBIT key offset value (offset位偏移量,从0开始)
node2:6379> flushall
OK
node2:6379> setbit k1 1 1
0
node2:6379> get k1
@
node2:6379> setbit k1 7 1
0
node2:6379> get k1
A
node2:6379> setbit k1 7 2
ERR bit is not an integer or out of range

node2:6379> setbit k1 9 1
0

node2:6379> get k1
A@

在这里插入图片描述
在这里插入图片描述
2. 获取某一位上的值
语法:GETBIT key offset
在这里插入图片描述

node2:6379> getbit k1 7
1
node2:6379> getbit k1 8
0
node2:6379> getbit k1 1
1
  1. 返回指定值 0 或者 1 在指定区间上第一次出现的位置偏移量
    语法:BITPOS key bit [start] [end](字节索引,0表示第一个字节)
  summary: Find first bit set or clear in a string
  since: 5.0.5.7
  group: string

不指定查找范围,表示从全部内容中查找:BITPOS key bit

node2:6379> keys *
k1
node2:6379> bitpos k1 1
1
node2:6379> setbit k1 1 0
1
node2:6379> bitpos k1 1
7
node2:6379> setbit k1 7 0
1
node2:6379> bitpos k1 1
9

在这里插入图片描述
指定查找范围:

BITPOS  key  bit  start :从 start+1 个字节开始查找,直到尾部
BITPOS  key  bit  start  end:从 start+1 字节开始到 end+1 字节之间查找

然后将数据还原:

node2:6379> setbit k1 1 1
0
node2:6379> setbit k1 7 1
0

查找演示:

node2:6379> bitpos k1 1 0 0
1 #在第一个字节中查找1首次出现的下标
node2:6379> bitpos k1 1 0
1 #从第一个字节到值得最后一个字节查找1首次出现的下标
node2:6379> setbit k1 1 0
1 #将指定下标的值改为0
node2:6379> bitpos k1 1 0 0
7 #
node2:6379> bitpos k1 1 0
7
node2:6379> setbit k1 7 0
1
node2:6379> bitpos k1 1 0 0
-1  #在第一个字节中没有找到1,则返回-1
node2:6379> bitpos k1 1 0
9  #从第一个字节到值得最后一个字节查找
node2:6379> bitpos k1 1 0 1
9 #在第1和第2个字节总找1首次出现的位置
node2:6379> bitpos k1 1 0 2
9 #在第1到第3个字节查找1首次出现的位置,但数据总共2(小于end对应的3)个字节,不会抛错。
位操作
0  1  0  0  0  0  0  1
1  1  1  0  0  0  0  1
------------------------------
0  1  0  0  0  0  0  1   AND   全1为1,否则为0
1  1  1  0  0  0  0  1   OR    有1为1,否则为0
1  0  1  0  0  0  0  0   XOR   不同为1,相同为0
                         NOT   按位取反,0变1,1变0

对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上

operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种

BITOP AND destkey key [key ...] ,对一个或多个 key 求逻与,并将结果保存到 destkey

BITOP OR destkey key [key ...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey

BITOP XOR destkey key [key ...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey

BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey,按位取反。

除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入,当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0,空的 key 也被看作是包含 0 的字符串序列

  1. 思考:a 异或 b 是什么?

统计指定位区间上值为 1 的个数

BITCOUNT key [start] [end]  start end  字节的索引  正负方向
set k ab   bitcount k 1 1 
set mykey ab
bitcount mykey 1 1

从左向右从 0 开始,从右向左从 -1 开始,注意官方 start、end 是位,测试后是字节
BITCOUNT testkey 0 0 表示从索引为 0 个字节到索引为 0 个字节,就是第一个字节的统计

bitcount mykey 0 -1

BITCOUNT testkey 0 -1 等同于BITCOUNT testkey
最常用的就是 BITCOUNT testkey

01100001‬  a‬‬‬‬
01100010‬  b‬‬‬‬
01100011‬  c‬‬‬‬

01100001 01100010 01100011  abc
Redis 的二进制位
set s1 ab
bitcount s1
bitcount s1 0 0
bitcount s1 1 1
set ch 中
bitcount ch
bitcount ch 2 2
1B(byte)   1b  bit

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
登录不同的库

redis-cli --help
redis-cli -n 2 指定进入编号是2的数据库   redis中默认0-15  16个数据库
127.0.0.1:6379> select 2 切换数据库的命令

清除当前库数据
FLUSHDB
清除所有库中的数据
FLUSHALL

Bitmap 应用场景

网站用户的上线天数统计(活跃用户)
用户 ID 为 key,天作为 offset,上线置为 1 366> 000000000000000

366 /8  50Byte  16  50    500 000 000B

ID为500的用户,今年的第1天上线、第30天上线

SETBIT u500 1 1        1 0 0 000 0 …….1 0 00 0   > 365  /8  46 Byte
SETBIT u500 30 1
BITCOUNT u500  0 -1
KYES u*
u500  1  2020-07-01 14:23:48  200*20  Byte

按天统计网站活跃用户
天作为key,用户ID为offset,上线置为1 50 000 000 /8 = 6 250 000
求一段时间内活跃用户数 500 / 8 366 * 63Byte

SETBIT 20200901 15  1    0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 
SETBIT 20200903 123 1    0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 
SETBIT 20200906 123 1    0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 
                         0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0

求9月1日到9月10日的活跃用户
BITOP OR result 20200901 20600903 20200906
BITCOUNT result 0 -1 目标 key 为 aaa
结果为 4

List

List 简介在这里插入图片描述在这里插入图片描述在这里插入图片描述
  • 基于 Linked List 实现,双向无环链表
  • 元素是字符串类型
  • 列表头尾增删快,中间增删慢,增删元素是常态
  • 元素可以重复出现
  • 最多包含2^32-1元素在这里插入图片描述

列表的索引

	-	从左至右,从 0  开始
	-	从右至左,从 -1 开始

list:

	-	队列:L/R  R/L:出入方向不同为队列
	-	栈: L/L   R/R  :出入方向相同为栈
	-	数组:LINDEX LSET
	-	阻塞:BL BR
增加元素
  • 向列表左边增加元素
    语法:LPUSH key value [value ...]
node2:6379> lpush list a
(integer) 1
node2:6379> lpush list b c d e
(integer) 5
  • 向列表右边增加元素
    语法:RPUSH key value [value ...]
node2:6379> rpush list a b c d
(integer) 4
查看列表

语法:LRANGE key start stop
LRANGE 命令是列表类型最常用的命令之一,获取列表中的某一片段,将返回start、stop 之间的所有元素(包含两端的元素),索引从 0 开始。索引可以是负数,如:“-1” 代表最后边的一个元素。

node2:6379> lrange list 0 -1
1) "e"
2) "d"
3) "c"
4) "b"
5) "a"    #栈: L进/L出
node2:6379> lrange list 1 1
1) "d"
node2:6379> lrange list 1 2
1) "d"
2) "c"
从列表两端弹出元素

LPOP 命令从列表左边弹出一个元素,会分两步完成:
 第一步是将列表左边的元素从列表中移除
 第二步是返回被移除的元素值。

语法:

	LPOP key
	RPOP key
node2:6379> lpop list
"e"
node2:6379> lpop list
"d"
node2:6379> lpop list
"c"
node2:6379> lpop list
"b"
node2:6379> lpop list
"a"
node2:6379> lpush list a b c d e
(integer) 5
node2:6379> rpop list
"a"
node2:6379> rpop list
"b"   #左进右出  或右进左出  队列
将元素从一个列表转移到另一个列表中

语法:RPOPLPUSH source destination

node2:6379> lrange list 0 -1
1) "e"
2) "d"
3) "c"
4) "b"
5) "a"
node2:6379> RPOPLPUSH list list2
"a"
node2:6379> lrange list2 0 -1
1) "a"
获取、设定指定位置的元素

语法:LINDEX key index 获取
语法:LSET key index value 设定

node2:6379> lindex list 0
"e"
node2:6379> lindex list 2
"c"
node2:6379> lset list 2 C
OK
node2:6379> lindex list 2
"C"
获取列表中元素的个数

语法:LLEN key

node2:6379> llen list
(integer) 3
删除指定个数的元素

从列表头部开始删除值等于 value 的元素 count 次 , LIST 可以重复出现
语法:LREM key count value
count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count
count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值
count = 0 : 移除表中所有与 value 相等的值在这里插入图片描述

举例

node2:6379> RPUSH listkey c abc c ab 123 ab bj ab redis list
(integer) 10
node2:6379> lrange listkey 0 -1
 1) "c"
 2) "abc"
 3) "c"
 4) "ab"
 5) "123"
 6) "ab"
 7) "bj"
 8) "ab"
 9) "redis"
10) "list"
node2:6379> LREM listkey 2 ab
(integer) 2
node2:6379> lrange listkey 0 -1
1) "c"
2) "abc"
3) "c"
4) "123"
5) "bj"
6) "ab"
7) "redis"
8) "list"
去除指定范围外的元素

语法:LTRIM key start stop
举例

LTRIM listkey 2 4 #除了第2个到最后一个之外的全部删除(删第一个1)
#微博的评论最后500条
LTRIM u1234:forumid:comments 0 499
向列表中插入元素

该命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个参数是BEFORE还是AFTER来决定将value插入到该元素的前面还是后面。

语法:LINSERT key BEFORE|AFTER pivot value

node2:6379> flushdb
OK
node2:6379> LPUSH list3 a b d e
(integer) 4
node2:6379> LINSERT list3 before d C
(integer) 5
node2:6379> lrange list 0 -1
1) "e"
2) "C"
3) "d"
4) "b"
5) "a"
阻塞
  1. 如果弹出的列表不存在或者为空,就会阻塞
  2. 超时时间设置为 0,就是永久阻塞,直到有数据可以弹出
  3. 如果多个客户端阻塞在同一个列表上,使用 First In First Service 原则,先到先服务
    左右或者头尾阻塞弹出元素
BLPOP key [key ...] timeout
BRPOP key [key ...] timeout

演示步骤:先分别在两个 xshell 终端中通过 BLPOP list 0 阻塞弹出一个不存在的 list(或无元素的),出现阻塞现象。然后在复制一个 xshell 终端,向该集合中添加一个元素,则先阻塞的那个终端就弹出元素了,阻塞解除;在添加一个元素,第二个阻塞的终端也弹出元素,阻塞也解除。
BLPOP list 5 #5秒 list 不存在元素一直阻塞,到时间后结束。期间获取到元素则提前弹出和结束。

hash 散列在这里插入图片描述

  • 由 field 和关联的 value 组成的 map 键值对
  • field 和 value 是字符串类型
  • 一个 hash 中最多包含 2^32-1 键值对
赋值

HSET 命令不区分插入和更新操作,当执行插入操作时 HSET 命令返回 1,当执行更新操作时返回 0。
 一次只能设置一个字段值
语法:HSET key field value

node2:6379> hset gtjin name jinxf
(integer) 1
node2:6379> hset gtjin age 34
(integer) 1

 一次可以设置多个字段值
语法:HMSET key field value [field value ...]

node2:6379> hmset gtjin gender M phone 13412345678
OK

 当字段不存在时赋值,类似HSET,区别在于如果字段存在,该命令不执行任何操作
语法:HSETNX key field value

node2:6379> hsetnx gtjin name jinxingfu  # 0表示不做任何
(integer) 0 #如果gtjin中已经存在name字段则不做任何操作
node2:6379> hsetnx gtjin address kaifeng
(integer) 1  #如果gtjin中不存在address字段则添加成功。
取值

 一次只能获取一个字段值
语法:HGET key field

node2:6379> hget gtjin name
"jinxf"

 一次可以获取多个字段值
语法:HMGET key field [field ...]

node2:6379> hmget gtjin name age
1) "jinxf"
2) "34"

 获取所有字段值
语法:HGETALL key

  1. “name”
  2. “jinxf”
  3. “age”
  4. “34”
  5. “gender”
  6. “M”
  7. “phone”
  8. “13412345678”
  9. “address”
  10. “kaifeng”
Hash 的用途和过期对象删除策略

用途:节约内存空间和 CPU 资源开销。
每创建一个键,它都会为这个键储存一些附加的管理信息(比如这个键的类型,这个键最后一次被访问的时间等等)。所以数据库里面的键越多,redis 数据库服务器在储存附加管理信息方面耗费的内存就越多,花在管理数据库键上的 CPU 也会越多在字段对应的值上进行浮点数的增量计算

node2:6379> set gtjin:name jinxf
OK
node2:6379> set gtjin:age 34
OK
node2:6379> keys *
1) "gtjin:name"
2) "gtjin:age"
3) "list"
4) "gtjin"

在这里插入图片描述
主动删除:每个一定时间将 redis 对应内存中的数据,全遍历一遍,过期的删除。(问题:需要消耗的资源比较大,担心影响系统的性能)
被动删除:当一个对象被读取时,判断是否已经过去,如果过期就删除。(问题:如果一个已经过期的对象,长期都没有访问,就会留在内存中)
Redis 是如何删除过期对象的?
答:主动删除和被动删除联合实现。在这里插入图片描述

只获取字段名或字段值

语法: HKEYS key
    HVALS key

node2:6379> hkeys gtjin
1) "name"
2) "age"
3) "gender"
4) "phone"
5) "address"
node2:6379> hvals gtjin
1) "jinxf"
2) "34"
3) "M"
4) "13412345678"
5) "kaifeng"
获取字段数量

语法:HLEN key

node2:6379> hlen gtjin
(integer) 5
增加数字

增加整数语法:HINCRBY key field increment

增加小数语法:HINCRBYFLOAT key field increment

node2:6379> hincrby gtjin age 1
(integer) 35
node2:6379> hget gtjin age
"35"
node2:6379> hincrbyfloat gtjin age 0.5
"35.5"
删除字段

可以删除一个或多个字段,返回值是被删除的字段个数
语法:HDEL key field [field ...]

node2:6379> hdel gtjin address
(integer) 1
node2:6379> hdel gtjin phone address
(integer) 1
node2:6379> hdel gtjin name gender
(integer) 2
node2:6379> hdel gtjin name gender
(integer) 0
判断字段是否存在

语法:HEXISTS key field

node2:6379> hexists gtjin name
(integer) 0
node2:6379> hset gtjin name jinxf
(integer) 1
node2:6379> hexists gtjin name
(integer) 1
微博的好友关注

用户 ID 为 key,Field 为好友 ID,Value 为关注时间

node2:6379> hset user:1000 user:606 20200425
(integer) 1
node2:6379> hset user:1000 user:601 20200424
(integer) 1
node2:6379> hset user:1000 user:602 20200423
(integer) 1
node2:6379> hlen user:1000   #得到粉丝数
(integer) 3
node2:6379> hkeys user:1000  #得到粉丝id列表
1) "user:606"
2) "user:601"
3) "user:602"

用户维度统计
统计数包括:关注数、粉丝数、喜欢商品数、发帖数
用户为 Key,不同维度为 Field,Value 为统计数
比如关注了 5 人

HSET user:10000 follow 5
HINCRBY user:10000 follow 1

不适合 hash 的情况
 使用二进制位操作命令:因为 Redis 目前支持对字符串键进行 SETBIT、GETBIT、BITOP 等操作,如果你想使用这些操作,那么只能使用字符串键,虽然散列也能保存二进制数据
 使用过期键功能:Redis 的键过期功能目前只能对键进行过期操作,而不能对散列的字段进行过期操作,因此如果你要对键值对数据使用过期功能的话,那么只能把键值对储存在字符串里面

set 集合

set 介绍在这里插入图片描述

无序的、去重的
元素是字符串类型
最多包含2^32-1元素

增加一个或多个元素

语法:SADD key member [member ...]
如果元素已经存在,则自动忽略
举例

 node2:6379> sadd friends peter
(integer) 1
node2:6379> sadd friends jack tom john
(integer) 3
node2:6379> sadd friends may tom
(integer) 1

在这里插入图片描述

移除一个或者多个元素

语法: SREM key member [member ...]
元素不存在,自动忽略

node2:6379> srem friends peter
(integer) 1
node2:6379> srem friends tom john
(integer) 2
返回集合包含的所有元素

语法:SMEMBERS key
如果集合元素过多,例如百万个,需要遍历,可能会造成服务器阻塞,生产环境应避免使用。

node2:6379> smembers friends 
1) "may"
2) "jack"
检查给定元素是否存在于集合中

语法: SISMEMBER key member

node2:6379> sismember friends may
(integer) 1 #表示存在
node2:6379> sismember friends tom
(integer) 0 #表示不存在
集合的无序性
SADD friendsnew "peter" "jack" "tom" "john" "may" "ben"
SADD anotherfriends "peter" "jack" "tom" "john" "may" "ben"
SMEMBERS friendsnew
SMEMBERS anotherfriends

注意, SMEMBERS 有可能(数据量大时会出现)返回不同的结果,所以,如果需要存储有序且不重复的数据使用有序集合,存储有序可重复的使用列表。

随机返回集合中指定个数的,适合抽奖

语法:SRANDMEMBER key [count]

  1. 如果 count 为正数,且小于集合中元素的个数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合中元素的个数,那么返回整个集合 最多返回整个集合 conut>=0
  2. 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值 count < 0 长度为 count 绝对值,元素可能重复
  3. 如果 count 为 0,返回空
  4. 如果 count 不指定,随机返回一个元素
node2:6379> SADD friends "peter" "jack" "tom" "john" "may" "ben"
(integer) 6
node2:6379> SRANDMEMBER friends 3
1) "john"
2) "peter"
3) "ben"
node2:6379> SRANDMEMBER friends -5
1) "peter"
2) "jack"
3) "peter"
4) "john"
5) "john"
node2:6379> SRANDMEMBER friends 0
(empty list or set)
返回集合中元素的个数

语法:SCARD key
键的结果会保存信息,集合长度就记录在里面,所以不需要遍历

node2:6379> scard friends
(integer) 2
随机从集合中移除并返回这个被移除的元素

语法:SPOP key

node2:6379> scard friends
(integer) 2
node2:6379> spop friends
"jack"
node2:6379> scard friends
(integer) 1
把元素从源集合移动到目标集合

语法:SMOVE source destination member

node2:6379> SMEMBERS friends
1) "may"
node2:6379> smove friends fds may
(integer) 1
node2:6379> SMEMBERS fds
1) "may"
node2:6379> SMEMBERS friends
(empty list or set)
差集在这里插入图片描述

差集,具有方向性
SDIFF key [key ...],从第一个key的集合中去除其他集合和自己的交集部分

node2:6379> SADD number1 123 456 789
(integer) 3
node2:6379> SADD number2 123 456 999
(integer) 3
node2:6379>  SDIFF number1 number2
1) "789"
node2:6379>  SDIFF number2 number1
1) "999"

SDIFFSTORE destination key [key ...],将差集结果存储在目标 key 中

node2:6379> SDIFFSTORE number3 number1 number2
(integer) 1
node2:6379> SMEMBERS number3
1) "789"
交集在这里插入图片描述

语法: SINTER key [key ...],取所有集合交集部分

node2:6379> SINTER number1 number2
1) "123"
2) "456"

语法:SINTERSTORE destination key [key ...],将交集结果存储在目标 key 中

node2:6379> SINTERSTORE number4 number1 number2
(integer) 2
node2:6379> SMEMBERS number4
1) "123"
2) "456"
并集

语法:SUNION key [key ...],取所有集合并集
语法:sunionstore destination key [key ...],将并集结果存储在目标key中

node2:6379> SUNION number1 number2
1) "123"
2) "456"
3) "789"
4) "999"
node2:6379> sunionstore number5 number1 number2
(integer) 4
node2:6379> SMEMBERS number5
1) "123"
2) "456"
3) "789"
4) "999"

3.5.14 新浪微博的共同关注

需求:当用户访问另一个用户的时候,会显示出两个用户共同关注哪些相同的用户
设计:将每个用户关注的用户放在集合中,求交集即可

实现如下:liubei={'john','jack','may'}
          zhugeliang={'john','jack','tom'}
那么peter和ben的共同关注为:
          SINTER liubei zhugeliang 结果为 {'john','jack'}
          sinterstore lzfds liubei zhugeliang

SortedSet 集合

介绍
  1. 类似 Set 集合
  2. 有序的、去重的
  3. 元素是字符串类型
  4. 每一个元素都关联着一个浮点数分值(Score),并按照分值从小到大的顺序排列集合中的元素。分值可以相同,此时按照元素的字典序排序。
  5. 最多包含2^32-1元素

一个保存了水果价格的有序集合在这里插入图片描述
一个保存了员工薪水的有序集合在这里插入图片描述
一个有序集合,保存了正在阅读某些技术书的人数在这里插入图片描述

增加一个或多个元素

语法:ZADD key score member [score member ...]
如果元素已经存在,则使用新的 score 值
举例

[root@node2 ~]# redis-cli  --raw
node2:6379> ZADD fruits 3.2 香蕉
(integer) 1
node2:6379> ZADD fruits 2.0 西瓜
(integer) 1
node2:6379> ZADD fruits 4.0 番石榴 7.0 梨 6.8 芒果
(integer) 3

在这里插入图片描述

返回指定索引区间元素

语法:ZRANGE key start stop [WITHSCORES] start 和 stop 是按照排名来分割的。
如果 score 相同,则按照字典序 lexicographical order 排列,默认按照 score 从小到大,如果需要 score 从大到小排列,使用 ZREVRANGE在这里插入图片描述

node2:6379> zrange fruits 0 2
西瓜
香蕉
番石榴
node2:6379> zrange fruits 0 -1
西瓜
香蕉
番石榴
芒果
梨
node2:6379> zrange fruits 0 -1 withscores
西瓜
2
香蕉
3.2000000000000002
番石榴
4
芒果
6.7999999999999998
梨
7
node2:6379> zrange fruits -2 -1 withscores
芒果
6.7999999999999998
梨
7

语法:ZREVRANGE key start stop [WITHSCORES]

node2:6379> zrevrange fruits 0 2 withscores
梨
7
芒果
6.7999999999999998
番石榴
4
node2:6379> zrevrange fruits -2 -1 withscores
香蕉
3.2000000000000002
西瓜
2

在这里插入图片描述

移除一个或者多个元素

语法:ZREM key member [member ...] 元素不存在,自动忽略
举例

ZREM fruits 番石榴 梨 芒果
ZREM fruits 西瓜

在这里插入图片描述

显示分值

语法:ZSCORE key member
举例

ZSCORE fruits 芒果
ZSCORE fruits 西瓜

注意:计算机并不能精确表达每一个浮点数,都是一种近似表达

增加或者减少分值 浮点值

语法:ZINCRBY key increment member,increment为正数就是增加,为负数就是减少

ZINCRBY fruits 1.5 西瓜
ZINCRBY fruits -0.8 香蕉

在这里插入图片描述

返回元素的排名(索引)
  1. 语法:ZRANK key member 升序的排名
ZRANK fruits 西瓜   #0
ZRANK fruits 芒果   #3
  1. 语法:ZREVRANK key member 降序的排名
ZREVRANK fruits 西瓜
ZREVRANK fruits 芒果

在这里插入图片描述

返回指定分值区间元素
  1. 语法:ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count](升序)
    返回 score 默认属于 [min,max] 之间,元素按照 score 升序排列,score 相同字典序
    LIMIT 中 offset 代表跳过多少个元素,count 是返回几个。类似于 Mysql 使用小括号,修改区间为开区间,例如(5、(10、5
    -inf和+inf表示负无穷和正无穷
ZRANGEBYSCORE fruits 3.0 6.8
ZRANGEBYSCORE fruits (3.5 6.8
ZRANGEBYSCORE fruits (3.5 6.8)  #错误
ZRANGEBYSCORE fruits (3.5 (6.8
ZRANGEBYSCORE fruits -inf +inf
ZRANGEBYSCORE fruits -inf +inf limit 1 2

在这里插入图片描述

  1. 语法:ZREVRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count](降序)
    返回 score 默认属于 [min,max] 之间,元素按照 score 降序排列,score 相同字典降序
    LIMIT 中 offset 代表跳过多少个元素,count 是返回几个。类似于 Mysql
    使用小括号,修改区间为开区间,例如(5、(10
    -inf 和 +inf 表示负无穷和正无穷
    举例
ZREVRANGEBYSCORE fruits 6.8 3.0
ZREVRANGEBYSCORE fruits 6.8 (3.5
ZREVRANGEBYSCORE fruits +inf -inf
 
移除指定排名范围的元素

语法:ZREMRANGEBYRANK key start stop
举例

ZREMRANGEBYRANK fruits 0 2
ZRANGE fruits 0 -1

在这里插入图片描述
在这里插入图片描述

移除指定分值范围的元素

语法:ZREMRANGEBYSCORE key min max

举例

ZREMRANGEBYSCORE fruits 3.0 5.0 
ZRANGE fruits 0 -1
zremrangebyscore fruits -inf +inf
zremrangebyscore fruits (1 2

在这里插入图片描述

返回集合中元素个数

语法:zcard key

127.0.0.1:6379> zcard fruits
5
返回集合中指定分值区间的元素个数

语法:zcount key min max 分值 score

127.0.0.1:6379> zcount fruits  4 7
3  #返回分值在区间[4,7]
127.0.0.1:6379> zcount fruits  (4 7
2 #返回分值在区间(4,7]
127.0.0.1:6379> zcount  fruits -inf  7
5 #返回小于等于7的全部元素

在这里插入图片描述

并集
zunionstore destination numkeys key [key ...] [weights weight] [aggregate SUM|MIN|MAX]

numkeys 指定 key 的数量,必须写
weights 选项,与前面设定的 key 对应,对应 key 中每一个 score 都要乘以这个权重

aggregate 选项,指定并集结果的聚合方式

  • SUM:将所有集合中某一个元素的score值之和作为结果集中该成员的score值
  • MIN:将所有集合中某一个元素的score值中最小值作为结果集中该成员的score值
  • MAX:将所有集合中某一个元素的score值中最大值作为结果集中该成员的score值
    在这里插入图片描述
127.0.0.1:6379> zunionstore scores-all 2 scores1 scores2
    4
127.0.0.1:6379> zrange scores-all 0 -1 withscores
    ben
    60
    john
    60
    tom
    70
    peter
    170
127.0.0.1:6379> zunionstore sall_sum 2 scores1 scores2 aggregate sum
    4
127.0.0.1:6379> zrange sall_sum 0 -1 withscores
    ben
    60
    john
    60
    tom
    70
    peter
    170
127.0.0.1:6379> zunionstore sall_max 2 scores1 scores2 aggregate max
    4
127.0.0.1:6379> zrange sall_max 0 -1 withscores
    ben
    60
    john
    60
    tom
    70
    peter
    90
127.0.0.1:6379> zunionstore sall_min 2 scores1 scores2 aggregate min
    4
127.0.0.1:6379> zrange sall_min 0 -1 withscores
    ben
    60
    john
    60
    tom
    70
    peter
    80
127.0.0.1:6379> zunionstore weight_sum 2 scores1 scores2 weights 1 0.5 aggregate sum
    4
127.0.0.1:6379> zrange weight_sum 0 -1 withscores
    ben
    30
    john
    60
    tom
    70
    peter
    125
交集
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]

numkeys 指定 key 的数量,必须
WEIGHTS 选项,与前面设定的 key 对应,对应 key 中每一个 score 都要乘以这个权重
AGGREGATE 选项,指定并集结果的聚合方式
SUM:将所有集合中某一个元素的 score 值之和作为结果集中该成员的 score值
MIN:将所有集合中某一个元素的 score 值中最小值作为结果集中该成员的 score值
MAX:将所有集合中某一个元素的 score 值中最大值作为结果集中该成员的 score值

127.0.0.1:6379> zinterstore inter_score1 2 scores1 scores2
1
127.0.0.1:6379> zrange inter_score1 0 -1 withscores
peter
170
127.0.0.1:6379> zinterstore inter_score2 2 scores1 scores2 aggregate max
1
127.0.0.1:6379> zrange inter_score1 0 -1 withscores
peter
170
127.0.0.1:6379> zrange inter_score2 0 -1 withscores
peter
90
127.0.0.1:6379> zinterstore inter_score3 2 scores1 scores2 weights 1 0.5 aggregate sum
1
127.0.0.1:6379> zrange inter_score3 0 -1 withscores
peter
125
网易音乐排行榜

怎么做?
在这里插入图片描述

分析
每首歌的歌名作为元素(先不考虑重复)
每首歌的播放次数作为分值
ZREVRANGE 来获取播放次数最多的歌曲(就是最多播放榜了,云音乐热歌榜,没有竞价,没有权重)

zrevrange 来获取播放次数最多的歌曲(就是最多播放榜了,云音乐热歌榜,没有竞价,没有权重)

zrevrange new 0 9  #创建时间最新的前10首
zrevrange hot 0 9  #热度值最高前10首
zrevrange create 0 9 #原创分值最高的前10首
新浪微博翻页

新闻网站、博客、论坛、搜索引擎,页面列表条目多,都需要分页
blog这个key中使用时间戳作为score

127.0.0.1:6379> ZADD blog 1407000000 '今天天气不错'
1
127.0.0.1:6379> ZADD blog 1450000000 '今天我们学习Redis'
1
127.0.0.1:6379> ZADD blog 1560000000 '几个Redis使用示例'
1
127.0.0.1:6379> ZREVRANGE blog 0 1 #0=(cpn-1)*ps   cpn*ps-1
几个Redis使用示例
今天我们学习Redis
127.0.0.1:6379> ZREVRANGE blog 2 3 #2=(cpn-1)*ps   cpn*ps-1
今天天气不错
京东图书畅销榜

单日榜,计算出周榜单、月榜单、年榜单
怎么做?

京东图书周畅销榜
如果 bookboard-xxx 表示是每天售卖的增量数据:

ZADD bookboard-901 1000 'java' 1500 'Redis' 2000 'hadoop'
ZADD bookboard-902 1020 'java' 1500 'Redis' 2100 'hadoop' 
ZADD bookboard-903 1620 'java' 1510 'Redis' 3000 'hadoop'
ZUNIONSTORE bookboard-001:003 3 bookboard-001 bookboard-002 bookboard-003 AGGREGATE SUM
ZREVRANGE bookboard-001:003 0 9 withscores  #获取前十名

京东图书周畅销榜
如果 bookboard-xxx 表示是截止到目前售卖的全部数量:

ZADD bookboard-001 1000 'java' 1500 'Redis' 2000 'hadoop'
ZADD bookboard-002 1020 'java' 1500 'Redis' 2100 'python'  
ZADD bookboard-003 1620 'java' 1510 'Redis' 3000 'hadoop'
ZUNIONSTORE bookboard-001:003 3 bookboard-001 bookboard-002 bookboard-003 AGGREGATE MAX
ZREVRANGE bookboard-001:003 0 9 withscores  #获取前十名

并集,要么使用 max ,要么使用 SUM ,一般是用 max。
注意:参与并集运算的集合较多,会造成 Redis 服务器阻塞,因此最好放在空闲时间或者备用服务器上进行计算
zrevrange 倒序排列即可

ZREVRANGE blog start stop [withscores]

Stream 数据类型

什么是 stream 数据类型?

Stream 是 Redis 5.0 版本引入的一个新的数据类型,它以更抽象的方式模拟日志数据结构,但日志仍然是完整的:就像一个日志文件,通常实现为以只附加模式打开的文件,Redis流主要是一个仅附加数据结构。至少从概念上来讲,因为Redis流是一种在内存表示的抽象数据类型,他们实现了更加强大的操作,以此来克服日志文件本身的限制。
Stream 小河、小溪。水流 时间流。

127.0.0.1:6379> xadd wz * double kill
"1595944508325-0"
127.0.0.1:6379> xadd wz * triple kill
"1595944529670-0"

本质上是一个抽象日志。

为什么要学习stream?
  1. 其它五种数据结构不能实现的需求,可直接使用stream实现。
  2. 直接贴近业务需求,提升开发效率。
  3. 5G时代、物联网,各种传感器产生时间序列数据,定位未来。
Stream原理在这里插入图片描述在这里插入图片描述
xadd 增加对象或向已存在对象追加元素

 Key不存在则增加对象,并添加指定的field string元素
 Key存在则向该key指定的对象中追加field string元素
语法:XADD key ID field string [field string ...]
summary: Appends a new entry to a stream
since: 5.0.0
 ID包含两部分:时间戳(毫秒)-sequence(同一毫秒的数列号)组成
使用默认的ID添加:

127.0.0.1:6379> xadd wz * quadra kill
"1595948390242-0"

使用指定的ID添加:

127.0.0.1:6379> xadd wzheros 0-1 kai xiaoqiao
"0-1"
xlen

 作用:返回 stream 对象中元素的个数
语法:XLEN key

127.0.0.1:6379> xlen wz
(integer) 3
127.0.0.1:6379> xlen wzheros
(integer) 1
xdel

 作用:删除一个ID
语法:XDEL key ID [ID ...]

127.0.0.1:6379> xdel wz 1595948390242-0
(integer) 1
127.0.0.1:6379> XLEN wz
(integer) 2
xrange

 作用:返回 key 对应 stream 对象中给定 ID 范围的数据。
语法:XRANGE key start end [COUNT count]
特殊ID:- 最小ID + 最大ID

127.0.0.1:6379> xadd wz * quadra kill
"1595949618474-0"
127.0.0.1:6379> xrange wz - +
1) 1) "1595944508325-0"
   2) 1) "double"
      2) "kill"
2) 1) "1595944529670-0"
   2) 1) "triple"
      2) "kill"
3) 1) "1595949618474-0"
   2) 1) "quadra"
      2) "kill"
127.0.0.1:6379> xrange wz - + count 1
1) 1) "1595944508325-0"
   2) 1) "double"
      2) "kill"
127.0.0.1:6379> xrange wz 1595944508325-0 1595944529670-0
1) 1) "1595944508325-0"
   2) 1) "double"
      2) "kill"
2) 1) "1595944529670-0"
   2) 1) "triple"
      2) "kill"
xread

 作用:从一个或多个 stream 对象中读取数据
语法: XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
关键词:BLOCK 0:永久阻塞;$:表示获取最新的数据
获取 wz 1595944508325-0 之后的所有数据:

127.0.0.1:6379> xread streams wz 1595944508325-0
1) 1) "wz"
   2) 1) 1) "1595944529670-0"
         2) 1) "triple"
            2) "kill"
      2) 1) "1595949618474-0"
         2) 1) "quadra"
            2) "kill"

获取 wz 1595944508325-0 之后的一条数据:

127.0.0.1:6379> xread count 1 streams wz 1595944508325-0 
1) 1) "wz"
   2) 1) 1) "1595944529670-0"
         2) 1) "triple"
            2) "kill"

获取 wz 最新添加的数据,在未获取到之前一直阻塞直到获取到新的数据为止:

127.0.0.1:6379> xread block 0 streams wz $
#阻塞ing

复制一个当前窗口:

[root@node1 ~]# redis-cli 
127.0.0.1:6379> xadd wz * penta kill
"1595950479113-0"

之前阻塞的窗口立即获取到了数据:

127.0.0.1:6379> xread block 0 streams wz $
#从阻塞获取到数据后输出
1) 1) "wz"
   2) 1) 1) "1595950479113-0"
         2) 1) "penta"
            2) "kill"
(28.19s)#阻塞时间
xgroup 与 xreadgroup在这里插入图片描述

 作用:创建一个消费组
语法:XGROUP [CREATE key groupname id]

127.0.0.1:6379> xadd wzhs * hero kai
"1595951471267-0"
127.0.0.1:6379> xadd wzhs * hero luban
"1595951483480-0"
127.0.0.1:6379> xadd wzhs * hero baili
"1595951492613-0"
127.0.0.1:6379> xadd wzhs * hero liyuanfang
"1595951511105-0"
127.0.0.1:6379> xadd wzhs * hero direnjie
"1595951517069-0"
127.0.0.1:6379> xgroup create wzhs sheshou 1595951483480-0

将luban以后的所有射手(不包含luban)添加到消费组sheshou中。
 作用:从消费组中读取数据
语法: XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] STREAMS key [key …] ID [ID …]
sheshou:消费组 gtjin 消费者 wzhs:表示 key >:表示最新数据(或写成ID)

127.0.0.1:6379> xreadgroup group sheshou gtjin streams wzhs >
1) 1) "wzhs"
   2) 1) 1) "1595951492613-0"
         2) 1) "hero"
            2) "baili"
      2) 1) "1595951511105-0"
         2) 1) "hero"
            2) "liyuanfang"
      3) 1) "1595951517069-0"
         2) 1) "hero"
            2) "direnjie"
如果再次读取的话,将读取不到数据:
127.0.0.1:6379> xreadgroup group sheshou gtjin streams wzhs >
(nil)
除非再次向消费组中添加数据:
127.0.0.1:6379> xadd wzhs * hero huangzhong
"1595952094863-0"
127.0.0.1:6379> xreadgroup group sheshou gtjin streams wzhs >
1) 1) "wzhs"
   2) 1) 1) "1595952094863-0"
         2) 1) "hero"
            2) "huangzhong"
也可以读取指定ID之后的数据,比如1595951483480-0(luban的ID)
127.0.0.1:6379> xreadgroup group sheshou gtjin streams wzhs 1595951483480-0
1) 1) "wzhs"
   2) 1) 1) "1595951492613-0"
         2) 1) "hero"
            2) "baili"
      2) 1) "1595951511105-0"
         2) 1) "hero"
            2) "liyuanfang"
      3) 1) "1595951517069-0"
         2) 1) "hero"
            2) "direnjie"
      4) 1) "1595952094863-0"
         2) 1) "hero"
            2) "huangzhong"
如果只想读取一条数据:
127.0.0.1:6379> xreadgroup group sheshou gtjin count 1 streams wzhs 1595951483480-0
1) 1) "wzhs"
   2) 1) 1) "1595951492613-0"
         2) 1) "hero"
            2) "baili"
阻塞读取数据:
127.0.0.1:6379> xreadgroup group sheshou gtjin block 0 streams wzhs >
#阻塞

然后在另外一个 xshell 窗口中添加数据:

127.0.0.1:6379> xadd wzhs * hero yuji
"1595952556717-0"

阻塞窗口输出:

127.0.0.1:6379> xreadgroup group sheshou gtjin block 0 streams wzhs >
1) 1) "wzhs"
   2) 1) 1) "1595952556717-0"
         2) 1) "hero"
            2) "yuji"

更多内容参考:http://redis.cn/topics/streams-intro.html

通用命令

keys

返回满足给定 pattern 的所有 key
语法:keys pattern

node2:6379> keys mylist*
1) "mylist"
2) "mylist5"
3) "mylist6"
4) "mylist7"
5) "mylist8"
del

语法:DEL key

127.0.0.1:6379> del test
(integer) 1
persist key 删除过期
persist key1

查看剩余生存时间 TTL(Time To Live) key

ttl  key1

pttl key 查看剩余生存时间的毫秒值

pttl key1

key存在但没有设置 TTL,返回 -1
key存在,但还在生存期内,返回剩余的秒或者毫秒
key曾经存在,但已经消亡,返回 -2(5.0.5版本之前返回-1)

exists

作用:确认一个 key 是否存在
语法:exists key
示例:从结果来看,数据库中不存在 HongWan 这个 key,但是 age 这个 key 是存在的

node2:6379> exists gtjin
(integer) 0
node2:6379> exists age
(integer) 1
node2:6379>
expire

Redis 在实际使用过程中更多的用作缓存,然而缓存的数据一般都是需要设置生存时间的,即:到期后数据销毁。

EXPIRE key seconds			 设置key的生存时间(单位:秒)key在多少秒后会自动删除
TTL key 					查看key生于的生存时间
PERSIST key				清除生存时间 
PEXPIRE key milliseconds	生存时间设置单位为:毫秒

例子:

192.168.101.3:7002> set test 1		设置test的值为1
OK
192.168.101.3:7002> get test			获取test的值
"1"
192.168.101.3:7002> EXPIRE test 5	设置test的生存时间为5秒
(integer) 1
192.168.101.3:7002> TTL test			查看test的生于生成时间还有1秒删除
(integer) 1
192.168.101.3:7002> TTL test
(integer) -2
192.168.101.3:7002> get test			获取test的值,已经删除
(nil)
rename

作用:重命名 key
语法:rename oldkey newkey
示例:age 成功的被我们改名为 age_new 了

node2:6379[1]> keys *
1) "age"
node2:6379[1]> rename age age_new
OK
node2:6379[1]> keys *
1) "age_new"
node2:6379[1]>
type

作用:显示指定 key 的数据类型
语法:type key
示例:这个方法可以非常简单的判断出值的类型

node2:6379> type addr
string
node2:6379> type myzset2
zset
node2:6379> type mylist
list
node2:6379>

Redis 持久化(重要)

什么是持久化

将数据从掉电易失的内存存放到能够永久存储的设备上

Redis为什么需要持久化
    基于内存的
    缓存服务器,需要吗? 
    内存数据库,需要吗?
    消息队列,需要吗?
Redis持久化方式
    RDB(Redis DB)   hdfs:    fsimage
    AOF(AppendOnlyFile)   hdfs :    edit logs    关闭的

RDB

RDB 介绍
	RDB方式是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘。在默认情况下,Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。
	产生一个RDB两种方式:
    a. 阻塞方式:
      客户端中执行save命令, 阻塞Redis服务,无法响应客户端请求,创建新的dump.rdb替代旧文件

在这里插入图片描述在这里插入图片描述
b. 非阻塞方式:(复杂度高?)
bgsave
在这里插入图片描述

 策略:Redis 会在指定的情况下触发快照

  1. 符合自定义配置的快照规则

  2. 执行 save 或者 bgsave 命令

  3. 执行 flushall 命令

  4. 执行主从复制操作

    	在 redis.conf 中设置自定义快照规则
    (1)	格式:save <seconds> <changes>
    	示例:10:20 - 10:21 10000 持久化 
              10:21- 10:22  10000
                      10:26 10 
                      10:36  1
             10:36-10:37
    
save 900 1  : 表示15分钟(900秒钟)内至少1个键被更改则进行快照。
save 300 10 : 表示5分钟(300秒)内至少10个键被更改则进行快照。
save 60 10000 :表示1分钟内至少10000个键被更改则进行快照。
可以配置多个条件(每行配置一个条件),每个条件之间是“或”的关系。

(2) 配置 dir 指定 rdb 快照文件的位置

# Note that you must specify a directory here, not a file name.
dir /opt/redis-5.0/conf

(3) 配置 dbfilename 指定 rdb 快照文件的名称

# The filename where to dump the DB
dbfilename dump.rdb
	特别说明:
		Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存。
		根据数据量大小与结构和服务器性能不同,这个时间也不同。
	通常将记录一千万个字符串类型键、大小为1GB的快照文件载入到内存中需要花费20~30秒钟。
非阻塞模式快照原理

 快照过程

  1. redis 使用 fork 函数复制一份当前进程的副本(子进程)

  2. 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件。

  3. 当子进程写入完所有数据后会用该临时文件替换旧的 RDB 文件,至此,一次快照操作完成。

     注意事项

    1. redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。 9:00 5 -9:05
    2. 这就使得我们可以通过定时备份RDB文件来实现redis数据库的备份, RDB文件是经过压缩的二进制文件,占用的空间会小于内存中的数据,更加利于传输。
      在这里插入图片描述在这里插入图片描述
      内存: 512G
      redis:400G
      fork():copy on write
      子进程内存中存储父进程内存的指向,不必开辟真实 800G 的内存占用
      父进程不会阻塞,如果客户端修改了父进程的内存,阻塞(cow):父进程的值,会在子进程中开辟(旧的)。父进程才真正修改。阻塞是很小。
      小的窗口:9:00 BGSAVE 10:00完成,持久化数据存储的是9:00
      在这里插入图片描述

SAVE 和 BGSAVE 命令总结:

  • SAVE 不用创建新的进程,速度略快
  • BGSAVE 需要创建子进程,消耗额外的内存
  • SAVE 适合停机维护,服务低谷时段
  • BGSAVE 适合线上执行
RDB 优缺点

 缺点:使用 RDB 方式实现持久化,一旦 Redis 异常退出,就会丢失最后一次快照以后更改的所有数据。这个时候我们就需要根据具体的应用场景,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受范围。如果数据相对来说比较重要,希望将损失降到最小,则可以使用 AOF 方式进行持久化

 优点: RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无需执行任何磁盘 I/O 操作。同时这个也是一个缺点,如果数据集比较大的时候,fork 可以能比较耗时,造成服务器在一段时间内停止处理客户端的请求;

 生产环境:
创建一个定时任务 cron job,每小时或者每天将 dump.rdb 复制到指定目录。确保备份文件名称带有日期时间信息,便于管理和还原对应的时间点的快照版本,定时任务删除过期的备份。如果有必要,跨物理主机、跨机架、异地备份。

AOF

AOF介绍

 默认情况下Redis没有开启 AOF(append only file)方式的持久化
 开启 AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件,这一过程显然会降低Redis的性能,但大部分情况下这个影响是能够接受的,另外使用较快的硬盘可以提高AOF的性能。调整AOF持久化策略,可以在服务出现故障时,不丢失任何数据,也可以丢失一秒的数据。相对于RDB损失小得多。
AOF写入机制
AOF方式不能保证绝对不丢失数据,目前常见的操作系统中,执行系统调用write函数,将一些内容写入到某个文件里面时,为了提高效率,系统通常不会直接将内容写入硬盘里面,而是先将内容放入一个内存缓冲区(buffer)里面,等到缓冲区被填满,或者用户执行fsync调用和fdatasync调用时才将储存在缓冲区里的内容真正的写入到硬盘里,未写入磁盘之前,数据可能会丢失。在这里插入图片描述
写入磁盘的策略
appendfsync 选项,这个选项的值可以是 always、everysec 或者 no

  1. always:服务器每写入一个命令,就调用一次fdatasync,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,也不会丢失任何已经成功执行的命令数据 2020-09-24 11:00:01
  2. everysec(默认):服务器每一秒调用一次fdatasync,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,最多只丢失一秒钟内的执行的命令数据
  3. no:服务器不主动调用fdatasync,由操作系统决定何时将缓冲区里面的命令写入到硬盘。这种模式下,服务器遭遇意外停机时,丢失命令的数量是不确定的
    运行速度:always的速度慢,everysec和no都很快

 可以通过修改 redis.conf 配置文件中的 appendonly 参数开启

appendonly yes

 AOF 文件的保存位置和 RDB 文件的位置相同,都是通过 dir 参数设置的。

dir /opt/redis-5.0/conf

 默认的文件名是 appendonly.aof,可以通过 appendfilename 参数修改:

appendfilename appendonly.aof
AOF 重写在这里插入图片描述

AOF 重写机制

	AOF 文件过大
	合并重复的操作,AOF会使用尽可能少的命令来记录
	重写基于写时复制,直接将内存的数据反转为命令。
AOF 重写触发

手动:客户端向服务器发送 BGREWRITEAOF(bgrewriteaof)命令
自动:配置文件中的选项,自动执行 BGREWRITEAOF 命令

auto-aof-rewrite-min-size <size>,触发 AOF 重写所需的最小体积:只要在 AOF 文件的体积大于等于 size 时,才会考虑是否需要进行 AOF 重写,这个选项用于避免对体积过小的 AOF 文件进行重写死循环。auto-aof-rewrite-min-size 64mb当 AOF 文件大于 64MB 时候,可以考虑重写 AOF 文件
auto-aof-rewrite-percentage <percent>,指定触发重写所需的 AOF 文件体积百分比:当 AOF 文件的体积大于auto-aof-rewrite-min-size指定的体积,并且超过上一次重写之后的 AOF 文件体积的 percent % 时,就会触发 AOF 重写。(如果服务器刚刚启动不久,还没有进行过 AOF 重写,那么使用服务器启动时载入的 AOF 文件的体积来作为基准值)。将这个值设置为 0 表示关闭自动 AOF 重写

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64MB 
appendonly no/yes  关闭/开启

只有当 AOF 文件的增量大于起始 size 的 100% 时(就是文件大小翻了一倍),启动重写
默认关闭,请开启

重写过程
1、执行 AOF 重写请求
2、父进程执行 fork 创建子进程,开销等同于 bgsave 过程
3.1、主进程 fork 操作完成后,继续响应其他命令。所有修改命令依然写入 AOF 缓冲区,并根据 appendfsync 策略同步到磁盘,保证原有 AOF 机制正确性。
3.2、由于 fork 操作运用写时复制技术,子进程只能共享 fork 操作时的内存数据。由于父进程依然响应命令,redis 使用 “AOF重写缓冲区” 保存这部分新数据,防止新 AOF 文件生成期间丢失这部分数据。
4、子进程根据内存快照,按照命令合并规则写入到新 AOF 文件。每次批量写入硬盘数据量由 aof-rewrite-incremental-fsync 控制,默认是 32MB,防止单次刷盘数据过多造成硬盘阻塞。
5.1、(比如 8:00)新 AOF 文件写入完成后,子进程发送信号给父进程,父进程更新统计信息。
5.2、父进程把 AOF 重写缓冲区数据写入到新的 AOF 文件。
5.3、使用新 AOF 文件替换老文件,完成 AOF 重写。
注:如果写入操作的时候出现故障导致命令写半截,可以使用redis-check-aof工具修复
在这里插入图片描述

AOF 优缺点

优点

  • 写入机制,默认 fysnc 每秒执行,性能很好不阻塞服务,最多丢失一秒的数据
  • 重写机制,优化 AOF 文件
  • 如果误操作了(FLUSHALL 等),只要 AOF 未被重写,停止服务移除 AOF 文件尾部 FLUSHALL 命令,重启 Redis,可以将数据集恢复到 FLUSHALL 执行之前的状态

缺点

  • 相同数据集,AOF 文件体积较 RDB 大了很多
  • 恢复数据库速度比 RDB 慢(文本,命令重演)

如何选择 RDB 和 AOF

 一般来说,如果对数据的安全性要求非常高的话,应该同时使用两种持久化功能。
 如果可以承受数分钟以内的数据丢失,那么可以只使用 RDB 持久化。
 有很多用户都只使用 AOF 持久化, 但并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快 。
 两种持久化策略可以同时使用,也可以使用其中一种。如果同时使用的话, 那么 Redis 重启时,会优先使用 AOF 文件来还原数据??
更多关于 redis 持久化参考:http://redis.cn/topics/persistence.html

Redis 集群

	单机/单点
		单点故障/瓶颈:多个节点负载:面向数据:
			一变多(一致性<弱一致,最终一致性>) 可用性
			最终一致性:一部分角色确认    网络分区(脑裂) 过半机制
        镜像全量:数据容量不变
        切片:横向扩展
	集群分类
		分布式 :切片
			 集群 Cluster(redis3.x+)3.0+支持 redis集群
由多个 Redis 服务器组成的分布式网络服务集群

在这里插入图片描述
每一个 Redis 服务器称为节点 Node,节点之间会互相通信。两两相连
Redis 集群无中心节点 无主模型在这里插入图片描述

Redis 集群节点复制

 Redis 集群的每个节点都有两种角色可选:主节点 master node、从节点 slave node。其中主节点用于存储数据,而从节点则是某个主节点的复制品
 当用户需要处理更多读请求的时候,添加从节点可以扩展系统的读性能,因为 Redis 集群重用了单机 Redis 复制特性的代码,所以集群的复制行为和我们之前介绍的单机复制特性的行为是完全一样的在这里插入图片描述

Redis 集群故障转移

 Redis 集群的主节点内置了类似 Redis Sentinel 的节点故障检测和自动故障转移功能,当集群中的某个主节点下线时,集群中的其他在线主节点会注意到这一点,并对已下线的主节点进行故障转移
 集群进行故障转移的方法和 Redis Sentinel 进行故障转移的方法基本一样,不同的是,在集群里面,故障转移是由集群中其他在线的主节点负责进行的,所以集群不必另外使用 Redis Sentinel在这里插入图片描述

Redis 集群分片

 集群将整个数据库分为 16384 个槽位 slot,key 的槽位计算公式为slot_number=crc16(key)%16384,其中 crc16 为16 位的循环冗余校验和函数
 集群中的每个主节点都可以处理 0 个至 16383 个槽,当 16384 个槽都有某个节点在负责处理时,集群进入上线状态,并开始处理客户端发送的数据命令请求

举例

三个主节点7000、7001、7002平均分片16384个slot槽位
节点7000指派的槽位为0到5460
节点7001指派的槽位为5461到10922 
节点7002指派的槽位为10923到16383
新添加的节点700x指派的槽位如何分配?   

何时集群不能对外提供服务

1、 过半的主节点进程挂掉,不能对外提供服务 无法做主从切换 过半机制
2、 其中任意一个节点主从都挂掉,不能对外提供服务 数据不完整,不够 16384 个 hash slots
主节点过半机制判定一个主节点是否挂掉在这里插入图片描述

Redis 集群 Redirect 转向

 由于 Redis 集群无中心节点,请求会发给任意主节点
 主节点只会处理自己负责槽位的命令请求,其它槽位的命令请求,该主节点会返回客户端一个转向错误
 客户端根据错误中包含的地址和端口重新向正确的负责的主节点发起命令请求在这里插入图片描述

Redis 集群搭建

规划 6 个节点:3 个主节点,每一个主节点有一个从节点在这里插入图片描述

具体搭建步骤:

  1. 准备目录与配置文件
[root@node2 ~]# cd /opt/redis-5.0/
[root@node2 redis-5.0]# mkdir -p redis-cluster/700{0,1,2,3,4,5}
[root@node2 redis-5.0]# ls
bin  conf  dump.rdb  log  redis-cluster
[root@node2 redis-5.0]# cd redis-cluster/
[root@node2 redis-cluster]# ls
7000 7001  7002  7003  7004  7005
[root@node2 redis-cluster]# cd 7000
[root@node2 7000]# cp ../../conf/redis.conf  ./
[root@node2 7000]# vim redis.conf 
port 7000  #修改端口
dir /opt/redis-5.0/redis-cluster/7000/
logfile "/opt/redis-5.0/log/redis_7000.log"
pidfile /var/run/redis_7000.pid
cluster-enabled yes #启动集群模式(去掉注释)
cluster-config-file nodes-7000.conf #集群节点信息文件,这里700x最好和port对应上
cluster-node-timeout 10000
bind 127.0.0.1 192.168.20.73 #注释掉
protected-mode no  #关闭保护模式
  1. 然后将7000/redis.conf文件拷贝到剩下的 5 个 700x 目录
[root@node2 7000]# cd ../
[root@node2 redis-cluster]# cp 7001/redis.conf 7001/
[root@node2 redis-cluster]# cp 7001/redis.conf 7002/
[root@node2 redis-cluster]# cp 7001/redis.conf 7003/
[root@node2 redis-cluster]# cp 7001/redis.conf 7004/
[root@node2 redis-cluster]# cp 7001/redis.conf 7005/
  1. 分别修改 7001-7005 目录下的 redis.conf 文件
[root@node2 redis-cluster]# vim 7001/redis.conf 
[root@node2 redis-cluster]# vim 7002/redis.conf 
[root@node2 redis-cluster]# vim 7003/redis.conf 
[root@node2 redis-cluster]# vim 7004/redis.conf 
[root@node2 redis-cluster]# vim 7005/redis.conf 
可以用批量替换:
%s/源字符串/目的字符串/g --> %s/7000/700x/g
  1. 分别启动服务命令:
[root@node2 redis-cluster]# redis-server 7000/redis.conf
[root@node2 redis-cluster]# redis-server 7001/redis.conf 
[root@node2 redis-cluster]# redis-server 7002/redis.conf 
[root@node2 redis-cluster]# redis-server 7003/redis.conf 
[root@node2 redis-cluster]# redis-server 7004/redis.conf 
[root@node2 redis-cluster]# redis-server 7005/redis.conf 
#查看是否启动成功 
[root@node2 redis-cluster]# ps aux|grep redis
root       1191  1.2  0.7 152428  7828 ?        Ssl  11:38   0:00 redis-server *:7000 [cluster]
root       1166  0.3  0.7 152428  7832 ?        Ssl  11:38   0:00 redis-server *:7001 [cluster]
root       1171  0.4  0.7 152428  7824 ?        Ssl  11:38   0:00 redis-server *:7002 [cluster]
root       1176  0.5  0.7 152428  7828 ?        Ssl  11:38   0:00 redis-server *:7003 [cluster]
root       1181  0.5  0.7 152428  7824 ?        Ssl  11:38   0:00 redis-server *:7004 [cluster]
root       1186  0.7  0.7 152428  7828 ?        Ssl  11:38   0:00 redis-server *:7005 [cluster]
  1. 槽位认领
    redis.50 以前:在安装目录下的 src 中,找到 redis-trib.rb 这是 rubby 脚本执行程序,完成集群创建:
cd apps/redis-3.2.2/src/
./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001  127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

redis5.0以后:

[root@node2 redis-cluster]# redis-cli --cluster help
Cluster Manager Commands:
  create         host1:port1 ... hostN:portN
                 --cluster-replicas <arg> 

[root@node2 redis-cluster]#redis-cli --cluster create --cluster-replicas 1 192.168.20.73:7000 192.168.20.73:7001  192.168.20.73:7002 192.168.20.73:7003 192.168.20.73:7004 192.168.20.73:7005 
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.20.73:7004 to 192.168.20.73:7000
Adding replica 192.168.20.73:7005 to 192.168.20.73:7001
Adding replica 192.168.20.73:7003 to 192.168.20.73:7002
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 5c85c25bf5cfd34572dd70614d713cb386ca260b 192.168.20.73:7000
   slots:[0-5460] (5461 slots) master
M: e1c9d106a4ab3008f24f9765ef9ad323902ccb36 192.168.20.73:7001
   slots:[5461-10922] (5462 slots) master
M: fe33f6edf80450478653d5dccf52e241eb77d1a1 192.168.20.73:7002
   slots:[10923-16383] (5461 slots) master
S: d366328b276c5ec41395cc541445855d726aeaba 192.168.20.73:7003
   replicates 5c85c25bf5cfd34572dd70614d713cb386ca260b
S: e9a8e4315a7a23f9bdc700545797cb28fdf70789 192.168.20.73:7004
   replicates e1c9d106a4ab3008f24f9765ef9ad323902ccb36
S: fb0191f132783b9fa2ed2b5f696b9172dfa4ffe9 192.168.20.73:7005
   replicates fe33f6edf80450478653d5dccf52e241eb77d1a1
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 192.168.20.73:7000)
M: 5c85c25bf5cfd34572dd70614d713cb386ca260b 192.168.20.73:7000
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: fe33f6edf80450478653d5dccf52e241eb77d1a1 192.168.20.73:7002
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: d366328b276c5ec41395cc541445855d726aeaba 192.168.20.73:7003
   slots: (0 slots) slave
   replicates 5c85c25bf5cfd34572dd70614d713cb386ca260b
M: e1c9d106a4ab3008f24f9765ef9ad323902ccb36 192.168.20.73:7001
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: e9a8e4315a7a23f9bdc700545797cb28fdf70789 192.168.20.73:7004
   slots: (0 slots) slave
   replicates e1c9d106a4ab3008f24f9765ef9ad323902ccb36
S: fb0191f132783b9fa2ed2b5f696b9172dfa4ffe9 192.168.20.73:7005
   slots: (0 slots) slave
   replicates fe33f6edf80450478653d5dccf52e241eb77d1a1
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
  1. 数据测试
[root@node2 ~]# redis-cli -p 7000
127.0.0.1:7000> set k1 a
(error) MOVED 12706 127.0.0.1:7002

以上客户端建立的连接表示单机连接,-c表示集群连接。结束掉重连:

[root@node2 ~]# redis-cli -p 7000 -c
127.0.0.1:7000> set k1 a
-> Redirected to slot [12706] located at 127.0.0.1:7002
OK
127.0.0.1:7002> get k1
"a"
127.0.0.1:7002> set k2 b
-> Redirected to slot [449] located at 127.0.0.1:7000
OK
127.0.0.1:7000> get k2
"b"
  1. 高可用演示
    关闭 7000 端口对应的 redis 进程,经过短暂下线后,自动将 7003 切换为 Master
[root@node2 redis-cluster]# ps aux|grep redis
root       1220  0.1  1.2 163692 12668 ?        Ssl  11:56   0:01 redis-server *:7000 [cluster]
[root@node2 redis-cluster]# kill -9 1220
[root@node2 ~]# redis-cli -p 7003 -c
127.0.0.1:7003> get k2
"b"
127.0.0.1:7003> get k1
-> Redirected to slot [12706] located at 127.0.0.1:7002
"a"
  1. 进行验证: cluster info(查看集群信息)、cluster nodes(查看节点列表)在这里插入图片描述
  2. 启动 7000 后再进行验证:
[root@node2 redis-cluster]# redis-server 7000/redis.conf 
[root@node2 redis-cluster]# ps aux|grep redis
......
root       1281  1.0  1.2 159596 12132 ?        Ssl  12:21   0:00 redis-server *:7000 [cluster]
[root@node2 redis-cluster]# redis-cli -p 7003 -c

在这里插入图片描述

  1. 关闭集群则需要逐个进行关闭,使用命令:
redis-cli  -c -h 192.168.20.73  -p 7000 shutdown
......
redis-cli  -c -h 192.168.20.73  -p 7005 shutdown

添加节点

  1. 添加 7006、7007 配置准备,并启动
[root@node2 redis-cluster]# mkdir 7006 7007
[root@node2 redis-cluster]# cp 7000/redis.conf 7006/
[root@node2 redis-cluster]# cp 7000/redis.conf 7007/
[root@node2 redis-cluster]# vim 7006/redis.conf
:%s/7000/7006/g 
[root@node2 redis-cluster]# vim 7007/redis.conf 
:%s/7000/7007/g
#启动7006 7007
[root@node2 redis-cluster]# redis-server 7006/redis.conf 
[root@node2 redis-cluster]# redis-server 7007/redis.conf 
# 检查是否启动
[root@node2 redis-cluster]# ps aux|grep redis
......
root       1327  0.0  0.7 152428  7824 ?        Ssl  14:10   0:00 redis-server *:7006 [cluster]
root       1332  1.6  0.7 152428  7828 ?        Ssl  14:11   0:00 redis-server *:7007 [cluster]
  1. 查看添加节点的命令格式:
[root@node2 redis-cluster]# redis-cli --cluster help
......
add-node       new_host:new_port existing_host:existing_port
                 --cluster-slave
                 --cluster-master-id <arg>
  1. 添加 7006 到集群中
[root@node2 redis-cluster]# redis-cli --cluster add-node 192.168.20.73:7006 192.168.20.73:7002
[root@node2 redis-cluster]# redis-cli -h 192.168.20.73 -p 7000 -c
192.168.20.73:7000> cluster nodes #查看节点信息
fe33f6edf80450478653d5dccf52e241eb77d1a1 192.168.20.73:7002@17002 master - 0 1596176261764 3 connected 10923-16383
c5f38adad125a2a05432a2a023ffcd8061673bcc 192.168.20.73:7006@17006 master - 0 1596176260654 0 connected  暂时没有槽位
  1. 给 7006 分配 hash slots 1000 个
[root@node2 redis-cluster]# redis-cli --cluster help
reshard        host:port
                 --cluster-from <arg>
                 --cluster-to <arg>
                 --cluster-slots <arg>
                 --cluster-yes
[root@node2 redis-cluster]# redis-cli --cluster reshard 192.168.20.73:7002 --cluster-from all --cluster-to c5f38adad125a2a05432a2a023ffcd8061673bcc --cluster-slots 1000

[root@node2 redis-cluster]# redis-cli -p 7001 -c
127.0.0.1:7001> cluster nodes
c5f38adad125a2a05432a2a023ffcd8061673bcc192.168.20.73:7006@17006 master - 0 1596176704304 8 connected 0-1364 5461-6826 10923-12287
 0-1364 5461-6826 10923-12287
...... #1365+1366+1365=4096
  1. 将 7007 作为 7006 的从节点加入集群:
[root@node2 redis-cluster]# redis-cli --cluster add-node 192.168.20.73:7007 192.168.20.73:7002 --cluster-slave --cluster-master-id c5f38adad125a2a05432a2a023ffcd8061673bcc
[root@node2 redis-cluster]# redis-cli -p 7001 -c
127.0.0.1:7001> cluster nodes
f52f4e9d9d343c53565865d6f25342380a6da799 192.168.20.73:7007@17007 slave c5f38adad125a2a05432a2a023ffcd8061673bcc 0 1596177123069 8 connected
......

删除节点

 移除从节点

  1. 7007(从节点可直接删除)
[root@node2 ~]# redis-cli --cluster del-node 192.168.20.73:7002 f52f4e9d9d343c53565865d6f25342380a6da799 #7007的id

>>> Removing node f52f4e9d9d343c53565865d6f25342380a6da799 from cluster 192.168.20.73:7002
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.

2.查看是否移除掉

[root@node2 ~]# redis-cli -p 7001 -c
127.0.0.1:7001> cluster nodes
e9a8e4315a7a23f9bdc700545797cb28fdf70789 192.168.20.73:7004@17004 slave e1c9d106a4ab3008f24f9765ef9ad323902ccb36 0 1596177319510 5 connected
fe33f6edf80450478653d5dccf52e241eb77d1a1 192.168.20.73:7002@17002 master - 0 1596177318503 3 connected 12288-16383
5c85c25bf5cfd34572dd70614d713cb386ca260b 192.168.20.73:7000@17000 slave d366328b276c5ec41395cc541445855d726aeaba 0 1596177318503 7 connected
fb0191f132783b9fa2ed2b5f696b9172dfa4ffe9 192.168.20.73:7005@17005 slave fe33f6edf80450478653d5dccf52e241eb77d1a1 0 1596177318503 6 connected
e1c9d106a4ab3008f24f9765ef9ad323902ccb36 192.168.20.73:7001@17001 myself,master - 0 1596177317000 2 connected 6827-10922
d366328b276c5ec41395cc541445855d726aeaba 192.168.20.73:7003@17003 master - 0 1596177318000 7 connected 1365-5460
c5f38adad125a2a05432a2a023ffcd8061673bcc 192.168.20.73:7006@17006 master - 0 1596177319000 8 connected 0-1364 5461-6826 10923-12287

已经不存在 7007 了,表示删除成功!
 删除主节点:

  1. 迁移 hash slots
[root@node2 ~]# redis-cli --cluster reshard 192.168.20.73:7003 --cluster-from c5f38adad125a2a05432a2a023ffcd8061673bcc --cluster-to d366328b276c5ec41395cc541445855d726aeaba --cluster-slots 1365
[root@node2 ~]# redis-cli --cluster reshard 192.168.20.73:7001 --cluster-from c5f38adad125a2a05432a2a023ffcd8061673bcc --cluster-to e1c9d106a4ab3008f24f9765ef9ad323902ccb36 --cluster-slots 1366
[root@node2 ~]# redis-cli --cluster reshard 192.168.20.73:7002 --cluster-from c5f38adad125a2a05432a2a023ffcd8061673bcc --cluster-to fe33f6edf80450478653d5dccf52e241eb77d1a1 --cluster-slots 1365
  1. 查看节点的 slot
[root@node2 redis-cluster]# redis-cli -p 7001 -c
127.0.0.1:7001> cluster nodes
e9a8e4315a7a23f9bdc700545797cb28fdf70789 192.168.20.73:7004@17004 slave e1c9d106a4ab3008f24f9765ef9ad323902ccb36 0 1596178327537 10 connected
fe33f6edf80450478653d5dccf52e241eb77d1a1 192.168.20.73:7002@17002 master - 0 1596178327637 11 connected 10923-16383
5c85c25bf5cfd34572dd70614d713cb386ca260b 192.168.20.73:7000@17000 slave d366328b276c5ec41395cc541445855d726aeaba 0 1596178327000 9 connected
fb0191f132783b9fa2ed2b5f696b9172dfa4ffe9 192.168.20.73:7005@17005 slave fe33f6edf80450478653d5dccf52e241eb77d1a1 0 1596178327000 11 connected
e1c9d106a4ab3008f24f9765ef9ad323902ccb36 192.168.20.73:7001@17001 myself,master - 0 1596178327000 10 connected 5461-10922
d366328b276c5ec41395cc541445855d726aeaba 192.168.20.73:7003@17003 master - 0 1596178326000 9 connected 0-5460
c5f38adad125a2a05432a2a023ffcd8061673bcc 192.168.20.73:7006@17006 master - 0 1596178326530 8 connected
  1. 移除空的主节点
[root@node2 ~]# redis-cli --cluster del-node 192.168.20.73:7002 c5f38adad125a2a05432a2a023ffcd8061673bcc #7006的id
  1. 查看节点
[root@node2 ~]# redis-cli -p 7000 -c
127.0.0.1:7000> cluster nodes

7006已经被删除。

Redis 集群总结

 Redis 集群是一个由多个节点组成的分布式服务集群,它具有复制、高可用和分片特性
 Redis 的集群没有中心节点,并且带有复制和故障转移特性,这可用避免单个节点成为性能瓶颈,或者因为某个节点下线而导致整个集群下线
 集群中的主节点负责处理槽(储存数据),而从节点则是主节点的复制品
 Redis 集群将整个数据库分为 16384 个槽,数据库中的每个键都属于16384个槽中的其中一个
 集群中的每个主节点都可以负责 0 个至 16384 个槽,当16384 个槽都有节点在负责时,集群进入上线状态,可以执行客户端发送的数据命令
主节点只会执行和自己负责的槽有关的命令,当节点接收到不属于自己处理的槽的命令时,它将会处理指定槽的节点的地址返回给客户端,而客户端会向正确的节点重新发送

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值