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

Redis概述

Redis 能干嘛?

  1. 内存存储,持久化,内存中是断电既失,所以持久化很重要(RDB,AOF)
  2. 效率高,可以用于高速缓存
  3. 发布订阅系统
  4. 地图信息分析
  5. 计时器,计数器(浏览量!)

特性

  1. 多样的数据类型
  2. 持久化
  3. 集群
  4. 事务

学习中需要用到的东西

  1. 官网:https://redis.io/
  2. 中文网:http://www.redis.cn/

Linux安装

1、下载安装包

2、上传到/opt 文件夹下

3、解压redis安装包 tar -zxvf

4、进入解压后的redis 文件,可以看到redis配置文件 redis.conf

5、基本的环境安装

 yum install gcc-c++
 
redis6对gcc要求5.3以上
可以分步骤升级gcc
命令如下:
【root@emooco redis-6.0.6】# yum -y install centos-release-scl

【root@emooco redis-6.0.6】# yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils

【root@emooco redis-6.0.6】# scl enable devtoolset-9 bash
 
 make
 
 make install

6、redis默认安装路径 /usr/local/bin

7、将redis配置文件 redis.conf移动到/usr/local/bin/myconf

8、将redis配置文件中的daemonize 设置为yes

9、通过指定的配置文件开启redis

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

10、使用redis-cli进行连接

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

11、使用ps -ef|grep redis查看redis服务

12、shutdown关闭redis服务

测试性能

redis-banchmark是一个压力测试工具

官方自带的性能测试工具!

redis-banchmark

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

测试:

# 测试:100个并发连接  100000请求
 redis-banchmark -h localhost -p 6379 -c 100 -n 100000

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

如何查看这些分析:

基础知识

redis有16 个数据库,默认使用的 是第0个

使用select可以切换数据库

127.0.0.1:6379> select 3 # 切换数据库
OK
127.0.0.1:6379[3]> dbsize # 查看数据库大小
(integer) 0
127.0.0.1:6379[3]> set name aping # 设置name值
OK
127.0.0.1:6379[3]> get name # 获取name值
"aping"
127.0.0.1:6379[3]> keys * # 查看所有key值
1) "name"
127.0.0.1:6379[3]> flushdb # 清空数据库
OK
127.0.0.1:6379> keys *
1) "mylist:{tag}"
2) "myhash:{tag}:__rand_int__"
3) "counter:{tag}:__rand_int__"
4) "key:{tag}:__rand_int__"
127.0.0.1:6379> flushall # 清空所有的数据库内容
OK


Redis 是单线程的!

redis 是基于内存操作,内存和网络带宽决定redis的性能瓶颈,不依赖于CPU,所以使用单线程。

Redis是C语言写的,官方提供的数据为100000+的QPS:每秒查询率,完全不比同样使用key-value 的Memecache差!

Redis 为什么单线程还那么快?

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

2、误区2:多线程(CPU上下文切换!)一定比单线程效率高!

核心:redis是将所有的数据全部放在内存中的,所以说用单线程操作效率是最高的 ,多线程(CPU会进行上下文切换,耗时的操作!!),对于内存系统来说,没有上下文切换效率是最高的!多次读写都是在CPU上的,在内存情况下,这个就是最佳的方案!

五大数据类型

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings)散列(hashes)列表(lists)集合(sets)有序集合(sorted sets) 与范围查询, bitmapshyperloglogs地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication)LUA脚本(Lua scripting)LRU驱动事件(LRU eviction)事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

Redis-Key
exists :判断键值
move name 1 :代表将name值移动到1号数据库中
expire name 10 :name属性在10秒后过期

127.0.0.1:6379> move name 1 #代表将name值移动到1号数据库中
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> set name aping
OK
127.0.0.1:6379> clear
127.0.0.1:6379> get name
"aping"
127.0.0.1:6379> expire name 10 #name属性在10秒后过期
(integer) 1
127.0.0.1:6379> ttl name # 查看剩余多长时间过期
(integer) 1
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> set name aping
OK
127.0.0.1:6379> type name # 查看属性是什么类型 
string
127.0.0.1:6379> 

String(字符串)
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> append name ",hello" # 追加字符串,如果当前key不存在,就相当于 set key
(integer) 11
127.0.0.1:6379> strlen name # 获取name属性的字符长度
(integer) 11

