IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> Redis从头到尾 -> 正文阅读

[大数据]Redis从头到尾

1.nosql

为什么要用nosql

现在是2022年,是一个大数据的时代;技术更新迭代,年轻人越来越多,所以我们需要逼着自己学习,

只有不断学习,才能让自己的亲人过的更好。

1刚开始还是单机mysql的时代

用户APP通过ADL访问到数据库,仅此而已。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DmNuBGzB-1659370129109)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220422223820986.png)]

那个年代,要给简单的网站,访问量不会太大,单个数据库完全足够了。

那个时候更多的是静态的html网页,服务器完全没有压力。

这种情况下,未来的问题是哪些:

1.数据量太大,一个机器放不下

2.数据索引,一个机器放不下

3.访问量(读写混合),要给机器放不下

只要出现上面的一种情况,则必须要升级才能满足要求

Memcached(缓存)+Mysql+垂直分离(分库读写分离)

80%的访问都是在读数据库,同样的查询不断访问数据库比较影响性能,这个时候引入缓存。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jvMFSUfW-1659370129113)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220422233419558.png)]

发展过程:优化数据结构和索引–>文件缓存(IO)–>Memcached(当时热门的缓存技术),

不缺人,缺人才一定要学的好。

什么是Nosql

nosql not only sql 不仅仅时sql

关系型数据库:mysql,行,列

非关系型数据库:redis

很多数据类型,比如个人信息,地理位置,社交网络,这些数据的存储,不需要一个固定的格式,不需要多少操作就可以横向扩展! 就像Map<String,Object>使用键值对就可以控制。

Nosql的特点

解耦:不存在耦合关系

? 1.方便扩展(数据之间没有关系,很好扩展)

? 2.大数据量,高性能(redis一秒钟写8万次,读取11万次,nosql的缓存记录级时细粒度的缓存,性能很高)

? 3.数据类型多样性(不需要事先设计表就可以用,数据量特别大的表,一般人无法设计)

? 4.RDBMS(关系型数据库) 和NoSql

传统的RDBMS

- 结构化组织

- sql

- 数据和关系都存在表中

- 操作,数据语言定义
nosq
- 不仅仅时数据
- 没有固定的查询语言
- 键值对存储,列存储,文档存储,图形数据库(社交关系)
- 最终一致性(不看过程,只要看最终结果)
- cap定理和base(一地多活) 
- 高性能,高可用,高可扩(扩展)

3V+3高

大数据的3V:主要是描述问题的
1.海量Volume
2.多样Variety
3.实时Velocity
大数据的3高:主要是对程序的需求
1.高并发
2.高可扩(随时可以水平拆分,就是机器不够了,可以通过添加机器来解决)
3.高性能 (保证高性能,满足客户的体验需求)

真正的公司实际运用中,肯定时RDBMS和NOSQL同时使用。

阿里巴巴演进

技术记不得,只有学好基础,才能扎实扎实。

阿里巴巴第五代:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ac7ZZMZh-1659370129116)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220423111538952.png)]

数据架构,逐渐离谱:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aMJP3ze5-1659370129117)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220423112028944.png)]

# 1商品的基本信息:

?	名称,价格,商家信息

?	通过关系型数据库 mysql,oracle,来解决 (早年去IOE 王坚:推荐文章,阿里云的那群疯子。)

?	淘宝的mysql已经不是原来的mysql

#2.商品的描述,评论(文字比较多多)

?	文档型数据库,mongoDB;

# 3图片

分布式文件系统 FastDFS
- 淘宝自己的 TFS
- Google 的 GFS
- Hadoop 的HDFS   大数据必须要学
- 阿里云的 云存储

# 4.商品搜索
	- 搜索引擎,solr,elasticsearch
	- Iserch 淘宝在用,  多隆,阿里云的第一个程序员
	所有牛逼的人,都有一段苦逼的岁月,只要有傻逼一样的坚持,终将牛逼。
# 5.商品热门的波段信息
   - 内存数据库
   - reids ,memache .....
# 6.商品的交易,外部的支付接口
	- 第三方的应用
	

一个简单的页面,背后不是我们想的那么简单

? 大型互联网的应用:

  • 数据类型太多

  • 数据源太多,经常重构

  • 数据改造,大面积改造

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uG99l23s-1659370129128)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220423113942652.png)]

    解决问题:没有什么加层,统一的API

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PAyyPLud-1659370129129)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220423114052821.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I8DiBdl4-1659370129131)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220423114150043.png)]

缓存设计:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gOcP0Co5-1659370129132)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220423114444636.png)]

这里以上都是nosql,入门技术。

nosql的四大分类

kv键值对

1.新浪:Redis

2.美团:Redis+Tair

3.阿里+百度:Redis+memaCache

文档型数据库(bson格式和json一样)

1.MongoDB(必须掌握)

? MongoDB是一个基于分布式文件存储的数据库,c++编写,主要是用于处理大量的文档

? MongoDB是介于关系型和非关系型之间的数据库,是功能最丰富,最像关系型数据库的产品。

2.ConthDB

列存储数据库

1.HBase

2.分布式文件系统

图关系数据库(存的是关系,不是图)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m3Dctzf0-1659370129133)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220423234333797.png)]

1.他不是存图形的,存的是关系,比如,朋友圈社交网络,广告推荐。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xf8TBLCK-1659370129134)(C:\Users\Administrator\Desktop\20200410144538483.png)]

2Redis入门

概述

Redis(Remote Dictionary Server ),即远程字典服务

是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

Redis能干嘛

1.内存存储,持久化,内存是断电即失所以说,持久化是很重要的(rdb,aof)

2.效率高,可以用于高速存储

3.发布订阅系统

4.地图信息分析

5.计时器,计数器(浏览量)

6…

特性

1.多样化的数据类型

2.持久化

3.集群

4.事务

。。。。

学习中需要用到的东西

1.官网: https://redis.io/

2.中文网:https://www.redis.net.cn/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0i2A88Gb-1659370129135)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220426104501607.png)]

注意:windows在github下载(已停更很久了)。

Redis推荐在linux服务器上搭建学习使用。

windows下使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-09xuZj3q-1659370129136)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220426153850618.png)]

Linux安装

1 .下载安装包redis-7.0.0.tar.gz

2.安装redis

移动redis安装包到opt
	mv  redis-7.0.0.tar.gz  /opt
解压安装包
tar -zxvf redis-7.0.0.tar.gz

解压完成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NooRjN19-1659370129137)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220505234934768.png)]

3.查看redis文件,可以看到配置文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TYVS4mya-1659370129138)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220505235120973.png)]

4.基本的环境安装

yum install gcc-c++
make //自动配置文件
make install //确认安装

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BOVwR2vd-1659370129139)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220506213507439.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hdBFp93O-1659370129140)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220506213652347.png)]

5.redis默认安装路径 /user/local/bin

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BDbRSyds-1659370129141)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220506214213518.png)]

6.将redis配置文件复制到当前目录下,先新建目录,再拷贝到新建目录下

以后这个配置文件启动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Joezr2b9-1659370129142)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220506214515610.png)]

7.reids默认不是后台启动,需要修改配置文件

vim redis.conf

修改后esc 退出   :wq保存,如果是root权限依然报无权限保存,可以::wq! 强制保存

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VaUqs44U-1659370129143)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220506221103851.png)]

8.启动redis

正常的启动方式,根据上面的配置文件启动
进入到安装目录
redis-server  kconfig/redis.config  //可能有反应,也可能没有反应

判断是否启动成功

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-md1PlQKz-1659370129144)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220506224230877.png)]

