??xml version="1.0" encoding="utf-8" standalone="yes"?>
Memcached对大家应该不陌生Q通过把Key映射到Memcached Server上,实现快速读取。我们可以动态对其节点增加,q未影响之前已经映射到内存的Key与memcached Server之间的关p,q就是因Z用了一致性哈希?br />因ؓMemcached的哈希策略是在其客户端实现的Q因此不同的客户端实C有区别,以Spymemcache、XmemcacheZQ都是用了KETAMA作ؓ其实现?/p>
因此Q我们也可以使用一致性hash法来解决Redis分布式这个问题。在介绍一致性hash法之前Q先介绍一下我之前想的一个方法,怎么把Key均匀的映到多台Redis Server上?/p>
׃LZ水^有限且对Redis研究的不深,文中有写的不对的地方h正?/strong>
该方案是前几天想的一个方法,主要思\是通过对缓存Key中的字母和数字的ascii码值求sumQ该sum值对Redis ServerL取余得到的数字即Key映射到的Redis ServerQ该Ҏ有一个很大的~陷是当Redis Server增加或减时Q基本上所有的Key都映不到对应的的Redis Server了。代码如下:
/// <summary> /// Ҏ~存的Key映射对应的Server /// </summary> /// <param name="Key"></param> /// <returns></returns> public static RedisClient GetRedisClientByKey(string Key) { List<RedisClientInfo> RedisClientList = new List<RedisClientInfo>(); RedisClientList.Add(new RedisClientInfo() { Num = 0, IPPort = "127.0.0.1:6379" }); RedisClientList.Add(new RedisClientInfo() { Num = 1, IPPort = "127.0.0.1:9001" }); char[] charKey = Key.ToCharArray(); //记录Key中的所有字母与数字的ascii码和 int KeyNum = 0; //记录余数 int Num = 0; foreach (var c in charKey) { if ((c >= 'a' && 'z' >= c) || (c >= 'A' && 'Z' >= c)) { System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding(); KeyNum = KeyNum + (int)asciiEncoding.GetBytes(c.ToString())[0]; } if (c >= '1' && '9' >= c) { KeyNum += Convert.ToInt32(c.ToString()); } } Num = KeyNum % RedisClientList.Count; return new RedisClient(RedisClientList.Where(it => it.Num == Num).First().IPPort); } //Redis客户端信?/span> public class RedisClientInfo { //Redis Server~号 public int Num { get; set; } //Redis Server IP地址和端口号 public string IPPort { get; set; } }
通过key做一致性哈希,实现key对应redisl点的分布?/p>
一致性哈希的实现Q?/p>
什么也不多说了Q直接上代码吧,LZ也是只知道点皮毛Q代码中q有一些看不懂的地方,留着以后慢慢琢磨
public class KetamaNodeLocator { //原文中的JAVAcTreeMap实现了ComparatorҎQ这里我囄事,直接用了net下的SortedListQ其中Comparer接口ҎQ?/span> private SortedList<long, string> ketamaNodes = new SortedList<long, string>(); private HashAlgorithm hashAlg; private int numReps = 160; //此处参数与JAVA版中有区别,因ؓ使用的静态方法,所以不再传递HashAlgorithm alg参数 public KetamaNodeLocator(List<string> nodes/*Qint nodeCopies*/) { ketamaNodes = new SortedList<long, string>(); //numReps = nodeCopies; //Ҏ有节点,生成nCopies个虚拟结?/span> foreach (string node in nodes) { //每四个虚拟结点ؓ一l?/span> for (int i = 0; i < numReps / 4; i++) { //getKeyForNodeҎl虚拟结点得到惟一名称 byte[] digest = HashAlgorithm.computeMd5(node + i); /** Md5是一?6字节长度的数l,?6字节的数l每四个字节一l,分别对应一个虚拟结点,q就是ؓ什么上面把虚拟l点四个划分一l的原因*/ for (int h = 0; h < 4; h++) { long m = HashAlgorithm.hash(digest, h); ketamaNodes[m] = node; } } } } public string GetPrimary(string k) { byte[] digest = HashAlgorithm.computeMd5(k); string rv = GetNodeForKey(HashAlgorithm.hash(digest, 0)); return rv; } string GetNodeForKey(long hash) { string rv; long key = hash; //如果扑ֈq个节点Q直接取节点Q返? if (!ketamaNodes.ContainsKey(key)) { //得到大于当前key的那个子MapQ然后从中取出第一个keyQ就是大于且d最q的那个key 说明详见: http://www.javaeye.com/topic/684087 var tailMap = from coll in ketamaNodes where coll.Key > hash select new { coll.Key }; if (tailMap == null || tailMap.Count() == 0) key = ketamaNodes.FirstOrDefault().Key; else key = tailMap.FirstOrDefault().Key; } rv = ketamaNodes[key]; return rv; } } public class HashAlgorithm { public static long hash(byte[] digest, int nTime) { long rv = ((long)(digest[3 + nTime * 4] & 0xFF) << 24) | ((long)(digest[2 + nTime * 4] & 0xFF) << 16) | ((long)(digest[1 + nTime * 4] & 0xFF) << 8) | ((long)digest[0 + nTime * 4] & 0xFF); return rv & 0xffffffffL; /* Truncate to 32-bits */ } /** * Get the md5 of the given key. */ public static byte[] computeMd5(string k) { MD5 md5 = new MD5CryptoServiceProvider(); byte[] keyBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(k)); md5.Clear(); //md5.update(keyBytes); //return md5.digest(); return keyBytes; } }
1、假设有两个serverQ?001?002Q@环调?0ơ看看KeyD不能均匀的映到server上,代码如下Q?/p>
static void Main(string[] args) { //假设的server List<string> nodes = new List<string>() { "0001","0002" }; KetamaNodeLocator k = new KetamaNodeLocator(nodes); string str = ""; for (int i = 0; i < 10; i++) { string Key="user_" + i; str += string.Format("Key:{0}分配到的Server为:{1}\n\n", Key, k.GetPrimary(Key)); } Console.WriteLine(str); Console.ReadLine(); }
E序q行两次的结果如下,发现Key基本上均匀的分配到Server节点上了?/p>
2、我们在d一?003的server节点Q代码如下:
static void Main(string[] args) { //假设的server List<string> nodes = new List<string>() { "0001","0002" ,"0003"}; KetamaNodeLocator k = new KetamaNodeLocator(nodes); string str = ""; for (int i = 0; i < 10; i++) { string Key="user_" + i; str += string.Format("Key:{0}分配到的Server为:{1}\n\n", Key, k.GetPrimary(Key)); } Console.WriteLine(str); Console.ReadLine(); }
E序q行两次的结果如下:
ҎW一ơ的q行l果发现只有user_5,user_7,user_9的缓存丢失,其他的缓存还可以命中?/p>
3、我们去掉server 0002Q运行两ơ的l果如下:
ҎW二ơ和本次q行l果发现 user_0,user_1,user_6 ~存丢失?/p>
通过一致性hash法可以很好的解决Redis分布式的问题Q且当Redis server增加或减的时候,之前存储的缓存命中率q是比较高的?br />
http://www.cnblogs.com/lc-chenlong/p/4194150.html
http://www.cnblogs.com/lc-chenlong/p/4195033.html
http://www.cnblogs.com/lc-chenlong/p/3218157.html
1?a target="_blank" style="color: #1d58d1; text-decoration: none;">http://blog.csdn.net/chen77716/article/details/5949166
2?a target="_blank" style="color: #1d58d1; text-decoration: none;">http://www.cr173.com/html/6474_2.html
?http://www.cnblogs.com/lc-chenlong/p/4195814.html?utm_source=tuicool&utm_medium=referral
上一我们讲C Redis 的主从复制技术,当实C多节点的 master-slave 后,我们也可以把它叫做集,但我们今天要讲的集群主要是利用切片技术来l徏的集?/p>
集群要实现的目的是要不同的 key 分散攄C同的 redis 节点Q这里我们需要一个规则或者算法,通常的做法是获取 key 的哈希|然后Ҏ节点数来求模Q但q种做法有其明显的弊端,当我们需要增加或减少一个节ҎQ会造成大量?key 无法命中Q这U比例是相当高的Q所以就有h提出了一致性哈希的概念?/p>
一致性哈希有四个重要特征Q?/p>
均衡性:也有人把它定义ؓq性,是指哈希的结果能够尽可能分布到所有的节点中去Q这样可以有效的利用每个节点上的资源?/p>
单调性:对于单调性有很多译让我非常的不解,而我惌的是当节Ҏ量变化时哈希的结果应可能的保护已分配的内容不会被重新分zֈ新的节点?/span>
但一致性哈希不是我们今天要介绍的重点,因ؓ Redis 引入另一U哈希槽Qhash slotQ的概念?/p>
Redis 集群中内|了 16384 个哈希槽Q当需要在 Redis 集群中放|一?key-value Ӟredis 先对 key 使用 crc16 法出一个结果,然后把结果对 16384 求余敎ͼq样每个 key 都会对应一个编号在 0-16383 之间的哈希槽Qredis 会根据节Ҏ量大致均{的哈希槽映射C同的节点?/p>
使用哈希槽的好处在于可以方便的d或移除节炏V?/p>
当需要增加节ҎQ只需要把其他节点的某些哈希槽挪到新节点就可以了;
当需要移除节ҎQ只需要把U除节点上的哈希槽挪到其他节点就行了Q?/p>
内部机制Q与我何qԌ对于我们来说Q在新增或移除节点的时候不要让我们先停掉所有的 redis 服务我就谢天谢地了,q点它做C?/p>
下面我们开始动手搭Z?redis 集群来体验一下?/p>
因ؓ我们要启动多?redis 实例Q虽然我们可以直接通过命o行来启动Q但始终是不怎么方便的,所以我们先来新Z个实例目录,分别?001Q?002Q?003Q目录名是 redis 实例的端口号?/p>
我这里已l徏好了目录Q然后我们把以前~译q和修改q的 redis-server、redis.confq两个文件分别拷贝到q三个目录里面,拯完之后就像这样子了:
我们打开 redis.conf 文gQؓ了简单v见,我们只保留下面几个配|项Q?/p>
daemonize yes
port 9001
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
注意Qport 要修Ҏ对应目录的名字,也就是每个实例要有不同的端口?/p>
下面我们分别启动q三个实例:
zhaoguihuadediannao:~ zhaogh$ cd applications/dev/redis-cluster
zhaoguihuadediannao:redis-cluster zhaogh$ cd 9001
zhaoguihuadediannao:9001 zhaogh$ ./redis-server ./redis.conf
zhaoguihuadediannao:9003 zhaogh$ cd ../9002
zhaoguihuadediannao:9002 zhaogh$ ./redis-server ./redis.conf
zhaoguihuadediannao:9002 zhaogh$ cd ../9003
zhaoguihuadediannao:9003 zhaogh$ ./redis-server ./redis.conf
zhaoguihuadediannao:9003 zhaogh$
接下来我们来创徏集群Q让三个实例互相通讯Q?/p>
zhaoguihuadediannao:src zhaogh$ ./redis-trib.rb create --replicas 0 127.0.0.1:9001 127.0.0.1:9002 127.0.0.1:9003
>>> Creating cluster
Connecting to node 127.0.0.1:9001: OK
Connecting to node 127.0.0.1:9002: OK
Connecting to node 127.0.0.1:9003: OK
>>> Performing hash slots allocation on 3 nodes...
Using 3 masters:
127.0.0.1:9001
127.0.0.1:9002
127.0.0.1:9003
M: 92c9912cb1ccf657c886ecd839dd32c66efd8762 127.0.0.1:9001
slots:0-5460 (5461 slots) master
M: b6d46fcb8b0e6ee373b09a4f2cbcec744d1a259b 127.0.0.1:9002
slots:5461-10922 (5462 slots) master
M: 44ab30c7c589ffb15b9b04dd827c72cfaeedacb2 127.0.0.1:9003
slots:10923-16383 (5461 slots) master
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join..
>>> Performing Cluster Check (using node 127.0.0.1:9001)
M: 92c9912cb1ccf657c886ecd839dd32c66efd8762 127.0.0.1:9001
slots:0-5460 (5461 slots) master
M: b6d46fcb8b0e6ee373b09a4f2cbcec744d1a259b 127.0.0.1:9002
slots:5461-10922 (5462 slots) master
M: 44ab30c7c589ffb15b9b04dd827c72cfaeedacb2 127.0.0.1:9003
slots:10923-16383 (5461 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
zhaoguihuadediannao:src zhaogh$
需要注意的是执?nbsp;redis-trib.rb 命o需?ruby 的支持,如果你没有安装可以先?nbsp;https://rubygems.org/gems/redis 下蝲Q然后离U安装?/p>
sudo gem install redis-3.0.7.gem --local
下面我们?redis 自带的客L试一下:
zhaoguihuadediannao:src zhaogh$ ./redis-cli -c -p 9001
127.0.0.1:9001> get testkey001
-> Redirected to slot [12786] located at 127.0.0.1:9003
(nil)
127.0.0.1:9003> set testkey002 testvalue002
-> Redirected to slot [401] located at 127.0.0.1:9001
OK
127.0.0.1:9001> get testkey002
"testvalue002"
127.0.0.1:9001> set testkey003 testvalue003
OK
127.0.0.1:9001>
可以看到Q虽然我们第一ơ连接的?001端口Q当我们去获?testkey001 的时候,redis cluster 自动帮我们重定向?9003 ?/p>
当我们在 9003 讄 testkey002 Ӟredis cluster 又重定向?9001 ?/p>
#q行用户
user www-data;
#启动q程,通常讄成和cpu的数量相{?br />worker_processes 1;#全局错误日志及PID文g
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;#工作模式及连接数上限
events {
use epoll; #epoll是多路复用IO(I/O Multiplexing)中的一U方?但是仅用于linux2.6以上内核,可以大大提高nginx的性能
worker_connections 1024;#单个后台worker processq程的最大ƈ发链接数
# multi_accept on;
}#讑֮http服务器,利用它的反向代理功能提供负蝲均衡支持
http {
#讑֮mimecd,cd由mime.type文g定义
include /etc/nginx/mime.types;
default_type application/octet-stream;
#讑֮日志格式
access_log /var/log/nginx/access.log;#sendfile 指o指定 nginx 是否调用 sendfile 函数Qzero copy 方式Q来输出文gQ对于普通应用,
#必须设ؓ on,如果用来q行下蝲{应用磁盘IO重负载应用,可设|ؓ offQ以q盘与网lI/O处理速度Q降低系l的uptime.
sendfile on;
#tcp_nopush on;#q接时旉
#keepalive_timeout 0;
keepalive_timeout 65;
tcp_nodelay on;
#开启gzip压羃
gzip on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";#讑֮h~冲
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;#讑֮负蝲均衡的服务器列表
upstream mysvr {
#weigth参数表示权|权D高被分配到的几率大
#本机上的Squid开?128端口
server 192.168.8.1:3128 weight=5;
server 192.168.8.2:80 weight=1;
server 192.168.8.3:80 weight=6;
}
server {
#侦听80端口
listen 80;
#定义使用www.xx.com讉K
server_name www.xx.com;#讑֮本虚拟主机的讉K日志
access_log logs/www.xx.com.access.log main;#默认h
location / {
root /root; #定义服务器的默认|站根目录位|?br /> index index.php index.html index.htm; #定义首页索引文g的名U?/p>fastcgi_pass www.xx.com;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}# 定义错误提示面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /root;
}#静态文Ӟnginx自己处理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root /var/www/virtual/htdocs;
#q期30天,静态文件不怎么更新Q过期可以设大一点,如果频繁更新Q则可以讄得小一炏V?br /> expires 30d;
}
#PHP 脚本h全部转发?FastCGI处理. 使用FastCGI默认配置.
location ~ \.php$ {
root /root;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/www/www$fastcgi_script_name;
include fastcgi_params;
}
#讑֮查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
auth_basic_user_file conf/htpasswd;
}
#止讉K .htxxx 文g
location ~ /\.ht {
deny all;
}
}
}
以上是一些基本的配置,使用Nginx最大的好处是负蝲均衡
如果要用负载均衡的?可以修改配置http节点如下Q?/p>
#讑֮http服务器,利用它的反向代理功能提供负蝲均衡支持
http {
#讑֮mimecd,cd由mime.type文g定义
include /etc/nginx/mime.types;
default_type application/octet-stream;
#讑֮日志格式
access_log /var/log/nginx/access.log;#省略上文有的一些配|节?/p>
#。。。。。。。。。?/p>
#讑֮负蝲均衡的服务器列表
upstream mysvr {
#weigth参数表示权|权D高被分配到的几率大
server 192.168.8.1x:3128 weight=5;#本机上的Squid开?128端口
server 192.168.8.2x:80 weight=1;
server 192.168.8.3x:80 weight=6;
}upstream mysvr2 {
#weigth参数表示权|权D高被分配到的几率大server 192.168.8.x:80 weight=1;
server 192.168.8.x:80 weight=6;
}#W一个虚拟服务器
server {
#侦听192.168.8.x?0端口
listen 80;
server_name 192.168.8.x;#对aspx后缀的进行负载均衡请?br /> location ~ .*\.aspx$ {
root /root; #定义服务器的默认|站根目录位|?br /> index index.php index.html index.htm; #定义首页索引文g的名U?/p>
proxy_pass http://mysvr ;#h转向mysvr 定义的服务器列表
#以下是一些反向代理的配置可删?
proxy_redirect off;
#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m; #允许客户端请求的最大单文g字节?br /> client_body_buffer_size 128k; #~冲Z理缓冲用Lh的最大字节数Q?br /> proxy_connect_timeout 90; #nginx跟后端服务器q接时旉(代理q接时)
proxy_send_timeout 90; #后端服务器数据回传时?代理发送超?
proxy_read_timeout 90; #q接成功后,后端服务器响应时?代理接收时)
proxy_buffer_size 4k; #讄代理服务器(nginxQ保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers~冲区,|页q_?2k以下的话Q这栯|?br /> proxy_busy_buffers_size 64k; #高负荷下~冲大小Qproxy_buffers*2Q?br /> proxy_temp_file_write_size 64k; #讑֮~存文g夹大,大于q个|从upstream服务器传}
}
}
以下使用W四U方案,集群环境Q?/p>
1. nginx最新版本:1.5.7
2. tomcat版本Q?.0.37
3. memcached最新版本:1.4.15
4. session复制同步使用memcache-session-manager最新版本:1.6.5
5. pȝQCentOS6.3
一、Nginx安装
- centos6.3默认未安装gcc-c++Q先装gccQ?/p>
yum -y install gcc-c++
装完后记得rebootpȝ?/p>
- cd到安装目?/p>
cd /usr/lcoal/src
- 安装pcre?/p>
cd /usr/local/src wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.21.tar.gz tar -zxvf pcre-8.21.tar.gz cd pcre-8.21 ./configure make make install
如果wget下蝲不到的话Q去官网下蝲pcre-8.12.tar.gz包拷贝到src下?/p>
- 安装zlib?/p>
cd /usr/local/src wget http://zlib.net/zlib-1.2.8.tar.gz tar -zxvf zlib-1.2.8.tar.gz cd zlib-1.2.8 ./configure make make install
- 安装ssl
cd /usr/local/src wget http://www.openssl.org/source/openssl-1.0.1c.tar.gz tar -zxvf openssl-1.0.1c.tar.gz
- 安装nginx
cd nginx-1.5.7 ./configure --prefix=/usr/local/nginx/nginx \ --with-http_ssl_module \ --with-pcre=/usr/local/src/pcre-8.12 \ --with-zlib=/usr/local/src/zlib-1.2.8 \ --with-openssl=/usr/local/src/openssl-1.0.1c make make install
安装成功Qcd /usr/local/nginx/conf/nginx.confQ修攚w|文Ӟ
http { ... upstream localhost { server localhost:8081; server localhost:8082; server localhost:8083; } ... } location / { root html; index index.html index.htm; proxy_pass http://localhost; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; }
二、memcached安装
- memcached安装较简单,需要先libevent库:
sudo yum install libevent libevent-devel wget http://www.danga.com/memcached/dist/memcached-1.4.15.tar.gz tar zxf memcached-1.4.15.tar.gz cd memcached-1.4.15 ./configure make sudo make install
安装成功Q默认安装在bin下)Q启动:
#-vv 控制台输?#-d 后台q行 /usr/local/bin/memcached -vv
启动后,可以telnet上去看下状态:
telnet 127.0.0.1 11211 stats
三、tomcat配置
1. 修改server.xml
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1"> ... <Context path="" docBase="/demo/appserver/app/cluster" debug="0" reloadable="true" crossContext="true"> <Manager
className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:192.168.2.43:11211" requestUriIgnorePattern=".*\.(png|gif|jpg|css|js|ico|jpeg|htm|html)$" sessionBackupAsync="false" sessionBackupTimeout="1800000" copyCollectionsForSerialization="false" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" /> </Context>
2. dmem和msm的依赖jar?/p>
couchbase-client-1.2.2.jar
javolution-5.4.3.1.jar
kryo-1.03.jar
kryo-serializers-0.10.jar
memcached-session-manager-1.6.5.jar
memcached-session-manager-tc6-1.6.5.jar
minlog-1.2.jar
msm-kryo-serializer-1.6.5.jar
reflectasm-0.9.jar
spymemcached-2.10.2.jar
注意点:
-msm1.6.5依赖了CouchbaseQ需要添加couchbase-client的jar包,否则启动会报Qjava.lang.NoClassDefFoundError: com/couchbase/client/CouchbaseClient?/p>
-tomcat6?使用不同msm支持包:memcached-session-manager-tc6-1.6.5.jar和memcached-session-manager-tc7-1.6.5.jarQ只可选一Q否则启动报错?/p>
-msm源码中的lib包版本太低:spymemcached-2.7.jar需要?.10.2Q否则启动tomcat报错Q?/p>
java.lang.NoSuchMethodError: net.spy.memcached.MemcachedClient.set(Ljava/lang/String;ILjava/lang/Object;)Lnet/spy/memcached/internal/OperationFuture;
at de.javakaffee.web.msm.BackupSessionTask.storeSessionInMemcached(BackupSessionTask.java:227)
kryo-serializers-0.8.jar需要?.10版本Q否则报错:
Caused by: java.lang.ClassNotFoundException: de.javakaffee.kryoserializers.DateSerializer
tomcat启动成功后可以去h面Qip端口会变化,session是不会变化的Q?/p>
memcached的状态可以看到同步session的操作日志:
一QNginx介:
Nginx一个高性能的HTTP和反向代理服务器Q?nbsp;h很高的稳定性和支持热部|Ӏ模块扩展也很容易。当遇到讉K的峰|或者有人恶意发h速连接时Q也很可能会D服务器物理内存耗尽频繁交换Q失d应,只能重启服务器,Nginx采取了分阶段资源分配技术,处理静态文件和无缓存的反向代理加速,实现了负载均衡和定wQ在q样高ƈ发的讉K情况下,能经受v高ƈ发的处理?/p>
二.Nginx安装与配|?/strong>
W一步:下蝲Nginx 安装?nbsp;
http://nginx.org/en/download.html
W二步:在linux上安装Nginx
1.#tar zxvf nginx-1.7.8.tar.gz //解压
2.#cd nginx-1.7.8
3.#./configure --with-http_stub_status_module --with-http_ssl_module//启动server状态页和https模块
会报~少PCRE library错误Q如图所C:
q时先执行第三步安装PCRE Q然后在3执行一下,q就可以?/p>
4.make && make install //~译q安?/p>
5.试一下安装配|是否正?Nginx安装?usr/local/nginx
#/usr/local/nginx/sbin/nginx -tQ如图所C:
W三步:在linux上安装PCRE
1.#tar zxvf pcre-8.10.tar.gz //解压
2.cd pcre-8.10
3../configure
4.make && make install//~译q安?/p>
三.Nginx +Tomcat 实现动静态分?/strong>
动静态分d是Nginx处理客户端的h的静态页?html面)或者图片,Tomcat处理客户端请求的动态页面(jsp面Q,因ؓNginx处理的静态页面的效率高于Tomcat?/p>
W一步:我们要配|Nginx文g
#vi /usr/local/nginx/conf/nginx.conf
#user nobody; worker_processes 1; error_log logs/error.log; pid logs/nginx.pid; events { use epoll; worker_connections 1024; } 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"'; access_log logs/access.log main; sendfile on; keepalive_timeout 65; gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.0; gzip_comp_level 2; gzip_types text/plain application/x-javascript text/css application/xml; gzip_vary on; server { listen 80 default; server_name localhost; <span style="color:#ff0000;"> location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ //由nginx处理静态页?lt;/span> { root /usr/tomcat/apache-tomcat-8081/webapps/ROOT; expires 30d; //~存到客L30? } error_page 404 /404.html; #redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } <span style="color:#ff0000;"> location ~ \.(jsp|do)$ {//所有jsp的动态请求都交给Tomcat处理 </span> <span style="color:#ff0000;"> proxy_pass http://192.168.74.129:8081; //来自jsp或者do的后~的请求交ltomcat处理</span> proxy_redirect off; proxy_set_header Host $host; //后端的Web服务器可以通过X-Forwarded-For获取用户真实IP proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; //允许客户端请求的最大单文g字节? client_body_buffer_size 128k; //~冲Z理缓冲用Lh的最大字节数 proxy_connect_timeout 90; //nginx跟后端服务器q接时旉 proxy_read_timeout 90; //q接成功后,后端服务器响应时? proxy_buffer_size 4k; //讄代理服务器(nginxQ保存用户头信息的缓冲区大小 proxy_buffers 6 32k; //proxy_buffers~冲区,|页q_?2k以下的话Q这栯|? proxy_busy_buffers_size 64k;//高负荷下~冲大小Qproxy_buffers*2Q? proxy_temp_file_write_size 64k; //讑֮~存文g夹大,大于q个|从upstream服务器传 } } }
W二步:在tomcat 下的webapps/ROOT下新建index.html静态页面,如图所C:
W三步:启动Nginx服务
#sbin/nginx 如图所C:
W四步:我们面讉Khttp://192.168.74.129/index.html 能正常显C正常的内容Q如图所C:
W五步:试Nginx 和Tomcat高ƈ发的情况下处理静态页面性能如何Q?/strong>
采用?nbsp;Linux ab|站压力试命o来测试一下性能
1.试一下Nginx 处理静态页面的性能
ab -c 100 -n 1000 http://192.168.74.129/index.html
q个表示同时处理100个请求ƈq行1000ơindex.html文g,如图所C:
2.试一下Tomcat处理静态页面的性能
ab -c 100 -n 1000 http://192.168.74.129:8081/index.html
q个表示同时处理100个请求ƈq行1000ơindex.html文g,如图所C:
相同的处理静态文ӞNginx处理的静态性能比Tomcat 好。Nginx每秒能请?388ơ,而tomcat只请?609ơ?/p>
ȝQ我们在Nginx配置文g中,配置静态交lNginx处理Q动态请求交lTomcatQ提供了性能?/p>
四.Nginx +Tomcat 负蝲均衡与容?/strong>
我们在高q发的情况下Qؓ了提高服务器的性能Q减了单台服务器的q发压力Q我们采用了集群部vQ还能解决ؓ了避免单台服务器挂掉Q服务不能访问这U情况下Q处理容错问题?/p>
W一步:我们q边部v了两天tomcat服务器,192.168.74.129:8081?92.168.74.129:8082
W二步:Nginx作ؓ了代理服务器Q客服端h服务器端Ӟ采用了负载均衡来处理Q这样就能^均的把客服端h分发到每一天服务器Q这样减服务器端的压力。配|Nginx下的nginx.conf文g?/strong>
#vi /usr/local/nginx/conf/nginx.conf
#user nobody; worker_processes 1; error_log logs/error.log; pid logs/nginx.pid; events { use epoll; worker_connections 1024; } 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"'; access_log logs/access.log main; sendfile on; keepalive_timeout 65; gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.0; gzip_comp_level 2; gzip_types text/plain application/x-javascript text/css application/xml; gzip_vary on; <span style="color:#ff0000;">upstream localhost_server { ip_hash; server 192.168.74.129:8081; server 192.168.74.129:8082; }</span> server { listen 80 default; server_name localhost; <span style="color:#ff0000;"> location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ //由nginx处理静态页?lt;/span> { root /usr/tomcat/apache-tomcat-8081/webapps/ROOT; expires 30d; //~存到客L30? } error_page 404 /404.html; #redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } <span style="color:#ff0000;">location ~ \.(jsp|do)$ {//所有jsp的动态请求都交给Tomcat处理 </span> <span style="color:#ff0000;">proxy_pass http://localhost_server; //来自jsp或者do的后~的请求交ltomcat处理</span> proxy_redirect off; proxy_set_header Host $host; //后端的Web服务器可以通过X-Forwarded-For获取用户真实IP proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; //允许客户端请求的最大单文g字节? client_body_buffer_size 128k; //~冲Z理缓冲用Lh的最大字节数 proxy_connect_timeout 90; //nginx跟后端服务器q接时旉 proxy_read_timeout 90; //q接成功后,后端服务器响应时? proxy_buffer_size 4k; //讄代理服务器(nginxQ保存用户头信息的缓冲区大小 proxy_buffers 6 32k; //proxy_buffers~冲区,|页q_?2k以下的话Q这栯|? proxy_busy_buffers_size 64k;//高负荷下~冲大小Qproxy_buffers*2Q? proxy_temp_file_write_size 64k; //讑֮~存文g夹大,大于q个|从upstream服务器传 } } }
说明Q?/p>
1.upstream 中的server是指向服务器的IPQ域名)和端口,后面q可以带参数
1)weight Q设|服务器的{发权?nbsp;默认值是1?/p>
2)max_fails Q?nbsp;是与fail_timeout配合使用Q是指在fail_timeout旉D内Q如果服务器转发p|ơ数过max_fails讄的|q台服务器就? 可用Qmax_fails默认值是1
3)fail_timeout :表示在该旉D内转发p|多少ơ就认ؓq台服务器不能用?/p>
4)downQ表C台服务器不能用?/p>
5)backupQ表CZip_hash讄的针对这台服务器无效Q只有在所有非备䆾的服务器都失效后Q才会向服务器{发请求?/p>
2.ip_hash 讄是在集群的服务器中,如果同一个客Lh转发到多个服务器上,每台服务器可能缓存同一份信息,q会造成资源的浪费,采用的ip_hash讄会把同一个客LW二ơ请求相同的信息Ӟ会{发到W一ơ请求的服务器端。但ip_hash不能和weight 同时使用?/p>