步长 i+=
127.0.0.1:6379> get views # 初始浏览量为0
"0"
127.0.0.1:6379> incr views # 自增1 浏览量加1
(integer) 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 # 自减1 浏览量减1
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incrby views 10 # 指定增加10 浏览量
(integer) 10
127.0.0.1:6379> incrby views 10
(integer) 20
127.0.0.1:6379> decrby views 10
(integer) 10
127.0.0.1:6379> decrby views 5 # 指定减少5 浏览量
(integer) 5
127.0.0.1:6379> 

##################################
# 字符串范围 range

127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set key1 "hello,aping"
OK
127.0.0.1:6379> get key1
"hello,aping"
127.0.0.1:6379> getrange key1 0 4 # 截取字符串 [0-3]
"hello"
127.0.0.1:6379> getrange key1 0 -1 # 获取全部字符串 和get key是一样的
"hello,aping"
127.0.0.1:6379> 

# 替换
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> get key2 
"abcdefg"
127.0.0.1:6379> setrange key2 1 a # 替换指定位置开始的字符
(integer) 7
127.0.0.1:6379> get key2
"aacdefg"
127.0.0.1:6379> 
########################################
# setex(set with expire) # 设置过期时间
# setnx(set if not exith)# 不存在在设置(会在分布式锁中用到)
127.0.0.1:6379> setex key3 40 hello # 设置key3的值为Holle,30秒后过期
OK
127.0.0.1:6379> ttl key3 # 查看过期时间
(integer) 28
127.0.0.1:6379> get key3
"hello"
127.0.0.1:6379> setnx mykey redis # 如果mykey不存在,创建redis
(integer) 1
127.0.0.1:6379> keys *
1) "mykey"
2) "key1"
3) "key"
4) "key2"
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setnx mykey inoondb # 如果mykey存在,创建失败!
(integer) 0
127.0.0.1:6379> get mykey
"redis"
127.0.0.1:6379> 

###########################################
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
OK
127.0.0.1:6379> mget k1 k2 k3 # 同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 # msetnx是一个原子性的操作,要么成功,要么失败
(integer) 0
127.0.0.1:6379> get k4
(nil)

#########################################

# 对象
set user:1 {name:aping,age:23} # 设置一个user:1 的对象,值为json字符来保存一个对象
# 冒号代表层级
127.0.0.1:6379> mset user:1:name aping user:1:age 23
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "aping"
2) "23"
127.0.0.1:6379> 

#########################################

getset # 先get然后在set
127.0.0.1:6379> getset db redis # 如果不存在值,则返回nil
(nil)
127.0.0.1:6379> getset db inoodb # 如果存在值,获取原来的值,并设置新的值
"redis" 
127.0.0.1:6379> get db
"inoodb"
127.0.0.1:6379> 




String类型的使用场景:可以是字符串和数字

List(列表)

在Redis里面。我们可以把list完成 栈、队列、阻塞队列

所有的命令都是用 l 开头的

127.0.0.1:6379> lpush list one # 将一个值或多个值插入到列表头部(左)
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1 # 获取全部的值
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1 # 通过区间获取具体的值
1) "three"
2) "two"
127.0.0.1:6379> rpush list four # 将一个值或多个值插入到列表尾部(右)
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
127.0.0.1:6379> 

#####################################

#移除
LPOP
RPOP

127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
127.0.0.1:6379> lpop list # 移除列表的第一个元素
"three"
127.0.0.1:6379> rpop list # 移除列表的最后一个元素
"four"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> 

#####################################
lindex 
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lindex list 1 # 根据下标获取list 中的某个值!
"one"
127.0.0.1:6379> lindex list 0
"two"

#####################################
llen 

127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> llen list # 获取 list 元素长度
(integer) 2
127.0.0.1:6379> 

#####################################

# 移除指定的值
lrem 

127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "three"
3) "two"
4) "pojo"
127.0.0.1:6379> lrem list 1 one # 移除list集合中指定个数的value,精确匹配
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "pojo"
127.0.0.1:6379> 

###################################、

 # ltrim 截取
 
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "aping"
3) "aping1"
4) "aping2"
127.0.0.1:6379> ltrim mylist 1 2  # 通过下标截取指定区间的长度,不在指定区间的元素被删除
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "aping"
2) "aping1"
127.0.0.1:6379> 

###########################################

