分布式缓存系统Memcached

wera00 2011-06-23

一、Memcache简介

Memcache是danga.com的一个项目,最早是为LiveJournal 服务的,目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力。它可以应对任意多个连接,使用非阻塞的网络IO。由于它的工作机制是在内存中开辟一块空间,然后建立一个HashTable,Memcached自管理这些HashTable。

在数据驱动的web开发中,经常要重复从数据库中取出相同的数据,这种重复极大的增加了数据库负载。缓存是解决这个问题的好办法。 Memcached就是这样一种高性能的、分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。

为什么会有Memcache和memcached两种名称?

其实Memcache是这个项目的名称,而memcached是它服务器端的主程序文件名。

Memcache官方网站:http://www.danga.com/memcached,或http://memcached.org/

二、Memcached能缓存什么

通过在内存里维护一个统一的巨大的hash表,Memcached能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。

三、Memcached快么

非常快!Memcached使用了libevent(如果可以的话,在linux下使用epoll)来均衡任何数量的打开链接,使用非阻塞的网络I/O,对内部对象实现引用计数(因此,针对多样的客户端,对象可以处在多样的状态),使用自己的页块分配器和哈希表,因此虚拟内存不会产生碎片并且虚拟内存分配的时间复杂度可以保证为0.。

Danga Interactive为提升Danga Interactive的速度研发了Memcached。目前,LiveJournal.com每天已经在向一百万用户提供多达两千万次的页面访问。而这些,是由一个由web服务器和数据库服务器组成的集群完成的。Memcached几乎完全放弃了任何数据都从数据库读取的方式,同时,它还缩短了用户查看页面的速度、更好的资源分配方式,以及Memcache失效时对数据库的访问速度。

四、Memcached的特点

Memcached的缓存是一种分布式的,可以让不同主机上的多个用户同时访问, 因此解决了共享内存只能单机应用的局限,更不会出现使用数据库做类似事情的时候,磁盘开销和阻塞的发生。

五、Memcached工作原理

首先memcached是以守护程序方式运行于一个或多个服务器中,随时接受客户端的连接操作,客户端可以由各种语言编写,目前已知的客户端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等。客户端在与memcached服务建立连接之后,接下来的事情就是存取对象了,每个被存取的对象都有一个唯一的标识符 key,存取操作均通过这个 key 进行,保存到memcached中的对象实际上是放置内存中的,并不是保存在cache文件中的,这也是为什么memcached能够如此高效快速的原因。注意,这些对象并不是持久的,服务停止之后,里边的数据就会丢失。

与许多cache工具类似,Memcached的原理并不复杂。它采用了C/S的模式,在 server 端启动服务进程,在启动时可以指定监听的ip与其对应的端口号,所使用的内存大小等几个关键参数。一旦启动,服务就一直处于可用状态。Memcached的目前版本是通过C实现,采用了单进程,单线程,异步I/O,基于事件 (event_based) 的服务方式。使用libevent作为事件通知实现。多个Server可以协同工作,但这些Server之间是没有任何通讯联系的,每个Server只是对自己的数据进行管理。Client端通过指定Server端的ip地址(通过域名应该也可以)。需要缓存的对象或数据是以 key->value 对的形式保存在Server端。key 的值通过hash进行转换,根据hash值把value传递到对应的具体的某个Server上。当需要获取对象数据时,也根据key进行。首先对key进行hash,通过获得的值可以确定它被保存在了哪台Server上,然后再向该Server发出请求。Client端只需要知道保存hash(key)的值在哪台服务器上就可以了。

其实说到底,memcached的工作就是在专门的机器的内存里维护一张巨大的hash表,来存储经常被读写的一些数组与文件,从而极大的提高网站的运行效率。

六、Memcached的安装

1、如果是LINUX系统,可以到官方网址http://memcached.org/进行下载,安装教程网上一大堆,这里不再叙述。

2、如果是WINDOWS系统,就到http://code.jellycan.com/memcached/下载稳定版,写这篇文档时,最新版本是memcached 1.2.6,下载win32 binary版本,具体的下载地址是:http://code.jellycan.com/files/memcached-1.2.6-win32-bin.zip

下载后解压到某个盘下面,比如在c:\memcached,然后打开命令提示符(cmd)窗口,输入下述命令:

view plain   copy
  1. c:\memcached\memcached.exe -d install   //安装Memcached 
  2. c:\memcached\memcached.exe -d start  //启动Memcached 

修改memcache的内存大小,可以在注册表里找到HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/memcached Server,修改ImagePath的值为

view plain   copy
  1. "C:/memcached/memcached.exe" -d runservice -m 512 