9.测试连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9qFYLXUc-1659370129145)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220506225441438.png)]

遇到的问题:redis已启动又重新启动了

[root@iZuf666vjdw36wtck8r51sZ bin]# redis-server 
338399:C 06 May 2022 22:46:21.111 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
338399:C 06 May 2022 22:46:21.111 # Redis version=7.0.0, bits=64, commit=00000000, modified=0, pid=338399, just started
338399:C 06 May 2022 22:46:21.111 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
338399:M 06 May 2022 22:46:21.112 * monotonic clock: POSIX clock_gettime
338399:M 06 May 2022 22:46:21.112 # Warning: Could not create server TCP listening socket *:6379: bind: Address already in use
338399:M 06 May 2022 22:46:21.112 # Failed listening on port 6379 (TCP), aborting.
[root@iZuf666vjdw36wtck8r51sZ bin]# 

10.判断Redis是否已启动

ps -ef | grep redis 



root      338060  337936  0 21:47 pts/3    00:00:00 vim redis.conf
root      338118  338072  0 22:00 pts/4    00:00:00 vim redis.conf
root      338141  338072  0 22:03 pts/4    00:00:00 vim redis.conf
root      338162  338072  0 22:09 pts/4    00:00:00 vim redis.conf
root      338175  338072  0 22:10 pts/4    00:00:00 vim redis.conf
root      338230  338072  0 22:18 pts/4    00:00:00 vim redis.conf
root      338294  338072  0 22:28 pts/4    00:00:00 redis-cli
root      338296  338072  0 22:29 pts/4    00:00:00 redis-cli
root      338298  338072  0 22:29 pts/4    00:00:00 redis-cli
root      338376       1  0 22:40 ?        00:00:00 redis-server 127.0.0.1:6379
root      338404  338072  0 22:47 pts/4    00:00:00 grep --color=auto redis

关闭线程

kill -9 338376

11.推出服务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ECfcBSbA-1659370129146)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220506225547340.png)]

12.后面需要实现单机多redis集群

性能测试

序号选项描述默认值
1-h指定服务器主机名127.0.0.1
2-p指定服务器端口6379
3-s指定服务器 socket
4-c指定并发连接数50
5-n指定请求数10000
6-d以字节的形式指定 SET/GET 值的数据大小2
7-k1=keep alive 0=reconnect1
8-rSET/GET/INCR 使用随机 key, SADD 使用随机值
9-P通过管道传输 请求1
10-q强制退出 redis。仅显示 query/sec 值
11–csv以 CSV 格式输出
12*-l*(L 的小写字母)生成循环,永久执行测试
13-t仅运行以逗号分隔的测试命令列表。
14*-I*(i 的大写字母)Idle 模式。仅打开 N 个 idle 连接并等待。
测试命令:
# redis-benchmark -h localhost -p 6379 -c 100 -n 100000

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eAKU02cA-1659370129146)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220507000722270.png)]

基础知识

1.Redis一共有16个数据库,默认使用第0个

? 可以使用select 方法切换数据库

127.0.0.1:6379> select 3  #切换数据库
OK
127.0.0.1:6379[3]> DBsize #查看DB大小
(integer) 0
127.0.0.1:6379[3]> dbsize #数据库大小  0
(integer) 0
127.0.0.1:6379[3]> select 7 #切换 到 7号数据库
OK
127.0.0.1:6379[7]> dbsize  #数据库大小 0
(integer) 0
127.0.0.1:6379[7]> set name huang  #7 号数据库set值
OK 
127.0.0.1:6379[7]> dbsize  # 7号数据库大小为 1
(integer) 1
127.0.0.1:6379[7]> select 3  #切换到3号数据库
OK
127.0.0.1:6379[3]> dbsize # 3 号数据库大小还是为 0
(integer) 0

2.查看数据库中所有的key

127.0.0.1:6379> keys *   # keys *  查看当前数据库中所有的key
1) "key:__rand_int__"
2) "mylist"
3) "kuang"
4) "age"

3.清除当前数据库中所有的key

4.清楚所有数据库的key

127.0.0.1:6379> flushdb  #清除当前数据库所有的 key
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> flushall  #清除所有数据库所有的 key

Redis是单线程

官方表示,Redis是基于内存的操作,CPU不是影响性能的主要因素,Redis的性能瓶颈是内存和网络带宽,所有可以用单线程就用单线程了。

Redis的单线程为什么这么快?

误区1:高性能的服务器一定是多线程的

误区2:多线程的一定比单线程快

cpu>大于内存>硬盘

核心:Redis是基于内存的,所有数据都放在内存中,所以说单线程的操作效率是最高的,多线程需要上下文切换,反而会消耗性能。

Redis的五大数据类型

官方文档

Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串哈希表列表集合有序集合位图hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区

Redis-key

127.0.0.1:6379> keys *  #当前数据库索引key
(empty array)
127.0.0.1:6379> set name huang  # set值
OK
127.0.0.1:6379> set age 11
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> exists name  #判断当前key再当前数据库是否存在
(integer) 1
127.0.0.1:6379> exists name2 #不存在则返回0
(integer) 0
127.0.0.1:6379> move name 1  # 移出key  1表示第一个数据库 
(integer) 1

127.0.0.1:6379[7]> move name 8  # 数据库7  move命令是 move  key  8
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> expire age 10 #设置这个key的有效时间 ,单位为  秒
(integer) 1
127.0.0.1:6379> ttl age  # 查询这个key的时间,
(integer) 7
127.0.0.1:6379> ttl age
(integer) 3
127.0.0.1:6379> ttl age  # 返回-2 表示这个key已经超时,相当于删除不存在了
(integer) -2
127.0.0.1:6379> type name # 查看key的类型
string

更多的命令根据需要再官方文档查看

String(字符串)

127.0.0.1:6379> keys *  #查看所有的key
1) "name"
127.0.0.1:6379> get name  #获取key的值
"huge"
127.0.0.1:6379>  append name 'gege'  # 在key字符串后面拼接,如果没有相当于 set
(integer) 8
127.0.0.1:6379> get name
"hugegege"
127.0.0.1:6379> exists name  # 判断这个key是否存在
(integer) 1
127.0.0.1:6379> strlen name  # 获取这个key的值长度
(integer) 8
127.0.0.1:6379> append age 99  # 没有这个key的append相当于set
(integer) 2
127.0.0.1:6379> get age
"99"
#################################################################
# Java中的i++
# Java中i+=
127.0.0.1:6379> get name
"hugegege"
127.0.0.1:6379> get age
"99"
127.0.0.1:6379> append views 0 # 相当于set views 0
(integer) 1
127.0.0.1:6379> incr views  #自增长 1  i++
(integer) 1
127.0.0.1:6379> get views   #获取views的值 确实增加了1
"1"
127.0.0.1:6379> incr views  
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views # i--
(integer) 1
127.0.0.1:6379> get views  #
"1"
127.0.0.1:6379> incrby views 11  #步长增加  在原来基础上增加11
(integer) 12
127.0.0.1:6379> get views
"12"
127.0.0.1:6379> decrby views 4  #步长减少 在原有基础上减去 4
(integer) 8
127.0.0.1:6379> get views
"8"
127.0.0.1:6379> incr name   # 如果key的值不是integer则报错
(error) ERR value is not an integer or out of range
#############################################################################
#range
#字符串的范围
127.0.0.1:6379> get key1
"woshikey"
127.0.0.1:6379> getrange key1 1 6  # 截取字符窜【1,6】包含头尾
"oshike"
127.0.0.1:6379> getrange key1 3 -1 # 从下标3截取到最后
"hikey"
#替换
127.0.0.1:6379> get key2
"wshu"
127.0.0.1:6379> setrange key2 1 bu
(integer) 4
127.0.0.1:6379> get key2  #从指定位置开始替换  
"wbuu"
###############################################################################
# setex (set with expire) 设置过期时间
# setnx (set if not exist) 不存在再设置  ,在分布式锁中经常使用

