memcached

一、安装、启动

#安装

# wget http://memcached.googlecode.com/files/memcached-1.4.15.tar.gz

# tar zxvf memcached-1.4.15.tar.gz 

#./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent && make && make install

#后台启动:

./usr/local/memcached/bin/memcached -d -m 64 -u root -l 127.0.0.1  -p 11621 -c 1024 -P /usr/local/memcached/memcached.pid  

-d   以守护程序(daemon)方式运行

-m 1024  数据内存数量,不包含memcached本身占用,单位为 MB

-u root  指定用户,仅root可以使用此参数。

-l 127.0.0.1  监听的 IP 地址,本机可以不设置此参数

-p 11211  TCP端口,默认为11211,可以不设置

-c 1024 最大并发连接数,默认1024

-P 保存pid到指定文件

 

启动或重启memcached脚本

放到/usr/local/memcached/目录下

#!/bin/bash
#killall memcached
pid=`cat memcached.pid`
kill -9 $pid
sleep 12
./bin/memcached -d -m 128 -p 11211 -u root -P memcached.pid -v 1>>memcached.out 2>>memcached.err  

 

脚本测试:
拷贝一份memcached ,修改 start.sh端口,执行后
# ps -ef|grep memcached
root 23483 1 0 09:24 ? 00:00:00 ./bin/memcached -d -m 128 -p 11212 -u root -P memcached.pid -v
root 23504 1 0 09:26 ? 00:00:00 ./bin/memcached -d -m 128 -p 11211 -u root -P memcached.pid -v
root 23511 2640 0 09:26 pts/0 00:00:00 grep memcached

二、相关知识

主要目标:解决直接访问数据库压力大问题。

适用场景:不经常发生变化的对象信息,如:商品信息不适合,商品图片(图片名称、地址)、企业信息适合。

 

读取:先读缓存,没有再读库并直接设置缓存。

保存/修改/删除完,不能直接设置缓存:如果直接刷新缓存数据的话,后续操作发生异常,就会导致实际数据与缓存数据不一致,为了解决这个问题,只有保证数据更新成功,再循环刷缓存。因此,先将要刷新的缓存对象放置到临时容器中,等到操作成功后统一flush。

 

memcached是通过socket与服务端建立连接传输数据的,tcp协议。

 

取模的算法:有增/删server导致的cache全部不能命中的问题。

一致性hash算法:cache不能命中的问题仍然存在,但是只存在于2个节点之间的位置。

相对于取模的算法,一致性hash算法除了计算key的hash值外,还会计算每个server对应的hash值,然后将这些hash值映射到一个有限的值域上(比如0~2^32)。通过寻找hash值大于hash(key)的最小server作为存储该key数据的目标server。如果找不到,则直接把具有最小hash值的server作为目标server。

 

通过主机名判断所属地区: String hostName = InetAddress.getLocalHost().getHostName();

 

内存

64位能分配2GB以上的内存。32位每个进程最多只能使用2GB内存。
memcached启动时指定的内存分配量是memcached用于保存数据的量,没有包括“slab allocator”本身占用的内存、以及为了保存数据而设置的管理空间。因此,memcached进程的实际内存分配量要比指定的容量要大
一台服务器上启动多个问题:TCP连接数就会成倍增加,管理上也变得复杂
服务器的内存为4GB,却仅分配了3GB,是因为内存分配量超过这个值,就有可能导致内存交换(swap)。
简单的使用malloc和free,这样将产生大量的内存碎片,从而加重操作系统内存管理器的负担。memcached的内存管理机制采用了slab allocator内存分配和管理机制,以解决内存碎片问题。slab allocator基本原理是按照预先定义的大小,将内存分割为多种特定长度的trunk块,并将长度相同的trunk块归成slab组,每次请求内存时,采用最佳适应算法查询并获得一个trunk,用于保存item。
参考:memcached源码学习-内存管理机制slab allocator  http://blog.csdn.net/tankles/article/details/7027645

 

查内存           

$top

shift+m           

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                    

20888 xx    15   0 47040  32m  444 S  0.0  0.4  11:13.92    mem1  

 

 三、运行状态监控:

//windows cmd/linux 终端 连接memcached服务器
telnet ip port
//查询状态
stats
STAT pid 5085
STAT uptime 239832
STAT time 1385378823
STAT version 1.2.2
STAT pointer_size 64
STAT rusage_user 62.917435
STAT rusage_system 152.025888
STAT curr_items 45485
STAT total_items 3047438
STAT bytes 17357992
STAT curr_connections 2
STAT total_connections 86
STAT connection_structures 12
STAT cmd_get 7
STAT cmd_set 3047438
STAT get_hits 6
STAT get_misses 1
STAT evictions 0
STAT bytes_read 1052001370
STAT bytes_written 24410844
STAT limit_maxbytes 134217728
STAT threads 1
END

//退出
quit
遗失对主机的连接。

