原文:Docker Compose 部署 Redis 及原理讲解 | 懒人屋

Docker Compose 部署 Redis 及原理讲解

 4.4k  字    16  分钟    2019-10-16

文章背景

Redis是我们常用的一个NoSql的数据库,我个人在开发中也经常使用。
目前算是一个比较常用的工具了,我个人经常安装是单机版的,也没有什么集群的思想在里面,这篇文章的意思是自己在配置集群过程中的一点记录。
文章中的大部分内容算是抄袭的,如有侵权,可留言删除。原文链接在参考资料当中。
本文很长,没有耐心的直接右下角目录选择自己想看的部分。

Redis的集群方式

在网络搜索资料的时候看到 51life 的文章中写到目前Redis的集群方式有三种,我个人目前也没有进行什么深入的理解,先直接抄袭然后再去研究是不是如文章中所说的

  • 主从复制
  • 哨兵模式
  • Redis-Cluster集群

主从复制

主从复制的,从名称上就可以看出来有一个主库一个从库,数据上应该是一致的。一般可以用来做数据备份等。在2.8之前和之后有SYNCPSYNC的区别
需要持续了解的请查看Redis(二)集群 redis-cluster & redis主从同步

原理

  • 从服务器连接主服务器,发送SYNC命令;
  • 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
  • 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
  • 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
  • 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
  • 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;(从服务器初始化完成)
  • 主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。(从服务器初始化完成后的操作)

优点

  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离;
  • 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成;
  • Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力;
  • Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求;
  • Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。

缺点

  • Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
  • Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

哨兵模式

当主服务器中断服务后,可以将一个从服务器升级为主服务器,以便继续提供服务,但是这个过程需要人工手动来操作。
为此,Redis 2.8中提供了哨兵工具来实现自动化的系统监控和故障恢复功能。
哨兵的作用就是监控Redis系统的运行状况。它的功能包括以下两个:

  • 监控主服务器和从服务器是否正常运行;
  • 主服务器出现故障时自动将从服务器转换为主服务器。

工作方式

  • 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
  • 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)
  • 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态
  • 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
  • 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
  • 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
  • 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。

缺点

  • 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有;
  • 主从可以自动切换,系统更健壮,可用性更高。

缺点

  • Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

Redis-Cluster集群

redis的哨兵模式基本已经可以实现高可用,读写分离,但是在这种模式下每台redis服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了cluster模式,实现的redis的分布式存储,也就是说每台redis节点上存储不同的内容。

Redis-Cluster采用无中心结构,它的特点如下:

  • 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽;
  • 节点的fail是通过集群中超过半数的节点检测失效时才生效;
  • 客户端与redis节点直连,不需要中间代理层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。

工作方式

在redis的每一个节点上,都有这么两个东西,一个是插槽(slot),它的的取值范围是:0-16383。
还有一个就是cluster,可以理解为是一个集群管理的插件。
当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对16384求余数,这样每个key都会对应一个编号在0-16383之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。
当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。
如果主节点A和它的从节点A1都宕机了,那么该集群就无法再提供服务了。

Redis之缓存穿透、缓存击穿与缓存雪崩

为什么要将这个放置到这里呢?这个是在面试的时候经常遇到的,且在我们安装或者配置Redis的配置文件时起到决定作用。
这里依然要感谢作者 51life,说的直白点,如果他不写,我怎么抄袭?
开玩笑的,这个东西是方便自己学习的,参考资料中也有他原文的链接。

缓存穿透

缓存穿透,是指查询一个不存在的数据,由于数据不存在,所以数据不会被缓存,每次查询都是从数据库中去查询。
如果有人利用这个存在的漏洞去伪造大量的请求,那么很可能导致DB承受不了那么大的流量就挂掉了。

解决方案:

  • 事前预防:对所有请求进行参数校验(页面或者接口中),拒绝非法请求;
  • 事后预防:当查询到一个空的结果时,我们仍然将这个空的结果进行缓存,但是设置一个很短的过期时间。

缓存击穿

缓存击穿,就是在热点key失效的瞬间,海量的请求访问数据库,导致数据库崩溃。

解决方案:

  • 互斥锁:是在缓存KEY过期去更新的时候,先让程序去获取锁,只有获取到锁的线程才有资格去更新缓存KEY。其他没有获取到锁的线程则休眠片刻之后再次去获取最新的缓存数据。通过这种方式,同一时刻永远只有一个线程会去读取数据库,这样也就避免了海量数据库请求对于数据库的冲击。
  • 永不过期:将缓存设置为永不过期,通过定时任务去同步缓存和数据库的数据。