127.0.0.1:6379> keys *  #
(empty array)
127.0.0.1:6379> setex name 12 huge # 设置name  ,有效时间12 秒
OK
127.0.0.1:6379> ttl name # 查看剩余有效时间
(integer) 8
127.0.0.1:6379> ttl name
(integer) 5
127.0.0.1:6379> keys *  # 查看所有key'
1) "name"
127.0.0.1:6379> ttl name 
(integer) -2
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set name huge # 设置name
OK
127.0.0.1:6379> get name  # 获取name
"huge"
127.0.0.1:6379> set name gg  # set name 没有就设置新的,有就覆盖
OK
127.0.0.1:6379> get name
"gg"
127.0.0.1:6379> setnx name wos  # 不存在name 就设置,存在就不变
(integer) 0
127.0.0.1:6379> get name
"gg"
127.0.0.1:6379> setnx age 22  # 不存在就设置age ,存在就不变
(integer) 1
127.0.0.1:6379> get age
"22"
############################################################################
#mset
#mget
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 批量操作同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "name"
4) "age"
5) "k1"
127.0.0.1:6379> mget k1 k2 k3 name # 批量获取,同时获取多个值
1) "v1"
2) "v2"
3) "v3"
4) "gg"
127.0.0.1:6379> mget k1 k4  #
1) "v1"
2) (nil)
127.0.0.1:6379> msetnx k2 v2 k4 v4 #不存在则set,这是一个原子性操作
(integer) 0
127.0.0.1:6379> 
########################################################################
#对象
127.0.0.1:6379> set user:1 {name:huage,age:11}
OK
127.0.0.1:6379> get user:1
"{name:huage,age:11}"
#巧妙的设计key  
127.0.0.1:6379> mset user:1:name huge  user:1:age 12
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "huge"
2) "12"
############################################################################
#getset 先get再set
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set name hu
OK
127.0.0.1:6379> getset name huge  #存在则返回,再设置
"hu"
127.0.0.1:6379> get name
"huge"
127.0.0.1:6379> getset name huzu 
"huge"
127.0.0.1:6379> get name
"huzu"

数据结构是相同,所有很多方法都存在。

String:的值可以是字符窜,也可以是数字,作为数字可以用来实现一些必要是统计

阅读量,粉丝数,点在数 等等

List

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oEltsbCA-1659370129148)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220508150504536.png)]

在Redis中list可以被玩成栈(先进后出)队列(先进先出)阻塞队列(两边都可以出)

#lpush放入数据,lrange取出数据  从列表的左边放入或取出数据
#这样操作是
127.0.0.1:6379> keys *  #获取当前库所有的key
1) "name"
127.0.0.1:6379> flushdb #清楚当前库所有的key
OK
127.0.0.1:6379> lpush list one  # 放入一个数据 从列表的左边放入
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1 # 从第0个开始,取出所有的数据
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 3  # 从第0个开始,取出到第三个数据,下标越界取出所有
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1  #先进后出,后进先出
1) "three"
2) "two"
###############################################################################
# rpush  从列表的尾部 右边放入数据  
127.0.0.1:6379> rpush list right
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
####################################################################################
# lpop从左边开始从list中移出
# Rpop从右边开始从list中移出
127.0.0.1:6379> keys *
1) "list"
127.0.0.1:6379> Lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> lpop list   # 从左边开始移出第一个
"three"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "right"
127.0.0.1:6379> lpop list 2  #从左边开始,同时移出两个
1) "two"
2) "one"
127.0.0.1:6379> lrange list 0 -1
1) "right"
127.0.0.1:6379> lpush list left
(integer) 2
127.0.0.1:6379> rpop list  # 从右边开始移出一个
"right"
127.0.0.1:6379> lrange list 0 -1
1) "left"
######################################################################################
# index 根据下标获取元素
127.0.0.1:6379> lpush list a b c  # 从左边开始同时放入多个参数
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "c"
2) "b"
3) "a"
4) "left"
127.0.0.1:6379> lrange list 0 -1  
1) "c"
2) "b"
3) "a"
4) "left"
127.0.0.1:6379> rpush list 1 2 3 4# 从右边开始同时放入多个参数
(integer) 8
127.0.0.1:6379> lrange list 0 -1
1) "c"
2) "b"
3) "a"
4) "left"
5) "1"
6) "2"
7) "3"
8) "4"
127.0.0.1:6379> keys *
1) "1"
2) "list"
127.0.0.1:6379> move 1 1 # 移出move key index 
(integer) 1
127.0.0.1:6379> keys * 
1) "list"
127.0.0.1:6379> lindex list 0 #按照下标获取list值 下标从0开始
"c"
127.0.0.1:6379> lindex list 10
(nil)
127.0.0.1:6379> lindex list 7
"4"
#########################################################################
#Llen
127.0.0.1:6379> keys *
1) "list"
127.0.0.1:6379> llen list  # Llen获取队列的长度
(integer) 8
##########################################################################
# Lrem 从左边开始移除指定数量的指定值,可以同时移除多个相同的值
127.0.0.1:6379> 
#move list 1  # 从Redis中移出这个key,list只有一个值的时候可以使用
(integer) 1
127.0.0.1:6379> lpush list 1 1 2 2 3 3 4 5  # 同时向list中放入多个值,值可以相同
(integer) 8
127.0.0.1:6379> lrange list 0 -1 # 查看所有值
1) "5"
2) "4"
3) "3"
4) "3"
5) "2"
6) "2"
7) "1"
8) "1"
127.0.0.1:6379> lrem list 1 1  # 从左边开始,移出一个值为 1 的值
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "4"
3) "3"
4) "3"
5) "2"
6) "2"
7) "1"
127.0.0.1:6379> lrem list 2 3  # 从左边开始,移除两个值为 3  的值
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "4"
3) "2"
4) "2"
5) "1"
#######################################################################################
# trim 按照下标截取并保存
127.0.0.1:6379> lrange list 0 -1
1) "li4"
2) "li3"
3) "li2"
4) "li1"
5) "1"
127.0.0.1:6379> ltrim list 1 3 # 截取下标1 到 3 的值并保存到当前list
OK
127.0.0.1:6379> lrange list 0 -1 
1) "li3"
2) "li2"
3) "li1"
##################################################################################
#rpoplpush  移除最后面一个值放到下一个list中
127.0.0.1:6379> lpush list li1 li2 li3
(integer) 3
127.0.0.1:6379> lpush mylist my1 my2 my3
(integer) 3
127.0.0.1:6379> rpoplpush list mylist # 移出最后放入的值放入后后一个list中
"li1"
127.0.0.1:6379> lrange list 0 -1
1) "li3"
2) "li2"
127.0.0.1:6379> lrange mylist 0 -1
1) "li1"
2) "my3"
3) "my2"
4) "my1"
#################################################################################
#lset 将列表中指定下标的值更新为新的值
127.0.0.1:6379> lset list 2 line  #下标越界则报错
(error) ERR index out of range
127.0.0.1:6379> lset list 1 line # 将下标为1的值更新
OK
127.0.0.1:6379> lrange list 0 -1
1) "li2"
2) "line"
127.0.0.1:6379> 
##################################################################################
#linset  向列表中插入值
127.0.0.1:6379> lrange list 0 -1
1) "li2"
2) "li1"
3) "li1"
4) "li"
127.0.0.1:6379> linsert list before li1 li1b  # 向指定值前面插入,有相同值则选择第一个
(integer) 5
127.0.0.1:6379> linsert list after li1 li1f # 向指定值后面插入,有相同值则选择第一个
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "li2"
2) "li1b"
3) "li1"
4) "li1f"
5) "li1"
6) "li"

