微服务之缓存

引言

在微服务架构中,服务拆分导致系统复杂度呈指数级增长。据统计,高并发场景下直接访问数据库的请求响应时间可能增加300%-500%,而合理的缓存设计可将接口响应速度提升5-10倍。缓存作为分布式系统的"速度调节器",已成为现代微服务架构中不可或缺的关键组件。

一、 为什么需要缓存?

  1. 性能加速:将热点数据存储在内存中,访问速度比传统机械硬盘快10^5倍

  2. 流量削峰:抵御突发流量,某电商大促期间缓存承担了92%的请求

  3. 成本优化:1GB内存成本约0.3元/小时,而相同容量SSB的成本是其3倍

  4. 高可用保障:在数据库故障时提供降级保护

二、 主流缓存方案对比

缓存类型吞吐量数据结构持久化集群方案适用场景
Redis100,000 QPS丰富支持Codis/Cluster分布式缓存、会话共享
Memcached200,000 QPS单一不支持一致性Hash简单KV缓存
  1. 数据类型支持‌:

    • Redis‌支持多种数据结构,包括String、List、Set、Zset、Hash、Bitmap等,适合需要复杂数据操作的场景‌。
    • Memcached‌仅支持简单的key-value数据类型,适用于需要大量简单键值存储的场景‌。
  2. 持久化‌:

    • Redis‌支持RDB和AOF两种持久化方式,可以配置数据备份和恢复,适合需要数据持久化的场景‌。
    • Memcached‌不支持数据持久化,重启后数据会丢失,适合对数据持久性要求不高的场景‌。
  3. 性能和稳定性‌:

    • Redis‌在6.0版本之前使用单线程模型,适合IO密集型操作,但在处理计算密集型任务时可能会成为瓶颈。6.0版本后支持多线程,提升了处理复杂任务的能力‌1。
    • Memcached‌采用多线程模型,适合多核处理,但在某些操作上需要加锁,可能会影响性能‌。

三、 Java微服务缓存选型建议

  • Redis‌适用于需要复杂数据结构、高可用性和数据持久化的场景。例如,需要存储复杂对象、支持高并发读写、需要数据备份和恢复的场景‌3。
  • Memcached‌适用于纯key-value存储、高并发访问且对数据一致性要求不高的场景。例如,大规模的在线交易系统、需要快速读写大量数据的场景‌3。

在Java生态中,Redis以63.7%的采用率位居榜首(2023年JVM生态报告),其优势在于:

  • 支持String/Hash/List等6种数据结构

  • 提供RDB+AOF双重持久化方案

  • 原生支持Cluster集群模式

  • 丰富的扩展模块(RediSearch/BloomFilter等)

四、redis搭建

1. 单机模式部署

  •   linux安装gcc(c,c++编译器)用来编译redis

yum install gcc

  •  下载redis到opt目錄

cd /opt

wget http://download.redis.io/releases/redis-6.2.6.tar.gz

-- 这个网络不通的话 去

 wget https://gitee.com/Hellohanli/redis/blob/master/redis-6.2.6.tar.gz

  •  解压压缩包

tar -zxvf redis-6.2.6.tar.gz

  • 编译 

 # 在解压目录下执行

 make

  • 安装到指定目录 

make PREFIX=/usr/local/redis install  

  • 增加目录 

#配置文件存放路径

mkdir /usr/local/redis/conf

#数据存放目录

mkdir /usr/local/redis/data

#日志存放目录

mkdir /usr/local/redis/logs

#拷贝 配置文件到安装目录

cp /opt/redis-6.2.2/redis.conf /usr/local/redis/conf/redis.conf 

  •  修改安装目录下的配置文件,修改指定的内容即可,vi /usr/local/redis/conf/redis.conf

 #用于指定本机网卡对应的IP地址,如果是默认 127.0.0.1 的话,则只有本机可以访问。如果注释掉则表示客户端可以通过本机所有网卡进来,如果这样设置,且没有设置 requirepass 密码, redis 默认开始了保护模式 protected-mode,则其它客户端都可以连接,但是一发送命令就会失败

bind 192.168.86.140

#数据存放目录

dir /usr/local/redis/data

#是否后台运行

daemonize yes

#日志文件

logfile "/usr/local/redis/logs/redis.log"

#设置客户端连接后进行任何其他操作前需要使用的密码 requirepass pass

requirepass pass

  • 启动 redis-server 

cd /usr/local/redis/bin

./redis-server ../conf/redis.conf 

  • 检查 

ps -ef | grep redis

./redis-cli -h 127.0.0.1 -p 6379

2.集群模式部署 

2.1. 环境准备

  • 三台服务器:假设三台服务器的IP分别为:

    • 192.168.1.101(主节点)

    • 192.168.1.102(从节点1)

    • 192.168.1.103(从节点2)

  • Redis版本:Redis 6.x 或更高版本。

  • 端口规划

    • Redis 主从节点使用 6379 端口。

    • 哨兵节点使用 26379 端口。


