linux
1.实现Tomcat多虚拟主机
[11:12:14root@ubuntu ~]# vim /usr/local/tomcat/conf/server.xml
<Host name="www.luomu.org" appBase="/data/webapps/" unpackWARs="True" autoDeploy="false">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="luomu_access_log"
suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />
</Host>
##添加上多虚拟主机的配置
#每个<Host>元素定义了一个虚拟主机。
#需要根据实际需求配置name(虚拟主机名称)、appBase(应用程序的基本目录)、Alias(主机别名,可选)等属性
#创建虚拟主机目录
mkdir /data/webapps/ROOT -pv
chown -R tomcat.tomcat /data/webapps
echo www.luomu.org > /data/webapps/ROOT/index.html
[11:16:47root@ubuntu ~]# systemctl restart tomcat
#重启服务查看
2.定制tomcat的日志格式和反向代理tomcat
2.1定制tomcat的日志格式
通过编辑 Tomcat 的配置文件 server.xml 来配置访问日志的格式
[11:12:14root@ubuntu ~]# vim /usr/local/tomcat/conf/server.xml
#编辑 <Host> 元素配置里面的Valve
<Host name="www.luomu.org" appBase="/data/webapps/" unpackWARs="True" autoDeploy="false">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="luomu_access_log"
suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />
#directory: 指定日志文件存储的目录
#prefix: 日志文件名的前缀
#suffix: 日志文件名的后缀
#pattern: 定义访问日志的格式,可以使用预定义的格式串,也可以自定义组合
常用的日志格式串:
#%h: 远程主机名或 IP 地址
#%l: 远程登录名,如果不能获取则为 -
#%u: 认证用户名,如果没有认证则为 -
#%t: 请求的时间,使用 Common Log Format 格式(例如 [21/Apr/2024:10:30:31 +0800])
#"%r": 客户端发送的请求信息
#%s: HTTP 响应状态码
#%b: HTTP 响应的字节数
#%D: 表示请求处理时间(以毫秒为单位)
#" : 表示双引号
2.2反向代理tomcat
使用nginx反向代理到tomcat
[11:30:33root@localhost ~]# yum -y install nginx
[11:37:27root@localhost ~]# vim /etc/nginx/conf.d/tomcat.conf
server {
listen 80;
server_name www.luomu.org;
location / {
proxy_pass http://10.0.0.20:8080;
}
}
#启动nginx
[11:37:39root@localhost ~]# systemctl start nginx
3.tomcat 实现MSM集群
主机准备:
IP | 服务 | 软件 |
---|---|---|
10.0.0.8 | 调度器 | nginx |
10.0.0.20 | tomcat1 | tomcat9 |
10.0.0.22 | tomcat2 | tomcat9 |
10.0.0.28 | memcached1 | memcached |
10.0.0.38 | memcached2 | memcached |
3.1nginx主机
[12:52:24root@localhost ~]# yum -y install nginx
[17:46:14root@localhost ~]# cat /etc/nginx/conf.d/tomcat.conf
upstream tomcat-server {
server t1.luomu.org:8080;
server t2.luomu.org:8080;
}
server {
listen 80;
server_name proxy.wang.org;
location / {
proxy_pass http://tomcat-server;
}
}
#配置反向代理
[17:46:47root@localhost ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
10.0.0.8 proxy.wang.org
10.0.0.20 t1.luomu.org
10.0.0.22 t2.luomu.org
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
#配置域名解析
3.2memcached
[12:36:20root@localhost ~]# yum -y install memcached
[17:48:30root@localhost ~]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 0.0.0.0,::1"
##两个主机相同配置
3.3 tomcat
t1
[13:28:07root@ubuntu ~]# vim /usr/local/tomcat/conf/server.xml
<Engine name="Catalina" defaultHost="t1.luomu.org" jvmRoute="Tomcat1">
<Host name="t1.luomu.org" appBase="/data/webapps/" unpackWARs="True" autoDeploy="false">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="luomu_access_log"
suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />
</Host>
[17:51:14root@ubuntu ~]# vim /usr/local/tomcat/conf/context.xml
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:10.0.0.28:11211,n2:10.0.0.38:11211"
sticky="false"
sessionBackupAsync="false"
lockingMode="uriPattern:/path1|/path2"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
</Context>
[17:52:19root@ubuntu ~]# ls /usr/local/tomcat/lib/ -t |tail
kryo-3.0.3.jar
asm-5.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
minlog-1.3.1.jar
kryo-serializers-0.45.jar
msm-kryo-serializer-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
spymemcached-2.12.3.jar
memcached-session-manager-2.3.2.jar
#传入相关包
[13:28:53root@ubuntu ~]# cat /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tomcat test</title>
</head>
<body>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>
t2
[13:28:07root@ubuntu ~]# vim /usr/local/tomcat/conf/server.xml
<Engine name="Catalina" defaultHost="t2.luomu.org" jvmRoute="Tomcat2">
<Host name="t2.luomu.org" appBase="/data/webapps/" unpackWARs="True" autoDeploy="false">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="luomu_access_log"
suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />
</Host>
[17:51:14root@ubuntu ~]# vim /usr/local/tomcat/conf/context.xml
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:10.0.0.28:11211,n2:10.0.0.38:11211"
sticky="false"
sessionBackupAsync="false"
lockingMode="uriPattern:/path1|/path2"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
</Context>
[17:52:19root@ubuntu ~]# ls /usr/local/tomcat/lib/ -t |tail
kryo-3.0.3.jar
asm-5.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
minlog-1.3.1.jar
kryo-serializers-0.45.jar
msm-kryo-serializer-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
spymemcached-2.12.3.jar
memcached-session-manager-2.3.2.jar
#传入相关包
[13:28:53root@ubuntu ~]# cat /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tomcat test</title>
</head>
<body>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>
3.4测试访问
4.JVM垃圾回收算法和分代
Java 虚拟机(JVM)的垃圾回收(Garbage Collection,GC)是 Java 内存管理的核心部分,它负责自动回收不再被引用的对象,释放其占用的内存空间。为了提高垃圾回收的效率,JVM 使用了不同的垃圾回收算法和分代策略
4.1垃圾回收算法
1,标记-清除(Mark and Sweep):
- 标记阶段:从根对象出发,标记所有可达对象
- 清除阶段:清除未标记(不可达)的对象,并回收其内存
- 缺点:会产生内存碎片,不利于分配大对象
2.复制(Copying): - 将堆内存分为两块,每次只使用其中一块
- 在垃圾回收时,将存活对象复制到另一块空间,然后清除当前空间中的所有对象
- 适用于新生代,例如年轻代的垃圾回收
3.标记-压缩(Mark and Compact): - 标记阶段和标记-清除类似,但在清除阶段会将存活对象向一端移动,整理内存。 解决了标记-清除可能产生的内存碎片问题
- 增量式垃圾回收(Incremental Garbage Collection)
- 将整个垃圾回收过程分解成多个小步骤,交替执行
- 在执行垃圾回收的同时,允许应用程序继续运行
4.2分代策略
- JVM 将堆内存分为不同的代(Generations),通常包括新生代(Young Generation)、老年代(OldGeneration)和永久代(Permanent Generation,JDK 8 后被元空间(Metaspace)取代)
1.新生代(Young Generation):
- 包括 Eden 区和两个 Survivor 区
- 大多数新创建的对象首先分配在 Eden 区
- Minor GC 针对新生代进行,通常使用复制算法(如标记-复制)
2.老年代(Old Generation): - 存放生命周期较长的对象
- Major GC 或 Full GC 针对老年代进行,通常使用标记-清除或标记-整理算法
3.永久代 / 元空间(PermGen / Metaspace): - 存放类信息、方法信息等元数据
- JDK 8 及以后版本使用元空间代替永久代,存储在本地内存中
4.3垃圾回收器(Garbage Collectors)
Serial 收集器:单线程执行,适用于小型或客户端应用
Parallel 收集器:多线程执行,适用于多核服务器
CMS(Concurrent Mark Sweep)收集器:并发执行,减少停顿时间
G1(Garbage-First)收集器:分区整理,更好地控制停顿时间和吞吐量
4.3优化tomcat
[17:54:51root@ubuntu ~]# vim /usr/local/tomcat/bin/catalina.sh
JAVA_OPTS="-server -Xmx512m -Xms128m -XX:NewSize=48m -XX:MaxNewSize=200m - XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection - XX:CMSFullGCsBeforeCompaction=5"
1.-server:
- 指示 JVM 使用服务器模式,优化性能和吞吐量,适用于长时间运行的应用程序
2.-Xmx512m:
- 设置 JVM 最大堆内存大小为 512 MB
- 这表示 Java 应用程序运行时堆内存的最大可用空间
3.-Xms128m: - 设置 JVM 初始堆内存大小为 128 MB
- JVM 在启动时将分配此大小的堆内存
4.-XX:NewSize=48m: - 设置 JVM 新生代(Young Generation)的初始大小为 48 MB
5,-XX:MaxNewSize=200m:
- 设置 JVM 新生代的最大大小为 200 MB
- 新生代会根据应用程序的需求动态调整在此范围内
6.-XX:+UseConcMarkSweepGC: - 启用并发标记-清除(CMS)垃圾回收器
- CMS GC 是一种低停顿时间的垃圾回收器,适用于减少 Full GC 的停顿时间
7.-XX:+UseCMSCompactAtFullCollection: - 在进行 Full GC 时对老年代执行压缩
- 在 CMS 垃圾回收过程中,当老年代空间碎片化严重时执行压缩操作
8.-XX:CMSFullGCsBeforeCompaction=5: - 设置在进行 Full GC 前进行多少次 CMS 垃圾回收
- 指定执行多少次 CMS GC 后进行一次 Full GC,并在 Full GC 后进行老年代的压缩
5.总结memcache使用,安装和MSM原理
5.1memcache使用
常见参数
- -u username memcached运行的用户身份,必须普通用户
- -p 绑定的端口,默认11211
- -m num 最大内存,单位MB,默认64MB
- -c num 最大连接数,缺省1024
- -d 守护进程方式运行
- -f 增长因子Growth Factor,默认1.25
- -v 详细信息,-vv能看到详细信息
- -M 使用内存直到耗尽,不许LRU
- -U 设置UDP监听端口,0表示禁用UDP
#安装拓展包
18:25:01root@ubuntu ~]# apt install memstat
[18:25:01root@ubuntu ~]# apt -y install libmemcached-tools
[18:24:59root@ubuntu ~]# memcstat --servers=10.0.0.28
Server: 10.0.0.28 (11211)
pid: 4022
uptime: 21059
time: 1713695098
version: 1.5.22
libevent: 2.1.8-stable
pointer_size: 64
rusage_user: 2.286217
rusage_system: 2.075456
max_connections: 1024
curr_connections: 10
total_connections: 19
rejected_connections: 0
connection_structures: 11
reserved_fds: 20
cmd_get: 250
cmd_set: 282
cmd_flush: 0
cmd_touch: 0
cmd_meta: 0
get_hits: 196
get_misses: 54
get_expired: 0
get_flushed: 0
delete_misses: 0
delete_hits: 0
incr_misses: 0
incr_hits: 0
decr_misses: 0
decr_hits: 0
cas_misses: 0
cas_hits: 0
cas_badval: 0
touch_hits: 0
touch_misses: 0
auth_cmds: 0
auth_errors: 0
bytes_read: 31021
bytes_written: 26366
limit_maxbytes: 67108864
accepting_conns: 1
listen_disabled_num: 0
time_in_listen_disabled_us: 0
threads: 4
conn_yields: 0
hash_power_level: 16
hash_bytes: 524288
hash_is_expanding: 0
slab_reassign_rescues: 0
slab_reassign_chunk_rescues: 0
slab_reassign_evictions_nomem: 0
slab_reassign_inline_reclaim: 0
slab_reassign_busy_items: 0
slab_reassign_busy_deletes: 0
slab_reassign_running: 0
slabs_moved: 0
lru_crawler_running: 0
lru_crawler_starts: 6636
lru_maintainer_juggles: 76947
malloc_fails: 0
log_worker_dropped: 0
log_worker_written: 0
log_watcher_skipped: 0
log_watcher_sent: 0
bytes: 668
curr_items: 4
total_items: 146
slab_global_page_pool: 0
expired_unfetched: 4
evicted_unfetched: 0
evicted_active: 0
evictions: 0
reclaimed: 6
crawler_reclaimed: 0
crawler_items_checked: 35
lrutail_reflocked: 71
moves_to_cold: 215
moves_to_warm: 84
moves_within_lru: 7
direct_reclaims: 0
lru_bumps_dropped: 0
Server:
Memcached 服务器的 IP 地址和端口号
pid:
Memcached 进程的 PID(进程标识符)
uptime:
Memcached 服务器已运行的秒数
time:
服务器当前时间戳(Unix 时间)
version:
Memcached 版本号
libevent:
使用的 libevent 版本
pointer_size:
指针大小,通常为 64 位
rusage_user:
用户 CPU 时间(秒)
rusage_system:
系统 CPU 时间(秒)
max_connections:
允许的最大连接数
curr_connections:
当前打开的连接数
total_connections:
服务器启动以来已接受的连接总数
rejected_connections:
拒绝的连接数
connection_structures:
当前连接结构的数量
reserved_fds:
保留的文件描述符数量
cmd_get:
执行的 GET 命令总数
cmd_set:
执行的 SET 命令总数
cmd_flush:
执行的 FLUSH 命令总数
cmd_touch:
执行的 TOUCH 命令总数
cmd_meta:
执行的 META 命令总数
get_hits:
GET 命令中缓存命中的次数
get_misses:
GET 命令中缓存未命中的次数
get_expired:
GET 命令中缓存过期但未被获取的次数
get_flushed:
GET 命令中因 FLUSH 被清除的次数
delete_misses:
DELETE 命令中未找到键的次数
delete_hits:
DELETE 命令中找到并删除键的次数
incr_misses/decr_misses:
INCR/DECR 命令中未找到键的次数
incr_hits/decr_hits:
INCR/DECR 命令中找到并增加/减少键的次数
cas_misses/cas_hits/cas_badval:
CAS 命令中未找到键、找到并更新键、更新值不匹配的次数
touch_hits/touch_misses:
TOUCH 命令中找到/未找到键的次数
auth_cmds/auth_errors:
认证命令的总数和错误数
bytes_read/bytes_written:
从客户端读取/向客户端写入的字节数
limit_maxbytes:
设置的最大内存限制
accepting_conns:
是否接受新连接的标志(1 表示接受,0 表示不接受)
listen_disabled_num:
服务器因超出最大连接数而拒绝的连接数
threads:
当前线程数
其他字段:
包括各种统计信息,如内存使用、缓存命中率、LRU(最近最少使用)算法相关信息等
5.2MSM 原理
MSM(Memcached Session Manager)是一个用于将 Java Web 应用程序的会话数据存储到 Memcached 中的组件,以实现会话的分布式管理和持久化。其原理主要涉及以下几个方面:
1.会话复制和持久化:
MSM 使用 Memcached 作为会话数据的存储介质,将 Web 应用程序的会话数据存储在 Memcached 服务器上。这种方式可以将会话数据从应用服务器中解耦,实现会话的集群管理和持久化。通过在不同的应用服务器之间共享相同的会话数据,实现了会话的复制和共享
2.会话数据的序列化和反序列化:
MSM 将 Java 应用程序中的会话对象序列化成字节流,并将其存储到 Memcached 中。这样,不同的应用服务器可以通过访问 Memcached 来获取和操作会话数据。当会话数据从 Memcached 中读取回来时,MSM 负责将字节流反序列化为 Java 对象,以便应用程序能够恢复会话状态
3.会话的失效管理:
MSM 可以利用 Memcached 提供的过期时间机制来管理会话的失效。当会话超过预设的过期时间时,Memcached 将自动清除该会话数据,从而实现会话的自动失效和清理。MSM 会在应用服务器中监听会话过期事件,以便在会话失效时做出相应的处理
4.集群环境下的一致性和同步:
在多个应用服务器的集群环境中,MSM 需要处理会话数据的一致性和同步问题。通过 Memcached 提供的分布式缓存机制,不同的应用服务器可以通过共享同一个 Memcached 集群来实现会话数据的一致性。MSM 可以通过 Memcached 提供的 CAS(Compare and Swap)操作来处理并发访问问题,确保会话数据的同步和一致性
5.性能和可扩展性:
Memcached 是一个高性能、内存型的键值存储系统,具有良好的扩展性和高并发处理能力。MSM 利用 Memcached 的这些特性,能够有效地管理大规模的会话数据,提升 Web 应用程序的性能和可扩展性
总体来说,MSM 的原理是通过将会话数据存储到 Memcached 中,利用 Memcached 的分布式缓存特性和高性能特点,实现 Web 应用程序会话的集群管理、持久化和高效访问,从而提升应用程序的可靠性和性能