注意:Windows版本一般用作开发调试只用,不建议在产品环境中使用。

七、在Java中使用Memcached

本测试实例源码及相关类库下载:http://dl.dbank.com/c0bmxg9ezr

https://github.com/gwhalin/Memcached-Java-Client页面下载memcached java client,得到java_memcached-release_2.5.3.jar文件,将其添加到项目的classpath中。

下面就利用利用memcached java client来建立一个简单的应用一个简单的应用。

① 建立MemCachedManager类
package sunchis;  
  
import java.util.Date;  
  
import com.danga.MemCached.MemCachedClient;  
import com.danga.MemCached.SockIOPool;  
  
@SuppressWarnings("deprecation")  
public class MemCachedManager {  
    // 创建全局的唯一实例    
    protected static MemCachedClient mcc = new MemCachedClient();  
    protected static MemCachedManager memCachedManager = new MemCachedManager();  
      
    // 设置与缓存服务器的连接池  
    static {    
        // 服务器列表和其权重    
        String[] servers = { "127.0.0.1:11211" };    
        Integer[] weights = { 3 };    
          
        // 获取socke连接池的实例对象    
        SockIOPool pool = SockIOPool.getInstance();    
          
        // 设置服务器信息    
        pool.setServers(servers);    
        pool.setWeights(weights);    
          
        // 设置初始连接数、最小和最大连接数以及最大处理时间    
        pool.setInitConn(5);    
        pool.setMinConn(5);    
        pool.setMaxConn(250);    
        pool.setMaxIdle(1000 * 60 * 60 * 6);    
          
        // 设置主线程的睡眠时间    
        pool.setMaintSleep(30);    
          
        // 设置TCP的参数,连接超时等    
        pool.setNagle(false);    
        pool.setSocketTO(3000);    
        pool.setSocketConnectTO(0);    
          
        // 初始化连接池    
        pool.initialize();    
          
        // 压缩设置,超过指定大小(单位为K)的数据都会被压缩    
        mcc.setCompressEnable(true);    
        mcc.setCompressThreshold(64 * 1024);    
    }  
      
    /**   
     * 保护型构造方法,不允许实例化! */    
    protected MemCachedManager() {    
    }  
      
    /**   
     * 获取唯一实例 */    
    public static MemCachedManager getInstance() {    
        return memCachedManager;    
    }  
      
    /**   
     * 添加一个指定的值到缓存中.   
     * @param key   
     * @param value   
     * @return */    
    public boolean add(String key, Object value) {    
        return mcc.add(key, value);    
    }    
      
    public boolean add(String key, Object value, Date expiry) {    
        return mcc.add(key, value, expiry);    
    }    
      
    public boolean replace(String key, Object value) {    
        return mcc.replace(key, value);    
    }    
      
    public boolean replace(String key, Object value, Date expiry) {    
        return mcc.replace(key, value, expiry);    
    }  
      
    /**   
     * 根据指定的关键字获取对象.   
     * @param key   
     * @return */    
    public Object get(String key) {    
        return mcc.get(key);    
    }  
      
    public static void main(String[] args) {    
        MemCachedManager cache = MemCachedManager.getInstance();    
        cache.add("hello", 234);    
        System.out.print("get value : " + cache.get("hello"));    
    }   
}
② 建立数据模型TBean.java
 import java.io.Serializable;  
@SuppressWarnings("serial") 
public class TBean implements Serializable {     
private String name;      
public String getName() {
        return name;     
  }     
 public void setName(String name) {        
        this.name = name;    
  } 
}
③ 建立测试类TestMemcached.java
package sunchis;  
import org.junit.Test; 
import junit.framework.TestCase; 
 public class TestMemcached extends TestCase {     
private static MemCachedManager cache;         
 @Test       
public void testCache() {
           TBean tb = new TBean();
           tb.setName("三知开发网");
           cache.add("bean", tb); 
           TBean tb1 = (TBean) cache.get("bean"); 
           System.out.println("name=" + tb1.getName());       
           tb1.setName("www.sunchis.com"); 
           tb1 = (TBean) cache.get("bean");
           System.out.println("name=" + tb1.getName());
     }          
@Override
       protected void setUp() throws Exception {
           super.setUp(); 
          cache = MemCachedManager.getInstance();
       }
          @Override
       protected void tearDown() throws Exception {
           super.tearDown(); 
          cache = null; 
      }
  }
 
④ 测试结果

//第一次运行结果 
name=三知开发网 
name=www.sunchis.com  
//第二次运行结果 
name=www.sunchis.com 
name=www.sunchis.com

相关推荐