总结

1.世界上list是一个链表,可以通过before,after,left,right都可以插入值

2.如果key不存在则创建新的链表

3.如果key以存在则新增内容

4.如果移除所有的值,则一个空链表会消失

5.从两边插入或者修改值效率高,从中间处理元素效率相对较慢

set

Set中的值是不可以重复的

#
127.0.0.1:6379> sadd set hello helloWorld #sadd 向某个key中添加多个值
(integer) 2
127.0.0.1:6379> sadd set helloKuan  #
(integer) 1
127.0.0.1:6379> Smembers set  #smembers 获取set中的所有值
1) "helloWorld"
2) "helloKuan"
3) "hello"
127.0.0.1:6379> sismember set hello #sismember 判断某个set中是否包含某个值
(integer) 1
127.0.0.1:6379> 
#############################################################################
127.0.0.1:6379> scard set  # scard 获取set中元素个数
(integer) 3
#############################################################################
rem 移除某个元素
127.0.0.1:6379> smembers set #查看set集合下的所有元素
1) "helloWorld"
2) "helloKuan"
3) "hello"
127.0.0.1:6379> srem set hello # 移除一个元素
(integer) 1
127.0.0.1:6379> smembers set 
1) "helloWorld"
2) "helloKuan"
####################################################################################
srandmember 随机获取一个数
127.0.0.1:6379> smembers set  #查看所有的元素
1) "helloWorld"
2) "helloDage"
3) "lovekuangs"
4) "helloKuan"
5) "hello"
6) "helloKuangshen"
127.0.0.1:6379> srandmember set #随机查看一个元素
"lovekuangs"
127.0.0.1:6379> srandmember set
"helloKuan"
127.0.0.1:6379> srandmember set 2 #随机查看多个元素
1) "hello"
2) "lovekuangs"
127.0.0.1:6379> 
#####################################################################################
spop  随机从set中移除一个元素
127.0.0.1:6379> smembers set
1) "helloWorld"
2) "helloDage"
3) "lovekuangs"
4) "helloKuan"
5) "hello"
6) "helloKuangshen"
127.0.0.1:6379> spop set   # 从set中随机移除一个元素
"lovekuangs"
127.0.0.1:6379> spop set
"helloKuangshen"
127.0.0.1:6379> smembers set
1) "helloWorld"
2) "helloDage"
3) "helloKuan"
4) "hello"
127.0.0.1:6379> spop set 2 # 从set中随机移除多个元素
1) "hello"
2) "helloDage"
127.0.0.1:6379> smembers set
1) "helloWorld"
2) "helloKuan"
127.0.0.1:6379> 
############################################################################
smove 
127.0.0.1:6379> smove set set2 helloWorld  #将一个set中的某个元素移动到另外要给set中
(integer) 1
127.0.0.1:6379> smembers set2
1) "helloWorld"
2) "hello"
3) "set2"
###########################################################################
-差集
-交集  比如微博中的共同关注
-并集
127.0.0.1:6379> sadd key1 a b c #向set中添加多个元素
(integer) 3
127.0.0.1:6379> sadd key2 c d e
(integer) 3
127.0.0.1:6379> sdiff key1 key2 #获取两个set中,第一个相比第二个的差集
1) "a"
2) "b"
127.0.0.1:6379> sinter key1 key2 # 获取两个set中的相同元素
1) "c"
127.0.0.1:6379> sunion key1 key2 #获取两个set中的共同元素
1) "a"
2) "c"
3) "d"
4) "b"
5) "e"
可以用户共同好友,共同关注,相同爱好。。。。。。。。。。。。。。。。。。。。

Hash(哈希)

Map集合,key-map时候这个值是一个map集合,本质和String类型没有太大区别,还是一个简单的key-value

127.0.0.1:6379> hset user name huge age 11 #set 一个或者多个key-value
(integer) 2
127.0.0.1:6379> hmset user address suzhou genger boy # set 一个或者多个
OK
127.0.0.1:6379> hget user name # 获取hash下要给key
"huge"
127.0.0.1:6379> hmget user name age address genger  #获取hash下多个key
1) "huge"
2) "11"
3) "suzhou"
4) "boy"
127.0.0.1:6379> hgetall user  #获取hash下所有的key-value
1) "name"
2) "huge"
3) "age"
4) "11"
5) "address"
6) "suzhou"
7) "genger"
8) "boy"
127.0.0.1:6379> hdel user age #删除指定hash中指定key
(integer) 1
127.0.0.1:6379> hgetall user
1) "name"
2) "huge"
3) "address"
4) "suzhou
#######################################################################################
hlen
127.0.0.1:6379> hlen user #获取指定hash的元素数量
(integer) 3
#########################################################################################
hexists
127.0.0.1:6379> hexists user ss # 判断指定hash中指定key是否存在
(integer) 0
127.0.0.1:6379> hexists user name
(integer) 1
######################################################################################
#只获取所有的keys
#只获取所有的values
127.0.0.1:6379> hgetall user
1) "name"
2) "huge"
3) "address"
4) "suzhou"
127.0.0.1:6379> hkeys user # 获取所有的key
1) "name"
2) "address"
127.0.0.1:6379> hvals user # 获取所有的values
1) "huge"
2) "suzhou"
########################################################################################
incr
127.0.0.1:6379> hgetall user
1) "name"
2) "huge"
3) "address"
4) "suzhou"
5) "age"
6) "12"
127.0.0.1:6379> hincrby user age 1 #指定hash指定key增加指定值
(integer) 13
127.0.0.1:6379> hget user age
"13"
127.0.0.1:6379> hsetnx user gender 1 # 不存在就增加个key-value
(integer) 1
127.0.0.1:6379> hsetnx user gender 2
(integer) 0
127.0.0.1:6379> hgetall user
1) "name"
2) "huge"
3) "address"
4) "suzhou"
5) "age"
6) "13"
7) "gender"
8) "1"

hash特别适用于对象的存储。尤其是经常变动的信息。String更加适合用字符窜

Zset(有序的set)

在set的基础上增加一个值,set v1, zset score v2

127.0.0.1:6379> zadd myz 0 zo # 添加一个元素
(integer) 1
127.0.0.1:6379> zadd myz 1 z1 2 z2 #添加多个元素
(integer) 2
127.0.0.1:6379> zrange myz 0 -1
1) "zo"
2) "z1"
3) "z2
################################################################################
zrangebyscore
127.0.0.1:6379> zadd salary 2000 huge 3000 wenge 4000 muge 500 nige#添加多个元素
(integer) 4
127.0.0.1:6379> zrangebyscore salary -inf +inf  # 从小到大排序值
1) "nige"
2) "huge"
3) "wenge"
4) "muge"
127.0.0.1:6379> zrangebyscore salary -inf 4000 withscores #从无穷小到4000按照score排序,展示值和scores
1) "nige"
2) "500"
3) "huge"
4) "2000"
5) "wenge"
6) "3000"
7) "muge"
8) "4000"
127.0.0.1:6379> zrangebyscore salary 550 3500 withscores #从550到3500排序
1) "huge"
2) "2000"
3) "wenge"
4) "3000"