$ ./memcached-tool
Usage: memcached-tool <host[:port]> [mode]

       memcached-tool 10.0.0.5:11211 display    # shows slabs
       memcached-tool 10.0.0.5:11211            # same.  (default is display)
       memcached-tool 10.0.0.5:11211 stats      # shows general stats
       memcached-tool 10.0.0.5:11211 dump       # dumps keys and values
$ ./memcached-tool 192.168.1.238:11621 stats
#192.168.1.238:11621 Field       Value
                   bytes    17357992
              bytes_read  1052001603
           bytes_written    24415536
                 cmd_get           7
                 cmd_set     3047438
   connection_structures          12
        curr_connections           2
              curr_items       45485
               evictions           0
                get_hits           6
              get_misses           1
          limit_maxbytes   134217728
                     pid        5085
            pointer_size          64
           rusage_system  152.029887
             rusage_user   62.919434
                 threads           1
                    time  1385380482
       total_connections          91
             total_items     3047438
                  uptime      241491
                 version       1.2.2
                 
[search@sortserver0 script]$ ./memcached-tool 192.168.1.238:11621
  #  Item_Size  Max_age   Pages   Count   Full?  Evicted Evict_Time OOM
  7     384B      3022s      17   45467      no        0        0    0
 10     752B      2458s       1       6      no        0        0    0
 11     944B      2457s       1       2      no        0        0    0
 12     1.2K      2458s       1       1      no        0        0    0
 14     1.8K      2457s       1       1      no        0        0    0
 15     2.3K      2458s       1       1      no        0        0    0
 17     3.5K      2457s       1       1      no        0        0    0
 19     5.5K      3017s       1       3      no        0        0    0
 20     6.9K      2457s       1       1      no        0        0    0
 21     8.7K      2457s       1       1      no        0        0    0
 32   101.1K    232725s       1       1      no        0        0    0
                  
version: memcached的版本号。 
bytes:表示系统存储缓存对象所使用的存储空间,单位为字节。 
curr_connections:表示当前系统打开的连接数。
total_connections:表示从memcached服务启动到当前时间,系统打开过的连接的总数。 
limit_maxbytes:memcached服务缓存允许使用的最大字节数。总的可用储存空间大小 .与我们启动memcached服务设置的大小一致 。

         

四、客户端

java 客户端  Memcached Client目前有3种: Memcached Client for Java   SpyMemcached    XMemcached 

danga Memcached-Java-Client 下载地址:https://github.com/gwhalin/Memcached-Java-Client/downloads

 

danga 源码下载:https://github.com/gwhalin/Memcached-Java-Client/releases

import java.io.Serializable;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;

/**
 * 
 * @Description: 封装MemCached,同时向多台(跨机房)写一样的数据。
 *
 * @author thrillerzw
 * @version 1.0
 * @create time 2013-11-22 下午12:02:21
 */
public class MemcachedManager {

	private static Logger log = Logger.getLogger(MemcachedManager.class.getName());
	//存储所有服务器Memcached的实例
	private List<MemCachedClient> pools = new ArrayList<MemCachedClient>();

	private static Map<String, MemcachedManager> memManagerMap = new HashMap<String, MemcachedManager>();

	private MemcachedManager(String configFileName) {
		String servers[] = readMemcachedFile(configFileName);
		for (int i = 0; i < servers.length; i++) {
			MemCachedClient mc = new MemCachedClient("memcached" + i);
			String[] serverlist = { servers[i] };
			//没有参数为"default"
			SockIOPool pool = SockIOPool.getInstance("memcached" + i);
			pool.setServers(serverlist);
			pool.setInitConn(10);
			pool.setMinConn(5);
			pool.setMaxConn(1000);
			//private long maintSleep = 1000 * 30; // maintenance thread sleep time
			pool.setMaintSleep(30);
			//enable/disable Nagle's algorithm
			pool.setNagle(false);
			//默认1000 * 30  读超时
			pool.setSocketTO(1000 * 60);
			// 默认1000 * 3 连接超时
			pool.setSocketConnectTO(1000 * 5);
			// 初始化连接池 
			pool.initialize();
			// 2.5.1这2个方法过期,2.6.6已经没有这2个方法了。
			//压缩设置,超过指定大小(单位为K)的数据都会被压缩 
			/*mc.setCompressEnable(true);
			  mc.setCompressThreshold(64 * 1024);*/
			pools.add(mc);
		}
	}

	public static MemcachedManager getInstance(String configFileName) {
		MemcachedManager instance = memManagerMap.get(configFileName);
		if (instance == null) {
			instance = new MemcachedManager(configFileName);
			memManagerMap.put(configFileName, instance);
		}
		return instance;
	}