2.2. 安装Redis

在三台服务器上分别安装Redis。

2.2.1 安装依赖
# apt:是用于 Debian、Ubuntu
# yum:是用于 Red Hat、CentOS、Fedora  根据系统选择
sudo apt-get update
sudo apt-get install build-essential tcl
2.2.2 下载并编译Redis
# 下载压缩包
wget http://download.redis.io/releases/redis-6.2.6.tar.gz
# 解压压缩包
tar xzf redis-6.2.6.tar.gz
# 进入目录
cd redis-6.2.6
#编译
make
#安装
sudo make install

2.3. 配置主从节点

2.3.1 主节点配置(192.168.1.101)

编辑配置文件 /etc/redis/6379.conf

# 用于指定本机网卡对应的IP地址 
bind 192.168.1.101
port 6379
#是否后台运行
daemonize yes
#日志文件
logfile "/var/log/redis/redis.log"
dir /var/lib/redis

启动Redis:

redis-server /etc/redis/6379.conf
2.3.2 从节点1配置(192.168.1.102)

编辑配置文件 /etc/redis/6379.conf

bind 192.168.1.102
port 6379
daemonize yes
logfile "/var/log/redis/redis.log"
dir /var/lib/redis
slaveof 192.168.1.101 6379

启动Redis:

redis-server /etc/redis/6379.conf
2.3.3 从节点2配置(192.168.1.103)

编辑配置文件 /etc/redis/6379.conf

bind 192.168.1.103
port 6379
daemonize yes
logfile "/var/log/redis/redis.log"
dir /var/lib/redis
slaveof 192.168.1.101 6379

启动Redis:

redis-server /etc/redis/6379.conf

2.4. 配置哨兵节点

在三台服务器上分别配置哨兵。

2.4.1 哨兵配置文件(以192.168.1.101为例)

创建哨兵配置文件 /etc/redis/sentinel.conf

port 26379
#设置为后台运行
daemonize yes
#日志存放目录
logfile "/var/log/redis/sentinel.log"
#数据存放目录
dir /var/lib/redis

#监控名为 mymaster 的主节点,仲裁参数为 2,一般是哨兵个数的一半+1(类似于zookeeper的过半写成功机制) 
sentinel monitor mymaster 192.168.1.101 6379 2
#主机多长时间连接不上,哨兵就判定他挂了,单位毫秒 
sentinel down-after-milliseconds mymaster 5000
#这个命令用于设置在主节点被判定为不可用之后,进行故障转移所需的超时时间。
sentinel failover-timeout mymaster 10000
#这个命令用于设置在进行故障转移时,同时进行同步的从节点数量1表示在进行故障转移时只允许一个从节点进行同步
sentinel parallel-syncs mymaster 1
  • mymaster:主节点名称。

  • 2:至少需要2个哨兵同意才能触发故障转移。

2.4.2 启动哨兵

在三台服务器上分别启动哨兵:

redis-sentinel /etc/redis/sentinel.conf

2.5. 验证集群状态

2.5.1 检查主从复制

在主节点(192.168.1.101)上执行:

redis-cli -h 192.168.1.101 -p 6379 info replication

输出应显示两个从节点(192.168.1.102 和 192.168.1.103)。

2.5.2 检查哨兵状态

在任意一台服务器上执行:

redis-cli -h 192.168.1.101 -p 26379 info sentinel

输出应显示哨兵监控的主节点和从节点信息。


2.6. 测试故障转移

2.6.1 模拟主节点宕机

在主节点(192.168.1.101)上停止Redis:

redis-cli -h 192.168.1.101 -p 6379 shutdown
2.6.2 检查故障转移

在哨兵节点上执行:

redis-cli -h 192.168.1.102 -p 26379 sentinel get-master-addr-by-name mymaster

输出应显示新的主节点(如 192.168.1.102 或 192.168.1.103)。

2.6.3 恢复原主节点

重新启动原主节点(192.168.1.101):

redis-server /etc/redis/6379.conf

它会自动成为新主节点的从节点。


2.7. 总结

  • 主从复制:实现数据同步。

  • 哨兵机制:实现高可用和自动故障转移。

  • 故障转移:主节点宕机后,哨兵会自动选举新的主节点。

通过以上步骤,你已经成功部署了一个Redis集群(一主两从三哨兵)。

五、項目使用

        一主一从一哨兵的部署架构虽然在简单的测试环境中可能会使用,但在生产环境中不太合理。这种架构存在单点故障的风险,因为如果主节点或哨兵节点发生故障,整个系统可能会变得不可用。

      在生产环境中,建议至少部署三个或以上的哨兵实例,并且主节点和从节点也最好是多个。这样可以增加系统的可用性和容错能力,确保系统在面临故障时仍然能够继续提供服务。

