负载均衡
动态服务器的问题,往往就是并发能力太弱,往往需要多台动态服务器一起提供服务。如何把并发的压力分摊,就需要调度,采用一定的调度策略,将请求分发给不同的服务器,这就是Load Balance负载均衡。
当单机的Tomcat,演化出多机多级部署的时候,一个问题便凸显出来,这就是Session。而这个问题的由来,都是由于HTTP协议的设计之初没有想到未来的发展。
HTTP的无状态,有连接和短连接
- 无状态:指的是服务器端无法知道2次请求之间的联系,即使是前后2次请求来自同一个浏览器,也没有任何数据能够判断出是同一个浏览器的请求。后来可以通过cookie、session机制来判断。
- 浏览器端第一次HTTP请求服务器端时,在服务器端使用session这种技术,就可以在服务器端产生一个随机值即SessionID发给浏览器端,浏览器端收到后会保持这个SessionID在Cookie当中,这个Cookie值不能持久存储,浏览器关闭就消失。浏览器在每一次提交HTTP请求的时候会把这个SessionID传给服务器端,服务器端就可以通过比对知道是谁了
- Session通常会保存在服务器端内存中,如果没有持久化,则易丢失
- Session会定时过期。过期后浏览器如果再访问,服务端发现没有此ID,将重新获得新的SessionID
- 更换浏览器也将重新获得新的SessionID
- 有连接:是因为它基于TCP协议,是面向连接的,需要3次握手、4次断开。
- 短连接:Http 1.1之前,都是一个请求一个连接,而Tcp的连接创建销毁成本高,对服务器有很大的影响。所以,自Http 1.1开始,支持keep-alive,默认也开启,一个连接打开后,会保持一段时间(可设置),浏览器再访问该服务器就使用这个Tcp连接,减轻了服务器压力,提高了效率。
服务器端如果故障,即使Session被持久化了,但是服务没有恢复前都不能使用这些SessionID。
如果使用HAProxy或者Nginx等做负载均衡器,调度到了不同的Tomcat上,那么也会出现找不到SessionID的情况。
会话保持方式
1、session sticky会话黏性
+ Session绑定
- nginx:source ip
- HAProxy:cookie
优点:简单易配置
缺点:如果目标服务器故障后,如果没有做sessoin持久化,就会丢失session
2、session复制集群
Tomcat自己的提供的多播集群,通过多播将任何一台的session同步到其它节点。
缺点
+ Tomcat的同步节点不宜过多,互相及时通信同步session需要太多带宽
+ 每一台都拥有全部session,内存损耗太多
3、session server
session 共享服务器,使用memcached、redis做共享的Session服务器。
实验:nginx 负载均衡 tomcat
- 我们准备 3 台纯新的 CentOS7.6 服务器,关闭 selinux,清空防护墙
主机名 | ip地址 | 服务 |
---|---|---|
lbserver | 192.168.99.121 | nginx/httpd |
tomcat1 | 192.168.99.122 | tomcat |
tomcat2 | 192.168.99.123 | tomcat |
- tomcat1 服务器上
- 安装jdk
yum install java-1.8.0-openjdk-devel wget -y
- 下载tomcat
wget http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.42/bin/apache-tomcat-8.5.42.tar.gz
下载下了就上官网:http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8
- 解压
tar xf apache-tomcat-8.5.42.tar.gz -C /usr/local/
- 软链接
cd /usr/local/
ln -s apache-tomcat-8.5.42 tomcat
- 创建用户
useradd -r tomcat
- 设置权限
chown -RL tomcat.tomcat /usr/local/tomcat
- 创建 tomcat 项目目录
mkdir -p /data/webapps/ROOT
- 创建测试 session 使用的 index.jsp 页面
vim /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>lbjsptest</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>
- 设置权限
chown -RL tomcat.tomcat /data/webapps
- 修改tomcat配置
vim /usr/local/tomcat/conf/server.xml
...
<Engine name="Catalina" defaultHost="node1.com">
...
<Host name="node1.com" appBase="/data/webapps" autoDeploy="true">
</Host>
</Engine>
</Service>
</Server>
修改Engine,并在倒数第4行插入
- 启动tomcat
su - tomcat -c "/usr/local/tomcat/bin/startup.sh"
- 访问测试
linux端修改/etc/hosts
电脑端修改C:\Windows\System32\drivers\etc\\hosts
,在尾部添加
192.168.99.122 node1.com
或
curl node1.com:8080
- 把配置复制给tomcat2主机
scp -r apache-tomcat-8.5.42 192.168.99.123:/usr/local/tomcat
scp /data/webapps/ROOT/index.jsp 192.168.99.123:/root
- tomcat2 服务器上
- 安装jdk
yum install java-1.8.0-openjdk-devel wget -y
- 创建用户
useradd -r tomcat
- 创建 tomcat 项目目录
mkdir -p /data/webapps/ROOT
- 把index.jsp移动
cd
mv index.jsp /data/webapps/ROOT
- 设置权限
chown -R tomcat.tomcat /usr/local/tomcat
chown -R tomcat.tomcat /data/webapps
- 修改tomcat配置
vim /usr/local/tomcat/conf/server.xml
...
<Engine name="Catalina" defaultHost="node2.com">
...
<Host name="node2.com" appBase="/data/webapps" autoDeploy="true">
</Host>
</Engine>
</Service>
</Server>
修改Engine,并在倒数第4行插入
- 启动
su - tomcat -c "/usr/local/tomcat/bin/startup.sh"
- 添加域名解析
vim /etc/hosts
192.168.99.123 node2.com
- 测试
curl node2.com:8080
- nginx服务器上
- 安装nginx(需要epel源)
yum install nginx -y
- 修改配置
vim /etc/nginx/nginx.conf
http {
...
upstream tomcats {
server node1.com:8080;
server node2.com:8080;
}
server {
...
location ~* \.(jsp|do)$ {
proxy_pass http://tomcats;
}
...
- 检查语法
nginx -t
- 添加域名解析
vim /etc/hosts
192.168.99.122 node1.com
192.168.99.123 node2.com
192.168.99.121 webserver.com
- 启动服务
systemctl start nginx
- 测试
curl webserver.com/index.jsp
用浏览器测试更方便
使用 ip_hash 实现 session 绑定
- 修改配置
vim /etc/nginx/nginx.conf
http {
...
upstream tomcats {
ip_hash;
server node1.com:8080;
server node2.com:8080;
}
server {
...
- 重启服务
systemctl reload nginx
- 测试
curl webserver.com/index.jsp