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

目录 码农

最近部署了一个房地产的活动推广,通过砸金蛋的方式派发奖品吸引用户去售楼部看房。考虑到负载均衡,使用了 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层把该方法封装得太大,名字取得范围就很大,导致在用户端竟然调用了它(全部代码是我写的情况下都发生这种情况…团队开发的情况就可想而知)。

Let’s Encrypt – 免费的Https证书 使用总结

目录 码农

Let’s Encrypt 是一个新型的CA认证方式,简单,易得地获取 TLS/SSL 证书,能够提供 https 的web服务器加密传输。

nginx-letsencrypt

本次使用是在 Ubuntu Server 14.04 上,对web端到nginx之间进行加密,nginx到内网的Tomcat/Apache服务器不进行加密(也可以进行,但是个人觉得没有必要)。

Step 1 — 安装 Let’s Encrypt :

要想使用Let’s Encrypt,要先在服务器上安装Let’s Encrypt的客户端,现在更名为certbot,从他们的官方Github(https://github.com/certbot/certbot)上获取并安装。

安装 Git 和 bc :

sudo apt-get update;
sudo apt-get -y install git bc

安装客户端certbot:

sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
cd /opt/letsencrypt
./letsencrypt-auto --help all

将会进行安装,过程中可能会遇到我遇到的错误:no response “Installing Python packages”   FUCK GFW! 如果遇到其他错误,可以google一下,实在不行就去创建 一个issue。

至此,安装完成。

Step 2 — 生成证书 :

cd /opt/letsencrypt
./letsencrypt-auto certonly -d example.com -d www.example.com

certonly 有webroot参数,是限定在某个目录内,我们这里只需要把需要和带www.的二级域名设定,运行上面命令后,会让你输入 公司信息、你的邮箱、密码等信息。如果当前你服务器上 80端口有运行的程序,要先关闭掉。

运行完成后会出现:Output:

IMPORTANT NOTES:
 - If you lose your account credentials, you can recover through
   e-mails sent to sammy@digitalocean.com
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/example.com/fullchain.pem. Your
   cert will expire on 2016-03-15. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
 - Your account credentials have been saved in your Let's Encrypt
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Let's
   Encrypt so making regular backups of this folder is ideal.
 - If like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

这样的内容表示证书已经生成!!会提示里保存的位置,你可以进入查看了(这里是/etc/letsencrypt/live/example.com/fullchain.pem)
  • cert.pem: Your domain’s certificate
  • chain.pem: The Let’s Encrypt chain certificate
  • fullchain.pem: cert.pem and chain.pem combined
  • privkey.pem: Your certificate’s private key

好了,证书已经生成,下面我们将进行配置 nginx 。

Step 3 — 配置nginx :

在nginx的server配置中:

 listen 443 ssl;
 server_name www.example.com;
 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
 ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
 ssl_prefer_server_ciphers on;
 ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

这样,nginx就会在 https 端口 443 中监听了,在下面依然可以设置你将代理的内网服务器。配置成功后,打开你的网站查看吧。(当然最好做一个 http 的301跳转到https)

server {
 listen 80;
 server_name example.com www.example.com;
 return 301 https://www.example.com$request_uri;
}

Step 4 — renew证书 :

上面已经配置完成,但是 Let’s Encrypt 的证书有效期只有三个月,这就意味着三个月后就要更新一次。更新命令:

/opt/letsencrypt/letsencrypt-auto renew

这个命令会自动检查证书剩余时间,如果时间少于30天了,就会自动更新,为了让他自动进行更新,我们可以使用 crontab 来进行定时任务执行这个命令:

sudo crontab -e

然后在命令中输入(每半个月进行一次):

30 2 1,15 * * /etc/init.d/nginx stop
30 2 1,15 * * /opt/letsencrypt/letsencrypt-auto renew >> /var/log/le-renew.log
35 2 1,15 * * /etc/init.d/nginx reload

这个和 QuartZ 和 Spring-task 类似:

crontab0511141848

星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。
逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”
中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”
正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次。

More — 更新 Let’s Encrypt:

cd /opt/letsencrypt
sudo git pull

 

 

Mysql支持emoji图标存储

目录 码农

一 修改您的数据库、表、字段

utf8mb4完全向后兼容utf8,无乱码或其他数据丢失的形式出现。

# 对每一个数据库:
ALTER DATABASE 这里数据库名字 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
# 对每一个表:
ALTER TABLE 这里是表名字 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# 对每一个字段:
ALTER TABLE 这里是表名字 CHANGE 字段名字 重复字段名字 VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

二 修改mysql配置文件


[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

Ubuntu 中源码安装Nginx

目录 码农

在Ubuntu中,apt-get install nginx 的版本比较旧,想要使用一些高级功能就需要从官方下载,通过源码安装。 之前的安装过程一直出现问题,特将此记录在案:

准备工作:
  1. 下载 nginx : http://nginx.org/en/download.html
  2. 下载 PCRE : ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
1.1 安装PCRE :

Nginx中使用正则相关功能的依赖,所以需要安装PCRE:

tar zxvf pcre-8.38.tar.gz
cd pcre-8.38
./configure --prefix=/usr/local/pcre-8.38
#安装到/usr/local/pcre-8.38 下
make
sudo make install

如果上面命令报错

libtool: compile: unrecognized option `-DHAVE_CONFIG_H'
libtool: compile: Try `libtool --help' for more information.
make[1]: *** [pcrecpp.lo] Error 1

则安装:build-essential

apt-get install build-essential
1.2 安装依赖库:
sudo apt-get install libssl1.0.0 libssl-dev openssl zlib1g-dev

如果出现错误如:

The following packages have unmet dependencies:
libssl-dev : Depends: libssl1.0.0 (= 1.0.1f-1ubuntu2.21) but 1.0.1f-1ubuntu9 is to be installed
Recommends: libssl-doc but it is not going to be installed
E: Unable to correct problems, you have held broken packages.

在对应依赖后面加 /trusty (依赖冲突) 如:

sudo apt-get install libssl1.0.0/trusty libssl-dev/trusty openssl/trusty zlib1g-dev/trusty
1.3 安装nginx:
tar zxvf nginx-1.10.1.tar.gz
cd nginx-1.10.1
./configure --prefix=/usr/local/nginx --pid-path=/var/run/nginx.pid --with-http_stub_status_module --with-http_ssl_module --with-pcre=/root/pcre-8.38
make
sudo make install

注意:–with-pcre 的值为 pcre 解压后的文件目录,不是指定的安装目录,切记;
完成之后,需要将/usr/local/nginx/logs 目录设置为可写权限,里面是一系列得日志文件:

# sudo chmod 777 -R /usr/local/nginx/logs
1.4 注意事项

在源码安装的时候,需要安装编译环境,gcc ubuntu 下,可以直接 apt-get 安装:

 sudo apt-get install libtool
 sudo apt-get install gcc-c++

安装 gcc 出现如下错误:
安装 gcc-c++出错

Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Couldn't find package gcc-c

则先如下操作,再次安装:

 sudo apt-get install build-essential
 sudo apt-get update
 sudo apt-get upgrade
 sudo apt-get install gcc-c++

1.5 启动和停止/重启命令:

sudo /etc/init.d/nginx start   
sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx restart

Maven 项目问题总结

目录 码农

1. 项目初始化:

项目经常拷来拷去,有时候会报一个很奇怪的错误。明明源码一模一样,为什么复制到另一台机器上就会报错呢?项目不管是移动还是拷贝做好这几步:

  • 项目所在的目录,在.settings子目录里面,用文本编辑器打开org.eclipse.wst.common.project.facet.core.xml配置文件

    <?xml version=”1.0″ encoding=”UTF-8″?>
    <faceted-project>
    <fixed facet=”wst.jsdt.web”/>
    <installed facet=”java” version=”1.8″/>
    <installed facet=”jst.web” version=”3.0″/>
    <installed facet=”wst.jsdt.web” version=”1.0″/>
    </faceted-project>

    将 java 修改为对应的版本,jst.web 修改为 3.0;

    注意:

    1. 查看项目Java版本,在Eclipse环境中,鼠标右键选择项目,点击Properties,选择Java Compiler 可以在窗口右边看到编译器版本,如图:
    20160707113426
    一定要和前面的 java版本一致。

    2. web 项目 web.xml 版本一定 和 jst.web 版本一致,3.0 因为为:

    <web-app xmlns=”http://java.sun.com/xml/ns/javaee”
    xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
    xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd”
    version=”3.0″>
    <display-name>Servlet 3.0 Web Application</display-name>
    </web-app>

  • pom.xml 模版:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>com. projectName </groupId>
    	<artifactId> projectName </artifactId>
    	<packaging>war</packaging>
    	<version>2.0.0.01</version>
    	<name> projectName  Maven Webapp</name>
    	<url>http://maven.apache.org</url>
    	
    	<dependencies>
    		<dependency>
    			<groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>4.12</version>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    	
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        </properties>
    	<build>
    		<finalName> projectName </finalName>
    		<plugins>
    	        <plugin>
    	            <artifactId>maven-compiler-plugin</artifactId>
    	            <configuration>
    	                <source>1.8</source>
    	                <target>1.8</target>
    	            </configuration>
    	        </plugin>
    	    </plugins>
    	</build>
    	<repositories>
    		<repository>
    			<id>com.springsource.repository.bundles.release</id>
    			<name>Spring Maven Repository Repository</name>
    			<url>http://repository.springsource.com/maven/bundles/release</url>
    		</repository>
    		<repository>
    			<id>jboss</id>
    			<url>https://repository.jboss.org/nexus/content/groups/public/</url>
    		</repository>
    		<repository>
    			<id>sonatype</id>
    			<name>Sonatype Repository</name>
    			<url>http://repository.sonatype.org/content/groups/public/</url>
    		</repository>
    	</repositories>
    </project>

Linux中JDK安装:通过命令行安装和手动安装

目录 码农

命令行安装:( 推荐手动安装)

因为授权问题,Oracle JDK不包含在官方的PPA列表中,但感谢那些自由软件的贡献者,他们制作了一个PPA可以从Oracle官方下载最新版JDK到本地,自动安装和升级。 注意的是这个PPA是一个alpha版本,作者不承诺任何保障,使用者自己承担风险。(PPA:Personal Package Archive)

1.—-执行以下命令添加PPA,然后更新APT。
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update

2.—-如果报错(未报错忽略第二步),需要安装 add-apt-repository 功能:
sudo apt-get install python-software-properties
sudo apt-get install software-properties-common

3.—-更新完成后再搜索一下JDK包(有信息表示成功):
$ sudo apt-cache search oracle-java

oracle-jdk7-installer – Oracle JDK7 Installer meta package
oracle-java7-installer – Oracle Java(TM) Development Kit (JDK) 7
oracle-java6-installer – Oracle Java(TM) Development Kit (JDK) 6
oracle-java8-installer – Oracle Java(TM) Development Kit (JDK) 8
oracle-java7-set-default – Set Oracle JDK 7 as default Java
oracle-java6-set-default – Set Oracle JDK 6 as default Java
oracle-java8-set-default – Set Oracle JDK 8 as default Java

4.—搜索到了最新的JDK,选择安装Java8,执行:
sudo apt-get install oracle-java8-installer
安装都是自动完成的,中间会弹出提示要求接受Oracle的授权条款,全部同意就可以了。

5.—-如果需要设置环境变量可以执行:
sudo apt-get install oracle-java8-set-default

最后执行命令: java -version 如果出现的是 jdk8的信息就算成功了。javac java javah 都可以得到验证。

 

手动解压安装:

1.–从官网下载对应的JDK版本,放到系统某个文件夹中,个人推荐 /usr/local/java ,然后解压:
tar zxvf XXXXX.tar.gz

2.–编辑 /etc/profile ,修改环境变量:
export JAVA_HOME=/usr/local/java/jdk1.8.0_101
export CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH

3.–让配置生效:source /etc/profile

附.–建议使用vim,如果没有vim,安装:
sudo apt-get install -y vim
sudo update-alternatives --set editor /usr/bin/vim.basic

–Debian 系统要先安装sudo:
apt-get install sudo -y

最后执行命令: java -version 如果出现的是 jdk的信息就算成功了。javac java javah 都可以得到验证。