【Java】 Java中间件之Redis 搭建单机版Redis

1.什么是Redis

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 非关系型数据库(也可以称之为 NoSql 数据库 这里的 NoSql 不是没有Sql的意思  是 Not Only Sql 的意思 ),并提供多种语言的API
 

2.Redis的特点

1. 支持持久化

Redis支持持久化(RDB模式,AOF模式)重启后 Redis 可以从磁盘中重新将数据加载到内存中

2. 支持的数据结构

key-value ,String,list,set,zset,hash

3. 超高的性能

据官方数据表示Redis读的速度是110000次/秒 ,写的速度是81000次/秒

3.单线程

Redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销

Redis单线程指的是在网络请求模块使用了一个线程,不考虑并发安全问题,即一个线程处理处理所有的网络请求

其他模块仍然用了多线程

Redis 多路复用

多个网络Socket复用一个IO线程,本质还是那个网络请求模块的单线程通过记录跟踪每一个Sockt状态来同时管理多个IO流

4.为什么要用Redis

我的理解就是减轻数据库压力,快速响应用户请求

5.缓存雪崩

Redis是可以设置缓存过期时间的,简单的理解缓存雪崩就是 在同一时间大面积的缓存过期 ,从而导致访问直接怼到数据库上了,这压力可想而知,很可能会造成整个系统的崩溃

解决方案

1. 加锁 

保证不会有大量的线程对数据库一次性进行读写访问,减轻数据库压力

2. 分散缓存过期时间

简单说就是 缓存过期时间设置的分散点 别同时掉链子

6.缓存穿透

用户查询数据 数据库中没有 Redis缓存中也没有,这样导致每次都要去数据库查询一遍然后返回空值(相当于做了两次无用的查询)

黑客就会利用这个缓存穿透的漏洞 直接访问你的数据库,后果可想而知,搞不好会导致整个系统崩溃

解决方案

1. 布隆过滤器(常用)

采用布隆过滤器 将所有可能存在的数据哈希到一个足够大的bitmap中 一个一定不存在的数据会被这个bitmap拦截掉

2.  加锁

利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库,没得到锁,则休眠一段时间重试

总结 缓存穿透缓存雪崩 本质问题都是绕过Redis直接干到数据库上,给数据库造成巨大的压力从而导致系统崩溃,面试中常常会问到这两个问题

7.数据一致性问题

Redis经典操作就是 数据库读写 + Redis缓存

1. 先读缓存,发现缓存中没有数据,再去读数据库,在响应客户端请求的同时,将数据缓存到Redis中,要知道Redis写的速度可是81000/秒

2. 更新的时候先去数据库更新,同时删除Redis缓存,当客户端发来新的请求还是遵循第一步 先读再去缓存的原则

数据不一致问题 1

有这么一种场景 我们去更新数据库 数据库更新成功了 但Redis缓存删除却失败了 这就会导致数据的不一致问题

解决办法

按顺序执行 先删除缓存再去更新数据库,即便数据库更新失败 但缓存是空的了,这样再遵循 读写+缓存 的原则 数据还是一致的

数据不一致问题 2

有这么一种场景 当我们更新数据库的时候 先把缓存删了,然后去更新数据库,就在此时此刻 一个客户端请求干过来了,发现缓存中没有数据 直接去读数据库,此时你的数据还没有更新完成,但另一个客户端已经读到数据并放入Redis缓存中,这样导致了数据不一致

解决办法

在Java代码更新处加入重入锁保证在修改数据的时候没有其他线程来干扰我

8.过期策略淘汰策略

redis在set key 的时候可以指定 key 的过期时间(Expire Time)

key 到期后 Redis 对其删除的策略

1.  定期删除

每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除,该策略可以立即清除过期的数据,对内存很友好,但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量

2. 惰性删除

只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好,极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存

3. 定时过期

每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量

9.内存淘汰机制

大量过期key堆积在内存里,导致redis内存块耗尽了,这时候就要使用Redis的内存淘汰机制

策略如下

1. noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧

2.  allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)

3. allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧

4. volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)

5. volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key

6. volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

 

10.在Linux上搭建单机版前台启动Redis

如果不知道怎么在 vmware 上安装CentOS虚拟机  看这里

1. Redis 是C语言开发的,安装Redis需要C语言环境,如果没有 gcc 需要在线安装 针对Redis6.0 以上版本 需要按照以下命令依次执行

yum install -y gcc-c++

yum -y install centos-release-scl

yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
 
scl enable devtoolset-9 bash

echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile

2. 下载 Redis     Redis 下载地址

3. 将下载好的 Redis 压缩包上传到 CentOS 指定目录 这里我上传的目录是 /usr/local/apps

4. 执行redis 解压命令

tar -zxvf redis-6.0.8.tar.gz

5.  在 /usr/local 下创建 redis 文件夹 (这个文件夹使我们最终安装 Redis 的文件夹)

