才过去短短的一个礼拜,网站就快到10万pv了,真实佩服公司的营销手段啊,网站越来越慢了,这下老大可不高兴了,对我说:“村长啊,咱们这速度用户体验不咋地啊,过两天就没人来了,公司还指望这个赚钱呢,你赶紧’敏捷‘一下!”,我也着急啊,指望项目赚钱公司给我涨薪呢,这要是服务挂了娶媳妇的钱都没了,于是赶紧进行优化。

1、Nginx优化

#nginx推荐配置文件
worker_processes  8;    #CPU多少核就写多少,利用cpu多核的优势
error_log  logs/error.log warn; #随时记录错误
pid        logs/nginx.pid;
worker_rlimit_nofile 51200;
events {
    use epoll;
    worker_connections  51200;   #允许更多的请求量
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local]'
                      ' "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
    sendfile       on;
    tcp_nopush     on;
    tcp_nodelay    on;
    client_header_buffer_size 32k;
    large_client_header_buffers 4 32k;
    client_max_body_size 8m;
    server_tokens off;
    keepalive_timeout  60;
    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
    fastcgi_buffer_size 256k;
    fastcgi_buffers 2 256k;
    fastcgi_busy_buffers_size 256k;
    fastcgi_temp_file_write_size 256k;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
    gzip  on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    gzip_http_version 1.1;
    gzip_comp_level 2;
    gzip_types text/plain application/x-javascript text/css application/xml text/javascript;
    gzip_vary on;
    server {
        listen       80;
        server_name  a.bcd.com;
        root /data/www/domain;
        index index.html index.php;
        access_log  logs/a.access.log  main;
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
        try_files $uri $uri/ /index.php$request_uri;
        location ~ .*\.php {
            fastcgi_pass   unix:/data/soft/php/var/run/php.sock;
            fastcgi_index  index.php;
            include        fastcgi_params;
            fastcgi_split_path_info ^(.+\.php)(.*)$;
            fastcgi_param  PATH_INFO $fastcgi_path_info;
            fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        }
        location ~ .*\.(gif|jpg|png|swf|bmp|jpeg)$ {
            expires 7d;
        }
        location ~ .*\.(js|css)?$ {
            expires 1h;
        }
    }
}