rpoplpush # 移动列表的最后一个元素,将它移动到新的列表中

127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "hello"
3) "hello1"
4) "hello2"
5) "hello3"
127.0.0.1:6379> rpoplpush mylist onlist # 移动列表的最后一个元素,将它移动到新的列表中
"hello3"
127.0.0.1:6379> lrange mylist 0 -1 # 查看原来列表
1) "hello"
2) "hello"
3) "hello1"
4) "hello2"
127.0.0.1:6379> lrange onlist 0 -1 # 查看目标列表
1) "hello3"

############################################

lset 将列表中指定下标的值替换为另外一个值,更新操作

127.0.0.1:6379> exists list
(integer) 0
127.0.0.1:6379> lpush list value1 # 添加一个数据
(integer) 1
127.0.0.1:6379> lset list 0 aping # 将列表中第0下标的值替换为另外一个值
OK
127.0.0.1:6379> lrange list 0 0 # 查询第0个下标的值
1) "aping"
127.0.0.1:6379> lset list 1 abcd # 如果不存在,则会报错
(error)ERR index out of range

###########################################
linsert # 将某个具体的value插入到列表中某个元素的前面或后面

127.0.0.1:6379> lrange mylist 0 -1
1) "hello2"
2) "hello1"
3) "hello"
127.0.0.1:6379> linsert mylist before hello hello3
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello2"
2) "hello1"
3) "hello3"
4) "hello"
127.0.0.1:6379> 
127.0.0.1:6379> linsert mylist after hello hello5
(integer) 5
127.0.0.1:6379> lrange mylist 0 -1
1) "hello2"
2) "hello1"
3) "hello3"
4) "hello"
5) "hello5"
127.0.0.1:6379> 







1、List实际是一个链表,before node after , left right都可以插入值

2、如果key不存在,创建新的链表

3、如果key存在,新增内容

4、如果移除了所有值,空链表,也代表不存在

5、在列表两边插入值,效率最高。中间元素,效率低一点

Set(集合)

set中的值不能重复

127.0.0.1:6379> keys * 
1) "set"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd set hello # set集合中添加元素
(integer) 1
127.0.0.1:6379> sadd set aping
(integer) 1
127.0.0.1:6379> sadd set aping
(integer) 0
127.0.0.1:6379> smembers set # 获取set集合中的全部元素
1) "aping"
2) "hello"
127.0.0.1:6379> sismember set hello # 判断某一个值是不是在set集合中
(integer) 1
127.0.0.1:6379> scard set # 获取set集合中元素个数
(integer) 2
127.0.0.1:6379> 


################################################
srem # 移除集合中指定元素

127.0.0.1:6379> SMEMBERS set
1) "aping"
2) "hello"
127.0.0.1:6379> SREM set hello # 移除set集合中指定元素
(integer) 1
127.0.0.1:6379> SMEMBERS set
1) "aping"
127.0.0.1:6379> 

##############################################
set 无序不重复集合
srandmember # 随机抽取一个元素

127.0.0.1:6379> smembers set
1) "controller"
2) "dao"
3) "pojo"
4) "aping"
5) "service"
127.0.0.1:6379> srandmember set #随机抽取集合中的一个元素
"pojo"
127.0.0.1:6379> srandmember set
"aping"
127.0.0.1:6379> srandmember set 2 # 随机抽取集合中的两个元素
1) "service"
2) "pojo"
127.0.0.1:6379> srandmember set
"dao"
127.0.0.1:6379> 

#############################################

spop: 随机删除集合中元素,
删除指定的key,

127.0.0.1:6379> smembers set
1) "dao"
2) "service"
3) "controller"
4) "pojo"
5) "aping"
127.0.0.1:6379> spop myset
(nil)
127.0.0.1:6379> spop set
"dao"
127.0.0.1:6379> spop set
"controller"
127.0.0.1:6379> smembers set
1) "service"
2) "pojo"
3) "aping"
127.0.0.1:6379> 
########################################
将指定的值移动到拎一个集合中去
127.0.0.1:6379> smove set set2 hello2
(integer) 1
127.0.0.1:6379> smembers set
1) "hello3"
2) "hello1"
3) "hello"
127.0.0.1:6379> smembers set2
1) "aping1"
2) "aping"
3) "aping3"
4) "aping2"
5) "hello2"
127.0.0.1:6379> 
########################################

