java之Redis 专题 丨【奔跑吧!JAVA】

网友投稿 604 2022-05-29

一、 redis 基本知识

1.1. redis 概述

Redis 本质上是一个 Key-Value 类型的内存数据库,很像 memcached,整个 数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据 flush 到硬盘上进行保存。因为是纯内存操作,Redis 的性能非常出色,每秒 可以处理超过 10 万次读写操作,是已知性能最快的 Key-Value DB。Redis 的出色之处不仅仅是性能,

Redis 最大的魅力是支持保存多种数据结构,此外单 个 value 的最大限制是 1GB,不像 memcached 只能保存 1MB 的数据,另外 Redis 也可以对存入的 Key-Value 设置 expire 时间。

Redis 的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此 Redis 适合的场景主要局限在较小数据量的高性能操作和运算上。

【redis 是什么?】数据库分为关系数据库和键值数据库 redis 在本质上是键值数据库

1.xml 配置文件中配置 bean(JedisPool/JedisCluster),再配置属性注入指定 redis 的 host 和 port,集群的话需 要指定每一个 redis 的 host 和 port,在配置一个 bean(自己写的 JedisClient 接口)

2.【面相接口编程】项目中 JedisClient 接口工具类的书写

【接口】写一个 JedisClient 接口,接口中有 set、get、hset、hget、hdel、expire 等常用方法;

【实现类】分别用集群版的 JedisClientCluster 和单机版的 JedisClientPool 去实现,并重写方法,各自用自 己的方式实现功能;

【调用】在管理 redis 的时候,我们只需要@AutoWied(只打开一个得情况下)注入接口,只需要调用接 口里的方法,不用管调用的是集群版还是单机版的,这个可以在配置文件中控制。

【存值】项目中存的时候用的是存 hash 值,一个 key,对应一个 map(key,value);redis 可以存五种类型的数据(string、list、set、zset(sorted set)、hash);因为加入存入的是 string 的简单的 key/value 类型,不同表的 id 可能会重复, 所以在最前面要添加一个商品的大的类目作为区分

【应用逻辑】在查询一个商品的时候先查 redis 缓存,如果有取缓存,如果没有,查数据库,同步缓存; 当数据库跟新的时候,进行 redis 缓存的 id 覆盖/删除

1.2 java 管理 redis

1)通过 jedis 单机版的通过 JedisPool 获取一个 Jedis 对象来 set、get 管理,用完需要关闭 Jedis 集群版的通过 JedisCluster 来 set、get 管理

2)通过 spring data redis,项目中这种

1.3 Redis 五种数据类型(不能存储对象)

1.String:key-value(做缓存)

常用命令:

get /set /incr 加一

/decr 减一

2.Hash:key-fields-values(做缓存)

(相当于一个 key 对应一个 map,map 中还有 key-value)

常用命令:

hset:从 hash 中添加内容/hget:从 hash 中取内容

hset hash1 field3 3 /hget hash1 field3

3.List:有顺序可重复

常用命令:

添加:lpush/rpush/

查看:lrange list1 0 -1/

取删:lpop/ rpop

4.Set:无顺序,不能重复

常用命令:

添加:sadd set1 a b c c c d

查看:smembers set1

删除:srem set1 a

5.SortedSet(zset):有顺序,不能重复

常用命令:

分数添加:zadd zset1 2 a 5 b 1 c 6 d

分数查看:zrange zset1 0 -1

删除:zrem zset1 a

反过来顺序查看:zrevrange zset1 0 -1

1.4 key 命令

设置 10 秒钟过期: expire key 秒

查看过期时间(s) : ttl key

设置持久化: persist key , ttl key 值为-1,意思为持久保存,值为-2,意思是不存在/已经删掉了

1.5 Redis 持久化

RDB 持久化(默认方式)

该机制是指在制定的时间间隔内将内存中的数据集快照写入磁盘。

优点: 1.只有一份 rdb 文件,可随时备份

2.比 AOF 文件小,加载效率高

3.只提供 fork 子进程,不阻塞主进程,IO 操作比较少

AOF 持久化

该机制将以日志的形式记录服务器所处理的每一个写操作,在 Redis 服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。

优点: 1.每次改动同步数据安全性好

2.APPEND 方式追加日志,不会对旧日志文件产生影响

无持久化

我们可以通过配置的方式禁用 Redis 服务器的持久化功能,这样我们就可以将 Redis 视为一个功能加强版 的 memcached 了

