Redis的介绍及基本使用

2023-11-01

学习尚硅谷的Redis学习时所做的笔记

一、Redis的应用场景

①Redis的典型应用场景:

[1]缓存

使用Redis可以建立性能非常出色的缓存服务器,查询请求先在Redis中查找所需要的数据,如果能够查询到(命中)则直接返回,大大减轻关系型数据库的压力。

[2]数据临时存储位置

使用token(令牌)作为用户登录系统时的身份标识,这个token就可以在Redis中临时存储。

[3]分布式环境下解决Session不一致问题时的Session库

Spring提供了一种技术解决分布式环境下Session不一致问题,叫SpringSession。而Redis就可以为SpringSession提供一个数据存储空间。

[4]流式数据去重

在Redis中有一种数据类型是set,和Java中的Set集合很像,不允许存储重复数据。借助这个特性我们可以在Redis中使用set类型存储流式数据达到去重的目的。

②Redis不适用的场景

[1]直接查询value

Redis是一个严格的Key-value数据库,所有数据都必须通过key去找到value,Redis没有提供直接根据查询条件匹配value的方法。

[2]用多键一值表示特定关系

Redis中一个key对应一个value,没有多个key对应同一个value的情况。

[3]事务中回滚

Redis不支持回滚。如果一个命令在加入队列时没有检测出问题,那么队列执行时不会因为某一条命令失败而回滚。

二、Redis常用数据结构

1.总体结构

KEY VALUE
string
list
set
hash
zset

Redis中的数据,总体上是键值对,不同数据类型指的是键值对中值的类型。

2.string类型

Redis中最基本的类型,它是key对应的一个单一值。二进制安全,不必担心由于编码等问题导致二进制数据变化。所以redis的string可以包含任何数据,比如jpg图片或者序列化的对象。Redis中一个字符串值的最大容量是512M。

3.list类型

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层是双向链表,所以它操作时头尾效率高,中间效率低(额外花费查找插入位置的时间)。

在Redis中list类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是2^32-1个。

list是一个有序可以重复的数据类型。

4.set类型

Redis的set是string类型的无序集合。它是基于哈希表实现的。set类型插入数据时会自动去重。最大可以包含2^32-1个元素。

5.hash类型

本身就是一个键值对集合。可以当做Java中的Map<String,String>对待。每一个hash可以存储2^32-1个键值对。

6.zset类型

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。

7.Geospatial

Redis 在 3.2 推出 Geo 类型,该功能可以推算出地理位置信息,两地之间的距离。

8.HyperLogLogs

用于大数据量基数统计,速度非常快,占用内存非常小。每个HyperLogLog键只需要花费12KB内存,就可以计算接近 2^64个不同元素的基数。比如计算网站UV(User view,用户访问数量,一个用户一天访问同一个URL地址多次合并为一次)。

9.bitmap

直接对string的二进制位进行操作的一组命令

10.常用数据类型应用场景

数据类型 应用场景
string 分布式Session存储
分布式数据库ID
计数器:统计网站访问量
hash 存储对象信息(购物车中的商品信息)
存储表的信息
list 实现队列、栈操作
汇总日志
粉丝列表
关注的人列表
set 签到
打卡
点赞
zset 排行榜
百度热点搜索
geospatial 获取地理位置信息
两地之间的距离
hyperloglogs 基数统计
bitmaps 统计用户访问次数

三、Redis命令行操作

1.基本操作

①切换数据库

	Redis默认有16个数据库。
	115 # Set the number of databases. The default database is DB 0, you can select
	116 # a different one on a per-connection basis using SELECT <dbid> where
	117 # dbid is a number between 0 and 'databases'-1
	118 databases 16
	使用select进行切换,数据库索引从0开始
	127.0.0.1:6379> select 2
	OK
	127.0.0.1:6379[2]> select 0
	OK
	127.0.0.1:6379> 

②查看数据库长度

数据库长度就是这个数据库中存储了多少条数据

	127.0.0.1:6379> dbsize
	(integer) 3

③清空全库

	127.0.0.1:6379> flushall

2.KEY操作

在实际操作中对于Key的定义注意下面几点:

  • Key不要太长,超过1024字节将消耗过多内存,降低查询效率。尽管Redis支持的Key最大长度为512MB。
  • Key仍然要做到见名知意。
  • 在同一个项目中遵循同一个命名规范,习惯上多个单词用“:”分开。例如:“user:token:session:id”
  • Redis命令不区分大小写,Key区分大小写
KEYS PATTERN
	把匹配PATTERN的key返回。PATTERN中可以使用“*”匹配多个字符,使用“?”匹配单个字符
TYPE KEY
	返回KEY对应的值的类型
MOVE KEY DB
	把一组键值对数据移动到另一个数据库中
