第二十周
1、总结tomcat优化方法
##1、概述
Tomcat的运行依赖于JVM,从虚拟机的角度把Tomcat的调整分为外部环境调优 和 Tomcat 自身调优两部分
##2、外部环境JVM调优
Tomcat首先跑在JVM之上的,因为它的启动其实也只是一个java命令行,首先我们需要对这个JAVA的启动命令行进行调优。
帮助:man java
选项分类
-选项名称 此为标准选项,所有HotSpot都支持
-X选项名称 此为稳定的非标准选项
-XX:选项名称 非标准的不稳定选项,下一个版本可能会取消
#查看java命令标准选项
[root@centos ~]#java
#查看java的非标准选项
[root@centos8 ~]#java -X
#查看所有不稳定选项的当前生效值
[root@centos8 ~]#java -XX:+PrintFlagsFinal
#查看所有不稳定选项的默认值
[root@centos8 ~]#java -XX:+PrintFlagsInitial
#查看当前命令行的使用的选项设置
[root@centos8 ~]#java -XX:+PrintCommandLineFlags
实例:
[root@centos8 ~]#vim /usr/local/tomcat/bin/catalina.sh
JAVA_OPTS="-server -Xms4g -Xmx4g -Xss512k -Xmn1g -XX:CMSInitiatingOccupancyFraction=65 -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=10 -XX:NewRatio=2 -XX:PermSize=128m -XX:MaxPermSize=512m -XX:CMSFullGCsBeforeCompaction=5 -XX:+ExplicitGCInvokesConcurrent -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods"
-server:服务器模式
tomcat默认是以一种叫java –client的模式来运行的,server即意味着你的tomcat是以真实的production的模式在运行的,这也就意味着你的tomcat以 server模式运行时将拥有:更大、更高的并发处理能力,更快更强捷的JVM垃圾回收机制,可以获得更多的负载与吞吐量等。这个参数必须加上。
-Xms:设置应用程序初始使用的堆内存大小(年轻代+老年代) 4g
-Xmx:设置应用程序能获得的最大堆内存4g
调整堆大小的的目的是最小化垃圾收集的时间,以在特定的时间内最大化处理客户的请求。对于SUN和HP等虚拟机,推荐将最小堆大小和最大堆大小设置为同一值,因为这样可以避免浪费用于时常调整堆大小所需的 VM 资源。客户系统如果用到IBM虚拟机,要特别的注意设置-Xms和-Xmx一样大小会耽误垃圾回收的开始直到堆满,这样第一次垃圾回收就会变成非常昂贵的操作。推荐把-Xms设置为应用所需的最小值,这样会产生高效的垃圾回收。
#一台tomcat服务器并发连接数不高,生产建议分配物理内存通常4G到8G较多,如果需要更多连接,一般会利用虚拟化技术实现多台tomcat
-Xss:设定每个线程的堆栈大小512k
依据你的程序,看一个线程 大约需要占用多少内存,可能会有多少线程同时运行等。一般不易设置超过1M,要不然容易出现out ofmemory。
-Xmn:同时设置-XX:NewSize 和 -XX:MaxNewSize,代替两者。年轻代大小1g
-XX:CMSInitiatingOccupancyFraction=65
CMSInitiatingOccupancyFraction,这个参数设置有很大技巧,基本上满足(Xmx-Xmn)(100- CMSInitiatingOccupancyFraction)/100>=Xmn就 不会出现promotion failed。在我的应用中Xmx是4g,Xmn是1g,那么Xmx-Xmn是3096兆,也就是年老代有3096兆,CMSInitiatingOccupancyFraction=90说明年老代到65%满的时候开始执行对年老代的并发垃圾回收(CMS),这时还 剩35%的空间是3096*35%=1083.6兆,所以即使Xmn(也就是年轻代共1024兆)里所有对象都搬到年老代里,1083.6兆的空间也足够了,所以只要满 足上面的公式,就不会出现垃圾回收时的promotion failed;
因此这个参数的设置必须与Xmn关联在一起。
-XX:+AggressiveOpts
作用如其名(aggressive),启用这个参数,则每当JDK版本升级时,你的JVM都会使用最新加入的优化技术(如果有的话)
-XX:+UseBiasedLocking
启用一个优化了的线程锁,我们知道在我们的appserver,每个http请求就是一个线程,有的请求短有的请求长,就会有请求排队的现象,甚至还会出现线程阻塞,这个优化了的线程锁使得你的appserver内对线程处理自动进行最优调配。
-XX:+DisableExplicitGC
禁用Full gc显示调用“System.gc()”
-XX:MaxTenuringThreshold=10
设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一 个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率。
这个值的设置是根据本地的jprofiler监控后得到的一个理想的值,不能一概而论原搬照抄。
-XX:NewRatio=2:以比例方式设置新生代和老年代new/old=1/2
-XX:PermSize=128m
-XX:MaxPermSize=512m
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;
在数据量的很大的文件导出时,一定要把这两个值设置上,否则会出现内存溢出的错误。
-XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。那么,如果是物理内存4GB,那么64分之一就是64MB,这就是PermSize默认值,也就是永生代内存初始大小;四分之一是1024MB,这就是MaxPermSize默认大小。
-XX:CMSFullGCsBeforeCompaction=5
设置在执行多少次Full GC后对内存空间进行压缩整理
因为内存压缩整理的过程是没法并发执行的,所以难免要停顿,要尽量的减少这个停顿时间。根据具体情况,如果Full GC比较频繁,只调优这个参数的情况下,那么就不能每次都整理内存空间,不然积少成多,停顿的时间也是很可观的,此时就要调大该参数,让CMS在经过多次Full GC后再对内存空间进行压缩整理。
-XX:+ExplicitGCInvokesConcurrent
命令JVM无论什么时候调用系统GC,都执行CMS GC,而不是Full GC。
-XX:+UseConcMarkSweepGC
即CMS gc,这一特性只有jdk1.5即后续版本才具有的功能,它使用的是gc估算触发和heap占用触发。
我们知道频频繁的GC会造面JVM的大起大落从而影响到系统的效率,因此使用了CMS GC后可以在GC次数增多的情况下,每次GC的响应时间却很短,比如说使用了CMS GC后经过jprofiler的观察,GC被触发次数非常多,而每次GC耗时仅为几毫秒。
-XX:+UseParNewGC
对年轻代采用多线程并行回收,这样收得快。
-XX:+CMSParallelRemarkEnabled
在使用UseParNewGC 的情况下, 尽量减少 mark 的时间
-XX:+UseCMSCompactAtFullCollection
在使用concurrent gc 的情况下, 防止 memoryfragmention, 对live object 进行整理, 使 memory 碎片减少。
-XX:LargePageSizeInBytes=128m
指定 Java heap的分页页面大小
-XX:+UseFastAccessorMethods
get,set 方法转成本地代码
##2.1、Tomcat与其它web服务器整合使用
虽然tomcat也可以作web服务器,但其处理静态html的速度比不上apache,且其作为web服务器的功能远不如apache,因此我们想把 apache和tomcat集成起来,将html与jsp的功能部分进行明确分工,让tomcat只处理jsp部分,其它的由apache,IIS等这些 web服务器处理,由此大大节省了tomcat有限的工作线程 。
##2.2、负载均衡
在负载均衡的思路下,多台服务器为对等方式,每台服务器都具有同等的地位,可以单独对外提供服务而无须其他服务器的辅助。通过负载分担技术,将外部发送来的请求按一定规则分配到对称结构中的某一台服务器上,而接收到请求的服务器都独立回应客户机的请求。
提供服务的一组服务器组成了一个应用服务器集群(cluster),集群下的对等多机环境可以增加系统的并发处理能力,和单台机器出现故障系统的错误冗余能力;同时实现了负载均衡和系统高可靠性。
四种实现负载均衡的方式:
第一是通过DNS,但只能实现简单的轮流分配,不能处理故障;
第二如果是基于MS IIS,Windows 2003 server本身就带了负载均衡服务;
第三是硬件方式,通过交换机的功能或专门的负载均衡设备可以实现;
第四种是软件方式,通过一台负载均衡服务器进行,上面安装软件。使用nginx、Apache Httpd Server做负载平衡器。
##3、Tomcat 自身调优
##3.1、禁用DNS查询
当web应用程序要记录客户端的信息时,它也会记录客户端的IP地址或者通过域名服务器查找机器名转换为IP地址。DNS查询需要占用网络,并且包括可能从很多很远的服务器或者不起作用的服务器上去获取对应的IP的过程,这样会消耗一定的时间。
为了消除DNS查询对性能的影响我们可以关闭DNS查询,方式是修改server.xml 文件中的enableLookups参数值。
##3.2、调整线程数
connectionTimeout :连接超时时长,单位ms
maxThreads:最大线程数,默认200
minSpareThreads:最小空闲线程数
maxSpareThreads:最大空闲线程数
acceptCount:当启动线程满了之后,等待队列的最大长度,默认100
enableLookups:是否启用客户端主机名的DNS反向解析,缺省禁用,建议禁用,就使用客户端IP
就行
compression:是否启用传输压缩机制,建议 "on",CPU和流量的平衡
compressionMinSize:启用压缩传输的数据流最小值,单位是字节
compressableMimeType:定义启用压缩功能的MIME类型text/html, text/xml, text/css, text/javascrip
##3.3、加速JSP编译速度
当第一次访问一个JSP文件时,它会被转换为Java servlet源码,接着被编译成Java字节码。客户工程师可以控制使用哪个编译器,默认情况下,Tomcat使用命令行javac进行使用的编译器。也可以使用更快的编译器,这里将介绍如何优化它们。
在Tomcat 4.0中可以使用流行而且免费的Jikes编译器。Jikes编译器的速度要高于Sun的Java编译器。首先要安装Jikes(可访问http://oss.software.ibm.com/pub/jikes 获得更多的信息),接着需要在环境变量中设置JIKESPATH包含系统运行时所需的JAR文件。
装好Jikes以后还需要设置让JSP编译servlet使用Jikes,需要修改web.xml文件jspCompilerPlugin的值:
<param-name>jspCompilerPlugin</param-name>
<param-value>org.apache.jasper.compiler.JikesJavaCompiler</param-value>
在Tomcat 4.1(或更高版本),JSP的编译由包含在Tomcat里面的Ant程序控制器直接执行。客户开发人员需要在元素中定义一个名字叫”compiler”,并且在value中有一个支持编译的编译器名字,示例如下:
<param-name>compiler</param-name>
<param-value>jikes</param-value>
由于JSP页面在第一次使用时已经被编译,那么你可能希望在更新新的jsp页面后马上对它进行编译。实际上,这个过程完全可以自动化,因为可以确认的是新的JSP页面在生产服务器和在测试服务器上的运行效果是一样的。
在Tomcat4的bin目录下有一个名为jspc的脚本。它仅仅是运行翻译阶段,而不是编译阶段,使用它可以在当前目录生成Java源文件。它是调试JSP页面的一种有力的手段。
可以通过浏览器访问再确认一下编译的结果。这样就确保了文件被转换成servlet,被编译了可直接执行。这样也准确地模仿了真实用户访问JSP页面,可以看到给用户提供的功能。也抓紧这最后一刻修改出现的bug并且修改它。
Tomcat提供了一种通过请求来编译JSP页面的功能。客户可以在浏览器地址栏中输入http://localhost: 8080/examples/jsp/dates/date.jsp?jsp_precompile=true,这样Tomcat就会编译 data.jsp而不是执行它。此举唾手可得,不失为一种检验页面正确性的捷径
##3.4、NIO 配置
NIO (No-blocking I/O)从JDK 1.4起,NIO API作为一个基于缓冲区,并能提供非阻塞I/O操作的API被引入
TOMCAT可以支持高并发的企业级应用。其中有个很大的原因就是,配置良好的tomcat都会使用APR(Apache Portable Runtime),APR是Apache HTTP Server2.x的核心,它是高度可移植的本地库,它使用高性能的UXIN I/O操作,低性能的java io操作。
但是APR对客户开发人员而言可能稍稍有点难度,在很多OS平台上,可能需要重新编译APR。但是从Tomcat6.0以后, 客户开发人员很容易就可以用NIO的技术来提升tomcat的并发处理能力。但是为什么NIO可以提升tomcat的并发处理能力呢,我们先来看一下java 传统io与 java NIO的差别。
Java 传统的IO操作都是阻塞式的(blocking I/O), 如果有socket的编程基础,你会接触过堵塞socket和非堵塞socket,堵塞socket就是在accept、read、write等IO操作的时候,如果没有可用符合条件的资源,不马上返回,一直等待直到有资源为止。
而非堵塞socket则是在执行select的时候,当没有资源的时候堵塞,当有符合资源的时候,返回一个信号,然后程序就可以执行accept、read、write等操作,一般来说,如果使用堵塞socket,通常我们通常开一个线程accept socket,当读完这次socket请求的时候,开一个单独的线程处理这个socket请求;如果使用非堵塞socket,通常是只有一个线程,一开始是select状,当有信号的时候可以通过多路复用(Multiplexing)技术传递给一个指定的线程池来处理请求,然后原来的线程继续select状态。
最简单的多路复用技术可以通过java管道(Pipe)来实现。换句话说,如果客户端的并发请求很大的时候,客户系统可以使用少于客户端并发请求的线程数来处理这些请求,而这些来不及立即处理的请求会被阻塞在java管道或者队列里面,等待线程池的处理。
在web服务器上阻塞IO(BIO)与NIO一个比较重要的不同是,客户系统使用BIO的时候往往会为每一个web请求引入多线程,每个web请求一个单独的线程,所以并发量一旦上去了,线程数就上去了,CPU就忙着线程切换,所以BIO不合适高吞吐量、高可伸缩的web服务器;而NIO则是使用单线程(单个CPU)或者只使用少量的多线程(多CPU)来接受Socket,而由线程池来处理堵塞在pipe或者队列里的请求。
这样的话,只要OS可以接受TCP的连接,web服务器就可以处理该请求。大大提高了web服务器的可伸缩性。
客户只需要在server.xml里把 HTTP Connector做如下更改:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
改为
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
redirectPort="8443" />
然后启动服务器,如果出现org.apache.coyote.http11.Http11NioProtocol start的提示信息,表示NIO已经启动。其他的配置请参考官方配置文档。
##3.5、其它
Tomcat提供了防止恶意攻击或禁止某些机器访问的设置。
Tomcat提供了两个参数供你配置:RemoteHostValve 和RemoteAddrValve。
通过配置这两个参数,可以让你过滤来自请求的主机或IP地址,并允许或拒绝哪些主机/IP。与之类似的,在Apache的httpd文件里有对每个目录的允许/拒绝指定。
例如你可以把Admin Web application设置成只允许本地访问,设置如下:
<Context path=“/path/to/secret_files” >
<Valve className=“org.apache.catalina.valves.RemoteAddrValve”
allow=“127.0.0.1”deny=““/>
</Context>
如果没有给出允许主机的指定,那么与拒绝主机匹配的主机就会被拒绝,除此之外的都是允许的。与之类似,如果没有给出拒绝主机的指定,那么与允许主机匹配的主机就会被允许,除此之外的都是拒绝的。
##3.6、Java压力测试工具
PerfMa 致力于打造一站式IT系统稳定性保障解决方案,专注于性能评测与调优、故障根因定位与解决,为企业提供一系列技术产品与专家服务,提升系统研发与运行质量。
#社区产品
https://opts.console.perfma.com/
2、java程序出现oom如何解决?什么场景下会出现oom?
1、概述
OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”。当JVM因为没有足够的内存来为对象分配空间、并且垃圾回收器也已经没有空间可回收时,就会抛出这个error。
2、常见OOM情况及解决方法
情况一、java.lang.OutOfMemoryError: Java heap space —— > java 堆内存溢出
出现OOM原因:此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。
解决办法:对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms、-Xmx等修改。
举例:循环调用new A() 导致堆溢出
虚拟机参数:-Xms1M -Xmx1M -XX:+HeapDumpOnOutOfMemoryError,
解释:将-Xmx和-Xms设置为一样可以避免堆自动扩展。-XX:+HeapDumpOnOutOfMemoryError, 解释:可以让虚拟机在出现内存溢出异常时Dump出当前的堆内存转储快照,然后分析Dump文件
情况二、java.lang.OutOfMemoryError: PermGen space —— > java 永久代溢出 ,即方法区溢出了
出现OOM原因:一般出现于大量Class 或者 jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。另外,过多的常量,尤其是字符串,也会导致方法区溢出。
解决办法:此种情况可以通过更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m 的形式修改。
举例:循环调用String.intern()方法来写入常量池,常量池溢出。
虚拟机参数:-XX:PermSize=10M -XX:MaxPermSize=10M,
解释:表示JVM初始分配的永久代的容量和最大容量。(永久区内存不足,1.8后都在堆上。方法区=永久代,PermGen space”,即永久代)
情况三、java.lang.StackOverflowError ------> 不会抛OOM error,但也是比较常见的Java内存溢出。
出现OOM原因:JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。
解决办法 :可以通过虚拟机参数 -Xss 来设置栈的大小。
举例:循环调用对象引用的方式实现栈溢出。
虚拟机参数:-Xss128k,
解释:设置虚拟机栈的大小为128kn
在单线程下,无论栈帧太大还是虚拟机栈容量太小,内存无法分配的时候都会抛出以上错误。
3、##Jprofiler定位OOM的问题原因
JProfiler是一款功能强大的Java开发分析工具,它可以快速的帮助用户分析出存在的错误,软件还可对需要的显示类进行标记,包括了内存的分配情况和信息的视图等
JProfiler官网:http://www.ej-technologies.com/products/jprofiler/overview.html
3、简述redis特点及其应用场景
1、Redis 特点
1.1.速度快: 10W QPS,基于内存,C语言实现,而众所周知,C语言是“距离”操作系统最近的的编程语言,执行速度快
1.2.单线程:Redis采用了单线程的架构,避免了多线程的资源竞争问题
1.3.简单: 代码短小精悍(单机核心代码只有23000行左右),单线程开发容易,不依赖外部库,使用简单
1.4.持久化:Redis还支持两种方式的持久化,即将数据写入磁盘的方法,RDB和AOF,两种方法各有利弊。
1.5.支持多种数据结构:Redis的全程是Remote Dictionary Server,是集合了五种数据结构:字符串、列表、哈希、集合、有序集合,可以说五种数据结构都是围绕于key-value的形式,而value不仅仅可以是值,还能是具体的数据结构,这给予了Redis强大的变化性和灵活能力。
1.6.支持多种编程语言:Redis目前基本可以说和MySQL的知名度一样高了,太多的运用场景,太多的支持语言,常见的比如:java的jedis,Python的redis、PHP、C、C++等等。
1.7.功能丰富: 支持Lua脚本,发布订阅,事务,pipeline等功能
1.8.主从复制:数据库的主从复制、集群功能是非常重要的,可以在Redis异常挂了后不影响客户端的使用
1.9.支持高可用和分布式:Redis从2.8版本后提供了高可用实现的Redis Sentinel,即Redis的“哨兵机制”,可以保证Redis节点的故障发现和自动转移,这实现了Redis强大的分布式功能。
2、应用场景
2.1.Session 共享:常见于web集群中的Tomcat或者PHP中多web服务器session共享
2.2.缓存:数据查询、电商网站商品信息、新闻内容
2.3.计数器:访问排行榜、商品浏览数等和次数相关的数值统计场景
2.4.微博/微信社交场合:共同好友,粉丝数,关注,点赞评论等
2.5.消息队列:ELK的日志缓存、部分业务的订阅发布系统
2.6.地理位置: 基于GEO(地理信息定位),实现摇一摇,附近的人,外卖等功能
4、对比redis的RDB、AOF模式的优缺点
1.RDB模式优缺点
1.1.RDB 模式优点
1.1.1.RDB快照保存了某个时间点的数据,可以通过脚本执行redis指令bgsave(非阻塞,后台执行)或者save(会阻塞写操作,不推荐)命令自定义时间点备份,可以保留多个备份,当出现问题可以恢复到不同时间点的版本,很适合备份,并且此文件格式也支持有不少第三方工具可以进行后续的数据分析。比如: 可以在最近的24小时内,每小时备份一次RDB文件,并且在每个月的每一天,也备份一个RDB文件。这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。
1.1.2.RDB可以最大化Redis的性能,父进程在保存 RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘工/0操作。
1.1.3.RDB在大量数据,比如几个G的数据,恢复的速度比AOF的快
1.2.RDB 模式缺点
1.2.1.不能实时保存数据,可能会丢失自上一次执行RDB备份到当前的内存数据
如果你需要尽量避免在服务器故障时丢失数据,那么RDB不适合你。虽然Redis允许你设置不同的保存点(save point)来控制保存RDB文件的频率,但是,因为RDB文件需要保存整个数据集的状态,所以它并不是一个轻松快速的操作。因此一般会超过5分钟以上才保存一次RDB文件。在这种情况下,一旦发生故障停机,你就可能会丢失好几分钟的数据。
1.2.2.当数据量非常大的时候,从父进程fork子进程进行保存至RDB文件时需要一点时间,可能是毫秒或者秒,取决于磁盘IO性能
1.2.3.在数据集比较庞大时,fork()可能会非常耗时,造成服务器在一定时间内停止处理客户端﹔如果数据集非常巨大,并且CPU时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒或更久。虽然 AOF重写也需要进行fork(),但无论AOF重写的执行间隔有多长,数据的持久性都不会有任何损失
2.AOF模式优缺点
2.1.AOF 模式优点
2.1.1.数据安全性相对较高,根据所使用的fsync策略(fsync是同步内存中redis所有已经修改的文件到存储设备),默认是appendfsync everysec,即每秒执行一次 fsync,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync会在后台线程执行,所以主线程可以继续努力地处理命令请求)
2.1.2.由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中不需要seek, 即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,可以通过 redis-check-aof 工具来解决数据一致性的问题
2.1.3.Redis可以在 AOF文件体积变得过大时,自动地在后台对AOF进行重写,重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。整个重写操作是绝对安全的,因为Redis在创建新 AOF文件的过程中,append模式不断的将修改数据追加到现有的 AOF文件里面,即使重写过程中发生停机,现有的 AOF文件也不会丢失。而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始新AOF文件进行追加操作。
2.1.4.AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,也可以通过该文件完成数据的重建AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此 AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。导出(export)AOF文件。也非常简单:举个例子,如果不小心执行了FLUSHALL.命令,但只要AOF文件未被重写,那么只要停止服务器,移除 AOF文件末尾的FLUSHAL命令,并重启Redis ,就可以将数据集恢复到FLUSHALL执行之前的状态。
2.2.AOF 模式缺点
2.2.1.即使有些操作是重复的也会全部记录,AOF 的文件大小要大于 RDB 格式的文件
2.2.2.AOF 在恢复大数据集时的速度比 RDB 的恢复速度要慢
2.2.3.根据fsync策略不同,AOF速度可能会慢于RDB
2.2.4.bug 出现的可能性更多
3.RDB和AOF 的选择
3.1.如果主要充当缓存功能,或者可以承受数分钟数据的丢失, 通常生产环境一般只需启用RDB即可,此也是默认值
3.2.如果数据需要持久保存,一点不能丢失,可以选择同时开启RDB和AOF。一般不建议只开启AOF
5、实现redis哨兵,模拟master故障场景
1.概述
在哨兵(sentinel)机制中,可以解决redis高可用问题,即当master故障后可以自动将slave提升为master,从而可以保证redis服务的正常使用。
2.哨兵的实现
哨兵的前提是已经实现了一个redis的主从复制的运行环境,从而实现一个一主两从基于哨兵的高可用redis架构。注意: master 的配置文件中masterauth 和slave 都必须相同
sentinel master 10.0.0.150
sentinel slave1 10.0.0.160
sentinel slave2 10.0.0.170
2.1.哨兵的准备实现主从复制架构
2.1.1.所有主从节点的redis.conf中关健配置
[root@centos8 ~]#dnf -y install redis
[root@centos8 ~]#sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e 's/^# masterauth .*/masterauth 123456/' -e 's/^# requirepass .*/requirepass 123456/' /etc/redis.conf
2.1.2.所有从节点上
[root@centos8 ~]#echo "replicaof 10.0.0.150 6379" >> /etc/redis.conf
2.1.3.在所有主从节点执行
[root@centos8 ~]#systemctl enable --now redis
2.1.4.查看master服务器状态
[root@centos8 ~]#redis-cli -a 123456 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.160,port=6379,state=online,offset=84,lag=0
slave1:ip=10.0.0.170,port=6379,state=online,offset=84,lag=0
master_replid:a2491766a22c952f10cbdc8f4566d82c0ec87a7b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84
2.2.配置哨兵
Sentinel实际上是一个特殊的redis服务器,有些redis指令支持,但很多指令并不支持.默认监听在26379/tcp端口.哨兵可以不和Redis服务器部署在一起,但一般部署在一起,所有redis节点使用相同的配置文件。
2.2.1.编辑哨兵的配置文件
#如果是编译安装,在源码目录有sentinel.conf,复制到安装目录即可,如:/apps/redis/etc/sentinel.conf
所有哨兵服务器上配置
[root@centos8 ~]#vim /etc/redis-sentinel.conf
bind 0.0.0.0
port 26379
daemonize yes
pidfile "redis-sentinel.pid"
logfile ""
dir "/tmp"
#工作目录
sentinel monitor mymaster 10.0.0.8 6379 2
#指定当前mymaster集群中master服务器的地址和端口
#2为法定人数限制(quorum),即有几个sentinel认为master down了就进行故障转移,一般此值是所有sentinel节点(一般总数是>=3的 奇数,如:3,5,7等)的一半以上的整数值,比如,总数是3,3/2=1.5,取整为2,是master的ODOWN客观下线的依据
sentinel auth-pass mymaster 123456
#mymaster集群中master的密码,注意此行要在上面行的下面
sentinel down-after-milliseconds mymaster 30000
#(SDOWN)判断mymaster集群中所有节点的主观下线的时间,单位:毫秒,建议3000
sentinel parallel-syncs mymaster 1
#发生故障转移后,同时向新master同步数据的slave数量,数字越小总同步时间越长,但可以减轻新master的负载压力
sentinel failover-timeout mymaster 180000
#所有slaves指向新的master所需的超时时间,单位:毫秒
sentinel deny-scripts-reconfig yes
#禁止修改脚本
logfile /var/log/redis/sentinel.log
2.2.2.三台机器上启动哨兵服务
[root@centos8 ~]systemctl enable --now redis-sentinel.service
2.2.3.查看配置文件,确定myid不一样
[root@centos8 ~]#cat /etc/redis-sentinel.conf |grep myid
sentinel myid 6b318eb64c0e2f5c97a4a9120f38b9be4ba07dc7
[root@centos8 ~]#cat /etc/redis-sentinel.conf |grep myid
sentinel myid 7714ef6638d3caa3b9a1e89f81315ea584e3550f
[root@centos8 ~]#cat /etc/redis-sentinel.conf |grep myid
sentinel myid 107800d9f386633fbc5b25165ae3d076c52053aa
2.2.4.验证端口
[root@centos8 ~]#ss -ntl |grep 26379
LISTEN 0 128 0.0.0.0:26379 0.0.0.0:*
2.2.5.查看日志
[root@centos8 ~]#cat /var/log/redis/sentinel.log
32728:X 20 Jan 2022 18:08:31.874 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
32728:X 20 Jan 2022 18:08:31.874 # Redis version=5.0.3, bits=64, commit=00000000, modified=0, pid=32728, just started
32728:X 20 Jan 2022 18:08:31.874 # Configuration loaded
32728:X 20 Jan 2022 18:08:31.874 * supervised by systemd, will signal readiness
32728:X 20 Jan 2022 18:08:31.875 * Running mode=sentinel, port=26379.
32728:X 20 Jan 2022 18:08:31.875 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
32728:X 20 Jan 2022 18:08:31.876 # Sentinel ID is 6b318eb64c0e2f5c97a4a9120f38b9be4ba07dc7
32728:X 20 Jan 2022 18:08:31.876 # +monitor master mymaster 10.0.0.150 6379 quorum 2
32728:X 20 Jan 2022 18:08:31.876 * +slave slave 10.0.0.160:6379 10.0.0.160 6379 @ mymaster 10.0.0.150 6379
32728:X 20 Jan 2022 18:08:31.877 * +slave slave 10.0.0.170:6379 10.0.0.170 6379 @ mymaster 10.0.0.150 6379
32728:X 20 Jan 2022 18:12:12.831 * +sentinel sentinel 7714ef6638d3caa3b9a1e89f81315ea584e3550f 10.0.0.160 26379 @ mymaster 10.0.0.150 6379
32728:X 20 Jan 2022 18:12:41.172 * +sentinel sentinel 107800d9f386633fbc5b25165ae3d076c52053aa 10.0.0.170 26379 @ mymaster 10.0.0.150 6379
2.2.6.查看当前sentinel状态
[root@centos8 ~]#redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=10.0.0.150:6379,slaves=2,sentinels=3
3.模拟master故障
3.1.停止Redis Master测试故障转移。在10.0.0.150上执行
[root@centos8 ~]#killall redis-server
3.2.查看哨兵信息,已自动切换到10.0.0.160为主节点
[root@centos8 ~]#redis-cli -a 123456 -p 26379 info sentinel
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=10.0.0.160:6379,slaves=2,sentinels=3
3.3.故障转移时sentinel的信息
[root@centos8 ~]#cat /var/log/redis/sentinel.log
930:X 20 Jan 2022 18:39:36.834 # +sdown master mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:36.908 # +odown master mymaster 10.0.0.150 6379 #quorum 2/2
930:X 20 Jan 2022 18:39:36.908 # +new-epoch 3
930:X 20 Jan 2022 18:39:36.908 # +try-failover master mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:36.910 # +vote-for-leader 6b318eb64c0e2f5c97a4a9120f38b9be4ba07dc7 3
930:X 20 Jan 2022 18:39:36.913 # 7714ef6638d3caa3b9a1e89f81315ea584e3550f voted for 6b318eb64c0e2f5c97a4a9120f38b9be4ba07dc7 3
930:X 20 Jan 2022 18:39:36.913 # 107800d9f386633fbc5b25165ae3d076c52053aa voted for 6b318eb64c0e2f5c97a4a9120f38b9be4ba07dc7 3
930:X 20 Jan 2022 18:39:37.002 # +elected-leader master mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:37.002 # +failover-state-select-slave master mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:37.061 # +selected-slave slave 10.0.0.160:6379 10.0.0.160 6379 @ mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:37.061 * +failover-state-send-slaveof-noone slave 10.0.0.160:6379 10.0.0.160 6379 @ mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:37.147 * +failover-state-wait-promotion slave 10.0.0.160:6379 10.0.0.160 6379 @ mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:37.252 # +promoted-slave slave 10.0.0.160:6379 10.0.0.160 6379 @ mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:37.252 # +failover-state-reconf-slaves master mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:37.327 * +slave-reconf-sent slave 10.0.0.170:6379 10.0.0.170 6379 @ mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:37.876 * +slave-reconf-inprog slave 10.0.0.170:6379 10.0.0.170 6379 @ mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:37.983 # -odown master mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:38.917 * +slave-reconf-done slave 10.0.0.170:6379 10.0.0.170 6379 @ mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:39.017 # +failover-end master mymaster 10.0.0.150 6379
930:X 20 Jan 2022 18:39:39.017 # +switch-master mymaster 10.0.0.150 6379 10.0.0.160 6379
930:X 20 Jan 2022 18:39:39.017 * +slave slave 10.0.0.170:6379 10.0.0.170 6379 @ mymaster 10.0.0.160 6379
930:X 20 Jan 2022 18:39:39.017 * +slave slave 10.0.0.150:6379 10.0.0.150 6379 @ mymaster 10.0.0.160 6379
930:X 20 Jan 2022 18:40:09.089 # +sdown slave 10.0.0.150:6379 10.0.0.150 6379 @ mymaster 10.0.0.160 6379
3.4.故障转移后的redis配置文件会被自动修改,在10.0.0.170上查询
root@centos8 ~]#grep ^replicaof /etc/redis.conf
replicaof 10.0.0.160 6379
3.5.哨兵配置文件的sentinel monitor IP 同样也会被修改
[root@centos8 ~]#cat /etc/redis-sentinel.conf |grep -v ^# |grep monitor
sentinel monitor mymaster 10.0.0.160 6379 2
3.6.当前redis的状态为160节点为主,170节点为从
[root@centos8 ~]#redis-cli -a 123456 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.170,port=6379,state=online,offset=486781,lag=1
master_replid:433ef00d3756763aa600b3630775ee4f90cff41a
master_replid2:4a53d9f341ddfb8d32ec934d812f2b63f56d68e9
master_repl_offset:487051
second_repl_offset:325790
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:305377
repl_backlog_histlen:181675
3.7.恢复故障的原master重新加入redis集群,作为从节点
[root@centos8 ~]#systemctl restart redis
[root@centos8 ~]#cat /etc/redis.conf |grep replicaof
# Master-Replica replication. Use replicaof to make a Redis instance a copy of
# replicaof <masterip> <masterport>
replicaof 10.0.0.160 6379
4.sentinel 运维
手动让主节点下线
sentinel failover <masterName>
范例: 手动故障转移
[root@centos8 ~]#vim /etc/redis.conf
replica-priority 10 #指定优先级,值越小sentinel会优先将之选为新的master,默为值为100
[root@centos8 ~]#redis-cli -p 26379
127.0.0.1:26379> sentinel failover mymaster
OK