java-Nginx与Tomcat安装,配置及优化
1. java-Nginx安装,配置及优化
1.1 Nginx的安装
linux服务器三种安装方式:
1.rpm(或pkg)安装,类似以与Windows安装程序,是预编译好的程序。
- 使用的是通用参数编译,配置参数部署最佳
- 可控制性不强,比如对程序特定组件的定制性安装
- 通常安装包间有复杂依赖关系,操作比较复杂
2.yum(或者apt-get)安装,改良版的rpm,自动联网下载安装包,自动管理依赖关系
3.编译安装(方式在各类Linux发行版中差异不大)
- 可控制性强,config是可根据当前系统环境优化参数,可定制组件及安装参数
- 易出错,难度略高
1.2 nginx 安装 启动 关闭自动启动
sbin目录下:
启动: ./nginx
关闭: ./nginx -s stop
重载配置文件: ./nginx -s reload
1.3 Nginx的配置
配置文件位置: conf/nginx.conf
全局块
events块
http块
include: 引入配置文件
#顶层配置信息管理服务器级别行为
#一般一个进程足够了,你可以把连接数设得很大。如果有SSL、gzip这些比较消耗CPU的工作,而且是多核CPU的话,可以设为和CPU的数量一样。或者要处理很多很多的小文件,而且文件总大小比内存大很多的时候,也可以把进程数增加,以充分利用IO带宽(主要似乎是IO操作有block)
worker_processes 1;
#event指令与时间模型有关,配置处理连接有关信息
events{
#单个工作进程可以允许同时建立外部连接的数量
worker_connections 1024;
}
#http指令处理http请求:接受请求
http{
#mime type 映射
include mime.types; #引入另外一个配置文件
default_type application/octet-stream; #在mime.type不存在的时候, 默认的文件类型
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
#server 处理请求 表示一个虚拟主机,一台服务器可配置多个虚拟主机
#第一个server 除了匹配本身 server_name 指定的域名外, 还匹配其他server都不匹配的域名
server{
#监听端口
listen 80;
#识别的域名
server_name localhost;
#一个关键设置,与url参数乱码问题有关
charset utf-8;
#access_log logs/host.access.log main;
#一个server下面可以有多个location,每个location有不同的处理行为,根据表达式匹配,请求交个哪个location,
#根据location里面的表达式,映射到具体的处理行为
#location
#location表达式:
#syntax: location [=|~|~*|^~|@] /uri/ {...}
#分为两种匹配模式,普通字符串匹配,正则匹配
#无开头引导字符或以=开头标识普通字符串匹配
#以~或~*开头标识正则匹配,~*标识不区分大小写
#多个location时匹配规则
#总体是先普通后正则原则,只识别URI部分,例如请求为/test/1/abc.do?arg=xxx
#1. 先查找是否有=开头的精确匹配,即location = /test/1/abc.do {...}
#2. 再查找普通匹配,以最大前缀为规则,如有以下两个location
# location /test/ {...}
# location /test/1/ {...}
# 则匹配最后一项
#3. 匹配到一个普通格式后,搜索并未结束,而是暂存当前结果,并继续再搜索正则模式
#4. 在所有正则模式location中找到第一个匹配项后,以此匹配项为最终结果
# 所以正则匹配项规则受定义前后顺序影响,但普通匹配不会
#5. 如果未找到匹配项,则以3中缓存的结果为最终结果
#6. 如果一个匹配都没有,返回404
#location =/ {...} 与 location / {...}的差别
#前一个是精确匹配,只响应/请求,所有/xxx类请求,不会以,前缀匹配形式匹配到它,
#后一个正相反,所有请求必然都是以/开头,所以没有其他匹配结果的时候一定会执行到它
#location ^~ / {...} ^~意思是非正则,标识匹配到此模式不再继续正则搜索
#所有如果这样配置,相当于关闭了正则匹配功能
#因为一个请求在普通匹配规则下没得到其他普通匹配结果时,最终匹配到这里
#而这个 ^~指令又相当于不允许正则,相当于匹配到此为止
#精确匹配
location =/test {
...
}
#普通字符匹配
location /test {
...
}
location / {
root html; #指定根目录 绝对路径或者相对路径
index index.html index.htm; #请求到达后没有指定具体文件,默认用index指定的顺序,查找文件
#deny all; 拒绝请求,返回403
#allow all; 允许请求
}
location ^~ /test/ {
deny all;
}
#正则匹配
location ~ /test/.+\.jsp$ {
#代理
proxy_pass http://192.168.1.62:8080;
}
#正则匹配
location ~* \.jsp$ {
proxy_pass http://192.168.1.61:8080;
}
#定义各类错误页
error_page 404 /404.html;
#redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x/html {
root html;
}
# @类似于变量定义
# 错误执行另外一个代理服务器的时候,location 定义一个变量名, 用@符号
# error_page 403 http://www.121212.com这种定义不允许,所以利用@实现
error_page 403 @page403;
location @page403 {
proxy_pass = http://www.121212.com;
}
}
}
mime.types
Nginx 会根据mime type定义的对应关系来告诉浏览器如何处理服务器传给浏览器的这个文件,是打开还是下载;如果Web程序没设置,Nginx也没对应文件的扩展名,就用Nginx 里默认的 default_type定义的处理方式。
比如Nginx默认的配置中default_type application/octet-stream; 这个就是默认为下载,浏览器访问到未定义的扩展名的时候,就默认为下载该文件;如果将这个设置改成default_type text/html;那就是告诉浏览器默认的打开方式是把所有未设置的扩展名当HTML文件打开,虽然可能这样设置会很多打不开。
mime type 和文件扩展名的对应关系一般放在 mime.types这个文件里,然后用 include mime.types; 来加载
mime.types文件里是用types指令来定义的,下面是一个完整的定义:
mime.types文件
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
#application/x-javascript js;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
image/svg+xml svg;
application/java-archive jar war ear;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.ms-excel xls;
application/vnd.ms-powerpoint ppt;
application/vnd.wap.wmlc wmlc;
application/vnd.wap.xhtml+xml xhtml;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream eot;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mpeg mpeg mpg;
video/quicktime mov;
video/x-flv flv;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}
一般在Nginx的配置文件nginx.conf里面的http{}字段中配置即可,注意mime.types是在你的nginx的安装目录下,如果目录不是下面的,那你要自己手工修改:
参考博客: https://blog.csdn.net/qq_37788558/article/details/78621592
location
url匹配规则
location [=|~|~*|^~|@] /uri/ {
...
}
- = : 表示精确匹配后面的url
- ~ : 表示正则匹配,但是区分大小写
- ~* : 正则匹配,不区分大小写
- ^~ : 表示普通字符匹配,如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录
- @ : “@” 定义一个命名的 location,使用在内部定向时,例如 error_page
上述匹配规则的优先匹配顺序:
- = 前缀的指令严格匹配这个查询。如果找到,停止搜索;
- 所有剩下的常规字符串,最长的匹配。如果这个匹配使用 ^~ 前缀,搜索停止;
- 正则表达式,在配置文件中定义的顺序;
- 如果第 3 条规则产生匹配的话,结果被使用。否则,使用第 2 条规则的结果。
location表达式:
syntax: location [=|~|~*|^~|@] /uri/ {...}
分为两种匹配模式,普通字符串匹配,正则匹配 无开头引导字符或以=开头标识普通字符串匹配
以~或~*开头标识正则匹配,~*标识不区分大小写
多个location时匹配规则
总体是先普通后正则原则,只识别URI部分,例如请求为/test/1/abc.do?arg=xxx
- 先查找是否有=开头的精确匹配,即location = /test/1/abc.do {…}
- 再查找普通匹配,以最大前缀为规则,如有以下两个location
location /test/ {…} location /test/1/ {…} 则匹配最后一项 - 匹配到一个普通格式后,搜索并未结束,而是暂存当前结果,并继续再搜索正则模式
- 在所有正则模式location中找到第一个匹配项后,以此匹配项为最终结果
所以正则匹配项规则受定义前后顺序影响,但普通匹配不会 - 如果未找到匹配项,则以3中缓存的结果为最终结果
- 如果一个匹配都没有,返回404
location =/ {…} 与 location / {…}的差别 前一个是精确匹配,只响应/请求,所有/xxx类请求,不会以,前缀匹配形式匹配到它, 后一个正相反,所有请求必然都是以/开头,所以没有其他匹配结果的时候一定会执行到它
location ^~ / {...} ^~意思是非正则,标识匹配到此模式不再继续正则搜索
所有如果这样配置,相当于关闭了正则匹配功能
因为一个请求在普通匹配规则下没得到其他普通匹配结果时,最终匹配到这里 而这个 ^~指令又相当于不允许正则,相当于匹配到此为止
#精确匹配
location =/test {...}
#普通字符匹配
location /test {...}
location / {
root html; #指定根目录 绝对路径或者相对路径
index index.html index.htm; #请求到达后没有指定具体文件,默认用index指定的顺序,查找文件
#deny all; 拒绝请求,返回403
#allow all; 允许请求
}
location ^~ /test/ {
deny all;
}
#正则匹配
location ~ /test/.+\.jsp$ {
#代理
proxy_pass http://192.168.1.62:8080;
}
#正则匹配
location ~* \.jsp$ {
proxy_pass http://192.168.1.61:8080;
}
#定义各类错误页
error_page 404 /404.html;
#redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x/html {
root html;
}
# @类似于变量定义
# 错误执行另外一个代理服务器的时候,location 定义一个变量名, 用@符号
# error_page 403 http://www.121212.com这种定义不允许,所以利用@实现
error_page 403 @page403;
location @page403 {
proxy_pass = http://www.121212.com;
}
@ 类似于变量定义
# @类似于变量定义
# 错误执行另外一个代理服务器的时候,location 定义一个变量名, 用@符号
# error_page 403 http://www.121212.com这种定义不允许,所以利用@实现
error_page 403 @page403;
location @page403 {
proxy_pass = http://www.121212.com;
}
1.4 Nginx的优化
nginx.conf配置文件
全局块
nginx不同于apache服务器,当apache进行了大量优化设置后会有魔术般的明显提升性能效果,nginx在安装完成后,大部分参数都是最优化了,我们需要管理的东西并不多
阻塞和非阻塞网络模型:
同步阻塞模型,一请求一进(线)程,当进(线)程增加到一定程度后,更多的CPU时间浪费到切换CPU,性能急剧下降,所以负载率并不高
Nginx基于事件的非阻塞多路复用(epoll或kquene)模型,一个进程在段时间内可以响应大量的请求
案例:
#user nobody;
#工作进程数量:接受和处理用户请求
#建议值 <= CPU核心数量,一般高于cpu数量不会带来好处,也许还有进程切换开销的负面影响
worker_processes 4;
#将work process 绑定到特定的CPU上,避免进程在cpu间切换的开销
#多少个cpu,每组数字就有多少个数字 0/1
worker_cpu_affinity 0001 0010 0100 1000;
#8核4进程时的设置方法 worker_cpu_affinity 00000001 00000010 00000100 10000000
# 每个进程最大可打开文件描述符数量(linux上文件描述符比较广泛,网络端口,设备,磁盘文件都是)
# 文件描述符用完了,新的连接会拒绝,产生502类错误
# linux 最大可打开文件数可通过ulimit -n FILECNT或 /etc/security/limits.conf配置
# 理论值: 系统最大数量 / 进程数。但进程间工作量并不是平均分配的,所以可以设置的大一些
#越大越好
worker_rlimit_nofile 655350;
events{
...
}
worker_processes
工作进程数量:接受和处理用户请求
#工作进程数量:接受和处理用户请求
#建议值 <= CPU核心数量,一般高于cpu数量不会带来好处,也许还有进程切换开销的负面影响
worker_processes 4;
worker_cpu_affinity
将work process 绑定到特定的CPU上
#将work process 绑定到特定的CPU上,避免进程在cpu间切换的开销
#多少个cpu,每组数字就有多少个数字 0/1
worker_cpu_affinity 0001 0010 0100 1000;
#8核4进程时的设置方法 worker_cpu_affinity 00000001 00000010 00000100 10000000
worker_rlimit_nofile
每个进程最大可打开文件描述符数量
# 每个进程最大可打开文件描述符数量(linux上文件描述符比较广泛,网络端口,设备,磁盘文件都是)
# 文件描述符用完了,新的连接会拒绝,产生502类错误
# linux 最大可打开文件数可通过ulimit -n FILECNT或 /etc/security/limits.conf配置
# 理论值: 系统最大数量 / 进程数。但进程间工作量并不是平均分配的,所以可以设置的大一些
#越大越好
worker_rlimit_nofile 655350;
events块
....
events {
#并发响应能力的关键配置值
#每个进程允许的最大同时连接数,worker_connections * worker_processes = maxConnection;
#要注意maxConnection不等于可响应的用户数量,
#因为一般一个浏览器会同时开两条连接,如果反向代理,nginx到后端服务器的连接也要占用连接数
#所以,做静态服务器时,一般 maxClient = worker_connections * worker_processes /2
#做反向代理服务器时,maxClient = worker_connections * worker_processes /4
#这个值理论上越大越好,但最多可承受多少请求与配置和网络相关,也可最大可打开文件,最大可用sockets数量
worker_connections 200000;
#指明使用 epoll 或 kqueue (*BSD)
use epoll;
#备注:要达到超高负载下最好的网络响应能力,还有必要优化与网络相关的linux 参数
}
....
worker_connections
并发响应能力的关键配置值,每个进程允许的最大同时连接数
#并发响应能力的关键配置值
#每个进程允许的最大同时连接数,worker_connections * worker_processes = maxConnection;
#要注意maxConnection不等于可响应的用户数量,
#因为一般一个浏览器会同时开两条连接,如果反向代理,nginx到后端服务器的连接也要占用连接数
#所以,做静态服务器时,一般 maxClient = worker_connections * worker_processes /2
#做反向代理服务器时,maxClient = worker_connections * worker_processes /4
#这个值理论上越大越好,但最多可承受多少请求与配置和网络相关,也可最大可打开文件,最大可用sockets数量
worker_connections 200000;
maxClient:最大客户可用连接数
maxClient = worker_connections * worker_processes /2
做反向代理服务器时,maxClient = worker_connections * worker_processes /4
use
指定事件处理的时候,指定网络模型
基本不需要设置,nginx自动识别。
windows无法使用多路复用模型,这也是为什么nginx在windows上,性能不够好的原因
#指明使用 epoll 或 kqueue (*BSD)
use epoll;
http块
....
events{
...
}
https {
include mime.types;
dafault_type application/octet-stream;
#访问日式是否记录
#关闭此项可减少IO开销,但也无法记录访问信息,不利于业务分析,一般运维情况不建议使用
access_log off;
#错误日志
#crit:只记录更为严重的错误日志,可减少IO压力,或者关闭
error_log logs/error.log crit;
#access_log logs/access.log main;
#启用内核复制模式,应该保持开启达到最快IO效率,从磁盘级IO复制到网络级IO,不经过用户级,减少了几次复制过程【零拷贝技术】
sendfile on;
#简单说,启动如下两项配置,会在数据包达到一定大小后再发送数据
#这样会较少网络通信次数,降低阻塞概率,但也会影响响应及时性
#比较合适于文件下载这类的大数据包通信场景
#tcp_nohush on;
#tcp_nodelay on|off on禁用Nagle算法
#HTTP1.1支持持久连接alive
#连接存活时间: 降低每个连接的alive时间,可在一定程度上提高响应连接数量,所以一般可适当降低此值
keepalive_timeout 30s;
#启动内容压缩,有效降低网络流量,生产环境打开
gzip on;
#内容压缩最小长度:过短的就不要压缩,因为 过短的内容压缩效果不佳,压缩过程还会浪费系统资源
gzip_min_length 1000;
#可选值1~9,压缩级别越高,压缩率越高,但对系统性能要求越高
gzip_comp_level 4;
#压缩的内容类别
gzip_types text/plain text/css application/json application/x-javascript text/xml ...;
#静态文件缓存
#最大缓存数量,文件未使用存活期
#open_file_cache 打开文件,max:缓存文件最大个数,
#"inactive":文件存活期,"open_file_cache_min_uses"缓存文件在20s内使用至少2次,那么缓存文件不会被替换,是一个命中率有效的文件
#"open_file_cache_valid":表示多久验证缓存,会释放使用次数少的文件
open_file_cache max=655350 inactive=20s;
#验证缓存有效期时间间隔
open_file_cache_valid 30s;
#有效期内文件最少使用次数
open_file_cache_min_uses 2;
server {
...
}
}
日志
#访问日式是否记录
#关闭此项可减少IO开销,但也无法记录访问信息,不利于业务分析,一般运维情况不建议使用
access_log off;
#错误日志
#crit:只记录更为严重的错误日志,可减少IO压力,或者关闭
error_log logs/error.log crit;
#access_log logs/access.log main;
内核复制
#启用内核复制模式,应该保持开启达到最快IO效率,从磁盘级IO复制到网络级IO,不经过用户级,减少了几次复制过程【零拷贝技术】
sendfile on;
压缩
#启动内容压缩,有效降低网络流量,生产环境打开
gzip on;
#内容压缩最小长度:果断的就不要压缩,因为 过短的内容压缩效果不佳,压缩过程还会浪费系统资源
gzip_min_length 1000;
#可选值1~9,压缩级别越高,压缩率越高,但对系统性能要求越高
gzip_comp_level 4;
#压缩的内容类别
gzip_types text/plain text/css application/json application/x-javascript text/xml;
静态文件缓存
#静态文件缓存
#最大缓存数量,文件未使用存活期
#open_file_cache 打开文件,max:缓存文件最大个数,
#"inactive":文件存活期,"open_file_cache_min_uses"缓存文件在20s内使用至少2次,那么缓存文件不会被替换,是一个命中率有效的文件
#"open_file_cache_valid":表示多久验证缓存,回释放使用次数少的文件
open_file_cache max=655350 inactive=20s;
#验证缓存有效期时间间隔
open_file_cache_valid 30s;
#有效期内文件最少使用次数
open_file_cache_min_uses 2;
2. Tomcat安装,配置及优化
2.1 安装JDK
下载 jdk1.8.0_51.tar.gz 解压…在下面添加配置
/etc/profile.d/ 系统启动的时候,会执行这里面的 .sh文件
JAVA_HOME=/opt/jdk1.8.0_51
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME PATH
设置立即生效: source /etc/profile
2.2 Tomcat安装
日志: /logs/catalina.out
启动: /bin/start.sh
关闭: /bin/shutdown.sh
开机启动:/etc/rc.d/rc.local 文件 :用来设置开机自动运行
touch /var/lock/subsys/local
/opt/nginx/sbin/nginx
export JAVA_HOME=/opt/jdk1.8.0_51
$JAVA_HOME/bin/startup.sh
rc.local 比 profile.d 文件夹里面的控制脚本启动的更早,所以上面需要重新导出一遍JAVA_HOME命令
2.3 Tomcat的优化配置
内存使用配置
/bin/catalina.sh
......
#Windows下配置方法
#set JAVA_OPTS=%JAVA_OPTS% -server -Xms2048m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m -Djava.awt.headless=true
#通过内存设置充分利用服务器内存
#-server模式启动应用慢,但可以极大程度提高运行性能
#java 8开始,PermSize 被 MetaspaceSize 代替,MetaspaceSize共享heap,不会再有java.lang.outofMemoryError:PermGen space,可以不设置PermSize
#headless=true 适用于linux系统,于图形操作有关,如生成验证码,含义是当前适用的是无显示器的服务器,应用中如果获取系统显示有关参数会抛异常
#可通过 jmap -heap process_id查看设置是否成功
JAVA_OPTS=$JAVA_OPTS -server -Xms2048m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m -Djava.awt.headless=true
......
最大连接数配置
server.xml
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimetoue="20000"
redirectPort="8443"
maxThreads="500" #最大连接线程数
minSpareThreads="100" #最小空闲线程
maxSpareThreads="200" #最大空闲线程
acceptCount="200" #所有线程启动后,还允许接受的连接数量,也就是等待的线程数 ,最大可接受的任务:maxThreads+acceptCount
enableLookups="false" #是否允许DNS反查
/>
3. Nginx+Tomcat负载均衡详细配置
3.1 负载均衡配置的实现
正向代理和反向代理
**正向代理:如果把局域网外的 Internet 想象成一个巨大的资源库,则局域网中的客户端要访问 Internet,则需要通过代理服务器来访问,这种代理服务就称为正向代理。**对于反向代理,客户端对代理是无感知的,因为客户端不需要任何配置就可以访问,我们只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端,此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器 IP 地址。
代理一般分为正向代理和反向代理。
正向代理是一个位于客户端和原始服务器之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
反向代理实际运行方式是代理服务器接受网络上的连接请求。它将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给网络上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
可以这么认为,对于正向代理,代理服务器和客户端处于同一个局域网内;而反向代理,代理服务器和源站则处于同一个局域网内。
参考博客:https://blog.csdn.net/u010039418/article/details/80011127
https://www.cnblogs.com/xudong-bupt/p/8661523.html
nginx 充当代理服务器: 浏览器->Nginx->Tomcat,原理如下:
192.168.1.61服务器请求转到192.168.1.62中的tomcat
192.168.1.61中nginx配置如下: nginx.conf文件里面设置代理:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
#root html;
index index.html index.htm;
#代理配置
proxy_pass http://192.168.1.62:8080;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
修改完成后,配置文件生效:sbin/nginx -s reload
负载均衡
示意图如下: 三个要素:
1.服务器组
2.nginx配置
3.负载均衡策略
首先要有多个服务器,形成服务器组,nginx通过反向代理,将请求发送到服务器组上,根据负载均衡策略,分配请求到具体的服务器上。
打开nginx文件,实现负载均衡配置:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#定义服务器组,默认轮训方式发送请求
upstream tomcats {
server 192.168.1.62:8080;
server 192.168.1.63:8080;
}
server {
listen 80;
server_name localhost;
location / {
#root html;
index index.html index.htm;
#代理配置: 服务器组名,请求发送给服务器组
proxy_pass http://tomcats;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
upstream 参数
...
#配置用于负载均衡的服务器集群信息
upstream backends {
#均衡策略
#none 轮训(权重由weight决定)
#ip_hash
#fair
#url_hash
server 192.168.1.62:8080;
server 192.168.1.63;
#weight:权重,值越高负载越大;
#server 192.168.1.64 weigth=5;
#backup: 备份机,只有非备份机都挂掉,才启用:
server 192.168.1.64 backup;
#down: 停机标志,不会被访问
server 192.168.1.64 down;
#max_fails:达到指定次数认为服务器挂掉;
#fail_timeout:挂掉之后过多久再去测试是否已恢复
server 192.168.1.66 max_fails=2 fail_timeout=60s;
}
...
均衡策略
平均轮训 默认
1:1
权重
根据权重不大, 分配的ip数量不同,默认1:1
upstream backends {
server 192.168.1.62:8080 weight=5;
server 192.168.1.63:8080 weight=3;
}
ip_hash
用户访问的ip第一次访问的时候,会绑定到某一个均衡策略里面,指定的服务器上面,后续该ip的请求的,都会访问这个绑定的服务器ip地址。
使用方式:
upstream backends {
ip_hash; #在这指定使用了ip_hash方式
server 192.168.1.62:8080 ;
server 192.168.1.63:8080 ;
}
fair
第三方扩展的
下载: nginx-upstream-fair-master.zip
编译第三方文件:
在编译nginx的时候,
./configure --prefix=/opt/nginx --add-module=/tmp/nginx-upstream-fair-master
make & make install #如果第一次编译,
make #如果nginx之前已经编译过了, make:只是编译
cd objs #里面是扩展包,用里面的nginx替换掉外部的nginx
(用nginx文件带着第三方扩展模块,重新编译,然后编译的nginx替换掉之前的nginx文件,即可)
动态自动的,对服务器负载高的的服务器增加请求数量,自动调节
upstream backends {
fair;
server 192.168.1.62:8080 ;
server 192.168.1.63:8080 ;
}
url_hash
第三方扩展的
根据用户的url进行hash运算
电子商务网站,对于不同商品的,不同路径,在缓存了商品的独一无二的url之后,用户访问的话,都会映射到一个服务器上,如果数据在服务器上面缓存的话, 会极大提供并发。大量不同的商品在不同的服务器上面缓存起来。
3.2 负载均衡是Session的处理策略
问题
分布式负载均衡情况下 session存在的问题:
服务访问集群的时候,负载均衡策略把响应转发到不同的tomcat中,会导致下次访问请求,如果访问的不是之前的保存session的那个tomcat,那么此次就会获取不到session的值。
解决方式
三种策略,
1. 粘性session
用户锁定到某个tomcat中,
同一个用户的请求锁定到固定的某一个tomcat中,不存在session丢失的问题。
方式:ip_hash
优点:简单,session无需额外处理
缺点:缺乏容错性,这个tomcat一旦挂了,用户立刻感知到
2. session复制
session改变,会在集群里面广播,所有服务器同步session数据
优点:实时性好
缺点:网络负荷严重,可能造成后端性能低下
实现方式:
1.在tomcat的server.xml中开启 session复制开关
找到模块Engine
<Engine name="Catalina" defaultHost="localhost">
#打开注释 打开了tomcat的集群功能, tomcat7以后的版本,有默认值,可以无需配置,只需要打开这个即可
<Cuslter className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" >
<Channel className="org.apache.catalina.tries.group.GroupChannel">
<Receiver className="org.apcache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="4000" />
</Channel>
</Cluster>
</Engine>
2.在应用中通知tomcat,当前应用处于集群中
在web.xml中增加选项
<?xml version="1.0" encoding="UTF-8" ?>
...
#增加这个,标识当前应用可以处于集群当中
<distributable/>
...
在TOMCAT7以后,SERVER.XML取消CLUSTER这行注释之后表示TOMCAT开启了集群功能.TOMCAT的集群功能配备了发送器,接收器,内容转换器,还有各种监听借口,事件显示器等一系列功能.以上是在TOMCAT中的要进行修改的,对应的在开发的应用中要在WEB.XML中添加这么一条配置选项,位置如下图.添加完这两项配置后,这个应用就有了SESSION复制的功能了.
需要说明的是,因为在一台服务器上可能不止有一个TOMCAT,在配置参数的时候,不要使用默认参数,要自行进行手动配置.首先要考虑的就是端口冲突问题.比如上方的示例,如果一台服务器上有两个TOMCAT,默认指定不同端口.地址也是一样,因为开启该项功能,如果设置的是AUTO,会自动选择,如果选择错了,那么也就不能进行.通常服务器有两个网卡,一个是内网网卡,一个是外网的,我们的接收器是绑定在内网上的.因为我们的服务器集群是在内网的,所以接收器自然绑定的是内网的网卡,如果绑错了就会接收不到消息.
接收器Receiver修改:
多个tomcat存在冲突,端口修改,另外,需要指定网络
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" >
<Channel className="org.apache.catalina.tries.group.GroupChannel">
<Receiver className="org.apcache.catalina.tribes.transport.nio.NioReceiver" address="192.16.1.62" port="4002" />
</Channel>
</Cluster>
#另外一个:
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" >
<Channel className="org.apache.catalina.tries.group.GroupChannel">
<Receiver className="org.apcache.catalina.tribes.transport.nio.NioReceiver" address="192.16.1.63" port="4003" />
</Channel>
</Cluster>
3. 共享空间保存session
对于Session来说,肯定是频繁使用的,虽然你可以把它存放在数据库中,但是真正生产环境中我更推荐存放在性能更快的分布式KV数据中,例如:Memcached和Redis。
借助分布式缓存: memched,redis等,
粘性模式 MSM原理 sticky
将用户的每次请求固定到同一台服务器,需要一到多个memcached存储器,主从备份,数据一样,
一个tomcat指定一个memcached存储器,不同tomcat指定不同的memcached存储器,
用户请求到达tomcat,session会复制一份到memcached存储器,下次来如果是读取session,那么不需要读取memcached存储器,直接读取tomcat上面的session信息。
如果是修改session,tomcat修改完,数据保存到memcached存储器。
如果tomcat宕机,用户请求会转移到另外一个tomcat上面,
如果用户请求访问了另外一个tomcat,tomcat没有session,会去存储器上访问,数据保存到tomcat中。,相当于数据同步到tomcat中。
以tomcat为主存储,备份session到存储器中,tomcat中没有数据的时候,从存储器中获取。
非粘性模式 MSM原理non-sticky
memcached有多个服务,其中一个是主存储,其他是备份,数据是实时同步,
session数据写入备份存储器,同步到主存储,tomcat不保存session,读取的时候,从主存储获取。
msm配置:
1.复制jar包到tomcat/lib目录,jar分三类
-
spymemcached.har memcached java客户端 -
msm相关包
memcached-session-manager-{version}.jar 核心包
memcached-session-manager-tc{tomcat-version}-{version}.jar tomcat版本相关的包
- 序列化相关包,有多种可选方法,不设置时使用jdk自带序列化,其他可选kryo,javaolution,xstream
msm-{tools}-serializer-{version}.jar
2.配置Context,加入处理session的Manager MemcachedBackupSessionManager
Context查找顺序:
- conf/context.xml 全局配置,作用于所用应用
- conf/[enginename]/[hostname]/context.xml.default 全局配置,作用于指定host下全部应用
- conf/[enginename]/[hostname]/[contextpath].xml 只作用于contextpath指定的应用
- 应用META-INF/context.xml 只作用于本应用
- conf/server.xml 的模块下, 作用于Context docBase指定的应用
所以,只希望session管理作用于特定应用,最好用3,4方式设置,希望作用于全体,可用1,2,5设置
举个例子,
context-msm.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:192.168.1.62:11211,n2:192.168.1.63:11211"
failoverNodes="n1"
/>
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:192.168.1.62:11211,n2:192.168.1.63:11211"
failoverNodes="n1"
#忽略的模式
requestUriIgnorePattern=".*\.(jpg|png|css|js)$"
#二进制的协议,效率更高
memcachedProtocol="binary"
#指定第三方的序列化工具,性能比jdk自带的更高
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:192.168.1.62:11211,n2:192.168.1.63:11211"
sticky="false"
#粘性模式的时候, session异步备份模式,非粘性,需要同步
sessionBackupAsync="false"
#锁模式,session备份写入的时候,session才可以读取等操作,防止session操作混乱
lockingMode="auto"
#忽略的模式
requestUriIgnorePattern=".*\.(jpg|png|css|js)$"
#二进制的协议,效率更高
memcachedProtocol="binary"
#指定第三方的序列化工具,性能比jdk自带的更高
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
</Context>
4. 集群环境中应用代码应注意的问题
4.1 实体类序列化支持
实现 接口 Serializable
session里面的对象想,需要序列化
public class User implements Serializable {
private static final long serialVersionUID= 1L;
...
}
4.2 获取客户端IP地址
如果是nginx反向代理,tomcat服务器以为nginx是客户端,所以获取了nginx服务器的地址,
如果要获取真是的客户端的IP地址,需要在nginx代理配置参数
server {
listen 80;
server_name localhost;
location / {
#root html;
index index.html index.htm;
proxy_pass http://tomcats;
# 增加这个配置 ,把真实地客户端Ip地址放到请求头中,nginx 内置的环境变量:$remote_addr
proxy_set_header X-Real-IP $remote_addr;
}
...
}
设置了nginx从客户端中读取的ip,放到了请求头:"X-Real-IP"中,读取如下:
public static String getIp(HttpServletRequest request){
String remoteIp = request.GetRemoteAddr();
String headIp = request.getheader("X-Real-IP");
return headIp == null ? remoteIp : headIp;
}
4.3 nginx 中其他的信息
#负载均衡设置,将所有jsp请求发送到upstream backends 指定的服务器群上
location ~ \.jsp$ {
proxy_pass http://backends;
#真实的客户端IP
proxy_set_header X-Real_IP $remote_addr;
#请求头中Host信息, http://www.test.tt/index.jsp,用户可以取到客户端真实正确的host地址
proxy_set_header Host $host;
#代理路由信息,此处取IP有安全隐患,整个代理的路由信息,是各个nginx 等的ip信息
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#真实的用户访问协议
proxy_set_header X-Forwarded-Proto $scheme;
#默认值是default
#后端response 302时,tomcat header中location的host是http://192.168.1.62:8080
#因为tomcat收到的请求是nginx发过去的,nginx发起的请求url host是http://192.168.1.62:80
#设置default后,nginx自动把响应有中的location host部分替换成当前用户请求的host部分
#网上很多教程,将此值设置为 off 禁止了替换
#这样用户浏览器收到302后,跳到http://192.168.1.62:8080,直接将后端服务器暴露给浏览器
#所以除非特殊设置,否则不要做这种画蛇添足的操作
proxy_redirect default;
}
4.4 动静分离结果的预规划
高并发,资源类的文件,脚本,样式表,文件,
静态文件放到静态服务器,
tomcat放到动态服务器中
开发之前规划好。
总结:
负载均衡实现
session管理
5. 其他
Nginx 配置中nginx和alias的区别分析
root和alias都可以定义在location模块中,都是用来指定请求资源的真实路径;
root: *真实的路径是root指定的值加上location指定的值 。*
alias: 正如其名,alias指定的路径是location的别名,不管location的值怎么写,资源的 *真实路径都是 alias 指定的路径*
1、 alias 只能作用在location中,而root可以存在server、http和location中。
2、 alias 后面必须要用 “/” 结束,否则会找不到文件,而 root 则对 ”/” 可有可无。
本小节参考博客: https://blog.csdn.net/tuoni123/article/details/79712246
本文参考来源:极客学院 如有侵权,联系速删
|