127.0.0.1:6379> zrange salary 0 -1 withscores#zrange 默认从小到大
 1) "lige"
 2) "300"
 3) "huge"
 4) "2000"
 5) "wenge"
 6) "3000"
 7) "muge"
 8) "4000"
 9) "gaoge"
10) "4200"
127.0.0.1:6379> zrevrange salary 0 -1 withscores # zrevrange默认从大到小
 1) "gaoge"
 2) "4200"
 3) "muge"
 4) "4000"
 5) "wenge"
 6) "3000"
 7) "huge"
 8) "2000"
 9) "lige"
10) "300"
####################################################################################
rem  移除元素
127.0.0.1:6379> zrange salary 0 -1
1) "nige"
2) "huge"
3) "wenge"
4) "muge"
127.0.0.1:6379> zrem salary nige  #移除一个nige的元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "huge"
2) "wenge"
3) "muge"
################################################################################
zcard 获取数量
127.0.0.1:6379> zcard salary
(integer) 3
zcount 获取范围内的数量
127.0.0.1:6379> zrange salary 0 -1 withScores #正序查询所有
 1) "lige"
 2) "300"
 3) "huge"
 4) "2000"
 5) "wenge"
 6) "3000"
 7) "muge"
 8) "4000"
 9) "gaoge"
10) "4200"
127.0.0.1:6379> zcount salary 2000 4199 # 查询Score在两个值之间的数量
(integer) 3

其余的所有api,还有很多,如果工作中需要,可以根据官方文档来查找。

三种特殊数据类型

geospatial地理位置

朋友圈定位,附近的人,打车距离计算

Redis的Geo在Redis3.2版本就推出了,这个功能可以推算地理位置的信息,两地之间距离,方圆几里的人

可以查询测试一些数据:

只有六个命令:

geoadd

#向chia:city中添加地理位置
#可以从网上下载位置,导入到redis中
#经纬度有范围限制,如果错误了超出范围则报错
127.0.0.1:6379> geoadd china:city 116.41667 39.91667 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.43333 34.50000 shanghai  117.20000 39.13333 tianjing
(integer) 2
127.0.0.1:6379> geoadd china:city 113.23333 23.16667 guangzhou 113.51667 22.30000 zhuhai
(integer) 2

geopos

#获取某个地区的地理位置
127.0.0.1:6379> geopos china:city beijing guangzhou  #获取某个地区的精度和纬度
1) 1) "116.41667157411575317"
   2) "39.91667095273589183"
2) 1) "113.23332935571670532"
   2) "23.16667082372672581"

geodist

#获取两个地区之间的直线距离
127.0.0.1:6379> geodist china:city beijing shanghai  #两个城市的距离 默认单位米
"748346.9287"
127.0.0.1:6379> geodist china:city beijing shanghai km #两个城市距离,单位米
"748.3469"

georadius

#获取当前位置方圆xxx范围内的城市
#georadius key 经纬度  距离  单位  经纬度  直线距离  count  数量
127.0.0.1:6379> georadius china:city 110 35 1000 km 
1) "tianjing"
2) "beijing"
127.0.0.1:6379> georadius china:city 110 35 1000 km withcoord
1) 1) "tianjing"
   2) 1) "117.19999998807907104"
      2) "39.13333058676914078"
2) 1) "beijing"
   2) 1) "116.41667157411575317"
      2) "39.91667095273589183"
127.0.0.1:6379> georadius china:city 110 35 1000 km withcoord withdist
1) 1) "tianjing"
   2) "786.7743"
   3) 1) "117.19999998807907104"
      2) "39.13333058676914078"
2) 1) "beijing"
   2) "786.9892"
   3) 1) "116.41667157411575317"
      2) "39.91667095273589183"
127.0.0.1:6379> georadius china:city 110 35 1000 km withcoord withdist count 1
1) 1) "tianjing"
   2) "786.7743"
   3) 1) "117.19999998807907104"
      2) "39.13333058676914078"
127.0.0.1:6379> 

georadiusbymember

#以某个成员为中心,方圆一定范围内的其他元素
# georadiusbymember key 中心城市 距离 单位 经纬度  距离
127.0.0.1:6379> georadiusbymember china:city guangzhou 1000 km withcoord withdist
1) 1) "zhuhai"
   2) "100.6836"
   3) 1) "113.51667255163192749"
      2) "22.29999896492555678"
2) 1) "guangzhou"
   2) "0.0000"
   3) 1) "113.23332935571670532"
      2) "23.16667082372672581"


127.0.0.1:6379> georadiusbymember china:city guangzhou 1000 km 
1) "zhuhai"
2) "guangzhou"

geohash

#将经纬度转换为11位的hash值
127.0.0.1:6379> geohash china:city guangzhou
1) "ws0eb9mgxu0"
127.0.0.1:6379> geohash china:city guangzhou beijing
1) "ws0eb9mgxu0"
2) "wx4g14s53n0"

GEO的底层实现其实是set,可以通过一些set的命令执行GEO

127.0.0.1:6379> zrange china:city 0 -1 #查询所有的城市
1) "zhuhai"
2) "guangzhou"
3) "shanghai"
4) "tianjing"
5) "beijing"
127.0.0.1:6379> zrem china:city zhuhai #移除一个城市
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "guangzhou"
2) "shanghai"
3) "tianjing"
4) "beijing"

Hyperloglog

Redis 2.8.9版本就更新了Hyperloglog数据结构!

Redis Hyperloglog技术统计的算法。

优点:占用内存是固定的,2^64不同的元素技术,只需要12kb内存,如果要从内存角度来比较,Hyperloglog是首选。

网页的UV(访问量,一个人访问一个网站多次,算作一个人)

传统的方式,set保存用户的id,然后就可以统计set元素数量

这个方法如果保存大量的用户id,就会比较麻烦,我们的目的是为了统计,而不是保存用户id。

Hyperloglog 统计,存在0.81%的错误率,

127.0.0.1:6379> pfadd key1 a b c d de fg hi j k #创建第一组元素
(integer) 1
127.0.0.1:6379> pfcount key1  #统计第一组元素数量
(integer) 9
127.0.0.1:6379> pfadd key2 l m no p q rs t uv #创建第二组元素
(integer) 1
127.0.0.1:6379> pfcount key2  #统计第二组元素
(integer) 8
127.0.0.1:6379> pfmerge key3 key1 key2  #合并两组元素
OK
127.0.0.1:6379> pfcount key3  #统计合并后的元素数量
(integer) 17

如果允许误差的统计,那么就可以使用Hyperloglog

如果不允许误差的统计,那么就可以使用set,或者自己设定数据类型。

Bitmap

位存储

只要是统计只有两个状态的数据,就可以通过位存储来实现,比如:登陆未登陆,活跃不活跃,打卡未打卡,

Bitmaps位图数据结构,通过操作二进制位来进行记录,就只有0,1 两种状态。

测试,统计一周中打卡


127.0.0.1:6379> setbit wk 0 0  #给第一个位fu'zhi
(integer) 0
127.0.0.1:6379> setbit wk 1 1
(integer) 0
127.0.0.1:6379> setbit wk 2 1
(integer) 0
#统计某一天是否打卡
127.0.0.1:6379> getbit wk 2
(integer) 1
127.0.0.1:6379> setbit wk 3 1 
(integer) 0
127.0.0.1:6379> setbit wk 4 0
(integer) 0
127.0.0.1:6379> setbit wk 4 1
(integer) 0
#统计一周总打卡
127.0.0.1:6379> bitcount wk
(integer) 4