127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key1 d
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> sadd key2 f
(integer) 1
127.0.0.1:6379> sadd key2 g
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sdiff key1 key2 # 差集 查看key1和key2不同的值,显示key1不同的值
1) "a"
2) "b"
3) "d"
127.0.0.1:6379> sinter key1 key2 # 交集 查看key1和key2 相同的值,显示相同的值
1) "c"
127.0.0.1:6379> sunion key1 key2 # 并集 查看key1和key2 全部的值
1) "d"
2) "a"
3) "e"
4) "f"
5) "b"
6) "g"
7) "c"




Hash(哈希)

map集合

127.0.0.1:6379> hset hash field1 aping # set一个具体的 key-value
(integer) 1
127.0.0.1:6379> hmset hash field1 aping1 field2 hello # set多个 key-value
OK
127.0.0.1:6379> hget hash field1 # 获取hash集合中的key值
"aping1"
127.0.0.1:6379> hget hash field2
"hello"
127.0.0.1:6379> hmget hash field1 field2 # 获取hash集合中的多个key值
1) "aping1"
2) "hello"
127.0.0.1:6379> hgetall hash # 获取hash集合中全部数据
1) "field1"
2) "aping1"
3) "field2"
4) "hello"
127.0.0.1:6379> hdel hash field1 # 删除hash指定的key
(integer) 1
127.0.0.1:6379> hgetall hash
1) "field2"
2) "hello"
127.0.0.1:6379> hlen hash # 获取hash中的字段长度
(integer) 3
127.0.0.1:6379> hkeys hash # 获取hash中的全部key值
1) "field2"
2) "field3"
3) "field4"
127.0.0.1:6379> hvals hash # 获取hash中的所有value值
1) "hello"
2) "ioio"
3) "uiui"
127.0.0.1:6379> hexists hash field2 # 判断hash中field2是否存在
(integer) 1
127.0.0.1:6379> hsetnx hash hield5 hello# 如果不存在则设置
(integer) 1
127.0.0.1:6379> hsetnx hash hield5 aping# 如果存在则不能设置
(integer) 0
127.0.0.1:6379> 






Zset(有序集合)

在set的基础上,增加了一个值, set k1 v1 zset v1 score1 v1

127.0.0.1:6379> zadd myset 1 one # 添加一个值
(integer) 1
127.0.0.1:6379> zadd myset 2 two 3 three # 添加多个值
(integer) 2
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> 

##########################################

127.0.0.1:6379> zadd salary 2500 xiaoming 
(integer) 1
127.0.0.1:6379> zadd salary 3000 zhang
(integer) 1
127.0.0.1:6379> zadd salary 500 aping
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf # 用户名从小到大排序
1) "aping"
2) "xiaoming"
3) "zhang"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 显示全部的排序信息
1) "aping"
2) "500"
3) "xiaoming"
4) "2500"
5) "zhang"
6) "3000"
127.0.0.1:6379> zrangebyscore salary -inf 2500 withscores # 显示工资小于2500的升序排列
1) "aping"
2) "500"
3) "xiaoming"
4) "2500"

###########################################

# 移除rem中的元素

127.0.0.1:6379> zrange salary 0 -1
1) "aping"
2) "xiaoming"
3) "zhang"
127.0.0.1:6379> zrem salary xiaoming # 移除有序集合中的指定元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "aping"
2) "zhang"
127.0.0.1:6379> zcard salary # 获取有序集合中的个数
(integer) 2
127.0.0.1:6379> 

###########################################
127.0.0.1:6379> zadd set 1 a 2 b 3 c 4 d 5 e
(integer) 5
127.0.0.1:6379> zcount set 1 3 # 获取指定区间成员数量
(integer) 3
127.0.0.1:6379> 

案例:存储班级成绩表,工资表排序;普通消息,重要消息;带权重进行判断;

排行榜应用

三种特殊数据类型

geospatial(地理位置)

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

Redis的Geo在3.2版本就推出了

geoadd 添加地理位置

127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31,23 shanghai
(error) ERR value is not a valid float
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqin 114.05 22.52 shengzhen 120.16 30.24 hangzhou
(integer) 3
127.0.0.1:6379> geoadd china:city 108.96 34.26 xian
(integer) 1

geopos 获取指定城市经纬度