2、php优化(配置完通过/data/soft/php/sbin/php-fpm -t检测一下配置,其他命令网上有很多教程

vim /data/soft/php/etc/php-fpm.conf
#找到下面这句,默认是listen = 127.0.0.1
listen = /data/soft/php/var/run/php.sock
#取消掉注释
pid = run/php-fpm.pid
pm = dynamic #对于专用服务器,pm可以设置为static。
#如何控制子进程,选项有static和dynamic。如果选择static,则由pm.max_children指定固定的子进程数。如果选择dynamic,则由下开参数决定(每个进程正常运行一段时间大概占用20M-30M,所以根据自己的内存计算,比如我分配给php的内存是4G):
pm.max_children = 200 #,子进程最大数
pm.start_servers = 100 #,启动时的进程数
pm.min_spare_servers = 50 #,保证空闲进程数最小值,如果空闲进程小于此值,则创建新的子进程
pm.max_spare_servers = 150 #,保证空闲进程数最大值,如果空闲进程大于此值,则进行清理接下来就是优化


接下来通过安装zendopcache缓存php代码,我们都知道php是解释型语言,比java这种编译型的语言有一个很吃亏的地方,那就是php每次都要去硬盘读取代码,然后解释成中间码,然后在执行,而编译型语言就省略了这一步,因为他已经编译好了,安装zendocache的目的就是把php的代码提前“编译”到内存中,这样速度会快很多。

tar zxvf zendopcache-7.0.2.tgz
cd zendopcache-7.0.2
/data/soft/php/bin/phpize
./configure --with-php-config=/data/soft/php/bin/php-config
make && make install


执行成功后最后会出现一条Installing shared extensions:     /data/soft/php/lib/php/extensions/no-debug-non-zts-20100525/,把这个目录记录下来,打开php.ini

vim /data/soft/php/etc/php.ini
#找到下面这个地方,去掉注释然后把目录改成刚才的目录
extension_dir = "/data/soft/php/lib/php/extensions/no-debug-non-zts-20100525/"
#然后在页面的最下面写上
zend_extension=/data/soft/php/lib/php/extensions/no-debug-non-zts-20100525/opcache.so
opcache.enable_cli=1
opcache.memory_consumption=128 #共享内存大小, 这个根据你们的需求可调
opcache.interned_strings_buffer=8 #interned string的内存大小, 也可调
opcache.max_accelerated_files=4000 #最大缓存的文件数目
opcache.revalidate_freq=60 #60s检查一次文件更新
opcache.fast_shutdown=1 #打开快速关闭, 打开这个在PHP Request Shutdown的
                        #时候会收内存的速度会提高
opcache.save_comments=0 #不保存文件/函数的注释


重启php-fpm,然后通过phpinfo看到下图表示安装成功:

210615911.png

210618129.png

zendopcache的测试成绩

210645420.png


给php安装memcached和redis扩展

#安装php的memcached和redis扩展
#安装memcached扩展的时候需要依赖libmemcached,本来选择的最新版libmemcached-1.0.17.tar.gz,结果报错,查了很多资料都不行,结果换了一个版本就好了
tar zxvf libmemcahced-1.0.16.tar.gz
cd libmemcahced-1.0.16
./configure --prefix=/data/soft/libmemcahced
make && make install
#安装memcahced扩展
tar memcached-2.1.0.tgz
cd memcached-2.1.0
/data/soft/php/bin/phpize
./configure --with-php-config=/data/soft/php/bin/php-config --with-libmemcached=/data/soft/libmemcached


#安装php的memcached和redis扩展
#安装memcached扩展的时候需要依赖libmemcached,本来选择的最新版libmemcached-1.0.17.tar.gz,结果报错,查了很多资料都不行,结果换了一个版本就好了
tarzxvf libmemcahced-1.0.16.tar.gz
cdlibmemcahced-1.0.16
./configure--prefix=/data/soft/libmemcahced
make&& makeinstall
#安装memcahced扩展
tarzxvf memcached-2.1.0.tgz
cdmemcached-2.1.0
/data/soft/php/bin/phpize
./configure--with-php-config=/data/soft/php/bin/php-config--with-libmemcached-dir=/data/soft/libmemcached/
make&& makeinstall
#安装redis扩展
tarzxvf redis-2.2.4.tgz
cdredis-2.2.4
/data/soft/php/bin/phpize
./configure--with-php-config=/data/soft/php/bin/php-config
make&& makeinstall
#重启php-fpm
kill-USR2 `cat/data/soft/php/var/run/php-fpm.pid`
#修改php.ini
vim /data/soft/php/etc/php.ini
#在页面下面添加
[memcached]
extension=memcached.so
[redis]
extension=redis.so

查看phpinfo是否安装成功,如下表示安装成功

132507104.png

132509621.png

3、优化MySQL(声明一下,很多书中都说根据一定比例去设置,这种方法是没有什么科学根据的,还有不是设置的选项越多性能越好,而是根据压力测试一点点尝试出来的,所以最好根据压力测试作为配置的标准)

#mysql5.5以后innodb优化的已经很好了,完全可以代替MyISAM了,所以下面主要针对Innodb引擎
[mysqld]
basedir = /data/soft/mysql
datadir = /data/soft/mysql/data
port = 3306
server_id = 1
socket = /tmp/mysqld.sock
default_storage_engine = InnoDB
log-bin = binlog
expire_logs_days = 14
max_binlog_size = 5G
binlog_cache_size = 10M
max_binlog_cache_size = 20M
slow_query_log
long_query_time = 2
slow_query_log_file = /data/soft/mysql/data/slow.log
open_files_limit = 65535
innodb = FORCE
innodb_buffer_pool_size = 5G
innodb_log_file_size = 1G
#query_cache_size设置0的原因就是我这里写入的要求比较多,缓存的话反而性能降低
query_cache_size = 0
thread_cache_size = 64
table_definition_cache = 512
table_open_cache = 512
#设置连接最大数,可以设置大一点,对性能影响不大,而且避免造成瓶颈
max_connections = 2000
sort_buffer_size = 10M
#一次请求
max_allowed_packet = 6M
#sql_mode设置用于设置很多安全方面的东西,具体可以百度一下
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES


mysql性能就在那摆着呢,就算优化的再好也是有I/O瓶颈的,如果换做内存就好多了,我这里选择了Redis和Memcached,Redis用作消息队列和一些需要长久存储但是不重要的数据,比如排行等,而Memcahced用来缓存一些不需要持久话的数据,比如session,MySQL查询出来的数据等,下面是为了应用两个工具的安装步骤:

tar -zxvf memcached-1.4.17.tar.gz
cd memcached-1.4.17
./configure --prefix=/data/soft/memcached
make && make install
#安装完以后就启动一下memcached
/data/soft/memcached/bin/memcached -d -m 64m -c 10240
#查看一下是否启动
netstat -lnp | grep 11211
#安装Redis,redis和别的软件有点不一样,不需要configure直接make就行
tar -zxvf redis-2.8.3.tar.gz
mv redis-2.8.3 /data/soft/redis
make
#在下面有一redis.conf,修改如下
#1,是否以后台进程运行,默认为no
daemonize no
#2,如以后台进程运行,则需指定一个pid,默认为/var/run/redis.pid
pidfile /var/run/redis.pid
#3,监听端口,默认为6379
port 6379
#4,绑定主机IP,默认值为127.0.0.1(注释)
bind 127.0.0.1
#5,超时时间,默认为300(秒)
timeout 300
#6,日志记录等级,有4个可选值,debug,verbose(默认值),notice,warning
loglevel verbose
#7,日志记录方式,默认值为stdout
logfile stdout
#8,可用数据库数,默认值为16,默认数据库为0
databases 16
#9,指出在多长时间内,有多少次更新操作,就将数据同步到数据文件。这个可以多个条件配合,比如默认配置文件中的设置,就设置了三个条件。
900秒(15分钟)内至少有1个key被改变
save 900 1
300秒(5分钟)内至少有10个key被改变
save 300 10
#10,存储至本地数据库时是否压缩数据,默认为yes
rdbcompression yes
#11,本地数据库文件名,默认值为dump.rdb
dbfilename /root/redis_db/dump.rdb
#12,本地数据库存放路径,默认值为 ./
dir /root/redis_db/
#13,当本机为从服务时,设置主服务的IP及端口(注释)
slaveof
#14,当本机为从服务时,设置主服务的连接密码(注释)
masterauth
#15,连接密码(注释)
requirepass foobared
#16,最大客户端连接数,默认不限制(注释)
#maxclients 128
#17,设置最大内存,达到最大内存设置后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理后,任到达最大内存设置,将无法再进行写入操作。(注释)
maxmemory
#18,是否在每次更新操作后进行日志记录,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认值为no
appendonly yes
#19,更新日志文件名,默认值为appendonly.aof(注释)
appendfilename /root/redis_db/appendonly.aof
#20,更新日志条件,共有3个可选值。no表示等操作系统进行数据缓存同步到磁盘,always表示每次更新操作后手动调用fsync()将数据写到磁盘,everysec表示每秒同步一次(默认值)。
appendfsync everysec
#21,是否使用虚拟内存,默认值为no
vm-enabled yes
#22,虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
vm-swap-file /tmp/redis.swap
#23,将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的 (Redis的索引数据就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0。
vm-max-memory 0
#24,虚拟内存文件以块存储,每块32bytes
vm-page-size 32
#25,虚拟内在文件的最大数
vm-pages 134217728
#26,可以设置访问swap文件的线程数,设置最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的.可能会造成比较长时间的延迟,但是对数据完整性有很好的保证.
vm-max-threads 4
#27,把小的输出缓存放在一起,以便能够在一个TCP packet中为客户端发送多个响应,具体原理和真实效果我不是很清楚。所以根据注释,你不是很确定的时候就设置成yes
glueoutputbuf yes
#28,在redis 2.0中引入了hash数据结构。当hash中包含超过指定元素个数并且最大的元素没有超过临界时,hash将以一种特殊的编码方式(大大减少内存使用)来存储,这里可以设置这两个临界值
hash-max-zipmap-entries 64
#29,hash中一个元素的最大值
hash-max-zipmap-value 512
#30,开启之后,redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash,可以降低内存的使用。当你的使 用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。如果没有这么严格的实时性要求,可以设置 为yes,以便能够尽可能快的释放内存
activerehashing yes

配置完redis运行/data/soft/redis/src/redis-server /data/soft/redis/redis.conf,访问如下

122111414.png


然后就是运用explain分析sql,优化索引


4、优化Linux

#调整最大文件打开数
vim /etc/rc.local
#在下面添加
ulimit -SHn 65535
#优化linux内核,一下参考张晏的《实战Nginx》和余洪春的《构建高可用Linux》
vim /etc/sysctl.conf
#添加
net.ipv4.tcp_max_syn_backlog = 65536
net.core.netdev_max_backlog = 32768
net.core.somaxconn = 32768
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.ip_local_port_range = 1024 65535
#立即生效内核配置
/sbin/sysctl -p


经过各种修改以后,速度终于上来了,负载也下来了,赶紧向老大汇报,老大听后并没有特别高兴,只是说:“村长啊,咱们公司的线下的业务团队很给力啊,给咱们公司拉来了很多客户啊,平均每天都有几千pv的增长啊,你的服务大概能撑多长时间呢”,当时我半天没说出话来,我还以为就是撑着这10万pv呢,没想到会有这么多,看来不拿出点真本事不行了,我对领导说:“给我一个礼拜的时间,保证给你一个强悍的架构”,就这样我的架构之路开始了……

欲知后事如何,请听下回分解