Tomcat
server对应整体tomcat服务,内置一个叫 卡特玲娜的 service 。
会有多个connector连接,负责处理不同的服务端口,如http80 s 443。
在向里面会有多个host 、 每个虚拟host对应一个文件夹默认webapps,
每个host里有又会有多个servlet,处理不同的post和get请求,内置filter过滤器,所以request里面可以拿到不同的host和servleturi。
默认:
server.tomcat.max-threads=200
server.tomcat.max-connections=8912
server.tomcat.accept-count=100
server.tomcat.max-http-form-post-size=2MB
server.tomcat.min-spare-threads=10
server.tomcat.connection-timeout=60000
maxConnections、maxThreads、acceptCount 参数
accept-count:最大等待数
官方文档的说明为:当所有的请求处理线程都在使用时,所能接收的连接请求的队列的最大长度。当队列已满时,任何的连接请求都将被拒绝。accept-count的默认值为100。
详细的来说:当调用HTTP请求数达到tomcat的最大线程数时,还有新的HTTP请求到来,这时tomcat会将该请求放在等待队列中,这个acceptCount就是指能够接受的最大等待数,默认100。如果等待队列也被放满了,这个时候再来新的请求就会被tomcat拒绝(connection refused)。
maxThreads:最大线程数
每一次HTTP请求到达Web服务,tomcat都会创建一个线程来处理该请求,那么最大线程数决定了Web服务容器可以同时处理多少个请求。maxThreads默认200,肯定建议增加。但是,增加线程是有成本的,更多的线程,不仅仅会带来更多的线程上下文切换成本,而且意味着带来更多的内存消耗。JVM中默认情况下在创建新线程时会分配大小为1M的线程栈,所以,更多的线程异味着需要更多的内存。线程数的经验值为:1核2g内存为200,线程数经验值200;4核8g内存,线程数经验值800。
maxConnections:最大连接数
官方文档的说明为:这个参数是指在同一时间,tomcat能够接受的最大连接数。对于Java的阻塞式BIO,默认值是maxthreads的值;如果在BIO模式使用定制的Executor执行器,默认值将是执行器中maxthreads的值。对于Java 新的NIO模式,maxConnections 默认值是10000。
对于windows上APR/native IO模式,maxConnections默认值为8192,这是出于性能原因,如果配置的值不是1024的倍数,maxConnections 的实际值将减少到1024的最大倍数。
如果设置为-1,则禁用maxconnections功能,表示不限制tomcat容器的连接数。
maxConnections和accept-count的关系为:当连接数达到最大值maxConnections后,系统会继续接收连接,但不会超过acceptCount的值。
我们可以把tomcat比做一个火锅店,流程是取号、入座、叫服务员,可以做一下三个形象的类比:
acceptCount 最大等待数
可以类比为火锅店的排号处能够容纳排号的最大数量;排号的数量不是无限制的,火锅店的排号到了一定数据量之后,服务往往会说:已经客满。
maxConnections 最大连接数
可以类比为火锅店的大堂的餐桌数量,也就是可以就餐的桌数。如果所有的桌子都已经坐满,则表示餐厅已满,已经达到了服务的数量上线,不能再有顾客进入餐厅了。
maxThreads:最大线程数
可以类比为厨师的个数。每一个厨师,在同一时刻,只能给一张餐桌炒菜,就像极了JVM中的一条线程
ToB tomcat不用调,总共也没几个qps会从前端页面访问tomcat,最小10 最大200,白天用的繁忙的时候扩容最大值200。晚上就10,节约cpu资源,也没请求,不用考虑并发。
ToC 业务,一定要动,最大200太小了,一般配置为4c8g 放到800,而且最小,最大都一样,不要让它扩缩容,因为本来服务接口就是专门给Toc接口调用的,没有闲置,队列设置5000以上,连接数5w。
当然这个800,需要压测得出来,就是压最核心的一系列业务场景接口,请求的qps压力直接拉满1wqps请求去压,开始的时候最大默认200,之后得出一个平均的响应的tps,之后慢慢的调大tomcat线程池,看它的平均tps会不会上去,要是增多了就继续加,它会到达一直极限,就是再增加也不会变大的TPS了,那么就不需要动了,说明性能瓶颈已经不在tomcat了,其他的中间件压测调优思路也一样,就是基于现有的TPS,慢慢的优化参数。
Netty
1.Reactor主线程MainReactor对象通过select监听连接事件,收到事件后,通过Acceptor处理连接事件
2.当Acceptor处理连接事件后,MainReactor将连接分配给SubReactor
subreactor将连接加入到连接队列进行监听,并创建handler进行各种事件处理
3.当有新事件发生时,subreactor就会调用对应的handler处理
4.handler通过read读取数据,分发给后面的worker线程处理
5.worker线程池分配独立的worker线程进行业务处理,并返回结果
6.handler收到响应的结果后,再通过send将结果返回给client
7.Reactor主线程可以对应多个Reactor子线程,即MainRecator可以关联多个SubReactor
8.开发者可以自定义ChannelPipeline,创建多个自定义的Handler,类似拦截器
NIO
BIO,阻塞式io,每一个客户端读写事件都需要服务器一个线程去处理。
NIO,非阻塞io,一个服务器端线程可以同时处理多个客户端连接请求。
selector模式:服务端线程主动轮询客户端线程是否有io消息,没有则返回-1,有就进行处理。
epoll模式,服务端线程不需要主动轮询,由操作系统发送io事件,会自动的告诉服务线程去处理请求。
Nginx基本配置
http{# 定义upstream服务器组 upstream backend_servers{# 使用server指令定义后端服务器 server backend1.example.com;server backend2.example.com weight=2;# 权重设置为2,表示此服务器接收的请求是其他服务器的两倍 server192.168.1.1backup;# 作为备份服务器,当其他非备份服务器都不可用时才会被使用 server192.168.1.2down;# 当前标记为down,不会被调度到请求 # 还可以添加其他参数,如:#keepalive32;# 保持连接到上游服务器的空闲连接数# 负载均衡算法(可选,默认是轮询)#least_conn;# 使用最少连接的服务器#ip_hash;# 使用IP哈希实现会话持久性#hash$request_uri;# 根据请求URI的哈希值选择服务器#hash$remote_addr;# 根据客户端IP的哈希值选择服务器# 其他参数和指令...}server{listen80;server_name your_domain.com;location/{# 引用upstream服务器组进行代理 proxy_pass http://backend_servers;# 其他配置...proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}#...其他配置...}#...其他http块配置...}nginx -t 验证配置文件是否正确
nginx -s reload 不重启刷新配置
Lua脚本
EVAL “return tonumber(ARGV[1]) + tonumber(ARGV[2])” 参数个数 参数1 参数2
SCRIPT LOAD “return tonumber(ARGV[1]) + tonumber(ARGV[2])”
返回一个固定的hash值不会变
EVALSHA hash 2 3 4
启动时就把 SCRIPT LOAD 带上这样就可以防止重启redis丢失lua脚本的情况了。
keepalived
一台为主服务器(MASTER),一台为备份服务器(BACKUP),但是对外表现为一个虚拟IP,自定义检测脚本,进行探活。
Haproxy
类似nginx 7层负载均衡。
OpenResty+Lua+Nginx