一、简介
最近新上了一个营销项目(和微信结合),后台用的是Tomcat。开始上线的时候因为人数不多感觉没太多问题,随着正式环境的发布,开人有人反映服务器页面无法打开,连入tomcat查看时发现连接数已满且CPU也用到了极限,初始的架构如下图所示,其使用1台tomcat和一台数据库服务器。
该业务系统主要用于微信营销,顾客在微信上下单购买(抢)对应的商品,抢购成功后该商品(券)会自动生成条形码保存在该用户的注册信息中。用户凭券到实体店完成支付和取货操作。因为涉及券核销的问题(支付完成后即时核销),因此该业务无法放在云端(核销的数据和实体店销售数据需即时交互),最终只能通过本地的方案来解决。
首先考虑到的是将网上的连接通过负载均衡的方式分散来减轻服务器的压力,这方面可以使用nginx代理来实现;其次需要解决的问题是session,对比了几种方案发现nginx内置的ip_hash策略可以解决该问题,最终网络的架构变成了下图所示,在该方案中增加了4台服务器,其中一台nginx负载转发,另外四台为新增的tomcat服务。
二、安装Nginx
Nginx的安装配置十分简单,我这里实际用的是tengine版本,具体的安装方法可以参考” nginx配置指南之一”。这里需要注意的是它的编译参数,记得它的配置文件和日志文件的存放位置。
三、优化系统资源
文件限制
Linux系统中文件的打开个数及单用户最多拥有的进程数是有限制的,可以通过“ulimit -n”或“ulimit -u”来查看,详细的设置可以参考“ORACLE 11G在Linux下的标准安装方法(上)”。先修改/etc/security/limit.conf中的限制,如下图所示。
内核优化
内核中涉及的TCP相关的选项在大并发连接的情况下也需要做相应的调整否则可以出“TCP: time wait bucket table overflow” 的错误提示。具体修改/etc/sysctl.conf文件,如有特殊要求请结合实际情况修改。具体如下所示:
tcp_max_tw_buckets 系统在同时所处理的最大 timewait sockets 数目。如果超过此数的话﹐time-waitsocket 会被立即删除并且显示警告信息。
ip_local_port_range 用于向外连接的端口范围。
netdev_max_backlog 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目,对重负载服务器而言,该值需要调高一点。
tcp_max_orphans 处理不属于任何进程的套接字数量,不属于任程进程的进程就是“孤儿(orphans)进程”,在快速、大量的连接中这种进程会很多因此要适当的设置该参数,也可以用来防御简单的DoS攻击。
tcp_max_syn_backlog 用于记录尚未收到客户端确认信息的连接请求的最大值。
四、优化Nginx
epoll为linux下的必须模型,适用于2.6以后的内核版本,如下图所示:
优化代理配置
需要注意的是“proxy_max_temp_file_size”,它主要用来设置临时文件的最大值。当被请求的文件内容大于代理缓存的大小时,该文件会被存储到这个临时文件,但是如果被请求文件的内容大于这个值的时候,那么将会从上游的服务器(被代理的服务器)上直接同步传递,而不再使用代理缓存。该指令的默认值为1GB,如果设置为0,那么意味着禁止使用临时文件。
五、配置Nginx
Nginx配置如下所示,其中upstreambackend配置的是后端的tomcat应用,ip_hash表示启用该策略,用户的目的是为了解决后端session不一致的问题(在nginx前端还有CDN或是局域网的环境中须慎用)。
server段配置的是转发的路径和端口,需要注意“proxy_set_header Host $host:8162;”的写法。如果该变量后没有加8162端口则实际的转发会导致页面无法正常显示。其后的两条语句可以参考nginx日志的记录内容,主要用来记录外网实际的访问请求。
log_format字段用来生成指定的日志格式文件,相应的变量对应日志文件中的访问记录,可以对照下图来查看。
六、Nginx安全限制
随着业务的增加,网络连接的流量越来越大,合理的控制访问请求及连接数非常重要,否则仍会出现失去响应的情况。
七、增加IP限制功能
最简单也最容易实现的的方式是Nginx自带的IP访问控制,由模块ngx_http_limit_conn_module和来ngx_http_limit_req_module实现,通过它们可以实现对IP地址连接数及服务器访问请求数的控制。
要限制连接,必须先有一个容器对连接进行计数,在http段加入如下代码:"zone=" 给它一个名字,可以随便叫,这个名字要跟下面的limit_conn 一致,$binary_remote_addr = 用二进制来储存客户端的地址,1m 可以储存 32000 个并发会话。
限制请求数的方式和限制连接数类似,其中“rate=10r/s”表示一秒中处理的请求为10个,如果需要限制为每分钟不超过30个则表示为“rate=30r/m”;一个具体的设定如下所示:
http { limit_req_zone$binary_remote_addr zone=one:10m rate=10r/s; limit_conn_zone$binary_remote_addr zone=two:10m; }
在server段中加入以下内容,其中“burst=5”表示同时允许超过频率限制的请求数不多于5个;“limit_conn two 15”表示对于同一IP的连接数限制为15个。
limit_req zone=one burst=5; limit_conn two 15;
后续WAF模块的添加以及nginx相关的监控待整理。