127.0.0.1:6379> geopos china:city beijing
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
127.0.0.1:6379> geopos china:city beijing chongqin
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
2) 1) "106.49999767541885376"
   2) "29.52999957900659211"
127.0.0.1:6379> 

geodsit

两人之间的距离

单位:

  • m 米
  • km 千米
  • mi 英里
  • ft 英尺
127.0.0.1:6379> geodist china:city beijing chongqin
"1464070.8051"
127.0.0.1:6379> geodist china:city shanghai hangzhou 
"166761.2770"
127.0.0.1:6379> 

georadius 以给定的经纬度为中心,找出指定半径的元素

附近的人,通过经纬度为中心,来查询周围的人

所有的数据录入到 china:city ,结果才会更清楚

127.0.0.1:6379> georadius china:city 110 30 1000 km # 以110 30为经纬度为中心,寻找方圆1000km的城市
1) "chongqin"
2) "xian"
3) "shengzhen"
4) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 500 km
1) "chongqin"
2) "xian"
127.0.0.1:6379> georadius china:city 110 30 500 km withdist # 显示方圆500km 的城市和距离
1) 1) "chongqin"
   2) "341.9374"
2) 1) "xian"
   2) "483.8340"
127.0.0.1:6379> georadius china:city 110 30 500 km withcoord # 找出方圆500km的城市和经纬度
1) 1) "chongqin"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) 1) "108.96000176668167114"
      2) "34.25999964418929977"
127.0.0.1:6379> georadius china:city 110 30 500 km withcoord withdist count 1 # 找出一个方圆500km的城市和经纬度
1) 1) "chongqin"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
127.0.0.1:6379> 

georadiusbymember 找出指定元素周围的其他元素(包含指定元素)

127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km
1) "beijing"
2) "xian"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanhai 700 km
(error) ERR could not decode requested zset member
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 700 km
1) "hangzhou"
2) "shanghai"
127.0.0.1:6379> 

GEO 的底层是Zset,可以用Zset的命令来操作GEO

hyperloglog

数据结构

Redis Hyperloglog 基数统计的算法!

基数 :两个集合中不重复元素的数量

优点:占用的内存是固定的,如果从内存角度来考虑的话,hyperloglog是首选

但是hyperloglog会有0.81% 的错误率。

网页中的UV(一个人访问一个网站多次,但是还是算作一个人)

bitmaps

位存储

bitmaps:位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态

 #setbit : 设置位图,1代表打卡,0代表未打卡

127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 0
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0
127.0.0.1:6379> 
###################################

#getbit: 获取打卡信息

127.0.0.1:6379> getbit sign 6
(integer) 1
127.0.0.1:6379> getbit sign 3
(integer) 1
127.0.0.1:6379> 
###################################

# bitcount:统计打卡天数
127.0.0.1:6379> bitcount sign
(integer) 3
127.0.0.1:6379> 

事务

原子性:要么同时成功,要么同时失败!

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

Redis 没有隔离级别的概念

所有的命令在事务中,并没有直接被执行,是有发起执行命令的时候才会被执行!Exec

Redis事务本质:一组命令的执行!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!具有一次性,顺序性,排他性

Redis 的事务:

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

discard :放弃事务

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> discard # 放弃事务
OK
127.0.0.1:6379> get k2 # 事务队列中都不会被执行
(nil)
127.0.0.1:6379> 

编译时异常(代码有错! 命令有错!)事务中所有的命令都不会被执行

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> getset k3 # 错误的命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4 
QUEUED
127.0.0.1:6379> exec # 执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1 # 所有的命令都不会被执行
(nil)
127.0.0.1:6379> 

运行时异常,如果事务队列中存在语法性错误,其他命令是可以正常执行的,错误命令抛出异常,不存在原子性

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> incr k1 # 错误语法
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k3
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) OK
5) "v3"
127.0.0.1:6379> 

监控!Watch

悲观锁

  • 很悲观,认为什么时候都会出现问题,无论做什么都要加锁

乐观锁

  • 很乐观,认为什么时候都不会有问题,所以不会上锁,更新数据的时候去判断一下,在此期间是否有人修改过这个数据
  • 获取version
  • 更新的时候比较version
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money # 监视money对象
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec # 正常执行
1) (integer) 80
2) (integer) 20
127.0.0.1:6379> 

测试多线程修改,使用watch可以当做redis的乐观锁操作!