缓存雪崩

缓存雪崩,是指我们设置缓存时采用了相同的过期时间,导致很多key在某一时刻同时失效,请求全部转发到数据库,最终导致数据库瞬时压力过大而崩溃。

解决方案:

  • 在原有失效时间的基础上增加一个随机时间(例如1-5分钟),这样每个缓存过期时间的重复率就会降低,从而减少缓存雪崩的发生。

总结:缓存穿透是业务层面的漏洞导致非法请求,与请求量、缓存失效没关系。缓存击穿则只会出现在热点数据上,发生在缓存失效的瞬间,与业务没多大关系。缓存雪崩则是因为多个 KEY 同时失效,导致数据库请求太多。非热点数据也会导致缓存雪崩,只要同时失效的 KEY 足够多。

Redis的配置说明

看到上面的资料之后应该很多人明白了怎么去选择Redis的集群方式,那么现在我们来抄袭Redis的集群与主从复制(附Redis持久化)一文中对配置文件的讲解。
如果想要了解更多,请查看Redis(一) 数据结构与底层存储 & 事务 & 持久化 & lua,这比较全面

Redis持久化

Redis默认的方式,redis通过快照来将数据持久化到磁盘中。

设置持久化快照的条件:在redis.conf中修改持久化快照的条件,如下:

save 900 1 # 900秒内操作1次,将数据写入磁盘
save 300 10 # 300秒内操作10次,将数据写入磁盘
save 60 10000 # 60秒内操作10000次,将数据写入磁盘

持久化文件存储的目录:在redis.conf中可以指定持久化文件存储的目录:

# 当持久化出现错误之后,是否继续提供写服务
stop-writes-on-bgsave-error no
# 写的时候是否压缩
rdbcompression yes
# 数据存储到磁盘上的文件名称
dbfilename dump.rdb
# 存储数据的目录,这是相对于当前执行目录的
dir ./

一旦redis被非法关闭,那么会丢失最后一次持久化之后的数据。如果数据不重要的情况,可以不必理会。但数据不能丢失需要开启redis的aof。
实际在项目中也是两个一起使用的。

AOF方式

Redis默认是不使用该方式持久化的。Aof方式的持久化,是操作一次redis数据库,则将该操作的记录存储到aof持久化文件中。

开启aof方式的持久化方案:

# AOF的开关
appendonly no
# AOF文件的名字
appendfilename "appendonly.aof"
# 控制Redis调用fsync的频率(fsync:将数据从缓冲区写到磁盘)
appendfsync everysec
# 控制当执行重写时是否阻止调用fsync
no-appendfsync-on-rewrite no
# 用于控制AOF文件的自动重写规则
auto-aof-rewrite-percentage 100
# 用于控制AOF重写的最小文件大小。
auto-aof-rewrite-min-size 64mb
# 当aof-load-truncated被设置为yes时,Redis发现了问题之后会从AOF文件中尽可能地加载更多的数据
# 然后在log文件里记录这次错误。
aof-load-truncated yes
# 配置AOF文件保存的路径。RDB产生的文件也会被保存到这个路径下面
dir ./

appendfsync的三种模式:

  • no:从不调用fsync,由操作系统自行决定什么时候将缓冲区里的数据写入文件。大多数Linux系统是每30秒进行一次。这种模式的速度最快,效率最高,但是不能保证数据安全。
  • always:每次执行写操作之后都调用fsync。这种模式最慢,但也是最安全的,可以保证出错时最多只损失一次操作。这种模式由于不断地写入少量数据,会严重缩短固态硬盘的寿命。
  • everysec:每一秒调用一次fsync。是一种折中的方案,也是配置文件的默认值。当fsync调用时长超过一秒时,Redis会延迟下一次fsync的调用到下一秒。

AOF的优点:

AOF可以将数据的损失降到最低

AOF的缺点:

比RDB更占用存储空间、加载速度慢(一是因为存储的命令较多,二是因为编码格式与内存不一致,还需要处理编码)

Docker 配置 Redis 哨兵集群

这里没有配置存放磁盘保存什么的,正常是需要配置的。

主从模式

配置文件如下:

# 版本
version: '3.1'
# 服务配置
services:
# RedisMaster配置
master:
# 镜像名称
image: redis
# 容器名称
container_name: redis-master
# 是否开机启动
restart: always
# 执行命令
command: redis-server --port 6379 --requirepass 密码
# 端口映射
ports:
- 6379:6379
networks:
# 加入的网络的名称
redis:
# ipv4的ip地址
ipv4_address: 172.18.1.2 slave1:
# 镜像名称
image: redis
# 容器名称
container_name: redis-slave-6380
# 是否开机启动
restart: always
# 执行命令
command: redis-server --slaveof 172.18.1.2 6379 --port 6380 --requirepass 密码 --masterauth 密码
# 端口映射
ports:
- 6380:6379
networks:
# 加入的网络的名称
redis:
# ipv4的ip地址
ipv4_address: 172.18.1.3 slave2:
# 镜像名称
image: redis
# 容器名称
container_name: redis-slave-6381
# 是否开机启动
restart: always
# 执行命令
command: redis-server --slaveof 172.18.1.2 6379 --port 6381 --requirepass 密码 --masterauth 密码
# 端口映射
ports:
- 6381:6379
networks:
# 加入的网络的名称
redis:
# ipv4的ip地址
ipv4_address: 172.18.1.4 #定义网络组
networks:
# 网络组名称
redis:
# 网络的模式
driver: bridge
# 配置网络
ipam:
driver: default
config:
## ip地址网络 这里宿主机一般会是该网段的 172.18.1.1,所以不要设置自网段为1
- subnet: 172.18.1.0/24

Sentinel

port 26379
dir "/tmp"
# 自定义集群名,其中 127.0.0.1 为 redis-master 的 ip,6379 为 redis-master 的端口,2 为最小投票数(因为有 3 台 Sentinel 所以可以设置成 2)
sentinel monitor mymaster 172.18.1.2 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster 密码
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes

记得复制三份文件。

# 版本
version: '3.1'
# 服务配置
services:
# sentinel配置
sentinel-1:
# 镜像名称
image: redis
# 容器名称
container_name: redis-sentinel-1
# 是否开机启动
restart: always
# 文件夹映射
volumes:
- ./sentinel1.conf:/usr/local/etc/redis/sentinel.conf
# 执行命令
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
# 端口映射
ports:
- 26379:26379
networks:
# 加入的网络的名称
- redis sentinel-2:
# 镜像名称
image: redis
# 容器名称
container_name: redis-sentinel-2
# 是否开机启动
restart: always
# 文件夹映射
volumes:
- ./sentinel2.conf:/usr/local/etc/redis/sentinel.conf
# 执行命令
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
# 端口映射
ports:
- 26380:26379
networks:
# 加入的网络的名称
- redis sentinel-3:
# 镜像名称
image: redis
# 容器名称
container_name: redis-sentinel-3
# 是否开机启动
restart: always
# 文件夹映射
volumes:
- ./sentinel3.conf:/usr/local/etc/redis/sentinel.conf
# 执行命令
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
# 端口映射
ports:
- 26381:26379
networks:
# 加入的网络的名称
- redis networks:
redis:
external:
name: redis_redis

参考资料

扫一扫,分享到微信

aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMYAAADGCAAAAACs8KCBAAACLElEQVR42u3aWW7DMAwFwNz/0u4BgiiPpFPA0ugraFNZ4wKEuLxe8bqC9f7N9x2Sz+9/e9vCwMB4LKN6uPURk6d8+u0atj4DBgbGCYx86/XhqkFz/bfJ2TAwMDAS0vrx1TCNgYGB8WtGEkCr38fAwMDIk9j86JMr5s9zcQwMjAcyeqnm/3z+SX8DAwPjUYyruHqhNgmX12BhYGDszZg0IHupZvIKmg1RDAyMYxj3hsi86JbgC1VDDAyMjRiFi1cxc8wL/Tnp484YGBhHMpIG56To3xu8KAdcDAyMLRj5cfOt1wF3/fPqUwqTIxgYGBsx8oS2yu4dPblcYmBg7M3Im5G98tykoFa4IGJgYGzNmAw69Jqd86G0Ly1MDAyM7Rh5Qf+Gt1UswxVaCBgYGFszqulr9ZpYbSf0mhMYGBgnMHol/l4zMmHflfpiYGDsxKiOdiVjFjlmElgxMDDOYSTHSq6D1SvjOnHtvT4MDIxdGdUi1/rBeRmuegEd/R8wMDA2YuShsHqZy8NrNShjYGCcxshHJRJAdVBslAxjYGAcwMgT0byINtmzOpyBgYGxK+MqrrxA30tW88Q16mxgYGBswehNWOXF+rx8lu82GhfDwMB4LCMJspMxiF74rl4cMTAwTmDkgS9PQatNyl6DAQMDA6NaoE8S2mbpfx36MTAwMFpNgqRhmb+ILy8FAwPjAMa9pfwJu9k0xcDA2JrRq2VVm5rzZsO8CIiBgfFAxh/qyCLg37ZmNAAAAABJRU5ErkJggg==" alt="微信分享二维码">

