先说点题外话:
1 nginx:是一种http和反向代理软件,以稳定高效著称,实际中也经常用来做负载均衡高可用(我以前一直在用无敌的zxtm)
2 varnish:是一种加速http和反向代理软件,实际中主要用来作为前端代理cache,比如用在图片服务器
3 memcached:是一种被内存管理的(效率高)分布式内存对象缓存软件,主要在后台和数据库交互中减少数据库负载以及服务器性能
1 moxi是什么?
给一个简单前台lamp(p表示php)的架构示意(原文http://www.slideshare.net/northscale/moxi-memcached-proxy):

2 还需要对memcached代理嘛?
我们实际工作中有图片服务器,应用服务器,数据库服务器,反向代理服务器等,大公司的memcached就得几百台,我举个例子,比如有200台服务器,标配4G内存,大概这个memcached集群是200*3G(为什么不是4G?内存分配量超过这个值,就有可能导致内存交换(swap)),我想大家都经历过因为某些原因让memcached死掉的时候,怎么管理以及提高效率呢?我们要保证服务高可用不影响正常访问,分开集群而不是统一管理,我有2个办法
1 使用daemontools中的supervise,让死掉的memcached自动启动起来,请参看我以前的文章: 使用supervise让不稳定程序死掉自动马上重启
2 使用moxi集群,效果可能是这样的:
使用moxi作为memcached代理_第1张图片
3 moxi的优点特性
1 基于memcached开发,自然也是基于libevent、多线程模型,支持一致性hash(这个一致性hash和根据余数计算分散的研究有时间会专门说)
2 对于并发的gets请求,moxi会做合并来减少和memcache server的交互
3 对热点访问的cache(可以人工通过前缀key指定),moxi会在本 地缓存,使得moxi相当于memcache server的前端cache,能减少network hops。不过这种热点cache项相对要少很多,而且为保证能正确失效,热点cache需要被复制到moxi集群的每个节点
4 对于某种类型的key,在set时可以异步提交到memcache server而不需要client等待返回结果
5 可以配置请求的超时时间,如果超时就返回失败。如果直接操作memcache server,因为没有超时机制,在一些情况下会hang住很长时间(比如网络问题、memcache server处理大数据量的缓慢等)
6 memcache server不能访问时,Moxi会重试多次,如果失败就返回给client失败。Moxi支持动态的迁移memcache server配置。特别的,moxi可以做到将已有 的一台memcache server的数据迁移到新的机器上,当新机器数据准备就绪,moxi就将它替 换旧memcache server来提供服务。这个功能对memcache server的自动化运维很有帮助
4 究竟效果怎么样?
我现在不做运维,没有什么实际测试的数据,看一下这篇文章:http://blog.csdn.net/anghlq/article/details/6888324
里面这样写:
94 .2(memcached)
95.7 (moxi_memcached)  //moxi自己作为memcached ,你可以使用-p port方式
151.6 (moxi_proxy: +58%)      //moxi  memcached 代理,这就是我说的moxi代理
181.9(erl_proxy: +93%)             // 自己用 erl 弄的转发代理
196.8(java_proxy: +108%)                             // 基于 mina 的转发打理
235.4 (erl_proxy+moxi_proxy: +149%)   //erl+moxi 的双重转发
257.8(java_proxy+moxi_proxy: +173%)  //java+moxi 的双重转发
通过这个数据可以看见moxi能大幅提高效率

5 安装前准备
假如你不喜欢折腾也没有耐性,请,慎入
moxi难点:
1 源码很久没有更新提交了,清注意这一点
2 moxi文档相当稀少,就算有也基本是互相抄袭
3 安装步骤比较繁琐,依赖很多,很多报错网上没有解决办法,需要自己研究解决

6 安装moxi
sudo zypper in curl-devel  #需要这个curl头文件依赖,我的系统是opensuse
git clone git://github.com/dustin/libstrophe.git
cd libstrophe/
wget http://sourceforge.net/projects/expat/files/expat/2.1.0/expat-2.1.0.tar.gz/download
tar zxvf expat-2.1.0.tar.gz
mv expat-2.1.0 expat
./bootstrap.sh
./configure
make
sudo make install
sudo vi /etc/ld.so.conf #请注意更新类库,添加‘/usr/lib’和‘/usr/local/lib’,并且更新动态链接库
sudo /sbin/ldconfig
cd ..
git clone git://github.com/northscale/libconflate.git
cd libconflate
./config/autorun.sh
./configure
make
sudo make install
cd ..
git clone https://github.com/membase/libvbucket.git
cd libvbucket/
config/autorun.sh
./configure
make
sudo make install
cd ..
wget https://launchpad.net/libmemcached/1.0/1.0.8/+download/libmemcached-1.0.8.tar.gz  #这个libmemcached非那个libmemcached,请注意
tar zxvf libmemcached-1.0.8.tar.gz
cd libmemcached-1.0.8/
./configure
make
sudo make install
git clone https://github.com/steveyen/moxi.git
cd moxi/
config/autorun.sh
./configure --enable-moxi-libvbucket --enable-moxi-libmemcached   --with-memcached  #必须加这几个参数,否则运行中会报各种错(我深受其害)
make
sudo make install

7 使用moxi
为了测试效果,我写了个简单的python脚本:
#/bin/env python
import memcache
import sys
port =int(sys.argv[1])
flag = int(sys.argv[2])
mc = memcache.Client(['localhost:%s' % port], debug=1)
if flag:
    mc.set("a_key", "Some value")
print  mc.get("a_key")
注:这个脚本主要是最小化更改发现效果,其中第一个参数是端口号,第二个参数是一个标识,因为set操作第一次做,否则每次做set,get结果不对
第一种模式:网关代理:
启动方式:
dongwm@linux-dongwm:~> moxi -z 11311=localhost:11211,localhost:11212  #这个moxi启动在11311端口,给11211和112122个端口的memcached做网关

然后执行test脚本
dongwm@linux-dongwm:~> python test.py 11311 0
None  #因为没有set过,所以‘a_key’不存在
dongwm@linux-dongwm:~> python test.py 11311 1
Some value #通过moxi 设置 set‘a_key’ 
dongwm@linux-dongwm:~> python test.py 11211 0
Some value #直接去memcached取值,发现数据写在11211端口的那个mamcached
dongwm@linux-dongwm:~> python test.py 11212 0
None  #去11212端口的那个memcached取结果,数据没有存在这里
然后修改脚本,修改要设置的键‘a_key’为‘a_kez’(随意写的)
dongwm@linux-dongwm:~> python test.py 11311 0
None
dongwm@linux-dongwm:~> python test.py 11311 1
Some value
dongwm@linux-dongwm:~> python test.py 11211 0
None
dongwm@linux-dongwm:~> python test.py 11212 0
Some value
注意:这个键写在了11212端口的那个memcached,因为key不同
第二种模式:vbucket(virtual buckets)模式
这个模式,大家可以参看
http://dustin.github.com/2010/06/29/memcached-vbuckets.html
以下我说一下配置文件和语法
我这里一有个配置文件moxi.cfg:
dongwm@linux-dongwm:~/moxi/t> cat ./moxi_mock.cfg
11311 = {
  "hashAlgorithm": "CRC",  #好像就见过这一种hash算法
  "numReplicas": 1,  #这是设置多少个副本的数量,也可以设置比serverlist大
  "serverList": ["127.0.0.1:11211","127.0.0.1:11212"], #这个是我memcached列表
  "vBucketMap":   #vBucket映射配置,这个条目是2的幂,比如2,4,8
    [
     [0,1],  第一个条目,列表数值从0-numReplicas
     [1,0]  #这里不要有逗号
    ]
}
假如有3个memcached,可以如下配置:
11311 = {
  "hashAlgorithm": "CRC",
  "numReplicas": 2,
  "serverList": ["127.0.0.1:11211","127.0.0.1:11212","127.0.0.1:11213"],
  "vBucketMap":
    [
     [0,1,2],
     [1,0,2]
    ]
}
或者:
11311 = {
  "hashAlgorithm": "CRC",
  "numReplicas": 2,
  "serverList": ["127.0.0.1:11211","127.0.0.1:11212","127.0.0.1:11213"],
  "vBucketMap":
    [
      [0,1,2],  #这里有4条
      [1,0,2],
      [1,1,2],
      [1,2,0]
    ]
}
启动方式:          
dongwm@linux-dongwm:~> moxi -z ./moxi.cfg -d -P ~/moxi.pid -O ~/moxi.log
其中:-d表示daemon方式启动, -P 表示创建一个pid文件,杀掉程序可以使用 kill -9 `cat /moxi.pid` -O 表示记录日志到~/moxi.log
注意:假如你在moxi配置文件的当前目录,不能执行 moxi -z moxi.cfg  必须是./moxi.cfg