127.0.0.1:6379> watch money # 监控money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> INCRby out 10
QUEUED
127.0.0.1:6379> exec # 执行之前,另外一个线程修改了money值,会导致事务执行失败
(nil)
127.0.0.1:6379> 

Jedis

Jedis是redis 官方推荐的java连接开发工具,使用java操作redis 中间件。

测试!

1、导入对应的依赖

		<!-- jedis依赖 -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.6.3</version>
        </dependency>
        <!-- fastjson依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>

2、进行编码测试:

  • 连接数据库
  • 操作命令
  • 断开连接

SpringBoot整合

SpringBoot操作数据:Spring-Data jpa:jdbc mongodb redis!
springData 是springboot齐名的项目!

在springBoot 2.X之后,原来使用的jedis替换为lettuce

jedis:采用的是直连,多个线程操作的话是不安全的,如果想要避免不安全,使用jedis pool连接池!BIO模式

lettuce:采用netty ,可以在多个线程中进行共享,不存在线程不安全的情况,可以减少线程数据了,NIO模式

源码分析:

	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")//我们可以自己定义一个RedisTemplate来替换这个默认的
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
        //默认的RedisTemplate没有过多的设置,redis对象都是需要序列化!
        //两个反省都是object,object的类型,我们后面使用需要强制类型转换 
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

	@Bean 
	@ConditionalOnMissingBean//由于String是Redis中最长使用的一种类型,单独写了一种方法
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

整合测试

1、导入依赖

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

2、配置连接

#配置 redis
spring.redis.host=127.0.0.1
spring.redis.port=6379

3、测试

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        //redisTemplate 操作不同的数据类型,api和我们的指令是一样的
        //opsForValue 操作字符串,类似String
        //opsForList 操作List 类似List

        //除了基本的操作,常用的方法都是通过redisTemplate操作,
        //获取redis的连接对象
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.flushDb();
        connection.flushAll();

        redisTemplate.opsForValue().set("name","刘春平");

        System.out.println(redisTemplate.opsForValue().get("name"));
        
        
   @SuppressWarnings("rawtypes") private @Nullable RedisSerializer keySerializer = null;
	@SuppressWarnings("rawtypes") private @Nullable RedisSerializer valueSerializer = null;
	@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashKeySerializer = null;
	@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashValueSerializer = null;
	private RedisSerializer<String> stringSerializer = RedisSerializer.string();

Redis主从复制

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

环境配置

只配置主库,不配置从库


127.0.0.1:6379> info replication //查看当前库的信息
# Replication
role:master // 主机
connected_slaves:0 //没有从机
master_replid:a4789a5cef110c402d67aae2b62d4de12ff1bb99
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> 

复制3个配置文件,修改对应配置信息

1、端口

2、pid名

3、log文件名

4、dump.rdb名

修改后,启动配置的3个redis服务器,可以通过进程信息查看

[root@aping bin]# ps -ef|grep redis
root      2495     1  0 Sep06 ?        00:01:16 redis-server *:6379
root     25421     1  0 10:32 ?        00:00:00 redis-server 127.0.0.1:6380
root     25438     1  0 10:32 ?        00:00:00 redis-server 127.0.0.1:6381
root     25647 22852  0 10:34 pts/1    00:00:00 grep --color=auto redis
[root@aping bin]# 

一主二从

默认情况下,每台redis服务器都是主节点,一般情况下只用配置从机就好了

一主(79)二从(80,81)

slaveof 将当前服务器转变为指定服务器的从机

127.0.0.1:6380> slaveof 127.0.0.1 6379  //将当前服务器转变为指定服务器的从机
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:3
master_sync_in_progress:0
slave_repl_offset:140
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:a13fa8d33ca2b7964d01edfb578b3e121e7e763b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:140

真实的主从配置是在配置文件中配置,这样的话是永久的,我们这里使用的命令,是暂时的

细节

主机可以写,从机不能写只能读!主机中的所有信息和数据,都会被从机保存

哨兵模式

(自动选举老大的模式)

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,他会独立运行,其原理是哨兵通过发送命令,等待Redis的服务器响应,从而监控运行的多个Redis实例

假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1的主观认为服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover[故障转移]操作,切换成功后,就会通过发布订阅,让各个哨兵把自己监控的从服务器实现切换主机,这个国政成为客观下线

测试

一主二从