DEL KEY [KEY ...]
	根据KEY进行删除,至少要指定一个KEY
EXISTS KEY [KEY ...]
	检查指定的KEY是否存在。指定一个KEY时,存在返回1,不存在返回0。可以指定多个,返回存在的KEY的数量。
RENAME KEY NEWKEY
	重命名一个KEY,NEWKEY不管是否是已经存在的都会执行,如果NEWKEY已经存在则会被覆盖。
RENAMENX KEY NEWKEY
	只有在NEWKEY不存在时能够执行成功,否则失败
TTL KEY
	以秒为单位查看KEY还能存在多长时间
	正数:剩余的存活时间(单位:秒)
	-1:永不过期
	-2:不存在的Key
EXPIRE KEY SECONDS
	给一个KEY设置在SECONDS秒后过期,过期会被Redis移除。
PERSIST KEY
	移除过期时间,变成永久key

3.string操作

SET KEY VALUE [EX SECONDS] [PX MILLISECONDS] [NX|XX]
	给KEY设置一个string类型的值。
	EX参数用于设置存活的秒数。
	PX参数用于设置存活的毫秒数。
	NX参数表示当前命令中指定的KEY不存在才行。
	XX参数表示当前命令中指定的KEY存在才行。
GET KEY
	根据key得到值,只能用于string类型。
APPEND KEY VALUE
	把指定的value追加到KEY对应的原来的值后面,返回值是追加后字符串长度
STRLEN KEY
	直接返回字符串长度
INCR KEY
	自增1(要求:参与运算的数据必须是整数且不能超过整数Integer范围)
DECR KEY
	自减1(要求:参与运算的数据必须是整数且不能超过整数Integer范围)
INCRBY KEY INCREMENT
	原值+INCREMENT(要求:参与运算的数据必须是整数且不能超过整数Integer范围)
DECRBY KEY DECREMENT
	原值-DECREMENT(要求:参与运算的数据必须是整数且不能超过整数Integer范围)
GETRANGE KEY START END
	从字符串中取指定的一段,索引从0开始
	START是开始取值的索引
	END是结束取值的索引
SETRANGE KEY OFFSET VALUE
	从offset(从0开始的索引)开始使用VALUE进行替换
	包含offset位置
SETEX KEY SECONDS VALUE
	设置KEY,VALUE时指定存在秒数
SETNX KEY VALUE
	新建字符串类型的键值对
MSET KEY VALUE [KEY VALUE ...]
	一次性设置一组多个键值对
MGET KEY [KEY ...]
	一次性指定多个KEY,返回它们对应的值,没有值的KEY返回值是(nil)
MSETNX KEY VALUE [KEY VALUE ...]
	一次性新建多个值
GETSET KEY VALUE
	设置新值,同时能够将旧值返回

4.list操作

LPUSH key value [value ...]
	针对key指定的list,从左边放入元素
RPUSH key value [value ...]
	针对key指定的list,从右边放入元素
LRANGE key start stop
	根据list集合的索引打印元素数据
	正着数:0,1,2,3,...
	倒着数:-1,-2,-3,...
LLEN key
	返回list集合的长度
LPOP key
	从左边弹出一个元素。
	弹出=返回+删除。
RPOP key
	从右边弹出一个元素。
RPOPLPUSH source destination
	从source中RPOP一个元素,LPUSH到destination中
LINDEX key index
	根据索引从集合中取值
LINSERT key BEFORE|AFTER pivot value
	在pivot指定的值前面或后面插入value
	如果pivot值有重复的,那么就从左往右数,以第一个遇到的pivot为基准
	BEFORE表示放在pivot前面
	AFTER表示放在pivot后面
LPUSHX key value
	只能针对存在的list执行LPUSH
LREM key count value
	根据count指定的数量从key对应的list中删除value
	具体执行时从左往右删除,遇到一个删一个,删完为止
LSET key index value
	把指定索引位置的元素替换为另一个值
LTRIM key start stop
	仅保留指定区间的数据,两边的数据被删除

5.set操作

SADD key member [member ...]
	给key指定的set集合中存入数据,set会自动去重
SMEMBERS key
	返回可以指定的set集合中所有的元素
SCARD key
	返回集合中元素的数量
SISMEMBER key member
	检查当前指定member是否是集合中的元素
	返回1:表示是集合中的元素
	返回2:表示不是集合中的元素
SREM key member [member ...]
	从集合中删除元素
SINTER key [key ...]
	将指定的集合进行“交集”操作
	集合A:a,b,c
	集合B:b,c,d
	交集:b,c
SINTERSTORE destination key [key ...]
	取交集后存入destination
SDIFF key [key ...]
	将指定的集合执行“差集”操作
	集合A:a,b,c
	集合B:b,c,d
	A对B执行diff:a
	相当于:A-交集部分
