nginx负载均衡解释

Geek小A 发表了文章 0 个评论 3123 次浏览 2015-11-03 21:25 来自相关话题

一、特点 1.1 应用情况 Nginx做为一个强大的Web服务器软件,具有高性能、高并发性和低内存占用的特点。此外,其也能够提供强大的反向代理功能。俄罗斯大约有超过20%的虚拟主机采用Nginx作为反向代理服务器,在国内也 ...查看全部


一、特点


1.1 应用情况
Nginx做为一个强大的Web服务器软件,具有高性能、高并发性和低内存占用的特点。此外,其也能够提供强大的反向代理功能。俄罗斯大约有超过20%的虚拟主机采用Nginx作为反向代理服务器,在国内也有腾讯、新浪、网易等多家网站在使用Nginx作为反向代理服务器。据Netcraft统计,世界上最繁忙的网站中有11.48%使用Nginx作为其服务器或者代理服务器。基于反向代理的功能,Nginx作为负载均衡主要有以下几点理由:
    []高并发连接[/][]内存消耗少[/][]配置文件非常简单[/][]成本低廉[/][]支持Rewrite重写规则[/][]内置的健康检查功能[/][]节省带宽[/][]稳定性高[/]

1.2 架构

nginx_arch.jpg
nginx在启动后,会以daemon的方式在后台运行,后台进程包含一个master进程和多个worker进程。工作进程以非特权用户运行。 master进程主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。worker进程则是处理基本的网络事件。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。开发模型:epoll和kqueue。
    []支持的事件机制:kqueue、epoll、rt signals、/dev/poll 、event ports、select以及poll。[/][]支持的kqueue特性包括EV_CLEAR、EV_DISABLE、NOTE_LOWAT、EV_EOF,可用数据的数量,错误代码.[/][]支持sendfile、sendfile64和sendfilev;文件AIO;DIRECTIO;支持Accept-filters和TCP_DEFER_ACCEP.[/]
1.3 性能Nginx的高并发,官方测试支持5万并发连接。实际生产环境能到2-3万并发连接数。10000个非活跃的HTTP keep-alive 连接仅占用约2.5MB内存。三万并发连接下,10个Nginx进程,消耗内存150M。淘宝tengine团队说测试结果是“24G内存机器上,处理并发请求可达200万”。

二、负载均衡

2.1 协议支持Nginx工作在网络的7层,可以针对http应用本身来做分流策略。支持七层HTTP、HTTPS协议的负载均衡。对四层协议的支持需要第三方插件-yaoweibin的ngx_tcp_proxy_module实现了tcp upstream。https://github.com/yaoweibin/nginx_tcp_proxy_module此外,nginx本身也逐渐在完善对其他协议的支持:
    []Nginx 1.3.13 开发版支持WebSocket代理。[/][]Nginx 1.3.15开发版支持SPDY。[/]
2.2 均衡策略nginx的负载均衡策略可以划分为两大类:内置策略和扩展策略。内置策略包含加权轮询和ip hash,在默认情况下这两种策略会编译进nginx内核,只需在nginx配置中指明参数即可。扩展策略有很多,如fair、通用hash、consistent hash等,默认不编译进nginx内核。 1、加权轮询(weighted round robin)轮询的原理很简单,首先我们介绍一下轮询的基本流程。如下是处理一次请求的流程图:
ngx_wr_process.jpg
图中有两点需要注意,第一,如果可以把加权轮询算法分为先深搜索和先广搜索,那么nginx采用的是先深搜索算法,即将首先将请求都分给高权重的机器,直到该机器的权值降到了比其他机器低,才开始将请求分给下一个高权重的机器;第二,当所有后端机器都down掉时,nginx会立即将所有机器的标志位清成初始状态,以避免造成所有的机器都处在timeout的状态,从而导致整个前端被夯住。 2、ip haship hash是nginx内置的另一个负载均衡的策略,流程和轮询很类似,只是其中的算法和具体的策略有些变化,如下图所示:
ngx_iphash_process.jpg
ip hash算法的核心实现如下:
for(i = 0;i < 3;i++){     hash = (hash * 113 + iphp->addr) % 6271; } p = hash % iphp->rrp.peers->number;
从代码中可以看出,hash值既与ip有关又与后端机器的数量有关。经过测试,上述算法可以连续产生1045个互异的value,这是该算法的硬限制。对此nginx使用了保护机制,当经过20次hash仍然找不到可用的机器时,算法退化成轮询。因此,从本质上说,ip hash算法是一种变相的轮询算法,如果两个ip的初始hash值恰好相同,那么来自这两个ip的请求将永远落在同一台服务器上,这为均衡性埋下了很深的隐患。 3、fairfair策略是扩展策略,默认不被编译进nginx内核。其原理是根据后端服务器的响应时间判断负载情况,从中选出负载最轻的机器进行分流。这种策略具有很强的自适应性,但是实际的网络环境往往不是那么简单,因此要慎用。 4、通用hash、一致性hash这两种也是扩展策略,在具体的实现上有些差别,通用hash比较简单,可以以nginx内置的变量为key进行hash,一致性hash采用了nginx内置的一致性hash环,可以支持memcache。 

2.2 配置示例