1、配置哨兵配置问价sentinel.conf

//sentinel monitor 被监控的名称 127.0.0.1 6379 1
sentinel monitor myredis 127.0.0.1 6379 1

后面的数字1,代表主机挂了,从机投票,看让谁接替主机,票数最多的,就会成为主机!

2、配置之后,启动哨兵

28275:X 07 Sep 2021 15:55:47.795 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
28275:X 07 Sep 2021 15:55:47.795 # Redis version=6.0.6, bits=64, commit=00000000, modified=0, pid=28275, just started
28275:X 07 Sep 2021 15:55:47.795 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 6.0.6 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 28275
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

28275:X 07 Sep 2021 15:55:47.796 # Sentinel ID is d2a47f6812c610bc7083b567cbbafcb1104f9dc7
28275:X 07 Sep 2021 15:55:47.796 # +monitor master myredis 127.0.0.1 6379 quorum 1
28275:X 07 Sep 2021 15:55:47.798 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
28275:X 07 Sep 2021 15:55:47.801 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379

如果master节点断开了, 这个时候就会从从机中随机选择一个服务器!

如果宕机的主机回来了,只能归并到新的主机下,当做从机,这就是哨兵模式的规则

哨兵模式

优点:

1、哨兵集群,基于主从复制模式,所有的主从配置的优点,它全有

2、主从可以切换,故障可以转移,系统的可用性就会更好

3、哨兵模式就是自从模式的升级

缺点:

1、Redis不好在线扩容,集群容量到达上限,在线扩容就十分麻烦

2、实现哨兵模式的配置其实是很麻烦的,里面有很多选择

哨兵模式的全部配置

# Example sentinel.conf
 
# 哨兵sentinel实例运行的端口 默认26379
port 26379
 
# 哨兵sentinel的工作目录
dir /tmp
 
# 哨兵sentinel监控的redis主节点的 ip port 
# master-name  可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。
# quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
  sentinel monitor mymaster 127.0.0.1 6379 2
 
# 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码
# 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
 
 
# 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000
 
# 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步,
这个数字越小,完成failover所需的时间就越长,
但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。
可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1
 
 
 
# 故障转移的超时时间 failover-timeout 可以用在以下这些方面: 
#1. 同一个sentinel对同一个master两次failover之间的间隔时间。
#2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。  
#4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
# 默认三分钟
# sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000
 
# SCRIPTS EXECUTION
 
#配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
#对于脚本的运行结果有以下规则:
#若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
#若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
#如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
#一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
 
#通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,
这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,
一个是事件的类型,
一个是事件的描述。
如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
#通知脚本
# sentinel notification-script <master-name> <script-path>
  sentinel notification-script mymaster /var/redis/notify.sh
 
# 客户端重新配置主节点参数脚本
# 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。
# 以下参数将会在调用脚本时传给脚本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>总是“failover”,
# <role>是“leader”或者“observer”中的一个。 
# 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的
# 这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentinel client-reconfig-script <master-name> <script-path>
 sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

Redis缓存穿透和雪崩(面试高频,常用)

缓存穿透

概念

缓存穿透的概念很简单,用户想查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询,发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透

解决方案

布隆过滤器

一种数据结构,对所有可能查询的数据以hash 的形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力
timeout
sentinel failover-timeout mymaster 180000

SCRIPTS EXECUTION

#配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
#对于脚本的运行结果有以下规则:
#若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
#若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
#如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
#一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。

#通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,
这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,
一个是事件的类型,
一个是事件的描述。
如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
#通知脚本

sentinel notification-script

sentinel notification-script mymaster /var/redis/notify.sh

客户端重新配置主节点参数脚本

当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。

以下参数将会在调用脚本时传给脚本:

目前总是“failover”,

是“leader”或者“observer”中的一个。

参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的

这个脚本应该是通用的,能被多次调用,不是针对性的。

sentinel client-reconfig-script

sentinel client-reconfig-script mymaster /var/redis/reconfig.sh


### Redis缓存穿透和雪崩(面试高频,常用)

#### 缓存穿透

>概念

缓存穿透的概念很简单,用户想查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询,发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透

>解决方案

布隆过滤器

一种数据结构,对所有可能查询的数据以hash 的形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力
  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-02-06 13:53:32  更:2022-02-06 13:54:18 
 
开发: 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/24 14:10:25-

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