SDIFFSTORE destination key [key ...]
SUNION key [key ...]
	将指定的集合执行“并集”操作
	集合A:a,b,c
	集合B:b,c,d
	并集:a,b,c,d
SUNIONSTORE destination key [key ...]
SMOVE source destination member
	把member从source移动到destination

【测试数据
SADD testset a b c d e f g h i j k l m n o p q r s t u v w x y z aa bb cc dd ee ff gg hh ii jj kk ll mm nn oo pp qq rr ss tt uu vv ww xx yy zz
】

SSCAN key cursor [MATCH pattern] [COUNT count]
	基于游标的遍历。cursor是游标值,第一次显示第一块内容时,游标取值为0;根据后续返回的新的游标值获取下一块数据。直到游标值变成0,说明数据遍历完成。
SRANDMEMBER key [count]
	从集合中随机返回count个数量的元素,count不指定就返回1个(数据有可能重复出现)
SPOP key [count]
	从集合中随机弹出count个数量的元素,count不指定就弹出1个(保证不会有重复数据出现)

6.hash操作

HSET key field value
	插入新数据返回1
	修改旧数据返回0
HGETALL key
HGET key field
HLEN key
HKEYS key
HVALS key
HEXISTS key field
HDEL key field [field ...]
HINCRBY key field increment
HMGET key field [field ...]
HMSET key field value [field value ...]
HSETNX key field value
	要求field是新建的

7.zset操作

ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
ZRANGE key start stop [WITHSCORES]
ZCARD key
ZSCORE key member
ZINCRBY key increment member
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
	在分数的指定区间内返回数据
	min参数可以通过 -inf 表示负无穷
	max参数可以通过 +inf 表示正无穷

	默认是闭区间
	可以通过 (min (max 形式指定开区间,例如:(50 (80
ZRANK key member
	先对分数进行升序排序,返回member的排名。排名从0开始
ZREM key member [member ...]

8.Geospatial

查询经纬度数据:http://www.jsons.cn/lngcode

①添加地理位置

GEOADD key longitude latitude member [longitude latitude member ...]

规则:

1.两极无法直接添加,一般会下载城市数据,直接通过 Java 程序一次性导入。

2.取值范围

​ 有效的经度从 -180 度到 180 度。

​ 有效的纬度从 -85.05112878 度到 85.05112878 度。

​ 当坐标位置超出指定范围时,该命令将会返回一个错误。

3.已经添加的数据,是无法再次往里面添加的。

192.168.109.100:6379> GEOADD "china:city" 114.085947 22.547 shenzhen
(integer) 1
192.168.109.100:6379> GEOADD "china:city" 113.280637 23.125178 guangzhou
(integer) 1

②查询已添加的地理位置

Geo类型在Redis内部其实是使用zset类型存储的,所以可以使用zset的命令进行常规操作。

192.168.109.100:6379> ZRANGE china:city 0 -1 
1) "shenzhen"
2) "guangzhou"
192.168.109.100:6379> ZRANGE china:city 0 -1 WITHSCORES
1) "shenzhen"
2) "4046433733682118"
3) "guangzhou"
4) "4046533764066819"

③删除已添加的地理位置

192.168.109.100:6379> ZREM china:city guangzhou
(integer) 1

④获取指定地区的坐标值

192.168.109.100:6379> GEOPOS china:city shenzhen
1) 1) "114.08594459295272827"
   2) "22.54699993773966327"

⑤计算两地之间的直线距离

192.168.109.100:6379> GEODIST china:city guangzhou shenzhen km
"104.6426"

单位:

m 表示单位为米[默认值]。

km 表示单位为千米。

mi 表示单位为英里。

ft 表示单位为英尺。

如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位。

⑥以给定坐标为中心,在指定半径内查找元素

192.168.109.100:6379> GEORADIUS china:city 110 20 1000 km WITHCOORD WITHDIST
1) 1) "shenzhen"
   2) "509.4622"
   3) 1) "114.08594459295272827"
      2) "22.54699993773966327"
2) 1) "guangzhou"
   2) "485.7406"
   3) 1) "113.28063815832138062"
      2) "23.12517743834835215"

WITHCOORD表示显示经纬度

WITHDIST表示显示到中心的距离

⑦在指定元素周围查找其他元素

192.168.109.100:6379> GEORADIUSBYMEMBER china:city shenzhen 300 km WITHCOORD WITHDIST
1) 1) "shenzhen"
   2) "0.0000"
   3) 1) "114.08594459295272827"
      2) "22.54699993773966327"
2) 1) "guangzhou"
   2) "104.6426"
   3) 1) "113.28063815832138062"
      2) "23.12517743834835215"

9.hyperloglogs