Docker Compose 部署 Redis 及原理讲解 | 懒人屋的更多相关文章

  1. 使用Docker Compose部署基于Sentinel的高可用Redis集群

    使用Docker Compose部署基于Sentinel的高可用Redis集群 https://yq.aliyun.com/articles/57953 Docker系列之(五):使用Docker C ...

  2. 在Windows Server 2019通过Docker Compose部署Asp.Net Core

    一.安装Docker Enterprise 安装文档是: https://docs.docker.com/install/windows/docker-ee/ 安装完成后,如下图 二.首先,拉取一个W ...

  3. Docker Compose 部署前后端分离应用

    部署前后端分离应用 容器化 Abp 应用 关于 Abp 应用的容器化,其实和普通的 ASP.NET Core 应用差不多,大家可以参考我此前的文章. 唯一需要注意的是:因为 Abp 解决方案中有多个项 ...

  4. Docker Compose部署项目到容器-基于Tomcat和mysql的项目yml配置文件代码

    场景 Docker-Compose简介与Ubuntu Server 上安装Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

  5. 使用Docker Compose 部署Nexus后初次登录账号密码不正确,并且在nexus-data下没有admin,password

    场景 Ubuntu Server 上使用Docker Compose 部署Nexus(图文教程): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/ ...

  6. Ubuntu Server 上使用Docker Compose 部署Nexus(图文教程)

    场景 Docker-Compose简介与Ubuntu Server 上安装Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

  7. Docker Compose部署Nexus3时的docker-compose,yml代码

    场景 Docker-Compose简介与Ubuntu Server 上安装Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

  8. Docker Compose部署GitLab服务,搭建自己的代码托管平台(图文教程)

    场景 Docker-Compose简介与Ubuntu Server 上安装Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

  9. 使用Docker Compose 部署Nexus后提示:Unable to create directory /nexus-data/instance

    场景 Ubuntu Server 上使用Docker Compose 部署Nexus(图文教程): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/ ...

随机推荐

  1. jquery扩展方法(表单数据格式化为json对象)

    1.jquery扩展方法(表单数据格式化为json对象) <script type="text/javascript"> // 将表单数据序列化为一个json对象,例如 ...

  2. sh_08_打印分隔线

    sh_08_打印分隔线 def print_line(char, times): print(char * times) print_line("hi ", 40)

  3. 【Leetcode】判断平面中1个点是否落在三角形内

    参考资料: 题目: https://blog.csdn.net/dongtinghong/article/details/78657403 符号重载: https://blog.csdn.net/cd ...

  4. vue动态监听浏览器窗口高度

    HTML: <div ref="page"></div> JS: data(){ return{ clientHeight:'', } } mounted( ...

  5. 关于判断StringBuffer是否为空

    对于String和StringBuffer来说,都是通过创建新的char value[]数组来达到字符串改变的操作的,只不过String是通过新创建String对象来达到目的, 而StringBuff ...

  6. Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?

    if first time to install docker, be noted the docker engine started as root copied from: http://blog ...

  7. ZXing使用详解与范例(C#)

    介绍 ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口.Zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码.(引自百度百科) 用 ...

  8. 一、Jmeter启动报错:Could not initialize class org.apache.jmeter.gui.util.MenuFactory

    1.下载: plugins-manager.jar 包 2.地址:https://jmeter-plugins.org/install/Install/ 3.将jar包放到lib/ext 4.重启jm ...

  9. ls -i

    ls的不同选项有不同的含义: -l 是用long的长格式显示 条目信息 -a 显示所有的文件, 包括隐藏文件 -i: 是显示inode, 主要是用来查看硬链接的

  10. 3,、maven修改jar包下载为国内镜像下载地址

    maven 默认的中央仓库是在国外的服务器,下载速度慢,有时候稍不注意就下载出错 通常我将maven的中央仓库修改为阿里云的地址,下载速度很快体验非常好 修改conf下的setting.xml文件 在 ...