记一次活动系统的部署,对服务器的优化,对编码的反思

目录 码农

最近部署了一个房地产的活动推广,通过砸金蛋的方式派发奖品吸引用户去售楼部看房。考虑到负载均衡,使用了 nginx + tomcat + mysql 的分离部署方式,阿里云的内网流量是免费的,所以按量付费的情况会比较划算。下面记录对nginx、tomcat的配置优化。

tomcat:

tomcat默认采用Bio的模式,虽然自带有Nio,但是性能提升不明显,使用apr库性能提升更大,所以我们将:1 下载tomcat,2 安装apr库,3 安装tomcat-native (利用 APR 来提升Tomcat性能的本地API)

1. 下载tomcat:我比较喜欢把应用放在/opt 目录下 进入 opt 目录,下载tomcat8(tomcat官网有下载地址):

cd /opt
mkdir install
cd /opt/install
wget http://mirrors.hust.edu.cn/apache/tomcat/tomcat-8/v8.0.39/bin/apache-tomcat-8.0.39.tar.gz
cd /opt
tar zxvf /opt/install/apache-tomcat-8.0.39.tar.gz
# 创建一个install目录,用来放安装过程中的一些文件,看个人喜好。

2. 安装apr库:http://apr.apache.org/download.cgi 这里去下载,会有三个包需要安装:

  • APR主库:
cd /opt/install
wget http://mirrors.tuna.tsinghua.edu.cn/apache//apr/apr-1.5.2.tar.gz
tar zxvf apr-1.5.2.tar.gz
cd apr-1.5.2
./configure --prefix=/usr/local/apr
make
sudo make install
# 工具类都装到 /usr/local 符合传统,我会把常用的放到 /opt 下,看个人习惯吧
  • APR iconv:
cd /opt/install
wget http://mirrors.tuna.tsinghua.edu.cn/apache//apr/apr-iconv-1.2.1.tar.gz
tar zxvf apr-iconv-1.2.1.tar.gz
cd apr-iconv-1.2.1
./configure --prefix=/usr/local/apr-iconv --with-apr=/usr/local/apr
make
sudo make install
  • APR-util:
cd /opt/install
wget http://mirrors.tuna.tsinghua.edu.cn/apache//apr/apr-util-1.5.4.tar.gz
tar zxvf apr-util-1.5.4.tar.gz
cd apr-util-1.5.4
./configure --with-apr=/usr/local/apr
make
sudo make install
# 我都是把下载到包和安装过程中编译到东西统一放到了 /opt/install 目录,看个人喜好。

安装好了后,在系统变量中添加,然后 source /etc/profile 使变量生效:

vim /etc/profile
末尾添加:export LD_LIBRARY_PATH=/usr/local/apr/lib
source /etc/profile

3. 安装Tomcat Native 来调用apr库,提升tomcat性能,需要使用 openssl 1.0.2 以上版本(通过命令 openssl version 查看版本来决定是否安装openssl:

cd /opt/install
wget https://www.openssl.org/source/openssl-1.1.0c.tar.gz
tar zxvf openssl-1.1.0c.tar.gz
cd openssl-1.1.0c
./config --prefix=/usr/local/openssl -fPIC
make
sudo make install
mv /usr/bin/openssl ~
ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl
openssl version
# -fPIC 参数请自行百度, install 后是为了更新软链
# 出错加上下面这个:
ln -s /usr/local/lib/libssl.so.1.1 /usr/lib/libssl.so.1.1 
ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/libcrypto.so.1.1
cd /opt/install
wget http://mirrors.cnnic.cn/apache/tomcat/tomcat-connectors/native/1.2.10/source/tomcat-native-1.2.10-src.tar.gz
tar zxvf tomcat-native-1.2.10-src.tar.gz
cd tomcat-native-1.2.10-src/native
./configure --with-apr=/usr/local/apr --with-ssl=/usr/bin
make
sudo make install

tomcat 所依赖的库安装完毕,现在设置tomcat的配置文件:

<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
 <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="off" />
 <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
 <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

 <Service name="Catalina">
 <Connector port="8080" 
 protocol="org.apache.coyote.http11.Http11AprProtocol"
 connectionTimeout="20000"
 redirectPort="8443"
 maxThreads="500" 
 minSpareThreads="20" 
 acceptCount="300" 
 disableUploadTimeout="true" 
 enableLookups="false" 
 URIEncoding="UTF-8" />

 <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
 <Engine name="Catalina" defaultHost="localhost">
 <Host name="localhost" appBase="/opt/webapps"
 unpackWARs="true" autoDeploy="true">
 <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
 prefix="localhost_access_log" suffix=".txt"
 pattern="%h %l %u %t &quot;%r&quot; %s %b" />
 <Context path="" docBase="/opt/webapps/zjd" reloadable="false"/>
 </Host>
 </Engine>
 </Service>
</Server>

tomcat 的配置文件就是这样,可以查询每项的意义自己调整。tomcat最主要的优化在于JVM 的设置,这篇文章Linux中JDK安装:通过命令行安装和手动安装 手动安装的方式,环境变量中的 JAVA_OPTS 进行设置,本次优化后的环境变量:(记得 source /etc/profile 使其生效)

export JAVA_HOME=/usr/local/java/jdk1.8.0_112
export JAVA_OPTS="-server -Xms1024m -Xmx3072m"
export CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
export CATALINA_HOME=/opt/tomcat
export LD_LIBRARY_PATH=/usr/local/apr/lib

nginx:

nginx需要安装最新的稳定版,安装请参考之前的文章,因为我们tomcat会采用 Bio、Nio、Apr,所以需要升级openssl到更新版本,记得先装新版本的openssl(参考上面tomcat部分),在安装依赖库的时候 注意不要再安装 openssl 了!之前的这篇文章Ubuntu 中源码安装Nginx ,好了 nginx 也装好了,其调优的配置文件:

worker_processes 2;# 系统有几个核心就设置为多少
events {
 worker_connections 1024;
}
http {
 include mime.types;
 default_type application/octet-stream;
 sendfile on;
 tcp_nopush on;
 keepalive_timeout 65;
 gzip on;
 gzip_vary on;
 gzip_proxied any;
 gzip_min_length 10240;

 upstream servers {
 server 127.0.0.1:8080 fail_timeout=0;
 }
 server {
 listen 80;
 server_name xxxxxx.com;

 location ~ .*\.(gif|jpg|jpeg|png|ico|swf)$ {
 root /opt/webapps/zjd/asset/static; 
 expires 30d;
 }
 
 location / {
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header Host $http_host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_redirect off;
 proxy_connect_timeout 240;
 proxy_send_timeout 240;
 proxy_read_timeout 240;
 proxy_pass http://servers;
 }
 
 error_page 400 500 /opt/tomcat/webapps/zjd/asset/views/error.html;
 }

}

项目打包上传就开始运行了,两核4G内存,完全无压力,内存最高才到 37%,cpu 就没上过15%。。。刚开始就这么大人同时砸(因为开始时间是定好了的,所以一开始的压力最大)后台数据:

qq20161217-1634132x

代码上的反思:

  1. 改动很小的(基本上不改变)要使用缓存,开发时就要想到这点,架构上就引入缓存,或者部署上线前要对这块进行优化,重复读取是不可取的。
  2. 单一职责,本次上线后分析日志,发现有一个请求速度很慢,跟踪发现调用了后台管理员才会使用的复杂sql,而这是因为service层把该方法封装得太大,名字取得范围就很大,导致在用户端竟然调用了它(全部代码是我写的情况下都发生这种情况…团队开发的情况就可想而知)。