①基数概念

一个集合中不重复元素的个数。例如:集合{1,2,5,1,7,2,5}中元素个数是7,但是基数是4。而hyperloglogs的主要功能就是进行基数统计。

②hyperloglogs命令

[1]添加
192.168.109.100:6379> PFADD user:access:1 tom jerry andy jim andy jerry tom
(integer) 1
192.168.109.100:6379> PFADD user:access:2 andy jerry tom bob kate
(integer) 1
192.168.109.100:6379> PFADD user:access:3 mary harry tom jerry
(integer) 1
[2]统计
192.168.109.100:6379> PFCOUNT user:access:1 user:access:2 user:access:3
(integer) 8
[3]合并
192.168.109.100:6379> PFMERGE user:access:merge user:access:1 user:access:2 user:access:3
OK
192.168.109.100:6379> PFCOUNT user:access:merge
(integer) 8

10.bitmap位图

直接对数据的二进制位进行操作

192.168.109.100:6379[5]> set a hello
OK
192.168.109.100:6379[5]> GETBIT a 0
(integer) 0
192.168.109.100:6379[5]> GETBIT a 1
(integer) 1
192.168.109.100:6379[5]> GETBIT a 2
(integer) 1
192.168.109.100:6379[5]> GETBIT a 3
(integer) 0
192.168.109.100:6379[5]> GETBIT a 4
(integer) 1
192.168.109.100:6379[5]> GETBIT a 5
(integer) 0
192.168.109.100:6379[5]> SETBIT a 5 1
(integer) 0
192.168.109.100:6379[5]> get a
"lello"
192.168.109.100:6379[5]> BITCOUNT a
(integer) 22

setbit设置指定比特位

getbit获取指定比特位

bitcount统计所有比特位中1的数量

四、Redis持久化机制

Redis工作时数据都存储在内存中,万一服务器断电,则所有数据都会丢失。针对这种情况,Redis采用持久化机制来增强数据安全性。说白了就是把内存里的数据保存到硬盘上。

1.RDB

①机制描述

在满足特定触发条件时把内存中的数据本身作为一个快照保存到硬盘上的文件中。Redis默认开启RDB机制。

②触发时机

[1]基于默认配置
save 900 1
save 300 10
save 60 10000

含义

配置 含义
save 900 1 900秒内至少有一次修改则触发保存操作
save 300 10 300秒内至少有10次修改则触发保存操作
save 60 10000 60秒内至少有1万次修改则触发保存操作
[2]使用保存命令

save或bgsave

[3]使用flushall命令

这个命令也会产生dump.rdb文件,但里面是空的,没有意义

[4]服务器关闭

如果执行SHUTDOWN命令让Redis正常退出,那么此前Redis就会执行一次持久化保存。

③相关配置

配置项 取值 作用
save “” 禁用RDB机制
dbfilename 文件名,例如:dump.rdb 设置RDB机制下,数据存储文件的文件名
dir Redis工作目录路径 指定存放持久化文件的目录的路径。注意:这里指定的必须是目录不能是文件名

④思考

RDB 机制能够保证数据的绝对安全吗?

  • 机制本身并不能保证绝对安全
  • 但是作为总体机制的一部分,RDB(或AOF)机制能够起到它独特的作用;整体机制综合来看是可靠的

2.AOF

①机制描述

根据配置文件中指定的策略,把生成数据的命令保存到硬盘上的文件中。一个AOF文件的内容可以参照下面的例子:

*2
$6
SELECT
$1
0
*3
$3
set
$3
num
$2
10
*2
$4
incr
$3
num
*2
$4
incr
$3
num
*2
$4
incr
$3
num

生成上面文件内容的Redis命令是:

set num 10
incr num
incr num
incr num

②AOF基本配置

配置项 取值 作用
appendonly yes 启用AOF持久化机制
no 禁用AOF持久化机制[默认值]
appendfilename “文件名” AOF持久化文件名
dir Redis工作目录路径 指定存放持久化文件的目录的路径。注意:这里指定的必须是目录不能是文件名
appendfsync always 每一次数据修改后都将执行文件写入操作,是最安全的方式但是速度缓慢。
everysec 每秒执行一次写入操作。折中。
no 由操作系统在适当的时候执行写入操作,Redis性能最好,数据保存次数最少。

::: warning

当 AOF 和 RDB 机制并存时,Redis 会优先采纳 AOF 机制。使用 AOF 持久化文件恢复内存中的数据。而 AOF 刚刚开启时 appendonly.aof 持久化文件中没有任何数据。拿空的 appendonly.aof 持久化文件恢复内存,就会导致以前所有数据都丢失。

:::

③AOF重写

对比下面两组命令:

AOF重写前 AOF重写后
set count 1
incr count
incr count
incr count
set count 4