同时应用 AOF 和 RDB(推荐用)

用 AOF 来保证数据不丢失,作为恢复数据的第一选择;用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,可以使用 RDB 进行快速的数据恢复。

二、redis 集群知识

2.1 redis 集群

集群指的是将几台服务器集中在一起,实现同一业务

目的:高可用、负载均衡、易扩展、数据安全、性能提升

技术:集群地址(虚拟 IP)、网络通信(监控消息)

功能:负载均衡、读写分离、故障转移

2.2 怎样判断 redis 服务是否正常?

ping-pong 机制来判断节点是否挂了

启动./redis-service redis.conf(后台运行)

客户端:./reids-cli -h -p (默认 6379)来连接

还可以通过哨兵模式监控(多了解下哨兵模式)

2.3 架构细节

(1)所有的 redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化速度和带宽.

(2)节点的 fail 是通过集群中超过半数的节点检测失效时才生效.

(3)客户端与 redis 节点直连,不需要中间 proxy 层.

客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可

(4)redis-cluster 把所有的物理节点映射到[0-16383]slot 上,cluster 负责维护

(5)每个节点存储的数据不一样,但每个节点都会有备份机,主从机存储一样的数据

集群如何存储数据

Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0- 16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点

2.4 redis 集群搭建过程(使用 ruby 脚本搭建集群)

-->删除 aof 和 rdb 文件

-->安装 ruby 和 ruby 使用的脚本包 redis-gem

--> 得到 redis-trib.rb,用它来创建集群

三、常问问题

1   为什么 redis 的查询速度比 mysql 数据库快?

1.存在物理内存中

2.是键值数据库,本身具有简单快捷的特点

redis 是怎样存入磁盘的?

dump.rdb 和 appendonly.aof 两个配置文件【rdbaof 热带暴风】

RDB:在指定时间间隔内将内存中的数据集快照写入磁盘(默认)

AOF:以日志的形式将记录服务器的每一个操作

2   为什么 redis 集群中必须至少有三个节点?

一个节点挂了,有一半以上的节点通过 ping-pong 方式的投票机制认为它挂了,那么这个集群就挂了.

但如果 只有 2 个节点,有一个挂了,另一个确定它挂了但百分比只占到了 50%,没有超过一半,这个集群也不会挂,所以至 少需要 3 个节点;

3   为什么每个 redis 集群需要至少 6 台服务器?

因为 redis 集群至少需要三个节点,要保证集群的高可用,每个节点都要一个备份机.理论上也需要 6 台虚拟机

4 redis 优缺点

Redis 的优点?

性能极高 – Redis 能支持超过 100K+ 每秒的读写频率。

丰富的数据类型 – Redis 支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。

原子 –

Redis 的所有操作都是原子性的,同时 Redis 还支持对几个操作全并后的原子性执行。

丰富的特性 – Redis 还支持 publish/subscribe, 通知, key 过期等等特性。

Redis 相比其它缓存,他有两种持久化机制,RDB 和 AOF,数据更安全。

Redis 的缺点?

是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此 Redis 适合的场景主要局限在较小数据量的高性能操作和运算上。

5 一致性哈希算法 一

致性哈希算法(Consistent Hashing Algorithm)是一种分布式算法,常用于负载均衡。twemproxy 也选择这种 算法,解决将 key-value 均匀分配到众多 server 上的问题。它可以取代传统的取模操作,解决了取模操作应对 增删 Server 的问题。

**

步骤

**

1. 先用 hash 算法将对应的节点 ip 哈希到一个具有 2^32 次方个桶的空间中,即 0~(2^32)-1 的数字空间。

现在我们可以将这些数字头尾相连,连接成一个闭合的环形

2. 当用户在客户端进行请求时候,首先根据 key 计算路由 hash 值,然后看 hash 值落到了 hash 环的哪个地方,根据 hash 值在 hash 环上的位置顺时针找距离最近的节点

3. 当新增节点的时候,和之前的做法一样,只需要把受到影响的数据迁移到新节点即可新增 Master4 节点:

4. 当移除节点的时候,和之前的做法一样,把移除节点的数据,迁移到顺时针距离最近的节点移除 Master2 节点:

当节点个数变动时,使用哈希一致性映射关系失效的对象非常少,迁移成本也非 常小。那么判断一个哈希算法好坏的指标有哪些呢?以下列出了 3 个指标:

