才过去短短的一个礼拜,网站就快到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看到下图表示安装成功:
zendopcache的测试成绩
给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是否安装成功,如下表示安装成功
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,访问如下
然后就是运用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呢,没想到会有这么多,看来不拿出点真本事不行了,我对领导说:“给我一个礼拜的时间,保证给你一个强悍的架构”,就这样我的架构之路开始了……
欲知后事如何,请听下回分解