两组命令执行后对于count来说最终的值是一致的,但是进行AOF重写后省略了中间过程,可以让AOF文件体积更小,缩短数据恢复时间。而Redis会根据AOF文件的体积来决定是否进行AOF重写。参考的配置项如下:

配置项 含义
auto-aof-rewrite-percentage 100 文件体积增大100%时执行AOF重写
auto-aof-rewrite-min-size 64mb 文件体积增长到64mb时执行AOF重写

实际工作中不要进行频繁的AOF重写,因为CPU、内存资源和硬盘资源二者之间肯定是CPU、内存资源更加宝贵,所以不应该过多耗费CPU性能去节省硬盘空间。另外数据恢复也不是高频操作,所以节约数据恢复时间价值也不是非常大。

3.持久化文件损坏修复

Redis服务器启动时如果读取了损坏的持久化文件会导致启动失败,此时为了让Redis服务器能够正常启动,需要对损坏的持久化文件进行修复。这里以AOF文件为例介绍修复操作的步骤。

  • 第一步:备份要修复的appendonly.aof文件

  • 第二步:执行修复程序

    /usr/local/redis/bin/redis-check-aof --fix /usr/local/redis/appendonly.aof

  • 第三步:重启Redis

注意:所谓修复持久化文件仅仅是把损坏的部分去掉,而没法把受损的数据找回。

4.扩展阅读:两种持久化机制的取舍

①RDB

[1]优势

适合大规模的数据恢复,速度较快

[2]劣势

会丢失最后一次快照后的所有修改,不能绝对保证数据的高度一致性和完整性。Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑,但上述成立有条件,Linux也有优化手段

②AOF

[1]优势

选择appendfsync always方式运行时理论上能够做到数据完整一致,但此时性能又不好。文件内容具备一定可读性,能够用来分析Redis工作情况。

[2]劣势

持久化相同的数据,文件体积比RDB大,恢复速度比RDB慢。效率在同步写入时低于RDB,不同步写入时与RDB相同。

③RDB和AOF并存

Redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整

RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份)、快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。

④使用建议

如果Redis仅仅作为缓存可以不使用任何持久化方式。

其他应用方式综合考虑性能和完整性、一致性要求。

RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。如果不开启AOF,仅靠Master-Slave Replication 实现高可用性能也不错。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构。

五、Redis事务控制

1.Redis事务控制的相关命令

命令名 作用
MULTI 表示开始收集命令,后面所有命令都不是马上执行,而是加入到一个队列中。
EXEC 执行MULTI后面命令队列中的所有命令。
DISCARD 放弃执行队列中的命令。
WATCH “观察“、”监控“一个KEY,在当前队列外的其他命令操作这个KEY时,放弃执行自己队列的命令
UNWATCH 放弃监控一个KEY

2.命令队列执行失败的两种情况

①加入队列时失败

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 20
QUEUED
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> incr age www
(error) ERR wrong number of arguments for 'incr' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

遇到了入队时即可检测到的错误,整个队列都不会执行。

②执行队列时失败

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 30
QUEUED
127.0.0.1:6379> incrby age 5
QUEUED
127.0.0.1:6379> incrby age 5
QUEUED
127.0.0.1:6379> incrby age ww
QUEUED
127.0.0.1:6379> incrby age 5
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (integer) 35
3) (integer) 40
4) (error) ERR value is not an integer or out of range
5) (integer) 45
127.0.0.1:6379> get age
"45"

错误在入队时检测不出来,整个队列执行时有错的命令执行失败,但是其他命令并没有回滚。

③Redis为什么不支持回滚

官方解释如下:

如果你有使用关系式数据库的经验, 那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。以下是这种做法的优点:
1.Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
2.因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。
有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。

3.悲观锁和乐观锁

在使用WATCH命令监控一个KEY后,当前队列中的命令会由于外部命令的执行而放弃,这是乐观锁的体现。

  • 悲观锁

    认为当前环境非常容易发生碰撞,所以执行操作前需要把数据锁定,操作完成后释放锁,其他操作才可以继续操作。

  • 乐观锁

    认为当前环境不容易发生碰撞,所以执行操作前不锁定数据,万一碰撞真的发生了,那么检查版本号:

    • 如果是基于最新的版本所做的修改:服务器接受,修改成功
    • 如果是基于旧的版本号所做的修改:服务器不接受,修改失败,整个MULTI队列中的操作都被丢弃

六、Redis主从复制机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GX6y41qm-1683956525438)(./images/p02.png)]

1.读写分离的好处:

  • 性能优化:主服务器专注于写操作,可以用更适合写入数据的模式工作;同样,从服务器专注于读操作,可以用更适合读取数据的模式工作。
  • 强化数据安全,避免单点故障:由于数据同步机制的存在,各个服务器之间数据保持一致,所以其中某个服务器宕机不会导致数据丢失或无法访问。从这个角度说参与主从复制的Redis服务器构成了一个集群