以下是一个更具可靠性的Redis Sentinel部署示例:

  • 3个以上的哨兵实例:确保有足够的哨兵实例来达成共识,以便进行故障检测和自动故障转移。
  • 多个主节点和从节点:通过部署多个主节点和从节点,可以提高系统的可扩展性和容错能力。
  • 合理的故障转移配置:设置合理的故障转移超时时间、quorum值和故障转移执行的超时时间,以确保系统能够及时做出正确的故障转移决策。

六、问题解决

1.主从复制的时候,master 正常写入但是 salve 读取不到

  • 检查一下 master 的 bind 设置(用于指定本机网卡对应的IP地址 )
  • 检查一下 slave 的 masterauth 是否正确
  • 服务器的端口是否开通,防火墙是否拦截了

2.  Connection Refused

  • 错误描述:客户端连接 Redis 时,出现 Connection Refused 报错。
  • 问题原因:

        Redis服务没有启动。
        Redis配置文件 redis.conf 中的 bind 或 protected-mode 设置导致连接被拒绝。
        Redis设置了密码,但客户端未提供。

  • 解决方法:

       使用 redis-server 启动Redis服务,确保其正常运行。
       检查 redis.conf 文件中 bind 配置,确保服务绑定到正确的IP地址(例如可以设置为 0.0.0.0 以允许所有IP访问)。
       如果Redis启用了密码,客户端连接时需要提供密码:redis-cli -a your_password。

3.频繁报OOM

当redis占用内存超过或持平了服务器的内存上限,就会出现这个错误,新手尤其容易犯这类错误。正确的做法是设置缓存上限,并且搭配内存回收策略使用,下附常用回收策略:

#设置最大缓存,单位bytes,下面这条是设置最大缓存1G
maxmemory 1073741824

#回收策略

#默认,到达上限时抛出异常
maxmemory-policy noeviction 

#淘汰使用频率最低的键,包括持久键
maxmemory-policy allkeys-lru 

#淘汰使用频率最低的键,不包括持久键
maxmemory-policy volatile-lru

#随机淘汰,包括持久键
maxmemory-policy allkeys-random

#随机淘汰,不包括持久键
maxmemory-policy volatile-random

#淘汰有过期时间的键,距离原本过期时间最近的优先
maxmemory-policy volatile-ttl

4.redis设置后数据库压力不减

  • 缓存服务如果没有任何异常,那么有可能是缓存穿透。
  • 什么是缓存穿透呢?简单来说就是有人老是去请求不存在的数据。
  • 那什么是不存在的数据?假设数据库中用户id是从10000开始的,现在有人频繁去请求用户id为500的数据,这个id为500的数据就是不存在的数据。因为它不可能存在于数据库。
  • 这时候会怎么样呢?系统先查询缓存,查不到所以去查了数据库,也没有查到,所以直接返回空。但是下一次请求还是要走一遍缓存+数据库。这个时候只要一段简单的脚本就可以对数据库造成压力。
  • 解决方法很简单:当数据库查不到数据时,先设置一个null键入缓存,之后就任他刷。一般情况下会给这个null值设置一个过期时间。

5.redis主从同步延迟

在Redis中,主从同步延迟是一个常见的问题,特别是在高负载或网络延迟的环境下。这种延迟可能会导致数据在不同节点之间的不一致。以下是一些解决和优化Redis主从同步延迟的方法:

1. 优化网络环境

  • 确保网络带宽和低延迟:使用高速网络连接,并尽量减少网络延迟。

  • 使用更近的物理位置:如果可能,将主节点和从节点部署在地理位置更近的地方,以减少网络延迟。

2. 调整Redis配置

  • repl-backlog-size:增加复制积压缓冲区的大小。这个缓冲区用于主从节点断线重连后的数据同步。例如,设置repl-backlog-size为更大的值可以减少重新同步的需求。

   repl-backlog-size 1073741824 # 例如设置为1GB

  • repl-disable-tcp-nodelay:设置为no可以减少数据在网络上的延迟,但可能会轻微增加CPU使用率。

    repl-disable-tcp-nodelay no

3. 减少主节点负载

  • 优化查询:确保对Redis的查询是高效的,避免在大批量数据上执行复杂操作。

  • 使用更快的硬件:增加主节点的CPU和内存资源可以显著提高处理速度。

  • 读写分离:对于读操作非常频繁的应用,可以考虑设置多个从节点来分担读请求,从而减轻主节点的压力。

4. 使用更高效的同步策略

  • 增量复制:确保使用增量复制而不是全量复制,这可以通过调整slave-serve-stale-data配置实现。设置为yes可以在从节点落后时继续提供服务。

    slave-serve-stale-data yes

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半斤拿铁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值