6. 回到 /usr/local/apps 文件夹下并进入 redis 解压后的源码目录 执行 make 命令

cd /usr/local/apps/redis-6.0.8

直到出现 

Hint: It's a good idea to run 'make test' 

证明 make 命令执行成功

7. 安装 redis 执行如下命令 这里的 /usr/local/redis 就是第五步我们创建的 redis 文件夹

make install PREFIX=/usr/local/redis

出现

Hint: It's a good idea to run 'make test' 

证明安装成功

8. 启动 Redis  

进入 redis 安装目录

cd /usr/local/redis/bin

执行如下命令

./redis-server

出现小奶酪 证明 redis 启动成功

9. 关闭redis 

./redis-cli shutdown

11.Redis后台启动

上面我们已经将 redis 启动成功,接下来我们讲一下如何在后台启动 redis

1. 我们首先停掉 redis 服务  

ctrl+c 结束当前进程 (即 windows 拷贝快捷键)

2.  后端启动需要 redis.conf 配置文件  redis.conf 文件在redis编译目录下(/usr/local/apps/redis-6.0.8)

将其拷贝到 /usr/local/redis/bin/ 下

cp redis.conf /usr/local/redis/bin/

3. 进入  /usr/local/redis/bin/ 目录下 对 redis.conf  文件进行编辑  编辑技巧

daemonize no 节点更改为  daemonize yes

注释掉  bind 127.0.0.1 节点

 protected-mode  yes 节点更改为 protected-mode no

为后续的SpringBoot整合 Redis 连接做准备

4. 保存退出后 后台启动redis 

./redis-server redis.conf

5. 查看 redis 是否启动成功 

ps aux|grep redis

出现如下

证明启动成功

6. 关闭 redis

./redis-cli shutdown

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个同时支持 Redis 集群版与单机版的 Spring Boot Java 客户端的示例代码: 首先,你需要引入 Redis 客户端库 jedis: ```xml <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.5.3</version> </dependency> ``` 然后,你可以创建一个 RedisClient 类,实现连接池的初始化、数据操作等功能: ```java import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import redis.clients.jedis.*; import javax.annotation.PostConstruct; import java.util.HashSet; import java.util.Set; @Component public class RedisClient { private JedisPool jedisPool; private JedisCluster jedisCluster; @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.password}") private String password; @Value("${spring.redis.timeout}") private int timeout; @Value("${spring.redis.pool.max-active}") private int maxActive; @Value("${spring.redis.pool.max-idle}") private int maxIdle; @Value("${spring.redis.pool.max-wait}") private long maxWaitMillis; @Value("${spring.redis.pool.min-idle}") private int minIdle; @Value("${spring.redis.cluster.nodes}") private String clusterNodes; @Value("${spring.redis.cluster.max-redirects}") private int maxRedirects; @PostConstruct public void init() { if (clusterNodes == null || clusterNodes.isEmpty()) { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(maxActive); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMaxWaitMillis(maxWaitMillis); jedisPoolConfig.setMinIdle(minIdle); jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password); } else { Set<HostAndPort> jedisClusterNodes = new HashSet<>(); for (String node : clusterNodes.split(",")) { String[] parts = node.split(":"); jedisClusterNodes.add(new HostAndPort(parts[0], Integer.parseInt(parts[1]))); } JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(maxActive); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMaxWaitMillis(maxWaitMillis); jedisPoolConfig.setMinIdle(minIdle); jedisCluster = new JedisCluster(jedisClusterNodes, timeout, timeout, maxRedirects, password, jedisPoolConfig); } } public String get(String key) { if (jedisPool != null) { try (Jedis jedis = jedisPool.getResource()) { return jedis.get(key); } } else { return jedisCluster.get(key); } } public void set(String key, String value) { if (jedisPool != null) { try (Jedis jedis = jedisPool.getResource()) { jedis.set(key, value); } } else { jedisCluster.set(key, value); } } public void del(String key) { if (jedisPool != null) { try (Jedis jedis = jedisPool.getResource()) { jedis.del(key); } } else { jedisCluster.del(key); } } // 其他操作... public void close() { if (jedisPool != null) { jedisPool.close(); } else { jedisCluster.close(); } } } ``` 在这个示例中,我们增加了一个 init() 方法用来初始化 Redis 连接池,根据配置文件中是否配置了 Redis 集群节点信息来选择使用 JedisPool 还是 JedisCluster。然后,我们可以在 RedisClient 中实现 Redis 的各种操作方法,例如 get、set、del 等。 最后,我们可以在 Spring Boot 应用程序中使用 RedisClient 来连接 Redis,例如: ```java @Autowired RedisClient redisClient; redisClient.set("key", "value"); String value = redisClient.get("key"); System.out.println(value); redisClient.del("key"); redisClient.close(); ``` 这是一个同时支持 Redis 集群版与单机版的 Spring Boot Java 客户端示例,你可以根据实际需求进行扩展和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值