2.搭建步骤

①思路

Redis集群在运行时使用的是同一个可执行文件,只是对应的配置文件不同。

每个配置文件中相同的参数是:

daemonize yes
dir /usr/local/cluster-redis

不同的参数有:

配置项名称 作用 取值
port Redis服务器启动后监听的端口号 6000
7000
8000
dbfilename RDB文件存储位置 dump6000.rdb
dump7000.rdb
dump8000.rdb
logfile 日志文件位置 /var/logs/redis6000.log
/var/logs/redis7000.log
/var/logs/redis8000.log
pidfile pid文件位置 /var/run/redis6000.pid
/var/run/redis7000.pid
/var/run/redis8000.pid

②步骤

  • 第一步:创建/usr/local/cluster-redis目录
  • 第二步:把原始未经修改的redis.conf复制到/usr/local/cluster-redis目录
  • 第三步:把/usr/local/cluster-redis目录下的redis.conf复制为redis6000.conf
  • 第四步:按照既定计划修改redis6000.conf中的相关配置项
    • daemonize yes
    • dir
    • port
    • dbfilename
    • logfile
    • pidfile
  • 第五步:复制redis6000.conf为redis7000.conf
  • 第六步:修改redis7000.conf中的相关配置项
    • port
    • dbfilename
    • logfile
    • pidfile
  • 第七步:复制redis6000.conf为redis8000.conf
  • 第八步:修改redis8000.conf中的相关配置项
    • port
    • dbfilename
    • logfile
    • pidfile

③启动Redis主从复制集群

/usr/local/redis/bin/redis-server /usr/local/cluster-redis/redis6000.conf
/usr/local/redis/bin/redis-server /usr/local/cluster-redis/redis7000.conf
/usr/local/redis/bin/redis-server /usr/local/cluster-redis/redis8000.conf

使用redis-cli停止指定服务器的命令格式如下:

/usr/local/bin/redis-cli -h IP地址 -p 端口号 shutdown

3.主从关系

①查看主从关系

127.0.0.1:6000> info replication
# Replication
role:master
connected_slaves:0

刚刚启动的集群服务器中每一个节点服务器都认为自己是主服务器。需要建立主从关系。

②设定主从关系

在从机上指定主机位置即可

SLAVEOF 127.0.0.1 6000

③取消主从关系

在从机上执行命令

SLAVEOF NO ONE

4.初步测试

  • 测试1:在主机写入数据,在从机查看
  • 测试2:在从机写入数据报错。配置文件中的依据是:slave-read-only yes
  • 测试3:主机执行SHUTDOWN看从机状态
  • 测试4:主机恢复启动,看从机状态
  • 测试5:从机SHUTDOWN,此时主机写入数据,从机恢复启动查看状态。重新设定主从关系后看新写入的数据是否同步。

5.哨兵模式

①作用

通过哨兵服务器监控master/slave实现主从复制集群的自动管理。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5CsPS1oS-1683956525442)(./images/p04.png)]

②相关概念

[1]主观下线

1台哨兵检测到某节点服务器下线。

[2]客观下线

认为某个节点服务器下线的哨兵服务器达到指定数量。这个数量后面在哨兵的启动配置文件中指定。

提示:只有 master 服务器做客观下线的判断, slave 只做主观下线的判定。

[3]心跳检查

心跳(heart beat)检查:客户端为了确认服务器端是否正在运行,不断的给服务器端发送数据库包。通过服务器端返回的数据包判断服务器端是否正在运行的工作机制。

③配置方式

简单起见我们只配置一台哨兵。我们所需要做的就是创建一个哨兵服务器运行所需要的配置文件。

vim /usr/local/cluster-redis/sentinel.conf

格式 sentinel monitor 为主机命名 主机IP 主机端口号 将主机判定为下线时需要Sentinel同意的数量
例子 sentinel monitor mymaster 127.0.0.1 6000 1

④启动哨兵

/usr/local/redis/bin/redis-server /usr/local/cluster-redis/sentinel.conf –sentinel

+sdown master mymaster 127.0.0.1 6379 【主观下线】
+odown master mymaster 127.0.0.1 6379 #quorum 1/1【客观下线】
……
+vote-for-leader 17818eb9240c8a625d2c8a13ae9d99ae3a70f9d2 1【选举leader】
……
+failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379【把一个从机设置为主机】

-------------挂掉的主机又重新启动---------------------
-sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381【离开主观下线状态】
+convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381【转换为从机】