1、HTTP
 http {     upstream  www.exmaple.com  {       server   192.168.1.2:80;       server   192.168.1.3:80;     }     server{       listen  80;       server_name  www.example.com;       location / {                proxy_pass        http://www.example.com;                proxy_set_header   Host             $host;                proxy_set_header   X-Real-IP        $remote_addr;                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;       }       location /nginx_status {                stub_status on;                access_log off;                allow 192.168.1.1;#设置为可访问该状态信息的ip                deny all;       }     } }
2、TCP-ngx_tcp_proxy_module
tcp {     upstream cluster {         # simple round-robin         server 192.168.0.1:80;         server 192.168.0.2:80;         check interval=3000 rise=2 fall=5 timeout=1000;         #check interval=3000 rise=2 fall=5 timeout=1000 type=ssl_hello;         #check interval=3000 rise=2 fall=5 timeout=1000 type=http;         #check_http_send "GET / HTTP/1.0\r\n\r\n";         #check_http_expect_alive http_2xx http_3xx;     }     server {         listen 8888;         proxy_pass cluster;     } }
 

三、动态负载均衡

3.1 自身监控内置了对后端服务器的健康检查功能。如果Nginx proxy后端的某台服务器宕机了,会把返回错误的请求重新提交到另一个节点,不会影响前端访问。它没有独立的健康检查模块,而是使用业务请求作为健康检查,这省去了独立健康检查线程,这是好处。坏处是,当业务复杂时,可能出现误判,例如后端响应超时,这可能是后端宕机,也可能是某个业务请求自身出现问题,跟后端无关。3.2 可扩展性Nginx属于典型的微内核设计,其内核非常简洁和优雅,同时具有非常高的可扩展性。如下图所示:
nginx_jg.png
Nginx是纯C语言的实现,其可扩展性在于其模块化的设计。目前,Nginx已经有很多的第三方模块,大大扩展了自身的功能。nginx_lua_module可以将Lua语言嵌入到Nginx配置中,从而利用Lua极大增强了Nginx本身的编程能力,甚至可以不用配合其它脚本语言(如PHP或Python等),只靠Nginx本身就可以实现复杂业务的处理。3.3 配置修改nginx的配置架构如下图所示:
nginx_gx.png
Nginx支持热部署,几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。能够在不间断服务的情况下,对软件版本进行进行升级。Nginx的配置文件非常简单,风格跟程序一样通俗易懂,能够支持perl语法。使用nginx –s reload可以在运行时加载配置文件,便于运行时扩容/减容。重新加载配置时,master进程发送命令给当前正在运行的worker进程worker进程接到命令后会在处理完当前任务后退出。同时,master进程会启动新的worker进程来接管工作。

四、优势和劣势

4.1 优势[list=1][]可以很好地进行http 的头处理[/][]对http协议以及https的良好支持[/][]有足够的第三方插件供使用[/][]支持热部署,更改后端是平滑的[/]4.2 劣势[list=1][]缺少对session的支持[/][]对四层tcp的支持不够好[/][]post请求写文件系统,造成500 error[/][]缺乏主动的后端服务器健康监测[/][]默认的监控界面统计信息不全[/]

五、Tengine

5.1 特性[list=1][]继承Nginx-1.2.9的所有特性,100%兼容Nginx的配置;[/][]动态模块加载(DSO)支持。加入一个模块不再需要重新编译整个Tengine;[/][]输入过滤器机制支持。通过使用这种机制Web应用防火墙的编写更为方便;[/][]动态脚本语言Lua支持。扩展功能非常高效简单;[/][]支持管道(pipe)和syslog(本地和远端)形式的日志以及日志抽样;[/][]组合多个CSS、JavaScript文件的访问请求变成一个请求;[/][]更加强大的负载均衡能力,包括一致性hash模块、会话保持模块,还可以对后端的服务器进行主动健康检查,根据服务器状态自动上线下线;[/][]自动根据CPU数目设置进程个数和绑定CPU亲缘性;[/][]监控系统的负载和资源占用从而对系统进行保护;[/][]显示对运维人员更友好的出错信息,便于定位出错机器;[/][]更强大的防攻击(访问速度限制)模块;[/][]更方便的命令行参数,如列出编译的模块列表、支持的指令等;[/][]可以根据访问文件类型设置过期时间;[/]5.2 负载均衡负载均衡方面,Tengine主要有以下几个特点,基本上弥补了 nginx在负载均衡方面的欠缺:[list=1][]支持一致性Hash模块[/][]会话保持模块[/][]对后端服务器的主动健康检查。[/][]增加了请求体不缓存到磁盘的机制[/]

MySQL数据库进行分库备份shell脚本

koyo 发表了文章 0 个评论 2644 次浏览 2015-11-02 11:48 来自相关话题

[root@shell scripts]# vi fenbiao_backup.sh #!/bin/bash MysqlUser=root PassWord=backup123 Port=3306 ...查看全部
[root@shell scripts]# vi fenbiao_backup.sh 
#!/bin/bash
MysqlUser=root
PassWord=backup123
Port=3306
Socket="/data/$Port/mysql.sock"
MysqlCmd="mysql -u$MysqlUser -p$PassWord -S $Socket"
Database=`$MysqlCmd -e "show databases;"|egrep -v "Database|_schema|mysql"`
MysqlDump="mysqldump -u$MysqlUser -p$PassWord -S $Socket"
IP=`ifconfig eth0|awk -F "[ :]+" 'NR==2 {print $4}'`
BackupDir=/backup/$IP
[ -d $BackupDir ] || mkdir -p $BackupDir
for dbname in $Database
do
[ ! -d /$BackupDir/$dbname ] && mkdir -p /$BackupDir/$dbname
TABLE=`$MysqlCmd -e "show tables from $dbname;"|sed '1d'`
for table in $TABLE
do
$MysqlDump $dbname $table|gzip >/$BackupDir/$dbname/${dbname}_${table}_$(date +%F).sql.gz
done
done
分享原文

nginx之upstream模块缓存系统详解

空心菜 发表了文章 0 个评论 4629 次浏览 2015-11-01 17:48 来自相关话题

一般情况下,前端使用nginx做代理或7层负载并向后实现varish/squid做cache server的效果要好的多 nginx与squid做缓存比较,nginx比squid有着巨大的优势表现在: nginx是异步 ...查看全部
一般情况下,前端使用nginx做代理或7层负载并向后实现varish/squid做cache server的效果要好的多
nginx与squid做缓存比较,nginx比squid有着巨大的优势表现在:


nginx是异步


假如后端的web服务器,当用户的请求到达nginx的时候,nginx收到请求而不是立即将请求转发至web server; 
如果用户请求比较大,nginx将其在本地缓存,内存中不够用则在磁盘中缓存,当缓存完毕之后,再将请求一次性提交至后端web服务器,转发完成之后再向客户端响应也就意味着用户的连接只需要跟nginx建立连接即可,nginx与后端web一般都在内网中对接,只要带宽满足,很可能瞬间完成,因此来说对于后端服务器的压力及小,只需要建立几秒的连接就可以处理完成非常大的请求。


squid是同步


当用户请求到达squid中,在刚接收到用户请求的第一个报文立即与后端建立连接,因此在处理过程中,依旧保持着连接。 
所以说,nginx最大的优势就是在用户的连接处理的场景中,这样就使前端有大量的用户请求连接,但是在后端看上去只有少数部分,比如前端有1W并发进来,后端大概只能看到其10分之1 ,需要查找数据库的只有少数部分, 所以后端的web压力会小,但是前端分发器的压力会很大


nginx缓存机制


nginx要想实现反向代理那么就需要使用proxy_cache模块,以及配合其指令和参数,可以将用户的请求从上游服务器获取之后先存在本地磁盘。



缓存通常是键值对方式存储:

键 : 请求的rul
值 : 后端服务器响应的内容
所以当后续用户的请求到达之后,如果本地缓存服务器中存在的话则直接封装报文返回至用户;
但是如果服务器运行了很久,已保存N久的缓存数据,那在某一时刻后端服务器出现故障,nginx缓存已经无法找到其后端的服务器,那么缓存上游服务器对象是否还应该返回至用户; 
这些都是可配置的,我们定义缓存的时候,像这些缓存 是否可缓存,缓存的位置都要自己去配置的,并且一旦服务器故障,缓存的数据还能否直接响应客户端等等

事实上用户所在浏览器上保存的缓存称为私有缓存,而服务器上缓存的数据叫做公共缓存


有些数据只能在私有缓存中进行缓存,比如:
用户登录网站的用户名和密码的信息,这类肯定不能在服务器上缓存;
而用户的cookie信息一般也不能缓存,所以缓存服务器公共缓存服务器只要发现用户请求中有cookie则不缓存,但是一般电商站点为了追中用户的行为规则,则将每个请求数都加cookie,但对于图片这种静态内容附加cookie是没有意义的。 
所以对于缓存服务器来说必须处理这种机制,对于没必要加cookie的而用户已加cookie将其删掉并让缓存命中等,因此需要一系列缓存机制,这都是需要自己去定义的,比如缓存多久 否定缓存多久 重定向缓存多久 ...




配置Nginx缓存


参考:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_path
语法:
proxy_cache_path path [levels=levels] keys_zone=name:size [inactive=time] [max_size=size] [loader_files=number] [loader_sleep=time] [loader_threshold=time];
配置格式:
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m;
#定义/data/nginx/cache为缓存目录;
 levels=1:2 有2级子目录,最多为3级子目录,用冒号隔开定义3个数字,每个数字表示其目录名称;
 keys_zone=one:10m 用多大的空间保存键值;
以下为缓存对象的名字,方便引用并且避免名称冲突
file names in a cache will look like this:
/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c
使用示例
定义缓存必须在全局配置上下文中去定义
http {
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=STATIC:10m
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=STATIC:10m
inactive=24h max_size=1g;
}
proxy_cache_path必须定义在全局配置中,定义完之后可以在各location中来引用
在location中来使用proxy_cache来指定是否使用缓存,也可以定义多个缓存在location中引用不同的缓存定义
     server {
location / {
proxy_pass http://www.test.com;
proxy_set_header Host $host;
proxy_cache STATIC;
proxy_cache_valid 200 1d; #请求返回值为200的则缓存1day
proxy_cache_valid 301 302 10m; #请求返回值为301 302的则缓存10m
proxy_cache_vaild any 1m; #其他任何返回值缓存1m

#是否可以使用过期对象
proxy_cache_use_stale error timeout invalid_header updating
http_500 http_502 http_503 http_504;
}
}
}


实现缓存机制


步骤:
          (1)定义缓存必须在http全局中定义
          (2)而后在location中实现反向代理才有必要实现缓存
创建缓存目录
[root@node1 ~]# mkdir -p /data/cache/nginx/
编辑nginx配置文件
[root@node1 nginx]# vim nginx.conf
在http { }上下文中定义缓存
proxy_cache_path /data/cache/nginx/  levels=1:2 keys_zone=one:10m  max_size=1g;
    定义/data/cache/nginx/为缓存目录;
     levels=1:2 有2级子目录,最多为3级子目录,用冒号隔开定义3个数字,每个数字表示其目录名称;
     keys_zone=one:10m 用多大的空间保存键值,最大为10M;
     max_size=1g 表示缓存空间最大有1G;
在location中定义缓存规则并调用proy_cache_path
        location / {
proxy_pass http://10.0.10.83; #将请求都转发至10.0.10.83上去
proxy_cache one; #明确说明使用名称one这个cache

#以下为缓存规则
proxy_cache_valid 200 1h;
proxy_cache_valid 302 10m;
proxy_cache_valid any 1m;
}


保存退出检查语法并重新加载
[root@node1 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@node1 nginx]# nginx -s reload
查看缓存目录
[root@node1 nginx]# ll -th /data/cache/nginx/
total 0
看到目录中是空的,那么我们来使用curl命令访问一下看其是否能生成缓存文件
[root@node1 nginx]# curl 10.0.10.61

10.0.10.83

再次查看路径
[root@node1 nginx]# ll -th /data/cache/nginx/f/63/
total 4.0K
-rw-------. 1 nginx nginx 350 May 9 16:06 681ad4c77694b65d61c9985553a2763f
这时候目录中已经存在缓存信息,说明缓存已经生效,但是在某些场合,我们不能保证其已经被命中
那么再将upstream模块开启,因为upstream模块会给我们引入一些新的服务器变量,编辑如下:
        upstream webservers {			#定义名称
server 10.0.10.83;
#server 10.0.10.61; #将之前定义的注释
}
再定义location
        location / {
proxy_pass http://webservers; #引用upstream名称
proxy_cache one; #引用定义的缓存模块名称
proxy_cache_valid 200 1h;
proxy_cache_valid 302 10m;
proxy_cache_valid any 1m;
}
这样表示我们已经启用了upstream模块了而upstream模块会给我们引入一些新的服务器变量进来
比如cache_status,如果我们访问某个缓存页面的时候到底是否命中会通过这个变量保存下来,如果将其传递给客户端,那么我们就知道是否命中了
再将其加入首部header
        location / {
#root /web/htdocs/;
#index index.php index.html index.htm;
proxy_pass http://webservers;
proxy_cache one;
proxy_cache_valid 200 1h;
proxy_cache_valid 302 10m;
proxy_cache_valid any 1m;
add_header X-Via $server_addr; #定义这个header名为X-Via 通过变量$server_addr明确说明从哪个服务器来响应的 server_addr
add_header X-Cache-Status $upstream_cache_status; #明确说明是否命中 $upstream_cache_status为upstream模块
}
保存退出并检测语法
[root@node1 nginx]# /usr/local/nginx/sbin/nginx –t
[root@node1 nginx]# /usr/local/nginx/sbin/nginx –s reload
重新reload之后刷新测试,这里使用的是Google Chrome浏览器
nginx_chrome.png

如上所示,提示已命中,X-Via是我们自定义的header标签
也可以使用curl -I来查
[root@node1 nginx]# curl -I http://10.0.10.61
HTTP/1.1 200 OK
Server: nginx/1.4.2
Date: Fri, 09 May 2014 08:22:41 GMT
Content-Type: text/html
Content-Length: 20
Connection: keep-alive
Last-Modified: Mon, 12 Aug 2013 10:48:13 GMT
ETag: "fd91-14-4e3bddc687540"
X-Via: 10.0.10.61
X-Cache-Status: HIT
Accept-Ranges: bytes


启动压缩功能


nginx将响应报文发送至客户端之前可以启用压缩功能,这能够有效地节约带宽,并提高响应至客户端的速度。通常编译nginx默认会附带gzip压缩的功能,因此,可以直接启用之。
http {
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/json;
gzip_disable msie6; #如果对方是ie6的话,则不再使用压缩功能,,因为ie6浏览器不支持压缩
}
gzip_proxied指令可以定义对客户端请求哪类对象启用压缩功能,如“expired”表示对由于使用了expire首部定义而无法缓存的对象启用压缩功能,其它可接受的值还有“no-cache”、“no-store”、“private”、“no_last_modified”、“no_etag”和“auth”等,而“off”则表示关闭压缩功能
重新加载配置文件并访问
nginx_gzip.png


upstream模块的使用


upstream模块常用的指令有:
    []ip_hash: 基于客户端IP地址完成请求的分发,它可以保证来自于同一个客户端的请求始终被转发至同一个上游服务器,与lvs的机制是一样的;[/][]keepalive:每个worker进程为发送到upstream服务器的连接所缓存的个数;转发至服务器之后能否使用长连接,也尽可能避免三次握手与四次断开的次数,如果参数过大的话,会无形之中对后端服务器产生很大的压力,因此建议开启但不要太大[/][]least_conn:最少连接调度算法;类似于lvs的wlc算法的效果,因此一般来尽量避免和ip_hash一起用[/][]server:定义一个upstream服务器的地址,还可包括一系列可选参数,如:[/][]weight:权重;[/][]max_fails:最大失败连接次数,失败连接的超时时长由fail_timeout指定;[/][]fail_timeout:等待请求的目标服务器发送响应的时长;[/][]backup:用于fallback的目的,所有服务均故障时才启动此服务器;[/][]down:手动标记其不再处理任何请求;[/]

 示例:
upstream backend {
server www.magedu.com weight=5;
server www2.magedu.com:8080 max_fails=3 fail_timeout=30s;
}
upstream模块也能为非http类的应用实现负载均衡,如下面的示例定义了nginx为memcached服务实现负载均衡
 upstream memcachesrvs {          				#明确定义了一组实现负载均衡的服务器
server 172.16.100.6:11211; #而这组服务器向后分发的端口都是11211 ,是memcache的服务器端口
server 172.16.100.7:11211;
}
server {
location / {
set $memcached_key "$uri?$args"; #向后端memcache查询的时候,查询键是$uri?和$args组合起来的值
memcached_pass memcachesrvs; #通过memcachepass传递至memcachesrvs组服务器
error_page 404 = @fallback; #如果没有命中则则发送至其上游的其他服务器
}
location @fallback {
proxy_pass http://127.0.0.1:8080;
}
}
这样一来,找缓存的时候先在memcached里查找,如果不存在则再去找真实服务器,这样将nginx将memcached结合在了一起,将数据直接缓存在memcached内存当中,而不是nginx自己的缓存当中
 
实现后端服务器健康状态检查,使其一旦出现故障不再将其加进来,定义upstream:
    upstream webservers {
server 10.0.10.83 weight=1 max_fails=3 fail_timeout=2s; #最大允许3次失败,如果超过2秒则算超时
server 10.0.10.61 max_fails=3 fail_timeout=1s backup; #backup表示其主机始终不会生效除非组内所有主机全部故障
}
一般如果条件允许的情况下,本机也启动一个web服务器,但是这个服务器不是专门提供工作的,一旦后端服务器出现故障,那么则转至backup服务器,使其服务器专门为用户提供错误页面
proxy_cache通常也只能缓存本地服务器向后端服务器取得数据而进行缓存的,而后端通常都是静态服务器,如果基于fastcgi的方式获取数据的,而有希望对动态内容作缓存,那么就要涉及到fastcgi的自身缓存功能了

实现动态内容缓存
通过FastCGI协议取得的内容页可以缓存,但是时长需要自定义好
使用时将fastcgi_cache模块启用并定义参数即可,之前我们搭建了一套lnmp 这时我们要对fastcgi进行缓存
 
定义缓存目录
[root@node1 nginx]# mkdir -p /data/cache/fastcgi
编辑配置文件,在http{}中加入以下参数:
fastcgi_cache_path /data/cache/fastcgi levels=1:2:1 keys_zone=fcgi:20m  max_size=1g;
定义/data/cache/fastcgi为fastcgi缓存目录;
缓存目录分别为3级子目录;
Fcgi缓存大小为20M;
最大缓存为1G的空间;
而后location中启用fastcgi
        location ~ \.php$ {
root /web/htdocs/;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
以上参数为nginx默认配置,将以上参数启用之后,我们还需要对其加入一些参数:
location ~ \.php$ {
root /web/htdocs/;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
fastcgi_cache fcgi;
fastcgi_cache_valid 200 10m ;
fastcgi_cache_valid 301 2m ;
fastcgi_cache_valid any 1m ;
}
保存退出并检查语法
[root@node1 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重新加载配置文件
[root@node1 nginx]# nginx -s reload
这时我们再去请求动态内容
[root@mode ~]# curl http://10.0.10.61/index.php
再来查看是否生产缓存
[root@node1 ~]# ll /data/cache/fastcgi/e/27/4/
total 48
-rw-------. 1 nginx nginx 45873 May 10 12:55 d41d8cd98f00b204e9800998ecf8427e
使用ab压力测试其效果是否明显
首先将fastcgi缓存功能关闭
location ~ \.php$ {
root /web/htdocs;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
#将以下参数注释
#fastcgi_cache fcgi;
#fastcgi_cache_valid 200 10m ;
#fastcgi_cache_valid 301 2m ;
#fastcgi_cache_valid any 1m ;
}
重新加载配置文件
[root@node1 nginx]# nginx -s reload
使用ab命令对其进行压力测试
[root@mode ~]# ab -c 100 -n 2000 http://10.0.10.61/index.php
我们只关心Requests值 所以略过一部分信息
#···········略··············
Document Path: /index.php
Document Length: 45234 bytes

Concurrency Level: 100
Time taken for tests: 4.343977 seconds
Complete requests: 2000
Failed requests: 228
(Connect: 0, Length: 228, Exceptions: 0)
Write errors: 0
Total transferred: 90761752 bytes
HTML transferred: 90467752 bytes
Requests per second: 460.41 [#/sec] (mean)
Time per request: 217.199 [ms] (mean)
Time per request: 2.172 [ms] (mean, across all concurrent requests)
Transfer rate: 20403.88 [Kbytes/sec] received
#···········略··············
将缓存模块开启再次对其进行压力测试
得出数据:
Concurrency Level: 100
Time taken for tests: 1.576516 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 90896000 bytes
HTML transferred: 90602000 bytes
Requests per second: 1268.62 [#/sec] (mean)
Time per request: 78.826 [ms] (mean)
Time per request: 0.788 [ms] (mean, across all concurrent requests)
Transfer rate: 56304.53 [Kbytes/sec] received

Nginx+Keepalived实现网站高可用方案

push 发表了文章 0 个评论 4359 次浏览 2015-10-31 17:00 来自相关话题

公司内部 OA 系统要做线上高可用,避免单点故障,所以计划使用2台虚拟机通过 Keepalived 工具来实现 nginx 的高可用(High Avaiability),达到一台nginx入口服务器宕机,另一台备机自动接管服务的效果。  1. Ke ...查看全部
公司内部 OA 系统要做线上高可用,避免单点故障,所以计划使用2台虚拟机通过 Keepalived 工具来实现 nginx 的高可用(High Avaiability),达到一台nginx入口服务器宕机,另一台备机自动接管服务的效果。
 1. Keepalived介绍
Keepalived是一个基于VRRP协议来实现的服务高可用方案,可以利用其来避免IP单点故障,类似的工具还有heartbeat、corosync、pacemaker。但是它一般不会单独出现,而是与其它负载均衡技术(如lvs、haproxy、nginx)一起工作来达到集群的高可用。


1.1 VRRP协议


VRRP全称 Virtual Router Redundancy Protocol,即 虚拟路由冗余协议。可以认为它是实现路由器高可用的容错协议,即将N台提供相同功能的路由器组成一个路由器组(Router Group),这个组里面有一个master和多个backup,但在外界看来就像一台一样,构成虚拟路由器,拥有一个虚拟IP(vip,也就是路由器所在局域网内其他机器的默认路由),占有这个IP的master实际负责ARP相应和转发IP数据包,组中的其它路由器作为备份的角色处于待命状态。master会发组播消息,当backup在超时时间内收不到vrrp包时就认为master宕掉了,这时就需要根据VRRP的优先级来选举一个backup当master,保证路由器的高可用。
 
在VRRP协议实现里,虚拟路由器使用 00-00-5E-00-01-XX 作为虚拟MAC地址,XX就是唯一的 VRID (Virtual Router IDentifier),这个地址同一时间只有一个物理路由器占用。在虚拟路由器里面的物理路由器组里面通过多播IP地址 224.0.0.18 来定时发送通告消息。每个Router都有一个 1-255 之间的优先级别,级别最高的(highest priority)将成为主控(master)路由器。通过降低master的优先权可以让处于backup状态的路由器抢占(pro-empt)主路由器的状态,两个backup优先级相同的IP地址较大者为master,接管虚拟IP。
nginx-keepalived-vrrp.jpg

与heartbeat/corosync等比较:
Heartbeat、Corosync、Keepalived这三个集群组件我们到底选哪个好,首先我想说明的是,Heartbeat、Corosync是属于同一类型,Keepalived与Heartbeat、Corosync,根本不是同一类型的。Keepalived使用的vrrp协议方式,虚拟路由冗余协议 (Virtual Router Redundancy Protocol,简称VRRP);Heartbeat或Corosync是基于主机或网络服务的高可用方式;简单的说就是,Keepalived的目的是模拟路由器的高可用,Heartbeat或Corosync的目的是实现Service的高可用。

所以一般Keepalived是实现前端高可用,常用的前端高可用的组合有,就是我们常见的LVS+Keepalived、Nginx+Keepalived、HAproxy+Keepalived。而Heartbeat或Corosync是实现服务的高可用,常见的组合有Heartbeat v3(Corosync)+Pacemaker+NFS+Httpd 实现Web服务器的高可用、Heartbeat v3(Corosync)+Pacemaker+NFS+MySQL 实现MySQL服务器的高可用。总结一下,Keepalived中实现轻量级的高可用,一般用于前端高可用,且不需要共享存储,一般常用于两个节点的高可用。而Heartbeat(或Corosync)一般用于服务的高可用,且需要共享存储,一般用于多节点的高可用。这个问题我们说明白了。

又有博友会问了,那heartbaet与corosync我们又应该选择哪个好啊,我想说我们一般用corosync,因为corosync的运行机制更优于heartbeat,就连从heartbeat分离出来的pacemaker都说在以后的开发当中更倾向于corosync,所以现在corosync+pacemaker是最佳组合。


1.2 Keepalived + nginx


keepalived可以认为是VRRP协议在Linux上的实现,主要有三个模块,分别是core、check和vrrp。core模块为keepalived的核心,负责主进程的启动、维护以及全局配置文件的加载和解析。check负责健康检查,包括常见的各种检查方式。vrrp模块是来实现VRRP协议的。本文基于如下的拓扑图:
                   +-------------+
| uplink |
+-------------+
|
+
MASTER keep|alived BACKUP
172.29.88.224 172.29.88.222 172.29.88.225
+-------------+ +-------------+ +-------------+
| nginx01 |----| virtualIP |----| nginx02 |
+-------------+ +-------------+ +-------------+
|
+------------------+------------------+
| | |
+-------------+ +-------------+ +-------------+
| web01 | | web02 | | web03 |
+-------------+ +-------------+ +-------------+
2. keepalived实现nginx高可用


2.1安装


我的环境是CentOS 6.2 X86_64,直接通过yum方式安装最简单:
# yum install -y keepalived
# keepalived -v
Keepalived v1.2.13 (03/19,2015)


2.2 nginx监控脚本


该脚本检测ngnix的运行状态,并在nginx进程不存在时尝试重新启动ngnix,如果启动失败则停止keepalived,准备让其它机器接管。
/etc/keepalived/check_nginx.sh :
#!/bin/bash
counter=$(ps -C nginx --no-heading|wc -l)
if [ "${counter}" = "0" ]; then
/usr/local/bin/nginx
sleep 2
counter=$(ps -C nginx --no-heading|wc -l)
if [ "${counter}" = "0" ]; then
/etc/init.d/keepalived stop
fi
fi
你也可以根据自己的业务需求,总结出在什么情形下关闭keepalived,如 curl 主页连续2个5s没有响应则切换:
#!/bin/bash
# curl -IL http://localhost/member/login.htm
# curl --data "memberName=fengkan&password=22" http://localhost/member/login.htm

count = 0
for (( k=0; k<2; k++ ))
do
check_code=$( curl --connect-timeout 3 -sL -w "%{http_code}\\n" http://localhost/login.html -o /dev/null )
if [ "$check_code" != "200" ]; then
count = count +1
continue
else
count = 0
break
fi
done
if [ "$count" != "0" ]; then
# /etc/init.d/keepalived stop
exit 1
else
exit 0
fi


2.3 keepalived.conf


! Configuration File for keepalived
global_defs {
notification_email {
zhouxiao@example.com
itsection@example.com
}
notification_email_from itsection@example.com
smtp_server mail.example.com
smtp_connect_timeout 30
router_id LVS_DEVEL
}

vrrp_script chk_nginx {
# script "killall -0 nginx"
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -5
fall 3
rise 2
}

vrrp_instance VI_1 {
state MASTER
interface eth0
mcast_src_ip 172.29.88.224
virtual_router_id 51
priority 101
advert_int 2
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.29.88.222
}
track_script {
chk_nginx
}
}
在其它备机BACKUP上,只需要改变 state MASTER -> state BACKUP,priority 101 -> priority 100,mcast_src_ip 172.29.88.224 -> mcast_src_ip 172.29.88.225即可。
# service keepalived restart


2.4 配置选项说明


global_defs
    []notification_email : keepalived在发生诸如切换操作时需要发送email通知地址,后面的 smtp_server 相比也都知道是邮件服务器地址。也可以通过其它方式报警,毕竟邮件不是实时通知的。[/][]router_id : 机器标识,通常可设为hostname。故障发生时,邮件通知会用到[/]
vrrp_instance
    []state : 指定instance(Initial)的初始状态,就是说在配置好后,这台服务器的初始状态就是这里指定的,但这里指定的不算,还是得要通过竞选通过优先级来确定。如果这里设置为MASTER,但如若他的优先级不及另外一台,那么这台在发送通告时,会发送自己的优先级,另外一台发现优先级不如自己的高,那么他会就回抢占为MASTER[/][]interface : 实例绑定的网卡,因为在配置虚拟IP的时候必须是在已有的网卡上添加的[/][]mcast_src_ip : 发送多播数据包时的源IP地址,这里注意了,这里实际上就是在那个地址上发送VRRP通告,这个非常重要,一定要选择稳定的网卡端口来发送,这里相当于heartbeat的心跳端口,如果没有设置那么就用默认的绑定的网卡的IP,也就是interface指定的IP地址[/][]virtual_router_id : 这里设置VRID,这里非常重要,相同的VRID为一个组,他将决定多播的MAC地址[/][]priority : 设置本节点的优先级,优先级高的为master[/][]advert_int : 检查间隔,默认为1秒。这就是VRRP的定时器,MASTER每隔这样一个时间间隔,就会发送一个advertisement报文以通知组内其他路由器自己工作正常[/][]authentication : 定义认证方式和密码,主从必须一样[/][]virtual_ipaddress : 这里设置的就是VIP,也就是虚拟IP地址,他随着state的变化而增加删除,当state为master的时候就添加,当state为backup的时候删除,这里主要是有优先级来决定的,和state设置的值没有多大关系,这里可以设置多个IP地址[/][]track_script : 引用VRRP脚本,即在 vrrp_script 部分指定的名字。定期运行它们来改变优先级,并最终引发主备切换。[/]
vrrp_script告诉 keepalived 在什么情况下切换,所以尤为重要。可以有多个 vrrp_script
    []script : 自己写的检测脚本。也可以是一行命令如killall -0 nginx[/][]interval 2 : 每2s检测一次[/][]weight -5 : 检测失败(脚本返回非0)则优先级 -5[/][]fall 2 : 检测连续 2 次失败才算确定是真失败。会用weight减少优先级(1-255之间)[/][]rise 1 : 检测 1 次成功就算成功。但不修改优先级[/]
 这里要提示一下script一般有2种写法:[list=1][]通过脚本执行的返回结果,改变优先级,keepalived继续发送通告消息,backup比较优先级再决定[/][]脚本里面检测到异常,直接关闭keepalived进程,backup机器接收不到advertisement会抢占IP[/] 上文 vrrp_script 配置部分,killall -0 nginx属于第1种情况,/etc/keepalived/check_nginx.sh属于第2种情况(脚本中关闭keepalived)。个人更倾向于通过shell脚本判断,但有异常时exit 1,正常退出exit 0,然后keepalived根据动态调整的 vrrp_instance 优先级选举决定是否抢占VIP:
    []如果脚本执行结果为0,并且weight配置的值大于0,则优先级相应的增加[/][]如果脚本执行结果非0,并且weight配置的值小于0,则优先级相应的减少[/]
其他情况,原本配置的优先级不变,即配置文件中priority对应的值。提示:[list=1][]优先级不会不断的提高或者降低[/][]可以编写多个检测脚本并为每个检测脚本设置不同的weight(在配置中列出就行)[/][]不管提高优先级还是降低优先级,最终优先级的范围是在[1,254],不会出现优先级小于等于0或者优先级大于等于255的情况[/][]在MASTER节点的 vrrp_instance 中 配置 nopreempt ,当它异常恢复后,即使它 prio 更高也不会抢占,这样可以避免正常情况下做无谓的切换[/]以上可以做到利用脚本检测业务进程的状态,并动态调整优先级从而实现主备切换。 配置结束在默认的keepalive.conf里面还有 virtual_server,real_server 这样的配置,我们这用不到,它是为lvs准备的。 notify 可以定义在切换成MASTER或BACKUP时执行的脚本,如有需求请自行google。

2.5 nginx配置

当然nginx没有什么可配置的,因为它与keepalived并没有联系。但记住,2台nginx服务器上的配置应该是完全一样的(rsync同步),这样才能做到对用户透明,nginx.conf 里面的 server_name 尽量使用域名来代替,然后dns解析这个域名到虚拟IP 172.29.88.222。更多关于nginx内容配置请参考 这里

[list=1]

  • 测试

  • 根据上面的配置,初始化状态:172.29.88.224 (itoatest1,MASTER,101),172.29.88.222(itoatest2,BACKUP,100),nginx和keepalived都启动,虚拟IP 172.29.88.222 在 itoatest1 上:
    # 使用ip命令配置的地址,ifconfig查看不了
    [root@itoatest1 nginx-1.6]# ip a|grep eth0
    2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 172.29.88.224/24 brd 172.29.88.255 scope global eth0
    inet 172.29.88.222/32 scope global eth0
    直接关闭 itoatest1 上的nginx:/usr/local/nginx-1.6/sbin/nginx -s stop:
    [root@localhost keepalived]# ip a|grep eth0
    2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 172.29.88.224/24 brd 172.29.88.255 scope global eth0
    vip消失,漂移到 itoatest2:
    nginx-keepalived-vip.png

    同时可以看到两台服务器上 /var/log/messages:
    [size=16] itoatest1[/size]
    Jun 5 16:44:01 itoatest1 Keepalived_vrrp[44875]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 172.29.88.222
    Jun 5 16:44:06 itoatest1 Keepalived_vrrp[44875]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 172.29.88.222
    Jun 5 16:44:46 itoatest1 Keepalived_vrrp[44875]: VRRP_Script(chk_nginx) failed
    Jun 5 16:44:48 itoatest1 Keepalived_vrrp[44875]: VRRP_Instance(VI_1) Received higher prio advert
    Jun 5 16:44:48 itoatest1 Keepalived_vrrp[44875]: VRRP_Instance(VI_1) Entering BACKUP STATE
    Jun 5 16:44:48 itoatest1 Keepalived_vrrp[44875]: VRRP_Instance(VI_1) removing protocol VIPs.
    Jun 5 16:44:48 itoatest1 Keepalived_healthcheckers[44874]: Netlink reflector reports IP 172.29.88.222 removed

    [size=16] itoatest2[/size]
    Jun 5 16:44:00 itoatest2 Keepalived_vrrp[35555]: VRRP_Instance(VI_1) Transition to MASTER STATE
    Jun 5 16:44:00 itoatest2 Keepalived_vrrp[35555]: VRRP_Instance(VI_1) Received higher prio advert
    Jun 5 16:44:00 itoatest2 Keepalived_vrrp[35555]: VRRP_Instance(VI_1) Entering BACKUP STATE
    Jun 5 16:44:48 itoatest2 Keepalived_vrrp[35555]: VRRP_Instance(VI_1) forcing a new MASTER election
    Jun 5 16:44:48 itoatest2 Keepalived_vrrp[35555]: VRRP_Instance(VI_1) forcing a new MASTER election
    Jun 5 16:44:49 itoatest2 Keepalived_vrrp[35555]: VRRP_Instance(VI_1) Transition to MASTER STATE
    Jun 5 16:44:50 itoatest2 Keepalived_vrrp[35555]: VRRP_Instance(VI_1) Entering MASTER STATE
    Jun 5 16:44:50 itoatest2 Keepalived_vrrp[35555]: VRRP_Instance(VI_1) setting protocol VIPs.
    Jun 5 16:44:50 itoatest2 Keepalived_vrrp[35555]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 172.29.88.222
    Jun 5 16:44:50 itoatest2 Keepalived_healthcheckers[35554]: Netlink reflector reports IP 172.29.88.222 added
    Jun 5 16:44:55 itoatest2 Keepalived_vrrp[35555]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 172.29.88.222

    你也可以通过在两台服务器上抓包来查看 优先级priority 的变化:
    [size=16] itoatest1 上[/size]
    [size=16] 直接输出,或后加 -w itoatest-kl.cap存入文件用wireshark查看[/size]
    # tcpdump -vvv -n -i eth0 dst 224.0.0.18 and src 172.29.88.224
    nginx-keepalived-prio.png

    参考
    使用Keepalived实现Nginx高可用性
    High Availability Support Based on keepalived
    nginx+keepalived实现双机热备的高可用
    LVS原理详解及部署之五:LVS+keepalived实现负载均衡&高可用
    Keepalived双主模型中vrrp_script中权重改变故障排查
    虚拟路由器冗余协议【原理篇】VRRP详解
    Keepalived原理与实战精讲
    原文分享地址:http://seanlook.com/2015/05/18/nginx-keepalived-ha/

    Shell字符串的截取和拼接

    空心菜 发表了文章 0 个评论 3925 次浏览 2015-10-31 15:40 来自相关话题

    一、Linux 的字符串截取 假设有变量 var=http://www.hadoope.com/123.htm1.# 号截取,删除左边字符,保留右边字符。 [root@crh_ops sh]# echo ${var#*// ...查看全部


    一、Linux 的字符串截取


    假设有变量 var=http://www.hadoope.com/123.htm
    1.# 号截取,删除左边字符,保留右边字符。
    [root@crh_ops sh]# echo ${var#*//}
    www.hadoope.com/123.htm

    其中 var 是变量名,# 号是运算符,*// 表示从左边开始删除第一个 // 号及左边的所有字符
    即删除 http://
    结果是 :www.hadoope.com/123.htm
    2.[size=16] 号截取,删除左边字符,保留右边字符。[/size]
    [root@crh_ops sh]# echo ${var[size=16]*/}[/size]
    123.htm

    [size=16]*/ 表示从左边开始删除最后(最右边)一个 / 号及左边的所有字符[/size]
    即删除 http://www.hadoope.com/
    结果是 123.htm
    3.% 号截取,删除右边字符,保留左边字符。
    [root@crh_ops sh]# echo ${var%/*}
    结果是:http://www.hadoope.com

    %/* 表示从右边开始,删除第一个 / 号及右边的字符
    结果是:http://www.hadoope.com
    4.%% 号截取,删除右边字符,保留左边字符。
    [root@crh_ops sh]# echo ${var%%/*}
    http:

    %%/* 表示从右边开始,删除最后(最左边)一个 / 号及右边的字符
    结果是:http:
    5.从左边第几个字符开始,及字符的个数。
    [root@crh_ops sh]# echo ${var:0:5}
    http:

    其中的 0 表示左边第一个字符开始,5 表示字符的总个数。
    结果是:http:
    6.从左边第几个字符开始,一直到结束。
    [root@crh_ops sh]# echo ${var:7}
    www.hadoope.com/123.htm

    其中的 7 表示左边第8个字符开始,一直到结束。
    结果是 :www.hadoope.com/123.htm
    7.从右边第几个字符开始,及字符的个数。
    [root@crh_ops sh]# echo ${var:0-7:3}
    123

    其中的 0-7 表示右边算起第七个字符开始,3 表示字符的个数。
    结果是:123
    8.从右边第几个字符开始,一直到结束。
    [root@crh_ops sh]# echo ${var:0-7}
    123.htm

    表示从右边第七个字符开始,一直到结束。
    结果是:123.htm

    注:(左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示)


    二、Linux Shell 字符串的拼接方法


    如果想要在变量后面添加一个字符,可以用一下方法:
    [root@crh_ops sh]# value1=home
    [root@crh_ops sh]# value2=${value1}"="
    [root@crh_ops sh]# var3=${var1}${var2}
    [root@crh_ops sh]# echo $var3
    home=
    把要添加的字符串变量添加{},并且需要把$放到外面。这样输出的结果是:home=,也就是说连接成功。
    又如:
    [root@crh_ops sh]# var1=/etc/
    [root@crh_ops sh]# var2=yum.repos.d/
    [root@crh_ops sh]# var3=${var1}${var2}
    [root@crh_ops sh]# echo $var3
    /etc/yum.repos.d/

    原文地址:http://devopsh.com/860.html

    Nginx性能优化实例

    Geek小A 发表了文章 0 个评论 3729 次浏览 2015-10-31 15:34 来自相关话题

    WEB 性能优化是一个系统工程,涵盖很多方面,做好其中某个环节并不意味性能就能变好,但可以肯定地说,如果某个环节做得很糟糕,那么结果一定会变差。   首先说明下,本文提到的一些 Nginx 配置,需要较高版本 Linux 内核才支持。在 ...查看全部
    WEB 性能优化是一个系统工程,涵盖很多方面,做好其中某个环节并不意味性能就能变好,但可以肯定地说,如果某个环节做得很糟糕,那么结果一定会变差。
     
    首先说明下,本文提到的一些 Nginx 配置,需要较高版本 Linux 内核才支持。在实际生产环境中,升级服务器内核并不是一件容易的事,但为了获得最好的性能,有些升级还是必须的。很多公司服务器运维和项目开发并不在一个团队,一方追求稳定不出事故,另一方希望提升性能,本来就是矛盾的。那就商量着来吧!


    TCP 优化


    Nginx 关于 TCP 的优化基本都是修改系统内核提供的配置项,所以跟具体的 Linux 版本和系统配置有关,对这一块还不是非常熟悉,这里只能简单介绍下:
    http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 60;
    ... ...
    }
    第一行的 sendfile 配置可以提高 Nginx 静态资源托管效率。sendfile 是一个系统调用,直接在内核空间完成文件发送,不需要先 read 再 write,没有上下文切换开销。
     
    TCP_NOPUSH 是 FreeBSD 的一个 socket 选项,对应 Linux 的 TCP_CORK,Nginx 里统一用 tcp_nopush 来控制它,并且只有在启用了 sendfile 之后才生效。启用它之后,数据包会累计到一定大小之后才会发送,减小了额外开销,提高网络效率。

    TCP_NODELAY 也是一个 socket 选项,启用后会禁用 Nagle 算法,尽快发送数据,可以节约 200ms。Nginx 只会针对处于 keep-alive 状态的 TCP 连接才会启用 tcp_nodelay。

    可以看到 TCP_NOPUSH 是要等数据包累积到一定大小才发送,TCP_NODELAY 是要尽快发送,二者相互矛盾。实际上,它们确实可以一起用,最终的效果是先填满包,再尽快发送。
     
    关于这部分内容的更多介绍可以看这篇文章:http://t37.net/nginx-optimization-understanding-sendfile-tcp_nodelay-and-tcp_nopush.html
     
    配置最后一行用来指定服务端为每个 TCP 连接最多可以保持多长时间。Nginx 的默认值是 75 秒,有些浏览器最多只保持 60 秒,所以我统一设置为 60。

    另外,还有一个 TCP 优化策略叫 TCP Fast Open(TFO),这里先介绍下,配置在后面贴出。TFO 的作用是用来优化 TCP 握手过程。客户端第一次建立连接还是要走三次握手,所不同的是客户端在第一个 SYN 会设置一个 Fast Open 标识,服务端会生成 Fast Open Cookie 并放在 SYN-ACK 里,然后客户端就可以把这个 Cookie 存起来供之后的 SYN 用。下面这个图形象地描述了这个过程:
    tcp_trace.png

    关于 TCP Fast Open 的更多信息,可以查看RFC7413,或者这篇文章:Shaving your RTT with TCP Fast Open.需要注意的是,现阶段只有 Linux、ChromeOS 和 Android 5.0 的 Chrome / Chromium 才支持 TFO,所以实际用途并不大。
     
    5 月 26 日发布的 Nginx 1.9.1,增加了 reuseport 功能,意味着 Nginx 也开始支持 TCP 的 SO_REUSEPORT 选项了。这里也先简单介绍下,具体配置方法后面统一介绍。启用这个功能后,Nginx 会在指定的端口上监听多个 socket,每个 Worker 都能分到一个。请求过来时,系统内核会自动通过不同的 socket 分配给对应的 Worker,相比之前的单 socket 多 Worker 的模式,提高了分发效率。下面这个图形象地描述了这个过程:
    nginx1.png

    有关这部分内容的更多信息,可以查看 Nginx 的官方博客:Socket Sharding in NGINX Release 1.9.1。


    开启 Gzip


    我们在上线前,代码(JS、CSS 和 HTML)会做压缩,图片也会做压缩(PNGOUT、Pngcrush、JpegOptim、Gifsicle 等)。对于文本文件,在服务端发送响应之前进行 GZip 压缩也很重要,通常压缩后的文本大小会减小到原来的 1/4 - 1/3。下面是我的配置:
    http {
    gzip on;
    gzip_vary on;

    gzip_comp_level 6;
    gzip_buffers 16 8k;

    gzip_min_length 1000;
    gzip_proxied any;
    gzip_disable "msie6";

    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
    ... ...
    }
    这部分内容比较简单,只有两个地方需要解释下:
    gzip_vary 用来输出 Vary 响应头,用来解决某些缓存服务的一个问题.
     
    gzip_disable 指令接受一个正则表达式,当请求头中的 UserAgent 字段满足这个正则时,响应不会启用 GZip,这是为了解决在某些浏览器启用 GZip 带来的问题。特别地,指令值 msie6 等价于 MSIE [4-6]\.,但性能更好一些。另外,Nginx 0.8.11 后,msie6 并不会匹配 UA 包含 SV1 的 IE6(例如 Windows XP SP2 上的 IE6),因为这个版本的 IE6 已经修复了关于 GZip 的若干 Bug。


    开启缓存


    优化代码逻辑的极限是移除所有逻辑;优化请求的极限是不发送任何请求。这两点通过缓存都可以实现。


    服务端


    评论部分也早就换成了 Disqus,所以完全可以将页面静态化,这样就省掉了所有代码逻辑和数据库开销。实现静态化有很多种方案,我直接用的是 Nginx 的 proxy_cache
    proxy_cache_path  /home/jerry/cache/nginx/proxy_cache_path levels=1:2 keys_zone=pnc:300m inactive=7d max_size=10g;
    proxy_temp_path /home/jerry/cache/nginx/proxy_temp_path;
    proxy_cache_key $host$uri$is_args$args;

    server {
    location / {
    resolver 127.0.0.1;
    proxy_cache pnc;
    proxy_cache_valid 200 304 2h;
    proxy_cache_lock on;
    proxy_cache_lock_timeout 5s;
    proxy_cache_use_stale updating error timeout invalid_header http_500 http_502;

    proxy_http_version 1.1;

    proxy_ignore_headers Set-Cookie;
    ... ...
    }
    ... ...
    }
    首先,在配置最外层定义一个缓存目录,并指定名称(keys_zone)和其他属性,这样在配置 proxy_pass 时,就可以使用这个缓存了。这里我对状态值等于 200 和 304 的响应缓存了 2 小时。

    默认情况下,如果响应头里有 Set-Cookie 字段,Nginx 并不会缓存这次响应,因为它认为这次响应的内容是因人而异的。我的博客中,这个 Set-Cookie 对于用户来说没有用,也不会影响输出内容,所以我通过配置 proxy_ignore_header 移除了它。


    客户端


    服务端在输出响应时,可以通过响应头输出一些与缓存有关的信息,从而达到少发或不发请求的目的。HTTP/1.1 的缓存机制稍微有点复杂,这里简单介绍下:

    首先,服务端可以通过响应头里的 Last-Modified(最后修改时间) 或者 ETag(内容特征) 标记实体。浏览器会存下这些标记,并在下次请求时带上 If-Modified-Since: 上次 Last-Modified 的内容 或 If-None-Match: 上次 ETag 的内容,询问服务端资源是否过期。如果服务端发现并没有过期,直接返回一个状态码为 304、正文为空的响应,告知浏览器使用本地缓存;如果资源有更新,服务端返回状态码 200、新的 Last-Modified、Etag 和正文。这个过程被称之为 HTTP 的协商缓存,通常也叫做弱缓存。

    可以看到协商缓存并不会节省连接数,但是在缓存生效时,会大幅减小传输内容(304 响应没有正文,一般只有几百字节)。另外为什么有两个响应头都可以用来实现协商缓存呢?这是因为一开始用的 Last-Modified 有两个问题:1)只能精确到秒,1 秒内的多次变化反映不出来;2)时间采用绝对值,如果服务端 / 客户端时间不对都可能导致缓存失效 在轮询的负载均衡算法中,如果各机器读到的文件修改时间不一致,有缓存无故失效和缓存不更新的风险。HTTP/1.1 并没有规定 ETag 的生成规则,而一般实现者都是对资源内容做摘要,能解决前面两个问题。

    另外一种缓存机制是服务端通过响应头告诉浏览器,在什么时间之前(Expires)或在多长时间之内(Cache-Control: Max-age=xxx),不要再请求服务器了。这个机制我们通常称之为 HTTP 的强缓存。

    一旦资源命中强缓存规则后,再次访问完全没有 HTTP 请求(Chrome 开发者工具的 Network 面板依然会显示请求,但是会注明 from cache;Firefox 的 firebug 也类似,会注明 BFCache),这会大幅提升性能。所以我们一般会对 CSS、JS、图片等资源使用强缓存,而入口文件(HTML)一般使用协商缓存或不缓存,这样可以通过修改入口文件中对强缓存资源的引入 URL 来达到即时更新的目的。

    这里也解释下为什么有了 Expire,还要有 Cache-Control。也有两个原因:1)Cache-Control 功能更强大,对缓存的控制能力更强;2)Cache-Control 采用的 max-age 是相对时间,不受服务端 / 客户端时间不对的影响。

    另外关于浏览器的刷新(F5 / cmd + r)和强刷(Ctrl + F5 / shift + cmd +r):普通刷新会使用协商缓存,忽略强缓存;强刷会忽略浏览器所有缓存(并且请求头会携带 Cache-Control:no-cache 和 Pragma:no-cache,用来通知所有中间节点忽略缓存)。只有从地址栏或收藏夹输入网址、点击链接等情况下,浏览器才会使用强缓存。

    默认情况下,Nginx 对于静态资源都会输出 Last-Modified,而 ETag、Expire 和 Cache-Control 则需要自己配置:
    location ~ ^/static/ {
    root /home/jerry/www/blog/www;
    etag on;
    expires max;
    }
    expires 指令可以指定具体的 max-age,例如 10y 代表 10 年,如果指定为 max,最终输出的 Expires 会是 2037 年最后一天,Cache-Control 的 max-age 会是 10 年(准确说是 3650 天,315360000 秒)。


    使用 SPDY(HTTP/2)


    我的博客之前多次讲到过 HTTP/2(SPDY),现阶段 Nginx 只支持 SPDY/3.1,这样配置就可以启用了(编译 Nginx 时需要加上 --with-http_spdy_module 和 --with-http_ssl_module):
    server {
    listen 443 ssl spdy fastopen=3 reuseport;
    spdy_headers_comp 6;
    ... ...
    }
    那个 fastopen=3 用来开启前面介绍过的 TCP Fast Open 功能。3 代表最多只能有 3 个未经三次握手的 TCP 链接在排队。超过这个限制,服务端会退化到采用普通的 TCP 握手流程。这是为了减少资源耗尽攻击:TFO 可以在第一次 SYN 的时候发送 HTTP 请求,而服务端会校验 Fast Open Cookie(FOC),如果通过就开始处理请求。如果不加限制,恶意客户端可以利用合法的 FOC 发送大量请求耗光服务端资源。

    reuseport 就是用来启用前面介绍过的 TCP SO_REUSEPORT 选项的配置。


    HTTPS 优化


    建立 HTTPS 连接本身就慢(多了获取证书、校验证书、TLS 握手等等步骤),如果没有优化好只能是慢上加慢。
    server {
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    ssl_session_tickets on;

    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /xxx/root.crt;
    resolver 8.8.4.4 8.8.8.8 valid=300s;
    resolver_timeout 10s;
    ... ...
    }
    我的这部分配置就两部分内容:TLS 会话恢复和 OCSP stapling。

    TLS 会话恢复的目的是为了简化 TLS 握手,有两种方案:Session Cache 和 Session Ticket。他们都是将之前握手的 Session 存起来供后续连接使用,所不同是 Cache 存在服务端,占用服务端资源;Ticket 存在客户端,不占用服务端资源。另外目前主流浏览器都支持 Session Cache,而 Session Ticket 的支持度一般。

    ssl_stapling 开始的几行用来配置 OCSP stapling 策略。浏览器可能会在建立 TLS 连接时在线验证证书有效性,从而阻塞 TLS 握手,拖慢整体速度。OCSP stapling 是一种优化措施,服务端通过它可以在证书链中封装证书颁发机构的 OCSP(Online Certificate Status Protocol)响应,从而让浏览器跳过在线查询。服务端获取 OCSP 一方面更快(因为服务端一般有更好的网络环境),另一方面可以更好地缓存。
     
    这些策略设置好之后,可以通过 Qualys SSL Server Test 这个工具来验证是否生效,例如下图就是本博客的测试结果(via):
    nginx3.png

    在给 Nginx 指定证书时,需要选择合适的证书链。因为浏览器在验证证书信任链时,会从站点证书开始,递归验证父证书,直至信任的根证书。这里涉及到两个问题:1)服务器证书是在握手期间发送的,由于 TCP 初始拥塞窗口的存在,如果证书太长很可能会产生额外的往返开销;2)如果服务端证书没包含中间证书,大部分浏览器可以正常工作,但会暂停验证并根据子证书指定的父证书 URL 自己获取中间证书。这个过程会产生额外的 DNS 解析、建立 TCP 连接等开销。配置服务端证书链的最佳实践是包含站点证书和中间证书两部分。有的证书提供商签出来的证书级别比较多,这会导致证书链变长,选择的时候需要特别注意。


    原文作者:QuQu
    分享原文地址:https://imququ.com/post/my-nginx-conf-for-wpo.html


    Centos下apache网站乱码

    Geek小A 回复了问题 2 人关注 1 个回复 5250 次浏览 2015-10-31 00:09 来自相关话题

    Centos下扩展php的memcache模块脚本

    koyo 发表了文章 0 个评论 2450 次浏览 2015-10-30 00:52 来自相关话题

    #!/bin/bash #安装memcache的支持libevent yum -y install libevent #验证 ls -al /usr/lib | grep libeve ...查看全部
    #!/bin/bash

    #安装memcache的支持libevent
    yum -y install libevent

    #验证
    ls -al /usr/lib | grep libevent || echo "libevent install failed"

    #下载安装php的memcache扩展
    yum -y install gcc gcc-c++ autoconf
    cd /usr/local/src/;wget http://pecl.php.net/get/memcache-2.2.7.tgz
    tar zxf memcache-2.2.7.tgz
    cd memcache-2.2.7
    phpize
    ./configure
    make && make install

    echo "extension=memcache.so" >> /etc/php.ini


    php验证脚本


    
        $memcache = new Memcache;
    $memcache->connect('localhost', 11211) or die ("Could not connect");
    $memcache->set('key', 'test');
    $get_value = $memcache->get('key');
    echo $get_value;
    ?>

     

    inotify+unison实现数据双向实时同步

    陶亚可 发表了文章 0 个评论 4713 次浏览 2015-10-29 17:02 来自相关话题

    前几天做了一个新项目,网站架构是前端用的nginx反向代理了后端两台tomcat,这时候两台tomcat之间的数据实现实时同步,成了一个问题?  在网上搜寻了很多方案,在liux下做文件同步,有如下几种方式: []nfs实 ...查看全部


    前几天做了一个新项目,网站架构是前端用的nginx反向代理了后端两台tomcat,这时候两台tomcat之间的数据实现实时同步,成了一个问题?


     在网上搜寻了很多方案,在liux下做文件同步,有如下几种方式:
      []nfs实现web数据共享[/][]rsync +inotify实现web数据同步[/][]rsync+sersync更快更节约资源实现web数据同步[/][]unison+inotify实现web数据双向同步[/]

    在这里详细介绍第四种方案,前几种都有些各自的不足。只有第四种方案支持双向实时同步
    ,且当其中一台服务器宕机,也不会影响web的访问。(ps:之前一直喜欢nfs,配置非常简单,但是其有个致命的缺点就是其中一台web服务挂掉之后,会直接导致web页面无法访问)。

    Unison是一款跨平台的文件同步对象,不仅支撑本地对本地同步,也支撑经由过程SSH、RSH和Socket等收集和谈进行同步。
     Unison支撑双向同步操纵,你既可以从A同步到B,也可以从B同步到A,这些都不须要额外的设定。


    1、下载并且编译安装三个软件包


    (inotify-tools-3.14.tar.gz、ocaml-3.10.2.tar.gz、unison-2.32.52.tar.gz)
    [root@vmware1 tools]# wget http://caml.inria.fr/pub/distrib/ocaml-3.10/ocaml-3.10.2.tar.gz
    [root@vmware1 ~]# mkdir -p /taokey/tools
    [root@vmware1 ~]# cd /taokey/tools/
    [root@vmware1 tools]# wget http://caml.inria.fr/pub/distrib/ocaml-3.10/ocaml-3.10.2.tar.gz
    [root@vmware1 tools]# wget http://www.seas.upenn.edu/~bcpierce/unison//download/releases/unison-2.32.52/unison-2.32.52.tar.gz
    [root@vmware1 tools]# wget http://cloud.github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz

    [root@vmware1 tools]# tar xf inotify-tools-3.14.tar.gz
    [root@vmware1 tools]# tar xf ocaml-3.10.2.tar.gz
    [root@vmware1 tools]# ll
    总用量 3772
    drwxrwxrwx 5 1000 1000 4096 3月 14 2010 inotify-tools-3.14
    -rw-r--r-- 1 root root 358772 3月 14 2010 inotify-tools-3.14.tar.gz
    drwxrwxr-x 26 root wheel 4096 2月 29 2008 ocaml-3.10.2
    -rw-r--r-- 1 root root 2785669 2月 29 2008 ocaml-3.10.2.tar.gz
    drwxr-xr-x 7 501 wheel 4096 6月 30 2009 unison-2.32.52
    -rw-r--r-- 1 root root 697866 6月 30 2009 unison-2.32.52.tar.gz


    2、编译安装


    [size=16]编译安装inotify,需要安装gcc编译器,不然inotify编译报错。
    [root@vmware1 tools]# cd inotify-tools-3.14[/size]
    [root@vmware1 inotify-tools-3.14]# ./configure --prefix=/usr/local/inotify && make && make install

    [size=16]修改PATH环境变量
    [root@vmware1 inotify-tools-3.14]# cd /usr/local/inotify/[/size]
    [root@vmware1 inotify]# echo "PATH=/usr/local/inotify/bin:$PATH" >/etc/profile.d/inotify.sh
    [root@vmware1 inotify]# source /etc/profile.d/inotify.sh
    [size=16]添加库文件到系统识别的路径
    [root@vmware1 inotify]# echo "/usr/local/inotify/lib" >/etc/ld.so.conf.d/inotify.conf[/size]
    [root@vmware1 inotify]# ldconfig -v | grep inotify
    /usr/local/inotify/lib:
    libinotifytools.so.0 -> libinotifytools.so.0.4.1
    [size=16]链接库文件到系统识别的路径
    [root@vmware1 inotify]# ln -sv /usr/local/inotify/include/ /usr/include/inotify[/size]
    "/usr/include/inotify" -> "/usr/local/inotify/include/"
    [size=16]编译安装ocaml,unison依赖于ocaml
    [root@vmware1 ~]# cd /taokey/tools/ocaml-3.10.2[/size]
    [root@vmware1 ocaml-3.10.2]# ./configure
    [root@vmware1 ocaml-3.10.2]# make world opt
    [root@vmware1 ocaml-3.10.2]# make install
    [size=16]编译安装unison,安装依赖性包
    [root@vmware1 ocaml-3.10.2]# cd ../unison-2.32.52[/size]
    [root@vmware1 unison-2.32.52]# yum -y install ctags-etags
    [root@vmware1 unison-2.32.52]# make UISTYLE=text THREADS=true STATIC=true
    #UISTYLE=text THREADS=true STATIC=true 表示:使用命令方式,加入线程支持,以静态模式编译
    [size=16]make install会提示错误,此错误就是要你cp unison /usr/local/bin,复制即可
    [root@vmware1 unison-2.32.52]# make install[/size]
    mv /root/bin//unison /tmp/unison-10576
    mv: 无法获取"/root/bin//unison" 的文件状态(stat): 没有那个文件或目录
    make: [doinstall] 错误 1 (忽略)
    cp unison /root/bin/
    cp: 无法创建普通文件"/root/bin/": 是一个目录
    make: *** [doinstall] 错误 1
    [root@vmware1 unison-2.32.52]# cp unison /usr/local/bin
    在vmware2服务器192.168.1.12上,安装上述三个软件包。重复以上安装即可,步骤此处省略.


    3、免密码密钥登陆配置


    分别在服务器vmware1(192.168.1.11)和服务器vmware2(192.168.1.12)上生成ssh秘钥对。
    [root@vmware1 ~]# ssh-keygen -t rsa
    [root@vmware2 ~]# ssh-keygen -t rsa
    两台服务器之间实现免秘钥登陆。
    192.168.1.11:
    [root@vmware1 ~]# cd .ssh/
    [root@vmware1 .ssh]# touch authorized_keys
    [root@vmware1 .ssh]# cat id_rsa.pub >>authorized_keys
    [root@vmware1 .ssh]# scp authorized_keys 192.168.1.12:/root/.ssh

    192.168.12:
    [root@vmware2 ~]# cd .ssh/
    [root@vmware2 .ssh]# cat id_rsa.pub
    ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvVRA8c9QhTDBTOmbMWlRpQyPor2BOtTOCuPehvpEJdU4pSytLoSQBzQ1TOnbpeX7NSkhGDSTOFT96VdRMBPAF3mdDLg3j7mxPiMo3EDLSdo+kyPk1dVRnmfnplZms2mmFbZZnlRxd5FEgaY3vE/w1mJMMTrpgK+dZd7nOTmIx7QjIwGb5G31G+y7h7LGVpTR/amrJOw2POuzlOQnj2BNNkyGh2uIecBQ+zxNaTzZOoC2SLYPKnsIB5wSycbG5fN0sRMUzuV2R5fFYweb6IJ/2u0zJHhbLQDL9QtPGffb5wS9ZD23fb47HMwY1KPg9Dp7f6v/5vui5u8GPlO5k+aAKQ== root@vmware2
    需要把vmware2服务器上的id_rsa.pub复制到vmware1服务器上的authorized_keys文件中。
    [root@vmware1 .ssh]# cat authorized_keys 
    ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvVRA8c9QhTDBTOmbMWlRpQyPor2BOtTOCuPehvpEJdU4pSytLoSQBzQ1TOnbpeX7NSkhGDSTOFT96VdRMBPAF3mdDLg3j7mxPiMo3EDLSdo+kyPk1dVRnmfnplZms2mmFbZZnlRxd5FEgaY3vE/w1mJMMTrpgK+dZd7nOTmIx7QjIwGb5G31G+y7h7LGVpTR/amrJOw2POuzlOQnj2BNNkyGh2uIecBQ+zxNaTzZOoC2SLYPKnsIB5wSycbG5fN0sRMUzuV2R5fFYweb6IJ/2u0zJHhbLQDL9QtPGffb5wS9ZD23fb47HMwY1KPg9Dp7f6v/5vui5u8GPlO5k+aAKQ== root@vmware2
    完成之后,测试一下,是否可以免秘钥登陆。
    [root@vmware1 ~]# ssh 192.168.1.12
    reverse mapping checking getaddrinfo for bogon [192.168.1.12] failed - POSSIBLE BREAK-IN ATTEMPT!
    Last login: Tue Sep 9 22:03:33 2014 from 192.168.1.104
    [root@vmware2 ~]#
    最后,创建文件目录,编写脚本,实现数据实时同步。
    [root@vmware1 ~]# mkdir -p /var/vm1
    [root@vmware2 ~]# mkdir -p /var/vm2
    编unison同步的脚本进行测试
    [root@vmware1 ~]# cat unison-A.sh 
    ###################################################################[size=16]#[/size]
    #/bin/bash
    ipB="192.168.1.11"
    srcA="/var/vm1"
    dstB="/var/vm2"
    /usr/local/inotify/bin/inotifywait -mrq -e create,delete,modify,move $srcA | while read line; do
    /usr/local/bin/unison -batch $srcA ssh://$ipB/$dstB
    echo -n "$line " >> /var/log/inotify.log
    echo `date | cut -d " " -f1-4` >> /var/log/inotify.log
    done
    [root@vmware1 ~]# chmod o+x unison-A.sh
    [root@vmware1 ~]# sh unison-A.sh &
    vmware2服务器上:
    [root@vmware2 ~]# cat unison-B.sh 
    #/bin/bash
    ipA="192.168.1.11"
    srcB="/var/vm2"
    dstA="/var/vm1"
    /usr/local/inotify/bin/inotifywait -mrq -e create,delete,modify,move $srcB | while read line; do
    /usr/local/bin/unison -batch $srcB ssh://$ipA/$dstA
    echo -n "$line " >> /var/log/inotify.log
    echo `date | cut -d " " -f1-4` >> /var/log/inotify.log
    done
    [root@vmware2 ~]# sh unison-B.sh &
    [1] 10555
    [root@vmware1 ~]# cd /var/vm1/
    [root@vmware1 vm1]# ls
    a b c test
    [root@vmware2 ~]# cd /var/vm2/
    [root@vmware2 vm2]# ls
    a b c test
    [root@vmware2 vm2]# rm -rf test
    [root@vmware1 vm1]# ls
    a b c
    试验到此结束。

    shell如何截取字符串中的数字

    push 回复了问题 3 人关注 2 个回复 6300 次浏览 2015-10-28 11:11 来自相关话题