?????????????、?如果是在一定范围内的统计,好像是有问题不会用。

事务

Redis事务的本质:一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行过程中,顺序执行。

一次性(一次执行完毕),顺序性(按顺序执行),排他性(不可以被打断)执行命令。

—队列 set set set 执行—

所有命令在事务中,并没有被执行,只有在发起执行命令后才被执行。

Redis事务:

开启事务:multi

命令入队:

执行事务:exec

有时候会用到锁。

Redis 的单条命令是保证原子性的,但是一个事务是不保证原子性的。

执行一个事务

127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379(TX)> set k1 v1  # 命令入队
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3 
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> exec  #执行事务
1) OK
2) OK
3) OK
4) "v1"

取消一个事务

127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379(TX)> set k1 v1  #消息入队
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> discard #取消事务
OK
127.0.0.1:6379> exec      #执行事务会报错,因为事务已经取消
(error) ERR EXEC without MULTI

编译异常,所有命令都不会执行(相当于代码有问题,写完就看出来错误)

OK
127.0.0.1:6379> multi   #开启事务
OK
127.0.0.1:6379(TX)> set k1 1  #加入队列
QUEUED
127.0.0.1:6379(TX)> set k2 2
QUEUED
127.0.0.1:6379(TX)> set k3   #命令错误
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> set k4 4
QUEUED
127.0.0.1:6379(TX)> exec  #执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1  #所有命令都么有执行
(nil)
127.0.0.1:6379> get k4

事务执行时报错,除了报错的命令,不影响其他事务命令执行,事务执行不存在原子性问题

127.0.0.1:6379> multi  #开始事务
OK
127.0.0.1:6379(TX)> set k1 2  #加入队列
QUEUED
127.0.0.1:6379(TX)> set k2 k
QUEUED
127.0.0.1:6379(TX)> incr k2
QUEUED
127.0.0.1:6379(TX)> incr k1
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) (error) ERR value is not an integer or out of range #自增长报错
4) (integer) 3  #自增长
5) "3"   #  正常执行
6) "k"

监控 watch

悲观锁

? 很悲观,认为做什么都会出问题,所以做什么都加锁

乐观锁

? 很乐观,认为做什么都不会出问题,多以不会枷锁。在更新新数据的时候判断以下, 在此期间有没有人修改过数据。

获取version

更新的时候比较version

正常执行

27.0.0.1:6379> watch mony  #监控mony
OK
127.0.0.1:6379> multi  #事务
OK
127.0.0.1:6379(TX)> decrby mony 11
QUEUED
127.0.0.1:6379(TX)> incrby out 11
QUEUED
127.0.0.1:6379(TX)> exec  #执行事务
1) (integer) 79
2) (integer) 21

未正常执行

OK
127.0.0.1:6379> watch mony #监控mony
OK
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379(TX)> decrby mony 11
QUEUED
127.0.0.1:6379(TX)> incrby out 11
QUEUED
127.0.0.1:6379(TX)> exec  #执行失败
(nil)

#这个时候需要停止监控,重新获取version再进行接下来操作
127.0.0.1:6379> unwatch  #停止监控
OK
127.0.0.1:6379> watch mony #监控金额
OK
127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379(TX)> decrby mony 15
QUEUED
127.0.0.1:6379(TX)> incrby out 15
QUEUED
127.0.0.1:6379(TX)> exec  #事务正常执行
1) (integer) 75
2) (integer) 16

Jedis

用jedis来操作redis,这是最开始的操作redis的方法,方法名和Linux命令类似

<!--导入redis依赖-->
    <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!--导入fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.80</version>
        </dependency>
    </dependencies>
  public static void main(String[] args) {
       Jedis jedis = new Jedis("127.0.0.1",6379);
        System.out.println(jedis.ping());
       jedis.set("name","胡歌");
       
    }

输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gj6sIACS-1659370129149)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220516222811334.png)]

所有的API命令就是上面的linux命令,就是这么操作。

事务:

{
       Jedis jedis = new Jedis("127.0.0.1",6379);
        jedis.flushDB();
      Transaction transaction =jedis.multi();//开启事务

        try{
        transaction.set("user1","user");  //注意使用事务对象操作
        transaction.set("user2","user2");
        int s =1/0;
        transaction.exec();}
        catch (Exception e){
            transaction.discard();
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();
        }



    }

SpringBoot 整合Redis

springBoot操作数据库:spring-data jpa jdbc mongodb redis

SpringData 也是和springBoot 齐名项目

说明:在spingBoot2.0后,原来的jedis被换成了,lettuce

jedis:采用的是直连,多个线程同时操作的话存在不安全,想要安全,需要引入jedis ,pool 连接池。

lettuce:采用netty,实例可以采用多线程共享,不存在安全问题

整合测试

//配置类
@ConfigurationProperties(
    prefix = "spring.redis" //表示配置文件以这个开头
)
public class RedisProperties {
    private int database = 0;
    private String url;
    private String host = "localhost";
    private String username;
    private String password;
    private int port = 6379;
    private boolean ssl;
    private Duration timeout;
    private Duration connectTimeout;
    private String clientName;
    private RedisProperties.ClientType clientType;
    private RedisProperties.Sentinel sentinel;
    private RedisProperties.Cluster cluster;
    private final RedisProperties.Jedis jedis = new RedisProperties.Jedis();
    private final RedisProperties.Lettuce lettuce = new RedisProperties.Lettuce();


    
   //自动装配的类
@Bean
    @ConditionalOnMissingBean( name = {"redisTemplate"})//没有则生效,表示我们可以自己写一个替换
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        //默认的RedisTemplate,没有过多的设置,Redis需要序列化操作
        //两个泛型都是Object类型,我们后面使用需要强制转换为<Sting,Object>
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean//由于String类型是我们经常使用的,所以单独提炼出来要给Bean
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        return new StringRedisTemplate(redisConnectionFactory);
    }
# prefix = "spring.redis" //表示配置文件以这个开头
spring.redis.host=127.0.0.1
spring.redis.port=6379

导入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

测试:s

	 //redisTemplate 操作不同数据类型,api和我们的指令是相同的
        //opsForValue 操作字符串,类似String
        //opsForList 操作list类似list
        //opsForSet
        //opsForHash
        //opsForSet
        //opsForGeo
        //opsForHyperLogLog

        redisTemplate.opsForValue().set("redis","关注狂神")
            //通过不同的ops对象,操作不同的数据类型
       String str =(String) redisTemplate.opsForValue().get("redis");
        System.out.println(str);
 		//通过连接操作数据库
        RedisConnection collection =redisTemplate.getConnectionFactory().getConnection();
        collection.flushDb();

当我们需要在redis中传入一个对象的时候,虽然value值是一个Object,但是实际使用中,需要将对象进行序列化处理。

没有做序列化处理的时候,报错,没有进行序列化处理。

//没有做序列化处理的对象
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GUNxGLEK-1659370129150)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220517233837824.png)]

需要一个序列化对象1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pQ3nWg50-1659370129151)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220517234046890.png)]

//实现Serializable 序列化处理
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User implements Serializable {
    private String name;
    private int age;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sENfAPM9-1659370129152)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220517234428789.png)]

自定义RedisTemplate待添加


@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 我们为了自己开发方便,一般直接使用 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        // Json序列化配置
        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);
        // String 的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

RedisConf配置文件介绍

单位

启动的时候,通过配置文件,unit单位对大小写不敏感

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mpXUqoxl-1659370129153)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220518221015305.png)]