假设两个 slave 服务器参与选举:

  • 情况1:
    • slave A:投票给 slave B
    • slave B:投票给 slave A
    • 两个服务器各得一票,平手,不能确定,需要继续投票
  • 情况2:
    • slave A:投票给自己
    • slave B:投票给自己
    • 两个服务器各得一票,平手,不能确定,需要继续投票
  • 情况3:
    • slave A:投票给自己
    • slave B:投票给 slave A
    • slave A 得 2 票,slave B 没有得票,所以 slave A 当选

七、发布订阅

这个功能不是 Redis 的主要功能,实际开发时发布订阅方面的需求还是要找专门的消息队列产品来完成。

1.订阅一个频道

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

2.在一个频道上发布信息

127.0.0.1:6379> PUBLISH cctv hai
(integer) 1
127.0.0.1:6379> SUBSCRIBE cctv
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "cctv"
3) (integer) 1
1) "message"
2) "cctv"
3) "hai"

八、Jedis

Jedis 是我们 Java 程序连接 Redis 服务器的客户端。

1.一个对比

MySQL Redis
连接 Connection Jedis
连接池 C3P0、DBCP、Druid等等 JedisPool
操作完成 关闭连接 关闭连接

2.Redis准备

①理解Redis配置文件中bind配置项含义

bind后面跟的ip地址是客户端访问Redis时使用的IP地址。规则是:Redis要求客户端访问的地址,必须是 bind 配置项绑定的地址。看下面例子:

bind值 访问方式
127.0.0.1 ./redis-cli -h 127.0.0.1
192.168.200.100 ./redis-cli -h 192.168.200.100

所以,结论是:bind 配置项要绑定可以对外暴露的本机地址。那么 Redis 为什么会有这样的要求?就是因为在实际项目中,Redis 不是给用户直接访问的,而是给 Java 程序访问的。所以 Redis 只要绑定一个内部访问地址,就能够屏蔽外部的访问,所以这个地址绑定机制,能够对 Redis 进行保护。

②查看Linux系统本机IP

远程客户端访问Linux服务器时不能使用127.0.0.1,要使用网络上的实际IP。可以用ifconfig命令查看。

③将Redis配置文件中的bind配置项设置为本机IP。

bind [你的实际IP]
bind 192.168.200.100

3.Jedis

	<dependency>
		<groupId>redis.clients</groupId>
		<artifactId>jedis</artifactId>
		<version>2.9.0</version>
	</dependency>
//指定Redis服务器的IP地址和端口号
Jedis jedis = new Jedis("192.168.200.100", 6379);

//执行ping命令
String ping = jedis.ping();

System.out.println(ping);

//关闭连接
jedis.close();

4.JedisPool

//声明Linux服务器IP地址
String host = "192.168.200.100";

//声明Redis端口号
int port = Protocol.DEFAULT_PORT;

//创建连接池对象
JedisPool jedisPool = new JedisPool(host, port);

//获取Jedis对象连接Redis
Jedis jedis = jedisPool.getResource();

//执行具体操作
String ping = jedis.ping();

System.out.println(ping);

//关闭连接
jedisPool.close();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redis的介绍及基本使用 的相关文章

