本质就是一段Java程序
-
应用独立配置,例如单独配置应用日志、单独配置应用访问控制
注意:这里特别使用了软链接,原因就是以后版本升级,需要将软链接指向myappv2,重启Tomcat。
如果新版上线后,出现问题,重新修改软链接到上一个版本的目录,并重启,就可以实现回滚。
测试,可以看到轮询调度效果。
配置完reload nginx服务。测试一下看看效果。关闭Session对应的Tomcat服务,再重启启动它,看看Session的变化。
关闭httpd默认主机
loadfactor设置为1:2,便于观察。观察调度的结果是轮询的
发现Session不变了,一直找的同一个Tomcat服务器。
-
虽然,上面的做法实现客户端在一段时间内找同一台Tomcat,从而避免切换后导致的Session丢失。但是如果Tomcat节点挂掉,那么Session依旧丢失。
memcached的节点们;n1、n2只是别名,可以重新命名。
failoverNodes故障转移节点,n1是备用节点,n2是主存储节点。另一台Tomcat将n1改为n2,其主节点是n1,备用节点是n2。
配置成功后,网页访问以下,页面中看到了Session。然后运行下面的Python程序,就可以看到是否存储到了memcached中了。
t1、t2、n1、n2依次启动成功,分别使用 和 观察。
看起负载均衡调度器,通过来访问看看效果
可以看到浏览器端被调度到不同Tomcat上,但是都获得了同样的SessionID。
停止t2、n2看看效果,恢复看看效果。
- 通过多组实验,使用不同技术实现了session持久机制
-
对负载均衡影响小。但一旦后端服务器有故障,其上的session丢失。
- session复制集群,基于tomcat实现多个服务器内共享同步所有session。此方法可以保证任意一
台后端服务器故障,其余各服务器上还都存有全部session,对业务无影响。但是它基于多播实现
心跳,TCP单播实现复制,当设备节点过多,这种复制机制不是很好的解决方案。且并发连接多的
时候,单机上的所有session占据的内存空间非常巨大,甚至耗尽内存。 - session服务器,将所有的session存储到一个共享的内存空间中,使用多个冗余节点保存
session,这样做到session存储服务器的高可用,且占据业务服务器内存较小。是一种比较好的解
决session持久的解决方案。
-
以上的方法都有其适用性。生产环境中,应根据实际需要合理选择。
不过以上这些方法都是在内存中实现了session的保持,可以使用数据库或者文件系统,把session数据存储起来,持久化。这样服务器重启后,也可以重新恢复session数据。不过session数据是有时效性的,是否需要这样做,视情况而定。
Java目前是最流行的编程语言。
目前主要应用在企业级WEB开发和大数据领域。
class loader类加载器:将所需的类加载到内存,必要时将类实例化成实例。
图中中间部分是进程的内存逻辑结构,称为Jvm运行时区域,由下面几部分构成:
方法区:所有线程共享的内存空间,存放已加载的类信息、常量和静态变量。
heap堆:所有线程共享的内存空间,存放创建的所有对象。堆是靠GC垃圾回收器管理的。
Java栈:每个线程会分配一个栈,存放线程用的本地变量、方法参数和返回值等。
PC寄存器:PC, 即Program Counter,每一个线程用于记录当前线程正在执行的字节码指令地址。因为线程需要切换,当一个线程被切换回来需要执行的时候,知道执行到哪里了。
本地方法栈:为本地方法执行构建的内存空间,存放本地方法执行时的局部变量、操作数等。
所谓本地方法,简单的说是非Java实现的方法,例如操作系统的C编写的库提供的本地方法,Java调用这些本地方法接口执行。但是要注意,本地方法应该避免直接编程使用,因为Java可能跨平台使用,如果用了Windows API,换到了Linux平台部署就有了问题。
目前Oracle官方使用的是HotSpot, 它最早由一家名为"Longview Technologies"公司设计,使用了很 多优秀的设计理念和出色的性能,1997年该公司被SUN公司收购。后来随着JDK一起发布了HotSpot VM。目前HotSpot是最主要的VM。
安卓程序需要运行在JVM上,而安卓平台使用了Google自研的Java虚拟机——Dalvid,适合于内存、处 理器能力有限系统。
堆内存里面经常创建、销毁对象,内存也是被使用、被释放。如果不妥善处理,一个使用频繁的进程, 将可能有内存容量,但是无法分配出可用内存空间,因为没有连续成片的内存了,内存全是碎片化的数 据。
-
每一个堆内对象上都与一个私有引用计数器,记录着被引用的次数,引用计数清零,该对象所占用
堆内存就可以被回收。循环引用的对象都无法引用计数归零,就无法清除。 分垃圾标记阶段和内存释放阶段。标记阶段,找到所有可访问对象打个标记。清理阶段,遍历整个
先将可用内存分为大小相同两块区域A和B,每次只用其中一块,比如A。当A用完后,则将A中存活的对象复制到B。复制到B的时候连续的使用内存,最后将A一次性清除干净。缺点是比较浪费内存,能使用原来一半的内存,因为内存对半划分了,复制过程毕竟也是有代价。好处是没有碎片,复制过程中保证对象使用连续空间。 分垃圾标记阶段和内存整理阶段。标记阶段,找到所有可访问对象打个标记。内存清理阶段时,整理时将对象向内存一端移动,整理后存活对象连续的集中在内存一端。 既然上述垃圾回收算法都有优缺点,能不能对不同数据进行区分管理,不同分区对数据实施不同回收策略,分而治之。
1.7及以前,堆内存分为新生代、老年代、持久代。
1.8开始,持久代没有了,取而代之MetaSpace。
对于大多数垃圾回收算法而言,GC线程工作时,需要停止所有工作的线程,称为Stop The World。GC完成时,恢复其他工作线程运行。这也是JVM运行中最头疼的问题。
- 新生代:刚刚创建的对象
存活区Servivor Space:有2个存活区,一个是from区,一个是to区。它们大小相等、地位相同、可互换。 - to指的是本次复制数据的目标区
- 老年代:长时间存活的对象
- 持久代:JVM的类和方法
起始时,所有新建对象都出生在eden,当eden满了,启动GC。这个称为Young GC,Minor GC。
先标记eden存活对象,然后将存活对象复制到s0(假设本次是s0,也可以是s1,它们可以调换),eden剩余所有空间都“清空”。GC完成。
继续新建对象,当eden满了,启动GC。
先标记eden和s0中存活对象,然后将存活对象复制到s1。将eden和s0“清空”。
继续新建对象,当eden满了,启动GC。
先标记eden和s1中存活对象,然后将存活对象复制到s0。将eden和s1“清空”。
以后就重复上面的步骤。
大多数对象都不会存活很久,而且创建活动非常多,新生代就需要频繁垃圾回收。
但是,如果一个对象一直存活,它最后就在from、to来回复制,如果from区中对象复制次数达到阈值,就直接复制到老年代。
进入老年代的数据较少,所以老年代区被占满的速度较慢,所以垃圾回收也不频繁。老年代GC称为OldGC,Major GC。
由于老年代对象一般来说存活次数较长,所有较常采用标记-压缩算法。
Full GC:对所有“代”的内存进行垃圾回收Minor GC比较频繁,Major GC较少。但一般Major GC时,由于老年代对象也可以引用新生代对象,所以先进行一次Minor GC,然后在Major GC会提高效率。可以认为回收老年代的时候完成了一次Full
- 新生代搬向老年代,老年代空间不够
减少STW时长,串行变并行
减少GC次数,要分配合适的内存大小
对JVM调整策略应用极广
- 在大数据领域Hadoop生态各组件
- 在消息中间件领域的Kafka等
在不同领域对JVM需要不同的调整策略
- 串行垃圾回收器:一个GC线程完成回收工作
- 并行垃圾回收器:多个GC线程同时一起完成回收工作,充分利用CPU资源
指的是GC线程是否串并行
- 并发垃圾回收器:让GC线程垃圾回收某些阶段可以和工作线程一起进行。
- 独占垃圾回收器:只有GC在工作,STW一直进行到回收完毕,工作线程才能继续执行。
指的是GC线程和工作线程是否一起运行
一般情况下,我们大概可以使用以下原则:
客户端或较小程序,内存使用量不大,可以使用串行回收;
对于服务端大型计算,可以使用并行回收;
大型WEB应用,用户端不愿意等,尽量少的STW,可以使用并发回收;
设置应用程序初始使用的堆内存大小(新生代+老 年代) |
设置应用程序能获得的最大堆内存 早期JVM不建议超过32G,内存管理效率下降 |
设置最大新生代内存空间 |
以比例方式设置新生代和老年代 |
默认不指定,-Xmx大约使用了1/4的内存,当前本机内存指定约为1G。
-server:VM运行在server模式,为在服务器端最大化程序运行速度而优化
-client:VM运行在Client模式,为客户端环境减少启动时间而优化
- 新生代串行收集器:单线程、独占式串行,回收算法标记-复制
- 新生代并行收集器:将单线程的串行收集器变成了多线程并行、独占式
- 新生代并行回收收集器:多线程并行、独占式,使用复制算法,关注调整吞吐量
- 老年代串行收集器:单线程、独占式串行,回收算法使用标记-压缩
- 老年代并行回收收集器:多线程、独占式并行,回收算法使用标记-压缩,关注调整吞吐量
- 在某些阶段尽量使用和工作线程一起运行,减少停顿时长。是互联网站点服务端BS系统上较 佳的回收算法
- 分为4个阶段:初始标记、并发标记、重新标记、并发清除,在初始标记、重新标记时需要 STW。
- Garbage First是最新垃圾回收器,从JDK1.6实验性提供,JDK1.7发布,其设计目标是在多处理器、大内存服务器端提供优于CMS收集器的吞吐量和停顿控制的回收器。建议JDK8再考虑它。
- 分为4个阶段:初始标记、并发标记、最终标记、筛选回收。并发标记并发执行,其它阶段STW只有GC线程并行执行。
可以单独指定新生代、老年代的垃圾收集器
-
新生代使用 并行收集器 ,老年代使用 串行收集器
-
新生代使用 并行回收收集器 ,老年代使用 串行收集器
-
- 新生代使用 并行收集器 ,老年代使用 CMS收集器
- 响应时间要短,停顿短使用这个垃圾收集器
-
以上调试完成后,请移除这些参数,否则有非常多的日志输出
查看进程的运行环境参数,主要是jvm命令行参数 |
对jvm应用程序的资源和性能进行实时监控 |
查看所有线程的运行状态 |
查看jvm占用物理内存的状态 |
jinfo:输出给定的java进程的所有配置信息;
jstat:输出指定的java进程的统计信息
interval:时间间隔,单位是毫秒;
count:显示的次数;
YGC:新生代的垃圾回收次数;
YGCT:新生代垃圾回收消耗的时长;
GCT:GC消耗的总时长;
程序员常用堆栈情况查看工具
jstack:查看指定的java进程的线程栈的相关信息;
-l:long listings,会显示额外的锁信息,因此,发生死锁时常用此选项;
-m:混合模式,既输出java堆栈信息,也输出C/C++堆栈信息;
-F:当使用“jstack -l PID"无响应,可以使用-F强制输出信息;
查看堆空间的详细信息:
查看堆内存中的对象的数目:
live:只统计活动对象;
保存堆内存数据至文件中,而后使用jvisualvm或jhat进行查看:
-Xms:堆内存初始化大小; -Xmx:堆内存空间上限;
- acceptCount:当启动线程满了之后,等待队列的最大长度,默认100;
- enableLookups:是否启用客户端主机名的DNS反向解析,缺省禁用,建议禁用,就使用客户端IP就行;
- compression:是否启用传输压缩机制,建议“on",CPU和流量的平衡;
- compressionMinSize:启用压缩传输的数据流最小值,单位是字节;