	public String[] readMemcachedFile(String configFileName) {
		String servers[] = null;
		try {
			// 取得XML路
			SAXReader reader = new SAXReader();
			// 获得XML文档对象
			//Document document = reader.read("memcachedconfig.xml");
			Document document = reader.read(Thread.currentThread().getContextClassLoader().getResourceAsStream(configFileName));
			Element element = document.getRootElement();

			List list = element.elements();
			servers = new String[list.size()];
			for (int i = 0; i < list.size(); i++) {
				Element child = (Element) list.get(i);
				String hostName = child.elementText("IP");
				String port = child.elementText("PORT");
				//通过hostName获取hosts配置的ip。如果xml中配置的是ip,也没有问题。  servers[i]=ip+":"+port;
				servers[i] = InetAddress.getByName(hostName).getHostAddress() + ":" + port;
				log.info("INIT cach  eserver:" + servers[i]);
			}
		} catch (Exception e) {
			throw new RuntimeException("init Memcache server array error:", e);
		}
		if (servers == null || servers.length == 0) {
			throw new RuntimeException("init Memcache server array error: empty");
		}
		return servers;
	}

	/**
	 * 随机从一台服务器上查找对应key的值
	 * 若有,则返回
	 * 若没有,则遍历所有服务器
	 */
	public Object get(String key) {
		int num = (Math.abs(new Random().nextInt())) % pools.size();
		Object object = null;
		object = ((MemCachedClient) pools.get(num)).get(key);
		if (object != null) {
			return object;
		}
		for (int i = 0; i < pools.size(); i++) {
			if (i == num)
				continue;
			MemCachedClient mc = (MemCachedClient) pools.get(i);
			object = mc.get(key);
			if (object != null) {
				return object;
			}
		}
		return object;
	}

	/**
	 * 将数据存储到Memcached中(带有效时间)
	 * @param key 键值
	 * @param value 对象
	 * @param time 过期时间,若要设置过期时间,需time值大于1000,如果小于1000
	 * 			   则过期时间均为0,即为永不过期
	 */
	public void setMemcached(String key, Object value, long time) {

		for (int i = 0; i < pools.size(); i++) {
			MemCachedClient mc = (MemCachedClient) pools.get(i);
			log.debug(key + ":" + mc.set(key, value, new Date(time)));
		}

	}

	public void delete(String key) {
		for (int i = 0; i < pools.size(); i++) {
			MemCachedClient mc = (MemCachedClient) pools.get(i);
			mc.delete(key);
		}
	}

	public boolean flushAll() {
		boolean success = true;
		for (int i = 0; i < pools.size(); i++) {
			MemCachedClient mc = (MemCachedClient) pools.get(i);
			success = mc.flushAll();
		}
		return success;
	}

	/**
	 * 是否存在于每个mem中
	 * @param key
	 * @return
	 */
	public boolean keyExistsInAll(String key) {
		boolean exist = false;
		for (int i = 0; i < pools.size(); i++) {
			MemCachedClient mc = (MemCachedClient) pools.get(i);
			exist = mc.keyExists(key);
			if (!exist)
				return false;
		}
		return exist;
	}

	/**
	 * 是否存在于任意一个mem中
	 * @param key
	 * @return
	 */
	public boolean keyExistsInAny(String key) {
		boolean exist = false;
		for (int i = 0; i < pools.size(); i++) {
			MemCachedClient mc = (MemCachedClient) pools.get(i);
			exist = mc.keyExists(key);
			if (exist)
				return true;
		}
		return exist;
	}

	/**
	 * 
	 * @Description: 必须实现Serializable,否则取出来为null
	 *
	 * @author thrillerzw
	 * @version 1.0
	 * @create time 2014-4-22 下午4:25:11
	 */
	static class MyObject implements Serializable {
		/**
		 * @Fields serialVersionUID : TODO
		 */
		private static final long serialVersionUID = -2582821459094658151L;
		private int id;
		private String name;

		public int getId() {
			return id;
		}

		public void setId(int id) {
			this.id = id;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

	}

	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
		MemcachedManager memcachedManager = MemcachedManager.getInstance("sellerInfoMemcachedConfig.xml");

		MyObject o1 = new MyObject();
		o1.setId(1);
		o1.setName("thrillerzw中文");
		/*
		 * long time单位毫秒
		 * 0 或者 999:Thread.sleep(1000*10);后取出有值
		 * 1000 :Thread.sleep(1000); 后取出为null
		 */
		memcachedManager.setMemcached("key1", o1, 0);
		MyObject myObject = (MyObject) memcachedManager.get("key1");
		//0 :myObject=com.dhgate.searchranking.service.MemcachedManager$MyObject@19c0bd6
		System.out.println("myObject=" + myObject);
		try {
			Thread.sleep(1000 * 2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		myObject = (MyObject) memcachedManager.get("key1");
		System.out.println("myObject=" + myObject);
		//----------list----------
		List<MyObject> list = new ArrayList<MyObject>();
		list.add(o1);
		memcachedManager.setMemcached("keyList", list, 1000 * 10);
		List<MyObject> list2 = (List<MyObject>) memcachedManager.get("keyList");
		System.out.println("list2=" + list2);
	}

}

 

 

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值