随机推荐

  • Linux下JDK1.8安装及配置

    进入Linux系统Ubuntu debian或centos安装JDK1 8并配置环境变量 通过终端在 opt目录下新建base文件夹 命令行 sudo mkdir opt base 然后进入java目录 命令行 cd opt base 到官
  • Ubuntu安装Nvidia显卡驱动

    原来没那么复杂 https linuxconfig org how to install the nvidia drivers on ubuntu 18 04 bionic beaver linux 我用的第一种方法 安装途中遇到了一个 v
  • php ajax右边悬浮购物车,一个简单的php+Ajax购物车程序代码(1/2)_PHP教程

    cart name name this gt items SESSION this gt cart name setItemQuantity Set the quantity of an item param string order co
  • 远程服务器docker配置并启动jupyter lab

    前提摘要 在远程服务器docker中存在镜像 但想通过jupyter lab来更好的可视化代码结果 首先登录远程服务器ssh 并拉取镜像 p是端口映射 22给ssh连接 jupyter lab的默认端口是8889 8888是自己的端口号 n
  • Ubuntu下OpenResty 搭建高性能服务端

    Socke 介绍 Linux Socket 编程领域为了处理大量连接请求场景 需要使用非阻塞 I O 和复用 select poll epoll 是 Linux API 提供的 I O 复用方式 自从 Linux2 6 中加入了 epoll
  • 函数式,F#都做了哪些优化?

    非函数式语言中使用函数式风格的缺点 函数式的优点 想必大家都已经非常了解了 我们来看看 一般语言使用函数式风格可能带来的问题 变量默认是可变的 为了实现不可变性 开发者只能人为的规范不去改变变量的值 没有明确的变量修改提示 容易因失误改变变
  • 手撸软件测试框架——lua版(四)

    本文简单介绍一下开发测试用例用到的几个关键接口 1 断言 在测试用例中少不了对结果进行校验 校验的方法一般称为断言 assert 也就是说 在进行一系列的操作之后 断定会出现某个确定性的结果 如果这个确定性的结果如期出现 则断言成功 被测试
  • spring读取resources文件夹下的文件报错:cannot be resolved to absolute file path because it dose not reside in th

    spring springboot读取resources文件夹下的文件报错 cannot be resolved to absolute file path because it dose not reside in the file sy
  • k8s之存储、SC、STS、DS篇(一些常见的存储方案)

    为什么要做持久化存储 在k8s中部署的应用都是以pod容器的形式运行的 假如我们部署MySQL Redis等数据库 需要对这些数据库产生的数据做备份 因为Pod是有生命周期的 如果pod不挂载数据卷 那pod被删除或重启后这些数据会随之消失
  • 关于 最新版idea(2021.3.3) 在配置XML文件时候,因为没有加上 .xml变成了文档模式的解决方式

    关于 最新版idea 2021 3 3 在配置XML文件时候 因为没有加上 xml变成了文档模式的解决方式 首先就是关于自己的这个问题 自己到各大论坛上面找了半天 发现更多的都是旧版的 而且上面解决方式根本在新版的idea中根本不能用 最后
  • Hbase分布式集群搭建

    环境准备 hbase软件包 http mirror bit edu cn apache hbase 1 3 1 hbase 1 3 1 bin tar gz 完成hadoop集群环境搭建 安装hbase 首先在hadoop master安装
  • 门函数卷积_卷积及其应用

    卷积公式的由来 卷积公式最开始来自于古典概型 如题 掷两次公平的骰子 点数之和等于8的概率 设随机变量 为第一次掷得的点数 随机变量 为第二次掷得的点数 因此不考虑点数之和等于8的条件 则有 种样本空间 根据条件 相当于给随机变量的取值限定
  • 视觉SLAM十四讲 读书编程笔记 Chapter6 非线性优化

    Chapter6 非线性优化 实践 Ceres 1 安装Ceres依赖库 2 编译安装Ceres 3 曲线拟合问题描述 4 ceres使用方法 5 完整代码 实践 g2o 1 安装g2o依赖库 2 编译安装g2o 3 g2o使用方法 4 完
  • 正确配置并且测试HttpListener的方法(httpcfg的使用)

    在此我列出一些我个人遇到的问题和注意点 具体步骤可以参考后面的参考链接 1 用HttpListener写一个简单的http server 2 使用makecert创建服务器端的认证证书 makecert包含在Windows SDK 中 co
  • 我的世界java版高效率刷怪塔_我的世界超高效率刷怪塔制作教程 砍怪砍到手抽筋...

    刷怪塔能让我们的游戏变的非常的简单 因为无限的经验和物品让我们的游戏变的很爽 今天游戏园小编就为大家分享一个刷怪塔的制作教程 希望大家能够喜欢 做刷怪塔之前先来了解一下游戏刷怪的原理 网上很多人说 刷怪原里是 以玩家为中心 42米以外到72
  • 【多线程】synchronized同步代码块

    一 前言 使用synchronized声明的方法在 某些情况下是有弊端的 比如A线程调用同步的方法执行一个长时间的任务 那么B线程就必须等待比较长的时间才能执行 这种情况可以使用synchronized代码块去优化代码执行时间 也就是通常所
  • 五日均线指标编程案例讲解

    通达信指标编程指南 清泉老师带你一步一步学习通达信指标编程 让你慢慢成为指标编程专家 目录 通达信指标编程指南 文章目录 前言 一 什么是五日均线 二 五日均线编程步骤 1 设定均线参数 2 计算移动平均值 3 测试源代码 总结 前言 随着
  • 简单搭建mybatis开发环境

    目录 前言 1 项目目录结构总览 2 准备工作 2 1 新建测试项目 下载jar包 2 2 创建数据库表 本文使用的mysq数据库 3 环境搭建 3 1 根据目录结构创建对应文件 导包 3 2 配置资源文件 3 3 department包中
  • VM中某块盘无法使用

    现象 VM中有一块盘 进入mount点后 ls显示错误 root es10 data2 ls ls cannot open directory Input output error 跟踪分析 查看磁盘 root es10 lsblk gre
  • Redis的介绍及基本使用

    学习尚硅谷的Redis学习时所做的笔记 一 Redis的应用场景 Redis的典型应用场景 1 缓存 使用Redis可以建立性能非常出色的缓存服务器 查询请求先在Redis中查找所需要的数据 如果能够查询到 命中 则直接返回 大大减轻关系型