包含

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LuUnyzQB-1659370129154)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220518221331429.png)]

可以将多个配置文件包含到这一个配置文件中,就像学习spring中的xml文件使用import

网络

bind 127.0.0.1 -::1   #绑定的id,默认本地连接,可以修改
protected-mode yes     #保护模式
port 6379             #启动端口号,集群需要修改端口号
timeout  0             #超时 ,0表示永久有效

通用 GENERAL

daemonize yes  #以守护线程方式运行,后台运行,默认是 no  需要改成yes.
pidfile /var/run/redis_6379.pid # 如果以守护线程方式运行,就需要指定一个pid的进程文件

#日志
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)//debug 开发和测试
# verbose (many rarely useful info, but not a mess like the debug level)//大量,类似debug
# notice (moderately verbose, what you want in production probably)//通知性质的日志
# warning (only very important / critical messages are logged)//重要关键的信息才打印
loglevel notice
logfile ""     #日志的文件名,为空则是标准的日志输出
databases 16     #数据库数量 默认是16个

always-show-logo no# 是否显示启动的logo,

快照

#在规定的时间内,执行了多少次操作,进行持久化的操作,保存到.rdb .aof文件
#Redsi是内存数据库,断电即失。
# save ""
#
# Unless specified otherwise, by default Redis will save the DB:
#   * After 3600 seconds (an hour) if at least 1 change was performed
#   * After 300 seconds (5 minutes) if at least 100 changes were performed
#   * After 60 seconds if at least 10000 changes were performed
#
# You can set these explicitly by uncommenting the following line.
#
# save 3600 1 300 100 60 10000


stop-writes-on-bgsave-error yes # 持久化失败是否继续工作,默认  yes
rdbcompression yes    # 是否压缩 rdb文件。消耗cpu资源,默认开启
rdbchecksum yes          #保存rdb文件,是否进行错误校验
dbfilename dump.rdb         #rdb文件名
dir ./                        #rdb文件的保存目录

REPLICATION 主从复制,后面讲解

SECURITY 安全

#设置密码
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass "123456"
OK
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> 

#登陆
127.0.0.1:6379> ping
(error) NOAUTH Authentication required.
127.0.0.1:6379> 
127.0.0.1:6379> auth "123456"  使用密码登陆
OK
127.0.0.1:6379> ping
PONG

限制CLIENTS

maxclients 10000  #限制最大的客户端数
maxmemory <bytes> # Redis最大内存,单位是bytes
maxmemory-policy noeviction #内存满了之后的处理策略      删除过期key,报错

1、volatile-lru:只对设置了过期时间的key进行LRU算法进行删除
2、allkeys-lru : 对所有key执行LRU算法进行删除
3、volatile-lfu:只对设置了过期时间的key进行LFU算法进行删除
4、allkeys-lfu:对所有key执行LFU算法进行删除
5、volatile-random:随机删除设置有过期时间的key
6、allkeys-random:随机删除
7、volatile-ttl : 删除即将过期的
8、noeviction : 永不过期,返回错误

 

APPEND ONLY MODE 模式 aof配置

appendonly no    # 默认是不开启 aof模式,使用rdb

appendfilename "appendonly.aof"  #aof持久化文件名

# appendfsync always  #每修改一次,执行一次sync 消耗性能
appendfsync everysec  #每秒执行一次sync,可能丢失1s数据
# appendfsync no       # 不执行sync,操作系统自己执行,效率最高

Redis持久化

RDB Redis DataBase

Redis是内存数据库,断电即失,需要将内存文件持久化到磁盘中,

RDB Redis DataBase

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DVZtrqE2-1659370129155)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220519000047535.png)]

在指定的时间间隔内,将内存中的数据集体的写入到磁盘中,也就是快照,在恢复的时候将快照文件直接读到内存中。

Redis会单独创建fork一个子进程来持久化,会将数据写到一个临时文件中,待持久化过程都结束了,就用这个临时文件替换上次的持久化文件。整个过程,主进程不会进行IO操作,这就确保了极高的性能。如果需要进行大规模的数据恢复,且对数据恢复的完整性不是很敏感,那么RDB方式比AOF方式更高效,RDB的缺点是最后一次持久化会丢失数据。 默认rdb文件配置,不用修改

rdb保存的文件是dump.rdb

触发机制

1.满足rdb的save规则,自动生成文件

2.执行flushall命令,也会触发生成文件

3.默认退出redis的时候,会生成文件

备份生成rdb文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UZTOOdTG-1659370129156)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220519232608983.png)]

如何恢复rdb文件

1.只要将rdb文件放在redis启动目录下面,启动redis的时候,就会自动检擦读取rdb文件,恢复其中的数据

2.查看rdb文件需要存放的位置

127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin"
127.0.0.1:6379> 

正常情况下默认配置就够用了,但是我们需要学习其原理

优点:

1.适合大规模数据备份

2.对数据的完整性要求不是太高

缺点

1。保存备份需要时间间隔,如果此时宕机了,数据就会丢失

2.fork进程会占用一定的内容空间。

AOF append only file

将所有的命令都记录下来,恢复到适合将这些命令再执行一遍

? [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G1zoCnYf-1659370129156)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220519234019423.png)]

以日志的形式记录每一个写操作,将redis执行的所有写操作都记录下来(读操作不记录),只许追加文件不可以修改文件,reids启动的时候,会读取这个文件重新构造数据库,就是将日志中的所有命令都执行一遍以恢复数据

AOF 保存的文件:appendonly.aof

APPEND ONLY MODE

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rpA6dg2S-1659370129157)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220519234814321.png)]

默认是关闭的,修改成yes就可以

# appendfsync always  #每一次都记录
appendfsync everysec  #每一秒都记录
# appendfsync no       #不修改

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FD60t4Uy-1659370129158)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220520000839172.png)]

一个是生成的文件名,一个是再redis启动目录下的文件夹名。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Zke9jA3-1659370129160)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220520001105072.png)]

保存文件后,重启reids就可以生效了

修改aof生效的配置文件,需要重启redis,保证aop文件的存在,才能保存命令

如果aof文件发生了损坏,则无法启动reids,需要通过文件redis-check-aof来修复

文件修复

redis-check-aof --fic **.aof

修复文件后,可以正常启动Redis

Redis发布订阅

Redis发布订阅(pub/sub)是一种消息通讯模式:发送者发送消息,订阅者接收消息。微信,微博,关注系统!

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

订阅/发布消息图:

第一个:消息发送者,第二个:频道 第三个:消息订阅者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PrUCY6Tl-1659370129161)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220522231818364.png)]

下面是频道channel1和订阅这个频道的三个用户之间关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PB1JodW8-1659370129161)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220522233439607.png)]

当有消息通过命令publis发送到频道channel1时,就会发送给三个订阅者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PjCYbQUL-1659370129162)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220522233551056.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sYERFyVl-1659370129163)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220522233849410.png)]

测试

127.0.0.1:6379> subscribe kuangshen   #订阅的命令  订阅的频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "kuangshen"
3) (integer) 1
1) "message"
2) "kuangshen"
3) "hello \xbf\xf1\xc9\xf1"
1) "message"
2) "kuangshen"
3) "hello kuangshen"
1) "message"              #接收到的消息
2) "kuangshen"           # 消息来自的频道
3) "hello redis"           #消息内容d
publish kuangshen 'hello redis' #消息发送命令  发送消息的频道  消息内容
(integer) 1

此处选用添加用java代码实现的频道订阅

