1、概念html
Memcached是danga.com开发的一套分布式内存对象缓存系统,用于在动态系统中减小数据库负载,提高性能。java
Memcached处理的原子是每个(key,value)对(如下简称kv对),c++
key会经过一个hash算法转化成hash-key,便于查找、对比以及作到尽量的散列[其实就是散列在多台不一样的服务器上]算法
同时,memcached用的是一个二级散列,经过一张大hash表来维护。
spring
2、原理数据库
Memcached有两个核心组件组成:服务端(ms)和客户端(mc)。windows
step1.首先mc客户端拿到ms列表,api
step2.并对key作hash转化,根据hash值肯定kv对所存的ms位置。【先是保存】缓存
step3.而后在一个memcached的查询中,mc先经过计算key的hash值来肯定kv对所处在的ms位置。服务器
step4.当ms肯定后,客户端就会发送一个查询请求给对应的ms,让它来查找确切的数据。【这里是查询】
由于ms之间并无护卫备份,也就不须要互相通讯,因此效率较高。
3、适用场合
1.分布式应用。因为memcached自己基于分布式的系统,因此尤为适合大型的分布式系统。
2.数据库前段缓存。数据库经常是网站系统的瓶颈。数据库的大并发量访问,经常形成网站内存溢出。固然咱们也可使用Hibernate的缓存机制。但memcached是基于分布式的,并可独立于网站应用自己,因此更适合大型网站进行应用的拆分。
3.服务器间数据共享。举例来说,咱们将网站的登陆系统、查询系统拆分为两个应用,放在不一样的服务器上,并进行集群,那这个时候用户登陆后,登陆信息如何从登陆系统服务器同步到查询系统服务器呢?这时候,咱们即可以使用memcached,登陆系统将登陆信息缓存起来,查询系统即可以得到登陆信息,就像获取本地信息同样。
4、客户端版本
Memcached Client目前有一下四种:
Memcached Client for Java,比 SpyMemcached更稳定、更早、更普遍;
SpyMemcached,比 Memcached Client for Java更高效;
XMemcached,比 SpyMemcache并发效果更好。
alisoft-xplatform-asf-cache阿里软件的架构师岑文初进行封装的。里面的注释都是中文的,比较好
5、服务器端
安装
这里介绍windows环境的安装。
1.下载memcache的windows稳定版,解压放某个盘下面,好比在c:\memcached
2.在cmd下输入 'c:\memcached\memcached.exe -d install' 安装
3.再输入: 'c:\memcached\memcached.exe -d start' 启动。
之后memcached将做为windows的一个服务每次开机时自动启动。这样服务器端已经安装完毕了。
内存分配
默认状况下,ms是用一个内置的叫“块分配器”的组件来分配内存的。舍弃c++标准的malloc/free的内存分配,而采用块分配器的主要目的 是为了避免内存碎片,不然操做系统要花费更多时间来查找这些逻辑上连续的内存块(其实是断开的)。
用了块分配器,ms会轮流的对内存进行大块的分配,并 不断重用。固然因为块的大小各不相同,当数据大小和块大小不太相符的状况下,仍是有可能致使内存的浪费。
同时,ms对key和data都有相应的限制,
key的长度不能超过250字节,data也不能超过块大小的限制 --- 1MB。
由于 mc客户端所使用hash算法,并不会考虑到每一个ms服务端的内存大小。
理论上mc会分配几率上等量的kv对给每一个ms,这样若是每一个ms的内存都不太同样,那可能 会致使内存使用率的下降。
因此一种替代的解决方案是,根据每一个ms服务端的内存大小,找出他们的最大公约数,而后在每一个ms服务端上开n个容量=最大公约数的 instance,这样就等于拥有了多个容量大小同样的子ms,从而提供总体的内存使用率。
好比:
memcached服务器1:500M
Memcached服务器2:1500M
Memcached服务器3:2000M
最大公约数为500,
memcached服务器1创建(500/500)1个instance
memcached服务器2创建(1500/500)3个instance
memcached服务器3创建(2000/500)4个instance
缓存策略
当ms的hash表满了以后,新的插入数据会替代老的数据,更新的策略是LRU(最近最少使用),以及每一个kv对的有效时限。Kv对存储有效时限是在mc端由app设置并做为参数传给ms的。
同时ms采用是偷懒替代法,ms不会开额外的进程来实时监测过期的kv对并删除,而是当且仅当,新来一个插入的数据,而此时又没有多余的空间放了,才会进行清除动做。
6、范例
1.加载commons-pool-1.5.6.jar、java_memcached-release_2.6.6.jar、slf4j-api-1.6.1.jar、slf4j-simple-1.6.1.jar
2.建立memcached工具类:
- public class MemcachedUtil {
-
-
-
-
- private static MemCachedClient cachedClient = new MemCachedClient();
-
-
-
-
- static {
-
- SockIOPool pool = SockIOPool.getInstance();
-
-
- String[] servers = {"127.0.0.1:11211"};
- Integer[] weights = {3};
-
-
- pool.setServers(servers);
- pool.setWeights(weights);
-
-
- pool.setInitConn(10);
- pool.setMinConn(10);
- pool.setMaxConn(1000);
- pool.setMaxIdle(1000*60*60);
-
-
- pool.setMaintSleep(60);
-
-
- pool.setNagle(false);
- pool.setSocketTO(60);
- pool.setSocketConnectTO(0);
-
-
- pool.initialize();
-
-
-
-
- }
-
- private MemcachedUtil(){
- }
-
- public static boolean add(String key, Object value) {
- return cachedClient.add(key, value);
- }
-
- public static boolean add(String key, Object value, Integer expire) {
- return cachedClient.add(key, value, expire);
- }
-
- public static boolean put(String key, Object value) {
- return cachedClient.set(key, value);
- }
-
- public static boolean put(String key, Object value, Integer expire) {
- return cachedClient.set(key, value, expire);
- }
-
- public static boolean replace(String key, Object value) {
- return cachedClient.replace(key, value);
- }
-
- public static boolean replace(String key, Object value, Integer expire) {
- return cachedClient.replace(key, value, expire);
- }
-
- public static Object get(String key) {
- return cachedClient.get(key);
- }
-
- }
3. 建立须要缓存的对象:
- public class UserBean implements Serializable {
-
- private static final long serialVersionUID = 9174194101246733501L;
-
- private String username;
-
- private String password;
-
- public UserBean(String username, String password) {
- this.username = username;
- this.password = password;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + ((password == null) ? 0 : password.hashCode());
- result = prime * result
- + ((username == null) ? 0 : username.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- UserBean other = (UserBean) obj;
- if (password == null) {
- if (other.password != null)
- return false;
- } else if (!password.equals(other.password))
- return false;
- if (username == null) {
- if (other.username != null)
- return false;
- } else if (!username.equals(other.username))
- return false;
- return true;
- }
-
- @Override
- public String toString() {
- return "username:" + username + ",password:" + password;
- }
- }
4.建立测试用例:
- public class MemcachedUtilTest {
-
- @Test
- public void testMemcached() {
- MemcachedUtil.put("hello", "world", 60);
- String hello = (String) MemcachedUtil.get("hello");
- Assert.assertEquals("world", hello);
-
- for(int i = 0; i < 10000000; ++i) {
- UserBean userBean = new UserBean("Jason" + i, "123456-" + i);
- MemcachedUtil.put("user" + i, userBean, 60);
- Object obj = MemcachedUtil.get("user" + i);
- Assert.assertEquals(userBean, obj);
- }
- }
- }
5.经过spring注入memcached:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
-
- <bean id="memcachedPool" class="com.danga.MemCached.SockIOPool"
- factory-method="getInstance" init-method="initialize">
- <constructor-arg>
- <value>neeaMemcachedPool</value>
- </constructor-arg>
- <property name="servers">
- <list>
- <value>127.0.0.1:11211</value>
- </list>
- </property>
- <property name="initConn">
- <value>20</value>
- </property>
- <property name="minConn">
- <value>10</value>
- </property>
- <property name="maxConn">
- <value>50</value>
- </property>
- <property name="nagle">
- <value>false</value>
- </property>
- <property name="socketTO">
- <value>3000</value>
- </property>
- </bean>
- <bean id="memcachedClient" class="com.danga.MemCached.MemCachedClient">
- <constructor-arg>
- <value>neeaMemcachedPool</value>
- </constructor-arg>
- </bean>
- </beans>
6.建立测试用例:
- public class MemcachedSpringTest {
-
- private MemCachedClient cachedClient;
-
- @Before
- public void init() {
- ApplicationContext context = new ClassPathXmlApplicationContext("com/luo/config/beans.xml");
- cachedClient = (MemCachedClient)context.getBean("memcachedClient");
- }
-
- @Test
- public void testMemcachedSpring() {
- UserBean user = new UserBean("luo", "hi");
- cachedClient.set("user", user);
- UserBean cachedBean = (UserBean)user;
- Assert.assertEquals(user, cachedBean);
- }
- }
7、注意点
第1、memcached是在服务器端的内存中缓存对象的,不是缓存或硬盘;
第2、memcached的pool能够关联多个server,
String[] servers = {"10.20.185.12:11001","10.20.185.25:11001"};
Integer[] weights = {3,7};
该配置表示
30%的缓存在放在第一台服务器,
70%的将放在第二台服务器
这样即可以充分利用不一样服务器的内存了;
第3、我最困惑的是client是如何获得相应的pool的,后然看了点源码才知道是这样的。
client是经过pool的name关联到某个pool的,上面的例子中在SockIOPool pool = SockIOPool.getInstance(); 和MemCachedClient client=new MemCachedClient();虽然都没写poolName,但就是新建了一个”default“的pool,而后client关联到了这个”default“的pool。固然咱们在新建这两个对象时能够给定具体的poolName。
=============================memcached的命令行操做======================================================
set
add
replace
get
delete
前三个命令是用于操做存储在 memcached 中的键值对的标准修改命令。它们都很是简单易用,且都使用以下 所示的语法:
command <key> <flags> <expiration time> <bytes>
<span style="background-color: rgb(240, 240, 240); font-family: Arial;"><value></span>
表 1 定义了 memcached 修改命令的参数和用法。
表 1. memcached 修改命令参数
参数 |
用法 |
key |
key 用于查找缓存值 |
flags |
能够包括键值对的整型参数,客户机使用它存储关于键值对的额外信息 |
expiration time |
在缓存中保存键值对的时间长度(以秒为单位,0 表示永远) |
bytes |
在缓存中存储的字节点 |
value |
存储的值(始终位于第二行) |
如今,咱们来看看这些命令的实际使用。
在本地计算机链接到memcached服务:
命令:telnet 182.64.325.68 11211
进入dos界面
命令:get xyTags【这里的userId是xyTags】
命令:delete
userId
命令:set userId 0 0 5【这里的userId是key,须要另起一行来写入value】
命令:add userId 0 0 5
仅当缓存中不存在键时,add
命令才会向缓存中添加一个键值对。若是缓存中已经存在键,则以前的值将仍然保持相同,而且您将得到响应NOT_STORED。
下面是使用 add
命令的标准交互:
set userId 0 0 5
12345
STORED |
下一篇:memcached真实项目中的应用http://blog.csdn.net/sup_heaven/article/details/32728477