亿级流量场景下,大型缓存架构设计实现【1】---redis篇
正文前先来一波福利推荐:
福利一:
百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的VIP课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家。
福利二:
毕业答辩以及工作上各种答辩,平时积累了不少精品PPT,现在共享给大家,大大小小加起来有几千套,总有适合你的一款,很多是网上是下载不到。
获取方式:
微信关注 精品3分钟 ,id为 jingpin3mins,关注后回复 百万年薪架构师 ,精品收藏PPT 获取云盘链接,谢谢大家支持!
-----------------------正文开始---------------------------
*****************开篇介绍****************
-----------------------------------------------------------------------------------------------------------------------
三个重要的标准:
---大型缓存架构中需要首先说一下:
海量数据:支持海量数据缓存,支持大规模数据;
高并发:在亿级QPS的场景下,可以做到满足业务需求;
高可用:表示redis可以做到并且尽可能的做到可以持续使用。比如全年保持99.99%的时间处在可用状态,除非遇到各种断电等特殊灾害;
-------------------------------------------------------------------------------------------------------
商品详情页的系统架构介绍-->两种设计类型:
小型电商:
静态模板是固定的 数据库中的数据全量喧嚷到模板中,下次请求来了直接返回,速度也很快;
缺点:当数据上亿的时候,如果模板改定,把这些所有的数据在mysql中取出后渲染进模板,非常耗时,不现实;
大型电商
-- 使用大型的高级缓存架构:
设计缓存数据生产服务模块;
不需要再进行全量重新渲染,直接将最新的html模板推送到nginx服务器,请求过来后直接在nginx本地进行渲染进模板中返回请求;
************redis单机理论 ************
-----------------------------------------------------------------------------------------------------------------------
redis的重要性:
-------------------------------------------------------------------------------------------------------
虚拟机环境设置[1]
---- 安装ISO + 配置网络 + 安装JDK+Perl + SSH免密通信:
虚拟机中安装CentOS
启动一个virtual box虚拟机管理软件 使用CentOS 6.5镜像即可,CentOS-6.5-i386-minimal.iso
配置网络
vi /etc/sysconfig/network-scripts/ifcfg-eth0 ---- 修改linux的网络配置
删除对应的项目,保留如下的配置:
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=dhcp
wq保存;
重启网络:
service network restart
使用ifconfig查询当前自动分配的网址;
将当前的网址设置为静态ip,加入下面的静态配置:
BOOTPROTO=static
IPADDR=192.168.0.X
NETMASK=255.255.255.0
GATEWAY=192.168.0.1
网络服务重启:
service network restart
配置hosts【相当于给本机起别名】
vi /etc/hosts
192.168.0.X eshop-cache01
其他主机,添加类似配置。实现本机的hostname到ip地址的映射
配置SecureCRT【本人使用的Xshell 感觉也很好用】
此时就可以使用SecureCRT从本机连接到虚拟机进行操作了
关闭linux防火墙
service iptables stop
service ip6tables stop
chkconfig iptables off
chkconfig ip6tables off
vi /etc/selinux/config
SELINUX=disabled
关闭windows的防火墙
配置yum
yum clean all
yum makecache
yum install wget
------------------------------------------------------------------------------------------
在每个CentOS中都安装Java和Perl
(WinSCP,就是在windows宿主机和linux虚拟机之间互相传递文件的一个工具。)
(1)安装JDK
1、将jdk-7u60-linux-i586.rpm通过WinSCP上传到虚拟机中
2、安装JDK:rpm -ivh jdk-7u65-linux-i586.rpm
3、配置jdk相关的环境变量
vi .bashrc
export JAVA_HOME=/usr/java/latest
export PATH=$PATH:$JAVA_HOME/bin
source .bashrc
4、测试jdk安装是否成功:java -version
(2)安装Perl
yum install -y gcc
wget http://www.cpan.org/src/5.0/perl-5.16.1.tar.gz
tar -xzf perl-5.16.1.tar.gz
cd perl-5.16.1
./Configure -des -Dprefix=/usr/local/perl
make && make test && make install
perl -v
为什么要装perl?我们整个大型电商网站的详情页系统,复杂。java+nginx+lua,需要perl。
perl,是一个基础的编程语言的安装,tomcat,跑java web应用
------------------------------------------------------------------------------------------
3、在4个虚拟机中安装CentOS集群
(1)按照上述步骤,再安装三台一模一样环境的linux机器
(2)另外三台机器的hostname分别设置为eshop-cache02,eshop-cache03,eshop-cache04
(3)安装好之后,在每台机器的hosts文件里面,配置好所有的机器的ip地址到hostname的映射关系
比如说,在eshop-cache01的hosts里面
192.168.31.187 eshop-cache01
192.168.31.xxx eshop-cache02
192.168.31.xxx eshop-cache03
192.168.31.xxx eshop-cache04
------------------------------------------------------------------------------------------
4、配置4台CentOS为ssh免密码互相通信【此时四台linux虚拟机可以通过ssh实现无密码输入通信】
(1)首先在四台机器上配置对本机的ssh免密码登录
ssh-keygen -t rsa
生成本机的公钥,过程中不断敲回车即可,ssh-keygen命令默认会将公钥放在/root/.ssh目录下
cd /root/.ssh
cp id_rsa.pub authorized_keys
将公钥复制为authorized_keys文件,此时使用ssh连接本机就不需要输入密码了
(2)接着配置三台机器互相之间的ssh免密码登录
使用ssh-copy-id -i hostname命令将本机的公钥拷贝到指定机器的authorized_keys文件中
虚拟机环境设置[2]:
---- 单机版Redis安装以及生产环境设置(开机自启动)
1、安装单机版tcl + redis
1. wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz
2. tar -xzvf tcl8.6.1-src.tar.gz
3. cd /usr/local/tcl8.6.1/unix/
4. ./configure
5. make && make install
6. 使用redis-3.2.8.tar.gz(截止2017年4月的最新稳定版)
7. tar -zxvf redis-3.2.8.tar.gz
8. cd redis-3.2.8
9. make && make test && make install
------------------------------------------------------------------------
2、redis的生产环境启动方案
如果一般的学习课程,你就随便用redis-server启动一下redis,做一些实验,这样的话,没什么意义
1. 要把redis作为一个系统的daemon进程去运行的,每次系统启动,redis进程一起启动
(1)redis utils目录下,有个redis_init_script脚本
(2)将redis_init_script脚本拷贝到linux的/etc/init.d目录中(初始化目录),将redis_init_script重命名为redis_6379,6379是我们希望这个redis实例监听的端口号
(3)修改redis_6379脚本的第6行的REDISPORT,设置为相同的端口号(默认就是6379)
(4)创建两个目录:
/etc/redis(存放redis的配置文件),
/var/redis/6379(存放redis的持久化文件,也就是后面要使用的redis备份)
(5)修改redis配置文件(默认在根目录下,redis.conf),拷贝到/etc/redis目录中,修改名称为6379.conf
(6)修改redis.conf中的部分配置为生产环境
daemonize yes 让redis以daemon进程运行(守护线程,可以理解为java运行时的jvm线程,在后台进行service服务)
pidfile /var/run/redis_6379.pid 设置redis的pid文件位置 【/var/run 目录下放的是各程序的pid】
port 设置redis的监听端口号
dir /var/redis/ 设置持久化文件的存储位置
(7)启动redis,执行cd /etc/init.d, chmod 777 redis_6379,
./redis_6379 start
(8)确认redis进程是否启动,ps -ef | grep redis
(9)让redis跟随系统启动自动启动
在redis_6379脚本中,最上面,加入两行注释
# chkconfig: 2345 90 10
# description: Redis is a persistent key-value database
在Xshell中执行 chkconfig redis_6379 on
------------------------------------------------------------------------
3、redis cli的使用
redis-cli SHUTDOWN,连接本机的6379端口停止redis进程;
redis-cli -h 127.0.0.1 -p 6379 SHUTDOWN,制定要连接的ip和端口号
redis-cli PING,ping redis的端口,看是否正常
redis-cli,进入交互式命令行:
存取删测试:
set k1 v1
get k1
del k1
------------------------------------------------------------------------------------------------
redis的使用以及原理分析:
redis的技术,包括4块:
redis各种数据结构和命令的使用,包括java api的使用,这类操作命令其他的博客非常完善,可以经常性的查询熟悉;
redis一些特殊的解决方案的使用,pub/sub消息系统,分布式锁,输入的自动完成等;
redis日常的管理相关的命令;
redis企业级的集群部署和架构;
1、redis持久化的意义:
Note:
--- Redis在不使用备份的情况下会产生缓存雪崩问题,也就是redis宕机后,没有备份的情况下,所有查询操作全部直接涌入数据库,导致数据库机器宕机;
两种备份方式分析:
---下边堆 redis 写如数据的两种方式进行分析:
原理图:
redis 的 AOF 下的 rewrite 机制原理:
AOF和RDB两种模式:
AOF机制对每条写入命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写入指令来重新构建整个数据集
如果我们想要redis仅仅作为纯内存的缓存来用,那么可以禁止RDB和AOF所有的持久化机制【但是采用这种方式的项目是个高危项目】
通过RDB或AOF,都可以将redis内存中的数据给持久化到磁盘上面来,然后可以将这些数据备份到别的地方去,比如云服务
如果redis挂了,服务器上的内存和磁盘上的数据都丢了,可以从云服务上拷贝回来之前的数据,放到指定的目录中,然后重新启动redis,redis就会自动根据持久化数据文件中的数据,去恢复内存中的数据,继续对外提供服务【这个地方就可以看出redis确实很高级】
如果同时使用RDB和AOF两种持久化机制,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加完整
RDB持久化机制,对redis中的数据执行周期性的持久化,也就是每个固定的时间去做一次内存快照的保存工作,适合做冷备份。
-------------------------------------------------------------------------------------
RDB持久化机制的优点
(1)RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说Amazon的S3云服务上去,在国内可以是阿里云的ODPS分布式存储上,以预定好的备份策略来定期备份redis中的数据
(2)RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可
(3)相对于AOF持久化机制来说,直接基于RDB数据文件【AOF为指令日志】来重启和恢复redis进程,更加快速。【rdb基于数据,恢复速度快】
-------------------------------------------------------------------------------------
RDB持久化机制的缺点
(1)如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。
一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据。
(2)RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒
-------------------------------------------------------------------------------------
AOF持久化机制的优点
(1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据。
(2)AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复
(3)AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来。在创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。
(4)AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用 【 flushall 】 命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据。
-------------------------------------------------------------------------------------
AOF持久化机制的缺点
(1)对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
(2)AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的
(3)以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF就是为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。
-------------------------------------------------------------------------------------
linux环境下 redis 的默认配置中 AOF 模式是关闭的 可以从配置文件 appendonly=no 看到,而 默认打开的是 RDB 模式;
在两种模式都开启的情况下,做数据恢复的时候优先使用AOF的数据;
下面重点对AOF模式的配置进行分析:
设置appendonly=yes;
设置appendfsync,对于设置linux缓存oscache支持的选项 always, everysec,no;
设置auto-aof-rewrite-percentage 1-100 用来设置现在aof文件大小相比于上次rewrite时空间增加的比例 比如设置为100 则表示 在比上一次增大了一倍时再次rewrite
设置auto-aof-rewrite-min-size XXmb 最小rewrite空间大小,以mb为单位,必须超过该空间才有可能触发rewrite,每次都会进行比较;
AOF的 rewrite 过程描述:
rewrite的实现图,在创建新aof文件时如果有新的client加入数据时的场景,新的数据会都保存在新旧aof文件中后再删除旧的aof文件;
redis的数据受损修复功功能:
2、企业级的数据备份方案
RDB非常适合做冷备,每次生成之后,就不会再有修改了。
1、数据备份方案
(1)写linux的定时任务调度脚本,使用crontab定时调度脚本去做数据备份
(2)每小时都copy一份rdb的备份,到一个目录中去,仅仅保留最近48小时的备份
(3)每天都保留一份当日的rdb的备份,到一个目录中去,仅仅保留最近1个月的备份【相当于每个月保存30份备份】
(4)每次copy备份的时候,都把太旧的备份给删了
(5)每天晚上将当前服务器上所有的数据备份,发送一份到远程的云服务上去【云服务上以为单位】
2、数据恢复方案
(1)如果是redis进程挂掉,那么重启redis进程即可,直接基于AOF日志文件恢复数据
(2)如果是redis进程所在机器挂掉,那么重启机器后,尝试重启redis进程,尝试直接基于AOF日志文件进行数据恢复,AOF没有破损,也是可以直接基于AOF恢复的,AOF append-only,顺序写入,如果AOF文件破损,那么用 redis-check-aof fix【损坏部分容忍丢失,其实只丢失了一秒的数据量】
(3)如果redis当前最新的AOF和RDB文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复
当前最新的AOF和RDB文件都出现了丢失/损坏到无法恢复,一般不是机器的故障,人为
/var/redis/6379下的文件给删除了,找到RDB最新的一份备份,小时级的备份可以了,小时级的肯定是最新的,copy到redis里面去,就可以恢复到某一个小时的数据
容灾演练
停止redis,关闭aof,拷贝rdb备份,重启redis,确认数据恢复,直接在命令行热修改redis配置,打开aof,这个redis就会将内存中的数据对应的日志,写入aof文件中,此时aof和rdb两份数据文件的数据就同步了。
redis config set
热修改配置参数,可能配置文件中的实际的参数没有被持久化的修改,再次停止redis,手动修改配置文件,打开aof的命令,再次重启redis。
(4)如果当前机器上的所有RDB文件全部损坏,那么从远程的云服务上拉取最新的RDB快照回来恢复数据。
(5)如果是发现有重大的数据错误,比如某个小时上线的程序一下子将数据全部污染了,数据全错了,那么可以选择某个更早的时间点,对数据进行恢复
********** redis 三点式集群的搭建[重点] **********
单机的redis的一般场景下的极限值差不多读的QPS在5万左右,当然也收服务器的性能配置影响,所以高于这个极限值很大的境况下,redis随时有崩掉的危险,那么
怎么做到更高的QPS呢,总的思路就是读写分离,同时增加读的redis个数,因为在通常的场景下,读远远大于写;
这就引出了redis的主从结构话设计;
主从结构框架配置 必须实现 master 的持久化!!!
主从reids间的同步原理:
redis的主从通信基本流程:
runid的作用:
redis replication复制原理总结:
1、复制的完整流程
(1)slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始
master host和ip是从哪儿来的,redis.conf里面的slaveof配置的
(2)slave node内部有个定时任务,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接
(3)slave node发送ping命令给master node
(4)口令认证,如果master设置了requirepass,那么salve node必须发送masterauth的口令过去进行认证
(5)master node第一次执行全量复制,将所有数据发给slave node
(6)master node后续持续将写命令,异步复制给slave node
2、数据同步相关的核心机制
指的就是第一次slave连接msater的时候,执行的全量复制,那个过程里面你的一些细节的机制
(1)master和slave都会维护一个offset
master会在自身不断累加offset,slave也会在自身不断累加offset
slave每秒都会上报自己的offset给master,同时master也会保存每个slave的offset
这个倒不是说特定就用在全量复制的,主要是master和slave都要知道各自的数据的offset,才能知道互相之间的数据不一致的情况
(2)backlog
master node有一个backlog,默认是1MB大小
master node给slave node复制数据时,也会将数据在backlog中同步写一份
backlog主要是用来做全量复制中断候的增量复制的
(3)master run id
info server,可以看到master run id
如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id区分,run id不同就做全量复制
如果需要不更改run id重启redis,可以使用redis-cli debug reload命令
(4)psync
从节点使用psync从master node进行复制,psync runid offset
master node会根据自身的情况返回响应信息,可能是FULLRESYNC runid offset触发全量复制,可能是CONTINUE触发增量复制
3、全量复制
(1)master执行bgsave,在本地生成一份rdb快照文件
(2)master node将rdb快照文件发送给salve node,如果rdb复制时间超过60秒(repl-timeout),那么slave node就会认为复制失败,可以适当调节大这个参数
(3)对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s
(4)master node在生成rdb时,会将所有新的写命令缓存在内存中,在salve node保存了rdb之后,再将新的写命令复制给salve node
(5)client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败
(6)slave node接收到rdb之后,清空自己的旧数据,然后重新加载rdb到自己的内存中,同时基于旧的数据版本对外提供服务
(7)如果slave node开启了AOF,那么会立即执行BGREWRITEAOF,重写AOF
rdb生成、rdb通过网络拷贝、slave旧数据的清理、slave aof rewrite,很耗费时间
如果复制的数据量在4G~6G之间,那么很可能全量复制时间消耗到1分半到2分钟
4、增量复制
(1)如果全量复制过程中,master-slave网络连接断掉,那么salve重新连接master时,会触发增量复制
(2)master直接从自己的backlog中获取部分丢失的数据,发送给slave node,默认backlog就是1MB
(3)msater就是根据slave发送的psync中的offset来从backlog中获取数据的
5、heartbeat
主从节点互相都会发送heartbeat信息
master默认每隔10秒发送一次heartbeat,salve node每隔1秒发送一个heartbeat
6、异步复制
master每次接收到写命令之后,现在内部写入数据,然后异步发送给slave node
虚拟机配置主从结构的redis连接:
1、在slave node上配置如下即可:
slaveof 192.168.X.X 6379
2、强制读写分离
基于主从复制架构,实现读写分离 redis slave node必须设置为只读模式,默认开启,
slave-read-only yes
开启了只读的redis slave node,会拒绝所有的写操作,这样可以强制搭建成读写分离的架构
3、集群安全认证
master上启用安全认证,requirepass passwd
slave上设置连接口令,masterauth passwd
两个passwd需要保持一致
4、bind 对应的 IP
在master 和 slave 上都设置bind IP,默认为127.0.0.1 这里需要设置自己的虚拟机的ip
----------------------------------------------
5、进行验证
先开启master,使用
redis-cli -h IP -a passwd
命令操作,本人操作过,如果不加 -a passwd参数会出现 (error) NOAUTH Authentication required.错误,输入后进入redis命令号 输入
info replication
------------------------------------------------
进行验证
验证结果
【从中也可以看到 master和slave的offset此时是不一致的】
6、然后开启slave从redis; 输入
redis-cli -h IP
然后输入
info replication
进行信息验证;
验证结果
主从数据验证:
master:
slave:
可以看到master的RDB数据已经传到了slave中; 同时我们也可以知道,如果在slave上试图添加数据,会被无情的拒绝;
----------------------------------------------------- 更新至2018.8.19 22.46 -----------------------------------------------------
对搭建的主从架构进行QPS压力测试
进入 redis 安装目录的 src目录下;
执行
redis-benchmark -h IP -c n1 -n n2 -d n3
进行测试
-c <clients> Number of parallel connections (default 50)
-n <requests> Total number of requests (default 100000)
-d <size> Data size of SET/GET value in bytes (default 2)
本人机器测试如下:
我们可以看到 在Get操作中 QPS 为 76863 相当于每秒1.7W的访问量,虚拟机的配置为1G内存单CPU,如果进行水平扩容2台,架构由一台master加三台slave,则支持7.6W*2 = 22W的QPS,当然在生产场景下,与访问的数据大小存在关系;
redis实现99.99%高可用
------------------------------------------------------------------------------------------
----主备切换
在主从架构中slave发生问题时,如果是一台slave出现问题,不会影响整个架构的运行,因为其他的slave会顶替该宕机的slave,但是如果master出现了宕机,就没有机器继续给
slave机器复制数据,所以这时候需要采用一种机制来实现高可用性;
如何实现缓存架构的高可用性
-----【增加哨兵 Sentinel Node】
------------------------------------------------------------------------------------------
经典的三点哨兵集群介绍:
-----【为什么最少是3个哨兵,因为只要quorum 和 majority 都满足的情况下才可以进行故障转移】
如果哨兵集群中一个哨兵认为主节点宕机了,这种情况为sdowm,也就是主观宕机,此时可能存在误判,所以需要设置quorum,比如有三台机器,quorum设置
为2,则在有两台机器认为是sdown的情况下,变为odowm,也就是客观宕机,此时的判断一般是准确的。
哨兵是redis集群架构中非常重要的一个组件,主要功能如下:
(1)集群监控,负责监控redis master和slave进程是否正常工作
(2)消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
(3)故障转移,如果master node挂掉了,会自动转移到slave node上
(4)配置中心,如果故障转移发生了,通知client客户端新的master地址
哨兵本身也是分布式的,作为一个哨兵集群去运行,互相协同工作
(1)故障转移时,判断一个master node是宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题
(2)即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了
哨兵的核心知识 ----- 哨兵+redis部署架构
(1)哨兵至少需要3个实例,来保证自己的健壮性
(2)哨兵 + redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性
(3)对于哨兵 + redis主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练
------------------------------------------------------------------------------------------
哨兵模式的虚拟机模拟配置:
首先说一下这里有个坑爹的地方就是 坑了我三天才得以解决,就是哨兵在监视master 和 slave的时候,都需要配置密码,sentinel auth-pass mymaster redis-pass 这一步我配置的过程中漏掉了,导致哨兵一直监视不了主从架构,所以在配置的过程中一定要加上;
基本配置:
哨兵默认用26379端口,默认不能跟其他机器在指定端口连通,只能在本地访问 mkdir /etc/sentinal
mkdir -p /var/sentinal/5000 /etc/sentinal/5000.conf
在5000.conf文件中进行配置:
port 5000
bind 192.168.1.108
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.1.108 6379 2
sentinel down-after-milliseconds mymaster 30000 //超过多少毫秒跟一个redis实例断了连接,哨兵就可能认为这个redis实例挂了
sentinel failover-timeout mymaster 60000 //执行故障转移的timeout超时时长
sentinel parallel-syncs mymaster 1 //选举出新的master后 一次性把几个slave挂载上去
sentinel auth-pass mymaster redis-pass port 5000
bind 192.168.1.109
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.1.108 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster redis-pass
port 5000
bind 192.168.1.105
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.1.108 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster redis-pass
3、启动哨兵进程 在eshop-cache01、eshop-cache02、eshop-cache03三台机器上,分别启动三个哨兵进程,组成一个集群,观察一下日志的输出
redis-sentinel /etc/sentinal/5000.conf
redis-server /etc/sentinal/5000.conf --sentinel
日志里会显示出来,每个哨兵都能去监控到对应的redis master,并能够自动发现对应的slave,哨兵之间互相会自动进行发现,用的就是之前说的pub/sub,消息发布和订阅channel消息系统和机制 4、检查哨兵状态 redis-cli -h 192.168.1.108 -p 5000
sentinel master mymaster
SENTINEL slaves mymaster
SENTINEL sentinels mymaster SENTINEL get-master-addr-by-name mymaster
配置成功后的运行截图:
master的哨兵信息:
Slave上的哨兵信息:
master的哨兵监视信息:
slave的监视信息:
模式master 宕机后的情景:
将master的端口关闭掉,或者直接关闭master虚拟机,
------------------------------------------------------------------------------------------
在Master宕机以及分裂的异常情况下的处理方案:
Master宕机
第一种情况:在client不断往master写入数据,在准备将数据异步拷贝给各个slave的时候,此时master宕机的情况下,哨兵会选举新的master,然后clinet就会向
新的master写入数据,此时原来的master里边原来写入的那块数据就丢失了;
分裂的情况
第二种情况脑裂:
也就是master由于异常原因,独立出slave所在的网络,但是master可以继续工作,但此时哨兵检测到master的异常后,重新选出一个slave作为新的master,
此时的场景下存在了两个master,在新的master选举出来之前,然后client继续向原来的master写入数据,当选举新master完成后,原来的master恢复被被设置
为slave,此时旧的master缓存的数据就会被覆盖,导致数据丢失;
------------------------------------------------------------------
1、两种数据丢失的情况
主备切换的过程,可能会导致数据丢失
(1)异步复制导致的数据丢失
因为master -> slave的复制是异步的,所以可能有部分数据还没复制到slave,master就宕机了,此时这些部分数据就丢失了
(2)脑裂导致的数据丢失
脑裂,也就是说,某个master所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着
此时哨兵可能就会认为master宕机了,然后开启选举,将其他slave切换成了master
这个时候,集群里就会有两个master,也就是所谓的脑裂
此时虽然某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续写向旧master的数据可能也丢失了
因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据
------------------------------------------------------------------
解决方案:
在redis的配置文件配置参数:
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有1个slave,数据复制和同步的延迟不能超过10秒,如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了.
要求至少有1个slave,数据复制和同步的延迟不能超过10秒
如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了
上面两个配置可以减少异步复制和脑裂导致的数据丢失
(1)减少异步复制的数据丢失
有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求[可能redis会处理暂时写入,保存到自己一个缓存区,详见上边的“处理图”],这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内
(2)减少脑裂的数据丢失
如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求
这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失
上面的配置就确保了,如果跟任何一个slave丢了连接,在10秒后发现没有slave给自己ack,那么就拒绝新的写请求
因此在脑裂场景下,最多就丢失10秒的数据
------------------------------------------------------------------------------------------
如何在保持读写分离+高可用的架构下,还能横向扩容支撑1T+海量数据
1、redis cluster vs. replication + sentinal
replication + sentinal:如果你的数据量很少,主要是承载高并发高性能的场景,比如你的缓存一般就几个G,单机足够了一个mater,多个slave,要几个slave跟你的要求的读吞吐量有关系,
然后自己搭建一个sentinal集群,去保证redis主从架构的高可用性,就可以了。
redis cluster:主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用redis cluster
2、单机redis在海量数据面前的瓶颈
3、怎么才能够突破单机瓶颈,让redis支撑海量数据?
4、redis的集群架构
redis cluster
支撑N个redis master node,每个master node都可以挂载多个slave node
读写分离的架构,对于每个master来说,写就写到master,然后读就从mater对应的slave去读
高可用,因为每个master都有salve节点,那么如果mater挂掉,redis cluster这套机制,就会自动将某个slave切换成master
redis cluster(多master + 读写分离 + 高可用)
我们只要基于redis cluster去搭建redis集群即可,不需要手工去搭建replication复制+主从架构+读写分离+哨兵集群+高可用
*************redis clustor 介绍与搭建 *********
------针对海量数据+高并发+高可用的场景
讲解分布式数据存储的核心算法,数据分布的算法:
hash算法 -> 一致性hash算法(memcached) -> redis cluster,hash slot算法
用不同的算法,就决定了在多个master节点的时候,数据如何分布到这些节点上去,解决这个问题。
简单的取模 hash函数实现:
【严重的弊端,对机器的个数进行取模】
一致性hash算法:
对于一致性hash算法热点问题的改进:
redis slot的实现原理:
以前写的内容是master机器和slave机器分离,分别负责读写,但是到了 redis cluster之后,就不再读写分离,所有的读和写都是通过master进行的;
针对key进行hash slot运算找slot;
关于redis cluster不再使用三点哨兵集群模式那种读写分离的架构,所有的读和写都通过master就可以,如果想提高读或者写的QPS,则我们只需要进行水平扩容,增加master就可以,其中
多台slave的作用是为了增加高可用,用来做主备切换使用;
理论补充部分:
---- 记得需要补充;------ 2019-3-31补充如下:
**********************
1、redis cluster 搭建部署:
停止之前所有的实例,包括redis主从和哨兵集群,使用 redis cluster。
redis cluster: 自动,master+slave复制和读写分离,master+slave高可用和主备切换,支持多个master的hash slot支持数据分布式存储。 、redis cluster的重要配置 cluster-enabled <yes/no> cluster-config-file <filename>:
这是指定一个文件,供cluster模式下的redis实例将集群状态保存在那里,包括集群中其他机器的信息,比如节点的上线和下限,故障转移,不是我们去维护的,给它指定一个文件,让redis自己去维护的 cluster-node-timeout <milliseconds>:
节点存活超时时长,超过一定时长,认为节点宕机,master宕机的话就会触发主备切换,slave宕机就不会提供服务 、在三台机器上启动6个redis实例 --- 以其中一台举例 --- ()在eshop-cache01上部署目录 /etc/redis/XXX (存放redis的配置文件)
/var/redis/XXX (存放redis的持久化文件) ()编写配置文件 redis cluster集群,要求至少3个master,去组成一个高可用,健壮的分布式的集群,每个master都建议至少给一个slave,3个master,3个slave,最少的要求,正式环境下,建议都是说在6台机器上去搭建,至少3台机器。 保证,每个master都跟自己的slave不在同一台机器上,如果是6台自然更好,一个master+一个slave就死了 3台机器去搭建6个redis实例的redis cluster:
拿一台举例
-------------------------------------------------------
mkdir -p /etc/redis-cluster
mkdir -p /var/log/redis
mkdir -p /var/redis/ port
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-.conf
cluster-node-timeout
daemonize yes
pidfile /var/run/redis_7001.pid
dir /var/redis/
logfile /var/log/redis/.log
bind 192.168.31.187
appendonly yes
-------------------------------------------------------
至少要用3个master节点启动,每个master加一个slave节点,先选择6个节点,启动6个实例,将上面的配置文件,在/etc/redis下放6个,分别为:
eshop-cache01:
7001.conf,.conf,
eshop-cache02:
7003.conf,.conf,
eshop-cache03:
7005.conf,.conf ()准备生产环境的启动脚本 在/etc/init.d下,放6个启动脚本,分别为: redis_7001, redis_7002, redis_7003, redis_7004, redis_7005, redis_7006 每个启动脚本内,都修改对应的端口号,如下图:
()分别在3台机器上,启动6个redis实例 将每个配置文件中的slaveof给删除 、创建集群 下面方框内的内容废弃掉 ======================================================================= wget https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz
tar -zxvf ruby-2.3..tar.gz
./configure -prefix=/usr/local/ruby
make && make install
cd /usr/local/ruby
cp bin/ruby /usr/local/bin
cp bin/gem /usr/local/bin wget http://rubygems.org/downloads/redis-3.3.0.gem
gem install -l ./redis-3.3..gem
gem list --check redis gem ======================================================================= 因为,以前比如公司里面搭建集群,公司里的机器的环境,运维会帮你做好很多事情 在讲课的话,我们手工用从零开始装的linux虚拟机去搭建,那肯定会碰到各种各样的问题 yum install -y ruby
yum install -y rubygems
gem install redis cp /usr/local/redis-3.2./src/redis-trib.rb /usr/local/bin redis-trib.rb create --replicas 1 192.168.31.187:7001 192.168.31.187:7002 192.168.31.19:7003 192.168.31.19:7004 192.168.31.227:7005 192.168.31.227:7006 --replicas: 每个master有几个slave 6台机器,3个master,3个slave,尽量自己让master和slave不在一台机器上 yes redis-trib.rb check 192.168.31.187:7001 、读写分离+高可用+多master 读写分离:每个master都有一个slave
高可用:master宕机,slave自动被切换过去
多master:横向扩容支持更大数据量
2、redis cluster的实验,多master写入,主从复制,高可用
redis cluster搭建起来了
redis cluster,提供了多个master,数据可以分布式存储在多个master上; 每个master都带着slave,自动就做读写分离; 每个master如果故障,那么久会自动将slave切换成master,高可用
redis cluster的基本功能,来测试一下
1、实验多master写入 -> 海量数据的分布式存储
你在redis cluster写入数据的时候,其实是你可以将请求发送到任意一个master上去执行
但是,每个master都会计算这个key对应的CRC16值,然后对16384个hashslot取模,找到key对应的hashslot,找到hashslot对应的master
如果对应的master就在自己本地的话,set mykey1 v1,mykey1这个key对应的hashslot就在自己本地,那么自己就处理掉了
但是如果计算出来的hashslot在其他master上,那么就会给客户端返回一个moved error,告诉你,你得到哪个master上去执行这条写入的命令
什么叫做多master的写入,就是每条数据只能存在于一个master上,不同的master负责存储不同的数据,分布式的数据存储
100w条数据,5个master,每个master就负责存储20w条数据,分布式数据存储
大型的java系统架构,还专注在大数据系统架构,分布式,分布式存储,hadoop hdfs,分布式资源调度,hadoop yarn,分布式计算,hadoop mapreduce/hive
分布式的nosql数据库,hbase,分布式的协调,zookeeper,分布式通用计算引擎,spark,分布式的实时计算引擎,storm
如果你要处理海量数据,就涉及到了一个名词,叫做大数据,只要涉及到大数据,那么其实就会涉及到分布式
redis cluster,分布式
因为我来讲java系统的架构,有时候跟其他人不一样,纯搞java,但是我因为工作时间很长,早期专注做java架构,好多年,大数据兴起,就一直专注大数据系统架构
大数据相关的系统,也涉及很多的java系统架构,高并发、高可用、高性能、可扩展、分布式系统
会给大家稍微拓展一下知识面,从不同的角度去讲解一块知识
redis,高并发、高性能、每日上亿流量的大型电商网站的商品详情页系统的缓存架构,来讲解的,redis是作为大规模缓存架构中的底层的核心存储的支持
高并发、高性能、每日上亿流量,redis持久化 -> 灾难的时候,做数据恢复,复制 -> 读写分离,扩容slave,支撑更高的读吞吐,redis怎么支撑读QPS超过10万,几十万; 哨兵,在redis主从,一主多从,怎么保证99.99%可用性; redis cluster,海量数据
java架构课,架构思路和设计是很重要的,但是另外一点,我希望能够带着大家用真正java架构师的角度去看待一些技术,而不是仅仅停留在技术的一些细节的点
给大家从一些大数据的角度,去分析一下我们java架构领域中的一些技术
天下武功,都出自一脉,研究过各种大数据的系统,redis cluster讲解了很多原理,跟elasticsearch,很多底层的分布式原理,都是类似的
redis AOF,fsync
elasticsearch建立索引的时候,先写内存缓存,每秒钟把数据刷入os cache,接下来再每隔一定时间fsync到磁盘上去
redis cluster,写可以到任意master,任意master计算key的hashslot以后,告诉client,重定向,路由到其他mater去执行,分布式存储的一个经典的做法
elasticsearch,建立索引的时候,也会根据doc id/routing value,做路由,路由到某个其他节点,重定向到其他节点去执行
分布式的一些,hadoop,spark,storm里面很多核心的思想都是类似的
后面,马上把redis架构给讲完之后,就开始讲解业务系统的开发,包括高并发的商品详情页系统的大型的缓存架构,jedis cluster相关api去封装和测试对redis cluster的访问
jedis cluster api,就可以自动针对多个master进行写入和读取
2、实验不同master各自的slave读取 -> 读写分离
在这个redis cluster中,如果你要在slave读取数据,那么需要带上readonly指令,get mykey1
redis-cli -c -h xxxx -p xxxxx
启动,就会自动进行各种底层的重定向的操作
实验redis cluster的读写分离的时候,会发现有一定的限制性,默认情况下,redis cluster的核心的理念,主要是用slave做高可用的,每个master挂一两个slave,主要是做数据的热备,还有master故障时的主备切换,实现高可用的
redis cluster默认是不支持slave节点读或者写的,跟我们手动基于replication搭建的主从架构不一样的
slave node,readonly,get,这个时候才能在slave node进行读取
redis cluster,主从架构是出来,读写分离,复杂了点,也可以做,jedis客户端,对redis cluster的读写分离支持不太好的
默认的话就是读和写都到master上去执行的
如果你要让最流行的jedis做redis cluster的读写分离的访问,那可能还得自己修改一点jedis的源码,成本比较高
要不然你就是自己基于jedis,封装一下,自己做一个redis cluster的读写分离的访问api
核心的思路,就是说,redis cluster的时候,就没有所谓的读写分离的概念了
读写分离,是为了什么,主要是因为要建立一主多从的架构,才能横向任意扩展slave node去支撑更大的读吞吐量
redis cluster的架构下,实际上本身master就是可以任意扩展的,你如果要支撑更大的读吞吐量,或者写吞吐量,或者数据量,都可以直接对master进行横向扩展就可以了
也可以实现支撑更高的读吞吐的效果
不会去跟大家直接讲解的,很多东西都要带着一些疑问,未知,实际经过一些实验和操作之后,让你体会的更加深刻一些
redis cluster,主从架构,读写分离,没说错,没有撒谎
redis cluster,不太好,server层面,jedis client层面,对master做扩容,所以说扩容master,跟之前扩容slave,效果是一样的
3、实验自动故障切换 -> 高可用性
redis-trib.rb check 192.168.31.187:7001
比如把master1,187:7001,杀掉,看看它对应的19:7004能不能自动切换成master,可以自动切换
切换成master后的19:7004,可以直接读取数据
再试着把187:7001给重新启动,恢复过来,自动作为slave挂载到了19:7004上面去
3、实现redis cluster的水平扩容
redis cluster模式下,不建议做物理的读写分离了
我们建议通过master的水平扩容,来横向扩展读写吞吐量,还有支撑更多的海量数据
redis单机,读吞吐是5w/s,写吞吐2w/s
扩展redis更多master,那么如果有5台master,不就读吞吐可以达到总量25/s QPS,写可以达到10w/s QPS
redis单机,内存,6G,8G,fork类操作的时候很耗时,会导致请求延时的问题
扩容到5台master,能支撑的总的缓存数据量就是30G,40G
100台,600G,800G,甚至1T+,海量数据
----------------------------------------------------------
redis是怎么扩容的
------- 加入master 加入slave
1、加入新master
mkdir -p /var/redis/7007
port 7007
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-7007.conf
cluster-node-timeout 15000
daemonize yes
pidfile /var/run/redis_7007.pid
dir /var/redis/7007
logfile /var/log/redis/7007.log
bind 192.168.31.227
appendonly yes
搞一个7007.conf,再搞一个redis_7007启动脚本
手动启动一个新的redis实例,在7007端口上
redis-trib.rb add-node 192.168.31.227:7007 192.168.31.187:7001
redis-trib.rb check 192.168.31.187:7001
连接到新的redis实例上,cluster nodes,确认自己是否加入了集群,作为了一个新的master,
2、reshard一些数据过去
resharding的意思就是把一部分hash slot从一些node上迁移到另外一些node上
redis-trib.rb reshard 192.168.31.187:7001
要把之前3个master上,总共4096个hashslot迁移到新的第四个master上去
How many slots do you want to move (from 1 to 16384)? 4096
检查一下分配的情况:
3、添加node作为slave
eshop-cache03
mkdir -p /var/redis/7008
port 7008
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-7008.conf
cluster-node-timeout 15000
daemonize yes
pidfile /var/run/redis_7008.pid
dir /var/redis/7008
logfile /var/log/redis/7008.log
bind 192.168.31.227
appendonly yes
redis-trib.rb add-node --slave --master-id 28927912ea0d59f6b790a50cf606602a5ee48108 192.168.31.227:7008 192.168.31.187:7001
检查加入情况:
4、删除node
先用resharding将数据都移除到其他节点,确保node为空之后,才能执行remove操作
先将slot移空
移空后执行删除:
redis-trib.rb del-node 192.168.31.187:7001 bd5a40a6ddccbd46a0f4a2208eb25d2453c2a8db
2个是1365,1个是1366
当你清空了一个master的hashslot时,redis cluster就会自动将其slave挂载到其他master上去
这个时候就只要删除掉master就可以了
4、slave的自动迁移
---------为什么要存在冗余slave
比如现在有10个master,每个有1个slave,然后新增了3个slave作为冗余,有的master就有2个slave了,有的master出现了salve冗余
如果某个master的slave挂了,那么redis cluster会自动迁移一个冗余的slave给那个master
只要多加一些冗余的slave就可以了
为了避免的场景,就是说,如果你每个master只有一个slave,万一说一个slave死了,然后很快,master也死了,那可用性还是降低了
但是如果你给整个集群挂载了一些冗余slave,那么某个master的slave死了,冗余的slave会被自动迁移过去,作为master的新slave,此时即使那个master也死了
还是有一个slave会切换成master的
之前有一个master是有冗余slave的,直接让其他master其中的一个slave死掉,然后看有冗余slave会不会自动挂载到那个master
自动化迁移后:
5、redis cluster的核心原理分析:gossip通信、jedis smart定位、主备切换
一、节点间的内部通信机制
1、基础通信原理
(1)redis cluster节点间采取gossip协议进行通信
跟集中式不同,不是将集群元数据(节点信息,故障,等等)集中存储在某个节点上,而是互相之间不断通信,保持整个集群所有节点的数据是完整的
维护集群的元数据用得,集中式,一种叫做gossip
集中式:好处在于,元数据的更新和读取,时效性非常好,一旦元数据出现了变更,立即就更新到集中式的存储中,其他节点读取的时候立即就可以感知到; 不好在于,所有的元数据的跟新压力全部集中在一个地方,可能会导致元数据的存储有压力
gossip:好处在于,元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上去更新,有一定的延时,降低了压力; 缺点,元数据更新有延时,可能导致集群的一些操作会有一些滞后
我们刚才做reshard,去做另外一个操作,会发现说,configuration error,达成一致
(2)10000端口
每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+10000,比如7001,那么用于节点间通信的就是17001端口
每隔节点每隔一段时间都会往另外几个节点发送ping消息,同时其他几点接收到ping之后返回pong
(3)交换的信息
故障信息,节点的增加和移除,hash slot信息,等等
2、gossip协议
gossip协议包含多种消息,包括ping,pong,meet,fail,等等
meet: 某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通信
redis-trib.rb add-node
其实内部就是发送了一个gossip meet消息,给新加入的节点,通知那个节点去加入我们的集群
ping: 每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过ping交换元数据
每个节点每秒都会频繁发送ping给其他的集群,ping,频繁的互相之间交换数据,互相进行元数据的更新
pong: 返回ping和meet,包含自己的状态和其他信息,也可以用于信息广播和更新
fail: 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了
3、ping消息深入
ping很频繁,而且要携带一些元数据,所以可能会加重网络负担
每个节点每秒会执行10次ping,每次会选择5个最久没有通信的其他节点
当然如果发现某个节点通信延时达到了cluster_node_timeout / 2,那么立即发送ping,避免数据交换延时过长,落后的时间太长了
比如说,两个节点之间都10分钟没有交换数据了,那么整个集群处于严重的元数据不一致的情况,就会有问题
所以cluster_node_timeout可以调节,如果调节比较大,那么会降低发送的频率
每次ping,一个是带上自己节点的信息,还有就是带上1/10其他节点的信息,发送出去,进行数据交换
至少包含3个其他节点的信息,最多包含总节点-2个其他节点的信息
-------------------------------------------------------------------------------------------------------
二、面向集群的jedis内部实现原理
开发,jedis,redis的java client客户端,redis cluster,jedis cluster api
jedis cluster api与redis cluster集群交互的一些基本原理
1、基于重定向的客户端
redis-cli -c,自动重定向
(1)请求重定向
客户端可能会挑选任意一个redis实例去发送命令,每个redis实例接收到命令,都会计算key对应的hash slot
如果在本地就在本地处理,否则返回moved给客户端,让客户端进行重定向
cluster keyslot mykey,可以查看一个key对应的hash slot是什么
用redis-cli的时候,可以加入-c参数,支持自动的请求重定向,redis-cli接收到moved之后,会自动重定向到对应的节点执行命令
(2)计算hash slot
计算hash slot的算法,就是根据key计算CRC16值,然后对16384取模,拿到对应的hash slot
用hash tag可以手动指定key对应的slot,同一个hash tag下的key,都会在一个hash slot中,比如set mykey1:{100}和set mykey2:{100}
(3)hash slot查找
节点间通过gossip协议进行数据交换,就知道每个hash slot在哪个节点上
2、smart jedis
(1)什么是smart jedis
基于重定向的客户端,很消耗网络IO,因为大部分情况下,可能都会出现一次请求重定向,才能找到正确的节点
所以大部分的客户端,比如java redis客户端,就是jedis,都是smart的
本地维护一份hashslot -> node的映射表,缓存,大部分情况下,直接走本地缓存就可以找到hashslot -> node,不需要通过节点进行moved重定向
(2)JedisCluster的工作原理
在JedisCluster初始化的时候,就会随机选择一个node,初始化hashslot -> node映射表,同时为每个节点创建一个JedisPool连接池
每次基于JedisCluster执行操作,首先JedisCluster都会在本地计算key的hashslot,然后在本地映射表找到对应的节点
如果那个node正好还是持有那个hashslot,那么就ok; 如果说进行了reshard这样的操作,可能hashslot已经不在那个node上了,就会返回moved
如果JedisCluter API发现对应的节点返回moved,那么利用该节点的元数据,更新本地的hashslot -> node映射表缓存
重复上面几个步骤,直到找到对应的节点,如果重试超过5次,那么就报错,JedisClusterMaxRedirectionException
jedis老版本,可能会出现在集群某个节点故障还没完成自动切换恢复时,频繁更新hash slot,频繁ping节点检查活跃,导致大量网络IO开销
jedis最新版本,对于这些过度的hash slot更新和ping,都进行了优化,避免了类似问题
(3)hashslot迁移和ask重定向
如果hash slot正在迁移,那么会返回ask重定向给jedis
jedis接收到ask重定向之后,会重新定位到目标节点去执行,但是因为ask发生在hash slot迁移过程中,所以JedisCluster API收到ask是不会更新hashslot本地缓存
已经可以确定说,hashslot已经迁移完了,moved是会更新本地hashslot->node映射表缓存的
-------------------------------------------------------------------------------------------------------
三、高可用性与主备切换原理
redis cluster的高可用的原理,几乎跟哨兵是类似的
1、判断节点宕机
如果一个节点认为另外一个节点宕机,那么就是pfail,主观宕机
如果多个节点都认为另外一个节点宕机了,那么就是fail,客观宕机,跟哨兵的原理几乎一样,sdown,odown
在cluster-node-timeout内,某个节点一直没有返回pong,那么就被认为pfail
如果一个节点认为某个节点pfail了,那么会在gossip ping消息中,ping给其他节点,如果超过半数的节点都认为pfail了,那么就会变成fail
2、从节点过滤
对宕机的master node,从其所有的slave node中,选择一个切换成master node
检查每个slave node与master node断开连接的时间,如果超过了cluster-node-timeout * cluster-slave-validity-factor,那么就没有资格切换成master
这个也是跟哨兵是一样的,从节点超时过滤的步骤
3、从节点选举
哨兵:对所有从节点进行排序,slave priority,offset,run id
每个从节点,都根据自己对master复制数据的offset,来设置一个选举时间,offset越大(复制数据越多)的从节点,选举时间越靠前,优先进行选举
所有的master node开始slave选举投票,给要进行选举的slave进行投票,如果大部分master node(N/2 + 1)都投票给了某个从节点,那么选举通过,那个从节点可以切换成master
从节点执行主备切换,从节点切换为主节点
4、与哨兵比较
整个流程跟哨兵相比,非常类似,所以说,redis cluster功能强大,直接集成了replication和sentinal的功能
----------------------------------------------------------------------------------------------------
没有办法去给大家深入讲解redis底层的设计的细节,核心原理和设计的细节,
那个除非单独开一门课,redis底层原理深度剖析,redis源码对于咱们这个架
构课来说,主要关注的是架构,不是底层的细节,对于架构来说,核心的原理
的基本思路,是要梳理清晰的。
----------------------------------------------------------------------------------------------------
两套不同的redis缓存架构适用的不同场景
----我们主要使用的是redis cluster模式的缓存框架
************实战环节**********
亿级流量商品详情页的缓存架构:
我们之前的三十讲,主要是在讲解redis如何支撑海量数据、高并发读写、高可用服务的架构,redis架构。redis架构,在我们的真正类似商品详情页读高并发的系统中,redis就是底层的缓存存储的支持。
从这一讲开始,我们正式开始做业务系统的开发亿级流量以上的电商网站的商品详情页的系统,商品详情页系统,大量的业务,十几个人做一两年,堆出来复杂的业务系统
几十个小时的课程,讲解复杂的业务,把整体的架构给大家讲解清楚,然后浓缩和精炼里面的业务,提取部分业务,做一些简化,把整个详情页系统的流程跑出来。
架构,骨架,有少量的业务,血和肉,把整个项目串起来,在业务背景下,去学习架构。
讲解商品详情页系统,缓存架构,90%大量的业务代码(没有什么技术含量),10%的最优技术含量的就是架构,上亿流量,每秒QPS几万,上十万的,读并发,缓存架构
架构理解:
采用三级缓存:nginx本地缓存+redis分布式缓存+tomcat堆缓存的多级缓存架构
时效性要求非常高的数据:库存
一般来说,显示的库存,都是时效性要求会相对高一些,因为随着商品的不断的交易,库存会不断的变化。
当然,我们就希望当库存变化的时候,尽可能更快将库存显示到页面上去,而不是说等了很长时间,库存才反应到页面上去。
时效性要求不高的数据:时效性要求不高的数据:商品的基本信息(名称、颜色、版本、规格参数,等等)。
时效性高:商品价格/库存等时效性要求高的数据,而且种类较少,采取相关的服务系统每次发生了变更的时候,直接采取数据库和redis缓存双写的方案,这样缓存的时效性最高。
时效性不高:商品基本信息等时效性不高的数据,而且种类繁多,来自多种不同的系统,采取MQ异步通知的方式,写一个数据生产服务,监听MQ消息,然后异步拉取服务的数据,更新tomcat jvm缓存+redis缓存
---------------------------------------------------------------------------------
nginx+lua脚本做页面动态生成的工作,每次请求过来,优先从nginx本地缓存中提取各种数据,结合页面模板,生成需要的页面如果nginx本地缓存过期了,那么就从nginx到redis中去拉取数据,更新到nginx本地
如果redis中也被LRU算法清理掉了,那么就从nginx走http接口到后端的服务中拉取数据,数据生产服务中,现在本地tomcat里的jvm堆缓存中找,ehcache,如果也被LRU清理掉了,那么就重新发送请求到源头的服务中去拉取数据,然后再次更新tomcat堆内存缓存+redis缓存,并返回数据给nginx,nginx缓存到本地
---------------------------------------------------------------------------------
2、多级缓存架构中每一层的意义
nginx本地缓存,抗的是热数据的高并发访问,一般来说,商品的购买总是有热点的,比如每天购买iphone、nike、海尔等知名品牌的东西的人,总是比较多的
这些热数据,利用nginx本地缓存,由于经常被访问,所以可以被锁定在nginx的本地缓存内
大量的热数据的访问,就是经常会访问的那些数据,就会被保留在nginx本地缓存内,那么对这些热数据的大量访问,就直接走nginx就可以了
那么大量的访问,直接就可以走到nginx就行了,不需要走后续的各种网络开销了
redis分布式大规模缓存,抗的是很高的离散访问,支撑海量的数据,高并发的访问,高可用的服务
redis缓存最大量的数据,最完整的数据和缓存,1T+数据; 支撑高并发的访问,QPS最高到几十万; 可用性,非常好,提供非常稳定的服务
nginx本地内存有限,也就能cache住部分热数据,除了各种iphone、nike等热数据,其他相对不那么热的数据,可能流量会经常走到redis那里
利用redis cluster的多master写入,横向扩容,1T+以上海量数据支持,几十万的读写QPS,99.99%高可用性,那么就可以抗住大量的离散访问请求
tomcat jvm堆内存缓存,主要是抗redis大规模灾难的,如果redis出现了大规模的宕机,导致nginx大量流量直接涌入数据生产服务,那么最后的tomcat堆内存缓存至少可以再抗一下,不至于让数据库直接裸奔
同时tomcat jvm堆内存缓存,也可以抗住redis没有cache住的最后那少量的部分缓存
传统的缓存读写模式:【不涉及到高并发的访问】
在请求进行读和更新时候,对于缓存的操作是如何进行的:
读:先读缓存,无则进入数据库,然后更新缓存;
更新:删除缓存,更新数据库
Redis和数据库双写不一致问题:
一:不优先删除缓存的情况下,写入数据后,如果再清空缓存如果出现问题,则此时会出现不一致问
先产缓存 在删除
读写并发读写的时候可能出现下面这种双写不一致的问题:
在读并发很低的情况,很少的情况会出现这种双写不一致问题,如果每天商议的流量,则会可能出现不一致情况;
解决方案【建立串行写读队列】:
对读写串行队列需要考虑读的情况下,读的操作可能会hang的过久,需要根据业务场景进行测试;
继续补充中。。。。。
亿级流量场景下,大型缓存架构设计实现【1】---redis篇的更多相关文章
- 亿级流量场景下,大型架构设计实现【2】---storm篇
承接之前的博:亿级流量场景下,大型缓存架构设计实现 续写本博客: ****************** start: 接下来,我们是要讲解商品详情页缓存架构,缓存预热和解决方案,缓存预热可能导致整个系 ...
- 【高并发】亿级流量场景下如何为HTTP接口限流?看完我懂了!!
写在前面 在互联网应用中,高并发系统会面临一个重大的挑战,那就是大量流高并发访问,比如:天猫的双十一.京东618.秒杀.抢购促销等,这些都是典型的大流量高并发场景.关于秒杀,小伙伴们可以参见我的另一篇 ...
- 亿级流量场景下,大型架构设计实现【全文检索高级搜索---ElasticSearch篇】-- 中
1.Elasticsearch的基础分布式架构: 1.Elasticsearch对复杂分布式机制的透明隐藏特性2.Elasticsearch的垂直扩容与水平扩容3.增减或减少节点时的数据rebalan ...
- 高并发下的缓存架构设计演进及redis常见的缓存应用异象解决方案
待总结 缓存穿透 缓存击穿 缓存雪崩等
- java亿级流量电商详情页系统的大型高并发与高可用缓存架构实战视频教程
亿级流量电商详情页系统的大型高并发与高可用缓存架构实战 完整高清含源码,需要课程的联系QQ:2608609000 1[免费观看]课程介绍以及高并发高可用复杂系统中的缓存架构有哪些东西2[免费观看]基于 ...
- 【架构师之路】Nginx负载均衡与反向代理—《亿级流量网站架构核心技术》
本篇摘自<亿级流量网站架构核心技术>第二章 Nginx负载均衡与反向代理 部分内容. 当我们的应用单实例不能支撑用户请求时,此时就需要扩容,从一台服务器扩容到两台.几十台.几百台.然而,用 ...
- SpringCloud 亿级流量 架构演进
疯狂创客圈 Java 高并发[ 亿级流量聊天室实战]实战系列 [博客园总入口 ] 架构师成长+面试必备之 高并发基础书籍 [Netty Zookeeper Redis 高并发实战 ] 前言 Crazy ...
- Netty 100万级到亿级流量 高并发 仿微信 IM后台 开源项目实战
目录 写在前面 亿级流量IM的应用场景 十万级 单体IM 系统 高并发分布式IM系统架构 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之 -10[ 博客园 总入口 ] 写在前面 大家好 ...
- Netty Redis 亿级流量 高并发 实战 (长文 修正版)
目录 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之 -30[ 博客园 总入口 ] 写在前面 1.1. 快速的能力提升,巨大的应用价值 1.1.1. 飞速提升能力,并且满足实际开发要求 1 ...
随机推荐
- 整理4种Vue组件通信方式
整理4种Vue组件通信方式 重点是梳理了前两个,父子组件通信和eventBus通信,我觉得Vue文档里的说明还是有一些简易,我自己第一遍是没看明白. 父子组件的通信 非父子组件的eventBus通信 ...
- docker 及 docker-compose 的快速安装和简单使用
本篇将使用 DaoCloud 源在 Ubuntu 上简单快速安装 docker 及 docker-compose 并添加了通过 Dockerfile 及 docker-compose.yml 使用 n ...
- [Swift]LeetCode263. 丑数 | Ugly Number
Write a program to check whether a given number is an ugly number. Ugly numbers are positive numbers ...
- [Swift]LeetCode910. 最小差值 II | Smallest Range II
Given an array A of integers, for each integer A[i] we need to choose either x = -K or x = K, and ad ...
- [Swift]LeetCode953. 验证外星语词典 | Verifying an Alien Dictionary
In an alien language, surprisingly they also use english lowercase letters, but possibly in a differ ...
- Mysql的两种“排名第几且有可能为空的记录”写法(力扣176)
编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) . +----+--------+ | Id | Salary | +----+--------+ | 1 | 100 ...
- 文本编辑器激活系列(一):Sublime 安装、激活、汉化教程
如您激活出现问题,请点击这里加入:软件激活问题解决群 前言 推荐几款文本编辑器: Sublime:内嵌python解释器.大量插件 EditPlus:语法着色.内嵌浏览器 Notepad++:所见即所 ...
- .NET Core实战项目之CMS 第四章 入门篇-Git的快速入门及实战演练
写在前面 上篇文章我带着大家通过分析了一遍ASP.NET Core的源码了解了它的启动过程,然后又带着大家熟悉了一遍配置文件的加载方式,最后引出了依赖注入以及控制反转的概念!如果大家把前面几张都理解了 ...
- Python操作Redis及连接方式
前沿:随着互联网的高速发展,数据变得越来越重要,Python成为了人工智能的热门语言,而Nosql数据库已成为日常开发用品. 今天要写的是Python操作Redis Redis的安装我就不介绍了,你可 ...
- Hystrix是如何工作的
接上一篇:<Hystrix介绍> 流程图 下面这幅图相当重要 稍微解释一下上面的流程: Construct a HystrixCommand or HystrixObservableCom ...