Mecached使用方法和规范
一.Memcached使用背景
走秀网大部分数据保存到Oracle数据库中,应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大、访问的集中,就会出现RDBMS的负担加重、数据库响应恶化、网站显示延迟等重大影响。Memcached是对非常成熟的数据缓存方案。memcached是高性能的分布式内存缓存服务器。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性
二.memcached基本结构
使用场景:数据变化比较少,相对比较静态的数据,在业务允许的时间窗口,业务对时间不敏感。
不支持的特性不支持SQL查询,只有key,value存储和检索,memcached不是基于B+树结构。不保证数据存储的可靠性,因此memcached只是缓解数据库压力的有效补充,不能将之当做存储。
客户端
memcached client for java.版本:2.6.1 官方版memcached JAVA客户端API,应用广泛,运行比较稳定 。
数据分布的算法
Ø 求余取模算法:根据服务器台数的余数进行分散,求得键的整数哈希值,再除以服务器台数,根据其余数来选择服务器。
Ø 一致性hash算法:走秀网memcached服务器并不太多,暂不考虑使用,避免无谓的复杂性。
客户端常用API接口:
类型 | API | 说明 |
保存数据 | add( '键', '值', '期限' )
| 仅当存储空间中不存在键相同的数据时才保存 |
replace( '键', '值', '期限' ) | 仅当存储空间中存在键相同的数据时才保存 | |
set( '键', '值', '期限' ) | 与add和replace不同,无论何时都保存 | |
获取数据 | get(’键’) | 取单个item |
getMulti(“键的数组”) | 取多个item | |
删除数据 | delete('键', '阻塞时间(秒)'); | 删除第一个参数指定的键的数据。第二个参数指定一个时间值,可以禁止使用同样的键保存新数据。 此功能可以用于防止缓存数据的不完整。但是要注意,set函数忽视该阻塞,照常保存数据 |
计数器 | storeCounter | 使用storeCounter方法初始化一个计数器 |
加 |
incr('键') | 加1,已保证原子性 |
减 | Decr(’键’) | 减1,已保证原子性 |
清空缓存 | flushAll() | 清空所有memcached集群中的所有缓存 |
更详细的API,请见客户端官方网站和相关博客http://blog.csdn.net/qqiabc521/article/details/6438429
可能使用Cache的业务场景
业务类型 | Key ,value | 说明 |
类目(基本类目、运营类目) | 类目ID,类目名称 | memcached |
基本信息 | 业务ID,业务信息 |
|
权限信息 | 权限ID,权限信息 |
|
促销信息 | 促销规则,促销活动,黑名单、促销活动范围 | 促销规则使用Ehcache本地缓存,黑名单memcached |
排行榜 | 榜单ID,商品List |
|
用户profile信息 | userId,profile信息 | memcached |
商品点击计数 | 商品的点击数统计 | memcached |
SSO用户登录状态 | userId,status | memcached |
名品特卖(秒杀)活动 | 活动ID,活动信息 |
memcached |
三.使用memecached
POJO类(注意:必须实现Serializable接口)
public class Person implements java.io.Serializable{
private static final long serialVersionUID = 3664192604410686630L;
private String id;
private String name;
Person(){
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return id+" "+name;
}
}
Ø 使用客户端工具类:
如果没有集成Spring框架,可使用MemcachedClientFactory 工具类。
package com.xiu.cache.memcached.client;
import java.util.Date;
import com.danga.MemCached.MemCachedClient;
import com.xiu.common.cache.memcached.client.MemcachedClientFactory;
public class MemcachedClientApp {
public static void main(String[] args) {
MemCachedClient memCachedClient = MemcachedClientFactory.getInstance();
Person person = new Person();
person.setId("123");
person.setName("jack");
/* 将对象加入到memcached缓存 */
// 小于1000的值,除以1000以后都是0,即永不过期(最大过期时间是一个月)
boolean success = memCachedClient.set("123", person, new Date(10000));// 十秒后过期
/* 从memcached缓存中按key值取对象 */
Person person1 = (Person) memCachedClient.get("123");
if (person1 != null) {
System.out.println(person1.toString());
}
}
}
客户端工具类源码(memcached客户端工具公用类,放入公司common包中)
public class MemcachedClientFactory {
private static MemCachedClient memCachedClient;
private MemcachedClientFactory() {
}
static {
/*初始化SockIOPool,管理memcached的连接池*/
String[] servers = { "192.168.80.201:11211" };
SockIOPool pool = SockIOPool.getInstance();
pool.setServers(servers);
pool.setFailover(true);
pool.setInitConn(10);
pool.setMinConn(5);
pool.setMaxConn(2500);
pool.setMaintSleep(30);
pool.setNagle(false);
pool.setSocketTO(3000);
//设置hash算法,使用CRC32兼容hash算法,查找cache服务器使用余数方法
pool.setHashingAlg(2);
pool.setAliveCheck(true);
pool.initialize();
/*建立MemcachedClient实例*/
memCachedClient = new MemCachedClient();
}
public static MemCachedClient getInstance() {
return memCachedClient;
}
}
Ø 使用spring
mememcached客户端相关配置如下:
<?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-2.5.xsd">
<!-- Memcached 连接池 -->
<bean id="memcachedPool" class="com.danga.MemCached.SockIOPool"
factory-method="getInstance" init-method="initialize" destroy-method="shutDown">
<constructor-arg>
<value>neeaMemcachedPool</value>
</constructor-arg>
<property name="servers">
<!--<value>10.0.0.67:11211,10.0.0.111:11211</value> -->
<list>
<value>10.0.0.67:11211</value>
<value>10.0.0.111:11211</value>
</list>
</property>
<property name="initConn">
<value>100</value>
</property>
<!--多服务器负载均衡权重 -->
<property name="weights">
<list>
<value>5</value>
<value>5</value>
</list>
</property>
<property name="minConn">
<value>100</value>
</property>
<property name="maxConn">
<value>250</value>
</property>
<property name="maintSleep">
<value>30</value>
</property>
<property name="nagle">
<value>false</value>
</property>
<property name="socketTO">
<value>3000</value>
</property>
<property name="hashingAlg">
<value>2</value>
</property>
</bean>
<!-- Memcached 客户端 -->
<bean id="memcachedClient" class="com.danga.MemCached.MemCachedClient">
<constructor-arg>
<value>neeaMemcachedPool</value>
</constructor-arg>
</bean>
</beans>
使用memcached客户端代码:
// 初始化应用程序上下文
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 取得Memcached客户端bean的实例
MemCachedClient client = (MemCachedClient) context.getBean("memcachedClient");
四.memcached使用相关最佳实践
Ø 如果memcached服务器不可用(如宕机或者缓存失效过期),应用程序需要访问数据库。
Ø Memcached的key加业务相关的前缀,防止key重复
五.高级特性
1.memcachedHA(高可用性) 即使memcache当机,数据也不丢失。magent貌似是一个方案,似乎不成熟,见http://blog.csdn.net/istone8/article/details/4770510
2.缓存失效瞬间,对数据库冲击。可以考虑使用Memcache mutex设计模式 ,有兴趣者参加http://timyang.net/programming/memcache-mutex/
最好的memcached教程
见:memcached完全剖析 http://tech.idv2.com/2008/07/10/memcached-001/
使用规范:
1. MemcachedClientFactory 类作为客户端入口,引用memcached_client.jar包作为客户端
2. Key的前面加业务前缀:
业务前缀+key
各业务线的前缀分别是:
前端商城(包括CMS):mall
媒体中心:media
支付中心:pay
开发平台XOP: xop
订单中心:order
用户中心:user
服务中心:service
商品中心:goods
渠道中心:channel
营销中心:marketing
公共模块:common
其他:自行扩展
3. 使用
使用memcached需要申请,填写下表。
业务线 | Key,value | 估计占用的最大内存 | 失效时间 | 使用场景 | 描述 |
用户中心 | userId,loginStatus | 50M | 30分钟 | 用户登录 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|