知道了发布订阅功能的相关命令后,下面来看一下各个命令底层的实现原理。总体来说,发布和订阅功能相关的状态都保存在RedisServer中的pubsub_channels和pattern两个字段中:

struct redisServer{
// …

dict *pubsub_channels; // 保存所有订阅的频道关系
list *pattern;         // 保存所有订阅的频道的匹配模式

// ....

其中dict类型的pubsub_channels保存所有订阅的频道关系,key就是对应的频道名,value就是所有订阅该频道的客户端。由于订阅频道的客户端可能有多个,这里采用了链表的形式进行保存。如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Op0W8ScV-1659370129164)(C:\Users\Administrator\Desktop\20201027101917468.png)]

当客户端订阅某个频道时,如果pubsub_channels中已经有了该频道名,说明该频道已经有订阅者,将其直接添加到订阅者链表的尾部即可。如果pubsub_channels并没有指定的频道名,需要先将频道添加到pubsub_channels中,然后该客户端作为链表的头节点存在。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xvSIdORY-1659370129164)(C:\Users\Administrator\Desktop\2020102710192453.png)]

退订频道和订阅频道的动作相反,如果某个客户端想要退订某个频道,服务器会遍历pubsub_channels,找到对应频道的订阅者链表,将其从链表中删除。此外,如果该客户端是这个频道的唯一订阅者,删除订阅者后,还需要将该频道从pubsub_channels中删除。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gu6kp7mZ-1659370129165)(C:\Users\Administrator\Desktop\20201027101931368.png)]

Redis主从复制

主从复制,是指将一台Redis服务器上的数据复制到其他服务器,前者称为主节点,后者成为从节点;数据的复制是单向的,只能从主节点复制到从节点。主节点以写为主,从节点以读为主。

默认情况下,每一个服务器都是主节点,且一个主节点可以有多个从节点,一个从节点只能有一个主节点。

主从复制的主要作用

1.数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

2.故障恢复:当主节点出现故障时,可以由从节点提供服务,实现故障的快速修复;实际也是一种服务的冗余。

3.负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,(写Reids数据时连接主节点,读Redis数据时连接从节点),分担服务器负载;尤其是在写少读多的情况下,通过多个节点分担读负载,可以大大提高Redis服务器的并发量。

4.高可用(集群)基石:除了上述作用,主从复制还是哨兵和集群的基石,因此说主从复制是Redis高可用的基石。

一般来说,要将Redis用到项目中,一台Redis是万万不够的。原因如下:

1。从结构上,一台服务器发生单点故障,并且一台服务器处理所有的请求负载,压力过大。

2。从容量上,单个Redis服务器容量有限,就算一台服务器256G,也不能都用作Redis内存。一般来说,一台Redis的最大使用内存不超过20G。

比如一般的电商网站,都是一次上传,无数次的浏览,就是多读写少。

对于这种场景,我们可以使用以下架构。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D4W1Zj8R-1659370129166)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220523225909575.png)]

主从复制,读写分离,80%都在进行读操作,减缓服务器压力,架构中经常使用,一主二从

环境配置

127.0.0.1:6379> info replication   #查看当前库的细腻
# Replication
role:master   					#角色  master
connected_slaves:0              #没有从机
master_failover_state:no-failover
master_replid:240b4dca074dfd2a2d6976aa02dff6adc681478c
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

复制三个配置文件,修改以下配置:

1.端口 2.pid文件名 3.日志文件名 4.rdb文件名

根据配置文件启动三个服务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pT1O62dw-1659370129167)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220524000046395.png)]

一主二从

默认情况下每一台机器都是主机 :我们著需要配置从机

配置从机的方式,认老大

127.0.0.1:6380> SLAVEOF 127.0.0.1 6379   #  命令  IP  端口
OK
127.0.0.1:6380> info replication
# Replication
role:slave                             #当前角色
master_host:127.0.0.1                   #主机信息
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_read_repl_offset:14
slave_repl_offset:14
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:c09d97db61c0e6812c4bb076277c5561f3277eb1
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14
127.0.0.1:6380> 
127.0.0.1:6379> info replication    #查看主机信息
# Replication
role:master                        #主机
connected_slaves:2					#从机信息
slave0:ip=127.0.0.1,port=6380,state=online,offset=224,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=224,lag=1
master_failover_state:no-failover
master_replid:c09d97db61c0e6812c4bb076277c5561f3277eb1
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:224
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:224
127.0.0.1:6379> 

真实的主从配置都是在配置文件中完成,这样的配置是永久的,命令的配置是暂时的

细节

主机可以写,从机只能读取内容,主机的内容会被复制到从机。

在主机写入的数据,在从机可以读取。在从机写入则会报错:

127.0.0.1:6381> get k1
"v1"
127.0.0.1:6381> set k2 v2
(error) READONLY You can't write against a read only replica.
127.0.0.1:6381> 

测试:主机断开后,从机依然是连接到主机的从机,只有读操作没有写操作,主机回来后继续可以读取主机内容。

如果是使用命令行来配置的主从,从机断开后,这个时候重启从机,那么会变回主机。(配置文件永久)

只要变成从机,立马可以读取主机数据。

全量复制:第一次连接主机后,会将全部数据同步到从机

增量复制:连接过程中的同步为增量复制。

层层主从

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yS2RQCMi-1659370129168)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220524230625465.png)]

上一个从节点是下一个主节点,这样也可以实现主从复制

如果主节点宕机了,这个时候怎么选择一个主节点? 手动

谋朝篡位

根据命令实现:SLAVEOF no one

127.0.0.1:6380> SLAVEOF no one  #将从节点修改为主节点
OK
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:8ffaf32b5a5839e27120e4ee33e7ed80026700d0
master_replid2:c09d97db61c0e6812c4bb076277c5561f3277eb1
master_repl_offset:115286
second_repl_offset:115287
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_his

如果这个时候,上一个主节点回来了,已经是光杆司令了,需要从新执行命令才能层层主从。

哨兵模式

概述

主从切换的方法,当我们的主服务器宕机之后,需要我们手动选择一个从服务器切换成主服务器,费时费力,还有可能造成一段时间的的服务不可用。这个是不推荐的,在Redis2.8过后,就有了哨兵模式,自动监控切换。

哨兵模式,监控后台主机是否宕机,如果主机故障了,则通过投票的方式,选择一台从机设置为主机。

哨兵模式,是一种特殊的模式,首先Redis提供了命令,哨兵是一个独立的进程,作为进程会独立运行。

原理:哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zUEHjxsU-1659370129169)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220524234714568.png)]

这里哨兵的作用:

1。通过发送命令,让Redis服务器返回其监控其运行状态,包括主机和从机

2。当哨兵发现master宕机了,会自动将slave切换为master,然后通过 发布订阅模式通知其他从服务器,修改配置,更改主机.

然而一个哨兵进程对Redis服务器进行监控可能会出现问题,因此可以使用多个哨兵进行监控,各个哨兵之间也可以监控,形成多哨兵模式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GhMXkOTF-1659370129170)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220524235255196.png)]

如果主服务器宕机,哨兵1先发现了这个结果,这个时候不会立刻进行failover过程,仅仅是哨兵1主观的认为服务器不可以用,这种现象称为主观下线。当后面的哨兵也检测到这种现象,数量达到一定值的时候,那么哨兵之间就会进行一次投票,投票结果由一个哨兵发起执行failover(故障转移)操作。切换成功后,就会通过订阅发布的模式,让哨兵把自己监控的服务器现实切换主机,这个过程叫客观下线

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 10:50:33  更:2022-08-06 10:53:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:26:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码