1. tomcat实现多虚拟机
一键安装tomcat并启动,使用openjdk
#!/bin/bash
version=10.1.28
user=tomcat
group=tomcat
yum install java-17-openjdk.x86_64 java-17-openjdk-devel.x86_64 wget -y
wget https://mirrors.aliyun.com/apache/tomcat/tomcat-10/v${version}/bin/apache-tomcat-${version}.tar.gz
tar xf apache-tomcat-${version}.tar.gz -C /usr/local/src
cd /usr/local/src
mv apache-tomcat-${version} tomcat-${version}
ln -s tomcat-${version} tomcat
echo "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64" > /usr/local/src/tomcat/conf/tomcat.conf
useradd -r -s /sbin/nologin tomcat
chown -R tomcat.tomcat /usr/local/src/tomcat-${version}
cat > /usr/lib/systemd/system/tomcat.service << EOF
[Unit]
Description=Tomcat
After=syslog.target network.target
[Service]
Type=forking
EnvironmentFile=/usr/local/src/tomcat/conf/tomcat.conf
ExecStart=/usr/local/src/tomcat/bin/startup.sh
ExecStop=/usr/local/src/tomcat/bin/shutdown.sh
PrivateTmp=true
User=tomcat
Group=tomcat
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now tomcat
tomcat多主机配置
[root@centos8 ~]# mkdir -p /html/{web.app}/ROOT
[root@centos8 ~]# echo "this is website" > /html/web/ROOT/index.html
[root@centos8 ~]# echo "this is appsite" > /html/app/ROOT/index.html
[root@centos8 ~]# chown -R tomcat.tomcat /html/{web,app}/
2. tomcat定制访问日志格式
参数 | 描述 |
---|---|
%a | 远程IP地址 |
%A | 本地IP地址 |
%b | 发送的字节数(不包括HTTP标头) |
%B | 发送的字节数(不包括HTTP标头) |
%h | 远程主机名 |
%H | 请求协议 |
%l | 来自identd的远程逻辑用户名 |
%m | 请求方法(GET, POST, etc.) |
%p | 接收此请求的本地端口 |
%q | 查询字符串 |
%r | 请求的第一行 |
%s | 响应的HTTP状态码 |
%S | 用户会话ID |
%t | 日期和时间,通用日志格式 |
%u | 已通过身份验证的远程用户 |
%U | 请求的URL路径 |
%v | 本地服务器名称 |
%D | 处理请求所用的时间(毫秒) |
%T | 处理请求所用的时间(秒) |
%F | 提交响应所需的时间 |
%I | 当前请求线程名称 |
%X | 响应完成时的连接状态 |
… | … |
日志配置地方
[root@server ~]# vim /usr/local/src/tomcat/conf/server.xml
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" /> #说明"在html中表示双引号
[root@client ~]# curl 10.0.0.4:8080
[root@server ~]# tail -f /usr/local/src/tomcat/logs/localhost_access_log.`date +%Y-%m-%d`.txt #查看日志
3. tomcat实现MSM集群
修改server1主机的 conf/server.xml
[root@server1 ~]# vim /usr/local/src/tomcat/conf/server.xml
在<Host> </host>块中间加入下面内容
<Host>
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.3"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="10.0.0.4" #指定网卡的IP
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
</Host>
</Engine>
</Service>
</Server>
[root@server1 ~]#systemctl restart tomcat
修改server2主机的 conf/server.xml
[root@server2 ~]# vim /usr/local/src/tomcat/conf/server.xml
<Host>
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.3"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="10.0.0.6"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
</Host>
</Engine>
</Service>
</Server>
[root@cserver2 ~]#systemctl restart tomcat
4. JVM垃圾回收算法和分代
- 标记-清除 Mark-Sweep:分垃圾标记阶段和内存释放阶段。标记阶段,找到所有可访问对象打个标记。清理阶段,遍历整个堆,对未标记对象(即不再使用的对象)清理。最大的问题会造成内存碎片,但是效率很高,不浪费空间。
- 标记-压缩 (压实)Mark-Compact:分垃圾标记阶段和内存整理阶段。标记阶段,找到所有可访问对象打个标记。内存清理阶段时,整理时将对象向内存一端移动,整理后存活对象连续的集中在内存一端。好处是整理后内存空间连续分配,有大段的连续内存可分配,没有内存碎片。但内存整理过程有消耗,效率相对低下。
- 复制 Copying:先将可用内存分为大小相同两块区域A和B,每次只用其中一块,比如A。当A用完后,则将A中存活的对 象复制到B。复制到B的时候连续的使用内存,最后将A一次性清除干净。缺点是比较浪费内存,只能使用原来一半内存,因为内存对半划分了,复制过程毕竟也是有代价。好处是没有碎片,复制过程中保证对象使用连续空间
总结
效率: 复制算法>标记清除算法> 标记压缩算法
内存整齐度: 复制算法=标记压缩算法> 标记清除算法
内存利用率: 标记压缩算法=标记清除算法>复制算法
1.堆内存分代: 将heap内存空间分为三个不同类别: 年轻代、老年代、持久代Heap堆内存分为年轻代Young:Young Generation伊甸园区eden: 只有一个,刚刚创建的对象幸存(存活)区Servivor Space:有2个幸存区,一个是from区,一个是to区。大小相等、地位相同、可互换。from 指的是本次复制数据的源区to 指的是本次复制数据的目标区老年代Tenured:Old Generation, 长时间存活的对象
2 年轻代回收 Minor GC: 起始时,所有新建对象(特大对象直接进入老年代)都出生在eden,当eden满了,启动GC。这个称为Young GC 或者 Minor GC。先标记eden存活对象,然后将存活对象复制到s0(假设本次是s0,也可以是s1,它们可以调换),eden剩余所有空间都清空。GC完成。继续新建对象,当eden再次满了,启动GC。先同时标记eden和s0中存活对象,然后将存活对象复制到s1。将eden和s0清空,此次GC完成继续新建对象,当eden满了,启动GC。先标记eden和s1中存活对象,然后将存活对象复制到s0。将eden和s1清空,此次GC完成以后就重复上面的步骤。通常场景下,大多数对象都不会存活很久,而且创建活动非常多,新生代就需要频繁垃圾回收。但是,如果一个对象一直存活,它最后就在from、to来回复制,如果from区中对象复制次数达到阈值(默认15次,CMS为6次,可通过java的选项 -XX:MaxTenuringThreshold=N 指定),就直接复制到老年代。
3.老年代回收 Major GC: 进入老年代的数据较少,所以老年代区被占满的速度较慢,所以垃圾回收也不频繁如果老年代也满了,会触发老年代GC,称为Old GC或者 Major GC。由于老年代对象一般来说存活次数较长,所以较常采用标记-压缩算法。当老年代满时,会触发 Full GC,即对所有"代"的内存进行垃圾回收Minor GC比较频繁,Major GC较少。但一般Major GC时,由于老年代对象也可以引用新生代对象,所以先进行一次Minor GC,然后在Major GC会提高效率。可以认为回收老年代的时候完成了一次FullGC.所以可以认为 MajorGC = FullGC
5. memcache使用,安装和MSM原理
memcache介绍:Memcache是一个高性能的分布式内存对象缓存系统,用于加速动态 Web 应用程序通过减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高性能。
主要特性:
1. 简单易用:客户端和服务器之间的通信基于简单的 ASCII 协议。
2. 高可用性:可以部署多个Memcached服务器,应用程序自动负载均衡。
3. 无单点故障:如果某个Memcached 实例宕机,其他实例仍然可用。
4. 数据过期策略:支持设置数据的生存时间,到期后数据会被自动删除。
应用场景:
1. 数据库查询结果缓存:存储频繁访问的数据,减少对数据库的请求。
2. 会话数据存储:替代文件或数据库存储用户会话信息。
3. API 调用结果缓存:减少对外部服务的调用频率。
MSM 原理
Slab 分类:Memcached将内存划分为多个 slab 类别,每个类别对应一组固定大小的内存块。
内存块大小:每个 slab 类别中的内存块具有相同的大小,大小从 1KB 开始,每次翻倍。
Slab 类别:当 Memcached 接收到一个新项时,它会根据项的大小将其放置在合适的 slab 类别中。
分配和释放:当一个项被删除或过期时,其内存块不会立即释放,而是返回到 slab 类别中供重用。
Eviction Policy:当某个 slab 类别的内存不足时,Memcached 会根据一定的策略(如 LRU)释放旧的项以腾出空间。
Memcached 安装
[root@server ~]# yum install -y epel-release
[root@server ~]# yum install -y memcached
[root@server ~]# systemctl start memcached.service #进行启动
memcached使用
常用命令 | 意思 |
---|---|
set | 设置键值对 |
get | 获取键对应的值 |
delete | 删除键值对 |
replace | 如果键存在,则替换其值 |
append/prepend: | 在现有值的末尾/开头追加数据 |
increment/decrement: | 对整数值进行递增/递减操作 |
stats | 显示服务器统计信息 |
# 设置键值对
[root@server ~]# echo "set mykey 0 60 4\r\nvalue\r\n" | nc localhost 11211
# 获取键值对
[root@server ~]# echo "get mykey\r\n" | nc localhost 11211
# 删除键值对
[root@server ~]# echo "delete mykey\r\n" | nc localhost 11211
使用 Python 客户端操作 Memcached
[root@server ~]# pip install python-memcached
[root@server ~]# vim mem.py
import memcache
# 创建 Memcached 客户端
mc = memcache.Client(['127.0.0.1:11211'])
# 设置键值对
mc.set('mykey', 'Hello Memcached!')
# 获取键值对
value = mc.get('mykey')
print(value) # 输出: Hello Memcached!
# 删除键值对
mc.delete('mykey')
# 替换键值对(如果键存在)
mc.set('mykey', 'Hello!')
mc.replace('mykey', 'MyMemcached!')
# 追加数据
mc.set('mykey', 'My')
mc.append('mykey', 'Memcached!')
print(mc.get('mykey')) # 输出: MyMemcached!
# 递增/递减整数值
mc.set('counter', 1)
mc.incr('counter', 1)
print(mc.get('counter')) # 输出: 2
mc.decr('counter', 1)
print(mc.get('counter')) # 输出: 1
[root@server ~]# chmod +x mem.py
[root@server ~]# python mem.py