* 平衡性(Balance):

平衡性是指哈希的结果能够尽可能分散到不同的缓存服务器上去,这样可以使得所有的服务器得到利用。 一致性 hash 可以做到每个服务器都进行处理理请求,但是不能保证每个服务器处理的请求的数量大致相同

* 单调性(Monotonicity):

单调性是指如果已经有一些请求通过哈希分派到了相应的服务器进行处理,又有新的服务器加入到系统中时候,哈希的结果应保证原有的请求可以被映射到原有的或者新的服务器中去,而不会被映射到原来的其它服务器上去。

* 分散性(Spread):

分布式环境中,客户端请求时候可能不知道所有服务器的存在,可能只知道其中一部分服务器,在客户端 看来他看到的部分服务器会形成一个完整的 hash 环。如果多个客户端都把部分服务器作为一个完整 hash 环,那么可能会导致,同一个用户的请求被路由到不同的服务器进行处理。这种情况显然是应该避免的,因为它不

能保证同一个用户的请求落到同一个服务器。所谓分散性是指上述情况发生的严重程度。好的哈希算法应尽量避免尽量降低分散性。 而一致性 hash 具有很低的分散性。

6 使用过 Redis 做异步队列么,你是怎么用的?有什么缺点?

一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep 一会再重试。

缺点:

在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如 rabbitmq 等。

7 什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

缓存穿透

一般的缓存系统,都是按照 key 去缓存查询,如果不存在对应的 value,就应该去后端系统查找(比如 DB)。

一些恶意的请求会故意查询不存在的 key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免?

1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该 key 对应的数据 insert 了之后清理缓存。

2:对一定不存在的 key 进行过滤。可以把所有的可能存在的 key 放到一个大的 Bitmap 中,查询时通过该 bitmap 过滤。

缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。 导致系统崩溃。

如何避免?

1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个 key 只允许一个线程查询数据和写缓存,其他线程等待。

2:做二级缓存,A1 为原始缓存,A2 为拷贝缓存,A1 失效时,可以访问 A2,A1 缓存失效时间设置为短期,A2 设置为长期

3:不同的 key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

8 Redis 为什么是单线程的?

单纯的网络 IO 来说,量大到一定程度之后,多线程的确有优势——但并不是单纯的多线程,而是每个线程自 己有自己的 epoll 这样的模型,也就是多线程和 multiplexing 混合。一般这个开头我们都会跟一个“但是”。但是。还要考虑 Redis 操作的对象。它操作的对象是内存中的数据结构。如果在多线程中操作,那就需要为这些 对象加锁。最终来说,多线程性能有提高,但是每个线程的效率严重下降了。而且程序的逻辑严重复杂化。要知道 Redis 的数据结构并不全是简单KeyValue,还有列表,hash,map 等等复杂的结构,这些结构有可能会 进行很细粒度的操作,比如在很长的列表后面添加一个元素,在 hash 当中添加或者删除一个对象,等等。一些操作还可以合成 MULTI/EXEC 的组。这样一个操作中可能就需要加非常多的锁,导致的结果是同步开销大大增加。这还带来一个恶果就是吞吐量虽然增大,但是响应延迟可能会增加。

Redis 在权衡之后的选择是用单线程,突出自己功能的灵活性。在单线程基础上任何原子操作都可以几乎无代 价地实现,多么复杂的数据结构都可以轻松运用,甚至可以使用 Lua 脚本这样的功能。对于多线程来说这需要 高得多的代价。

并不是所有的 KV 数据库或者内存数据库都应该用单线程,比如 ZooKeeper 就是多线程的,最终还是看自己的意愿和取舍。单线程的威力实际上非常强大,每核心效率也非常高,在今天的虚拟化环境当中可以充分利 用云化环境来提高资源利用率。多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的,所以单线程、多进程的集群不失为一个时髦的解决方案。

9 redis 的通信协议是什么?

我们不需要一个特殊的 Redis客户端仅靠Telnet或者是文本流就可以跟Redis进行通讯。客户端的命令格式:

简单字符串Simple Strings,以“+"加号开头。错误Errors,以"-"减号开头。

整数型Integer,以“”冒号开头。

大字符串类型Bulk Strings,以"$美元符号开头。

java之Redis 专题 丨【奔跑吧!JAVA】

数组类型Arrays,以“*"星号开头。

set hello abc 一个简单的文本流就可以是redis的客户端

简单总结:具体可以见:

https://redis.io/topics/protocol ,

Redis 文档认为简单的实现,快速的解析,直观理解是采用 RESP 文本协议最重要的地方,有可能文本协议会造成一定量的流量浪费,但却在性能上和操作上快速简单,这中间也是一个权衡和协调的过程。

10 redis 使用场景

(1)、会话缓存(Session Cache)

(2)、全页缓存(FPC)

(3)、队列

(4)、排行榜/计数器

(5)、发布/订阅

11 如何提高缓存的利用率?

做数据的缓存时,因为数据量很大,而且缓存是把数据保存到内存中,此时不可能把所有的数据都放到缓存中。

所以需要设置数据缓存的有效期,当用户访问到非热点数据后,此数据放到缓存中,当缓存到期后就从缓 存中删除,而且长时间不会添加到缓存。而热点数据一旦从缓存中删除会马上又添加到缓存。这样可以提 高缓存的利用率,同时也减轻了数据库的压力。

12 项目中使用到了缓存,那么如何实现缓存同步的?

只要使用了缓存就涉及到缓存同步的问题。缓存同步其实就是当缓存的信息发生变化,也就是对后台对缓存的 数据进行增、删、改操作后,数据库中的数据发生了化同时要把缓存中的数据对应删除即可。当页面再次请求数据时,缓存中不能命中就会从数据库中查询并且添加到缓存中,即实现了缓存同步。

13 redis 事物,了解 CAS(check-and-set 操作实现乐观锁 )?

和 众 多 其 它 数 据 库 一 样 , Redis 作 为 NoSQL 数 据 库 也 同 样 提 供 了 事 务 机 制 。 在 Redis 中 , MULTI/EXEC/DISCARD/WATCH 这四个命令是我们实现事务的基石。相信对有关系型数据库开发经验的开发者 而言这一概念并不陌生,即便如此,我们还是会简要的列出

Redis 中

事务的实现特征:

1). 在事务中的所有命令都将会被串行化的顺序执行,事务执行期间,Redis 不会再为其它客户端的请求提供任

何服务,从而保证了事物中的所有命令被原子的执行。

2). 和关系型数据库中的事务相比,在 Redis 事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。

3). 我们可以通过 MULTI 命令开启一个事务,有关系型数据库开发经验的人可以将其理解为"BEGIN TRANSACTION"语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行 EXEC/DISCARD 命令来提交/回滚该事务内的所有操作。这两个 Redis 命令可被视为等同于关系型数据库中的 COMMIT/ROLLBACK 语句。

4). 在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不

会被服务器执行。然而如果网络中断事件是发生在客户端执行 EXEC 命令之后,那么该事务中的所有命令都会

被服务器执行。

5). 当使用 Append-Only 模式时,Redis 会通过调用系统函数 write 将该事务内的所有写操作在本次调用中全部 写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写 入到磁盘,而另外一部分数据却已经丢失。

Redis 服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的 错误提示。此时,我们就要充分利用 Redis 工具包中提供的 redis-check-aof 工具,该工具可以帮助我们定位到 数据不一致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动 Redis 服务器了。

14  Redis 有哪几种数据结构?

Redis 的数据结构有五种,分别是:

String——字符串

String 数据结构是简单的 key-value 类型,value 不仅可以是 String,也可以是数字(当数字类型用 Long 可以表示的时候 encoding 就是整型,其他都存储在 sdshdr 当做字符串)。

Hash——字典

在 Memcached 中,我们经常将一些结构化的信息打包成 hashmap,在客户端序列化后存储为一个字符串的值 (一般是 JSON 格式),比如用户的昵称、年龄、性别、积分等。

List——列表

List 说白了就是链表(redis 使用双端链表实现的 List),相信学过数据结构知识的人都应该能理解其结构。

Set——集合

Set 就是一个集合,集合的概念就是一堆不重复值的组合。利用 Redis 提供的 Set 数据结构,可以存储一些集合性的数据。

Sorted Set——有序集合

和 Sets 相比,Sorted Sets 是将 Set 中的元素增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,

1. 带有权重的元素,比如一个游戏的用户得分排行榜

2.比较复杂的数据结构,一般用到的场景不算太多

【奔跑吧!JAVA】有奖征文火热进行中:https://bbs.huaweicloud.com/blogs/265241

Java Redis Spring

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spark_算子调优
下一篇:GaussDB for DWS gds线下迁移
相关文章