memcached做一些页面或者其他数据缓存。一般会设置过期时间,memcached的数据都是定时失效的。当这一时刻遭遇大量访问时,可能会发生阻塞。
例如:
String cacheHtml = (String) MemCachedUtil.get(cacheKey);
if(StringUtils.isBlank(cacheHtml)){
cacheHtml=db.getData();
MemCachedUtil.set(cacheKey, cacheHtml, 60 * 10);
}
对于上面的代码,存在一个问题。每个获取cacheHtml为空的对象都会执行db.getData(),db.getData()在这一时刻同时调用,必然造成阻塞。那么这时我们可以引入一个标志,需要设置标志位的过期时间比cacheKey断。同时结合memcached的add方法属性(同一时刻,add方法只返回一个true,即只有一个对象add成功,其他皆为false)。专门控制cacheKey的值更新。
以下是本人在开发中的解决方案:
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String cacheHtml = (String) MemCachedUtil.get(cacheKey);
//判断cacheHtml的同时,留一个后门便于手动刷新数据
boolean needCache = StringUtils.isEmpty(cacheHtml) || "refresh".equals(request.getParameter("refresh"));
if (needCache || MemCachedUtil.add(cacheRefreshKey, cacheRefreshKey, 600* 17)) {
MyServletResponseWrapper myResp = new MyServletResponseWrapper(response);
chain.doFilter(req, MyResp );
cacheHtml = mstResp.toString();
MemCachedUtil.set(cacheKey, cacheHtml, 600* 20);
if (needCache) MemCachedUtil.set(cacheRefreshKey, cacheRefreshKey, 600 * 17);
}
resp.getWriter().write(cacheHtml);
}
/**
* Memcache 工具
*
*/
public class MemCachedUtil {
private static final Logger logger = Logger.getLogger(MemCachedUtil.class);
private static MemCachedClient cacheClient = new MemCachedClient();
/**超时时间,单位毫秒**/
private static long timeoutTime = 500;
static {
SockIOPool pool = SockIOPool.getInstance();
String[] servers = {"127.0.0.1:11911"};
Integer[] weights = {7};
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(3000);
pool.setSocketConnectTO(0);
pool.initialize();
}
public MemCachedUtil(){
};
/**
* 增加一个键值对到memchache。
* @param key
* @param value
* @param expire 单位秒 如果等于0,则永不过期
* @return 是否增加成功
*/
public static boolean set(String key, Object value, int expire) {
return cacheClient.set(key, value, new Date(expire*1000L));
}
/**
* 替换一个键值对,必须保证memchache已经有了key,否则会失败
* @param key
* @param value
* @param expire 单位秒 如果等于0,则永不过期
* @return
*/
public static boolean replace(String key, Object value, int expire) {
return cacheClient.replace(key, value, new Date(expire*1000L));
}
/**
* 获取对象
* @param key
* @return
*/
public static Object get(String key) {
return cacheClient.get(key);
}
/**
* 删除对象
* @param key
* @return
*/
public static boolean delete(String key) {
return cacheClient.delete(key);
}
/**
* 添加对象(若KEY已存在则返回false)
* @param key
* @param value
* @param expire 单位秒 如果等于0,则永不过期
* @return
*/
public static boolean add(String key, Object value, int expire) {
return cacheClient.add(key, value, new Date(expire * 1000L));
}
}
例如:
String cacheHtml = (String) MemCachedUtil.get(cacheKey);
if(StringUtils.isBlank(cacheHtml)){
cacheHtml=db.getData();
MemCachedUtil.set(cacheKey, cacheHtml, 60 * 10);
}
对于上面的代码,存在一个问题。每个获取cacheHtml为空的对象都会执行db.getData(),db.getData()在这一时刻同时调用,必然造成阻塞。那么这时我们可以引入一个标志,需要设置标志位的过期时间比cacheKey断。同时结合memcached的add方法属性(同一时刻,add方法只返回一个true,即只有一个对象add成功,其他皆为false)。专门控制cacheKey的值更新。
以下是本人在开发中的解决方案:
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String cacheHtml = (String) MemCachedUtil.get(cacheKey);
//判断cacheHtml的同时,留一个后门便于手动刷新数据
boolean needCache = StringUtils.isEmpty(cacheHtml) || "refresh".equals(request.getParameter("refresh"));
if (needCache || MemCachedUtil.add(cacheRefreshKey, cacheRefreshKey, 600* 17)) {
MyServletResponseWrapper myResp = new MyServletResponseWrapper(response);
chain.doFilter(req, MyResp );
cacheHtml = mstResp.toString();
MemCachedUtil.set(cacheKey, cacheHtml, 600* 20);
if (needCache) MemCachedUtil.set(cacheRefreshKey, cacheRefreshKey, 600 * 17);
}
resp.getWriter().write(cacheHtml);
}
/**
* Memcache 工具
*
*/
public class MemCachedUtil {
private static final Logger logger = Logger.getLogger(MemCachedUtil.class);
private static MemCachedClient cacheClient = new MemCachedClient();
/**超时时间,单位毫秒**/
private static long timeoutTime = 500;
static {
SockIOPool pool = SockIOPool.getInstance();
String[] servers = {"127.0.0.1:11911"};
Integer[] weights = {7};
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(3000);
pool.setSocketConnectTO(0);
pool.initialize();
}
public MemCachedUtil(){
};
/**
* 增加一个键值对到memchache。
* @param key
* @param value
* @param expire 单位秒 如果等于0,则永不过期
* @return 是否增加成功
*/
public static boolean set(String key, Object value, int expire) {
return cacheClient.set(key, value, new Date(expire*1000L));
}
/**
* 替换一个键值对,必须保证memchache已经有了key,否则会失败
* @param key
* @param value
* @param expire 单位秒 如果等于0,则永不过期
* @return
*/
public static boolean replace(String key, Object value, int expire) {
return cacheClient.replace(key, value, new Date(expire*1000L));
}
/**
* 获取对象
* @param key
* @return
*/
public static Object get(String key) {
return cacheClient.get(key);
}
/**
* 删除对象
* @param key
* @return
*/
public static boolean delete(String key) {
return cacheClient.delete(key);
}
/**
* 添加对象(若KEY已存在则返回false)
* @param key
* @param value
* @param expire 单位秒 如果等于0,则永不过期
* @return
*/
public static boolean add(String key, Object value, int expire) {
return cacheClient.add(key, value, new Date(expire * 1000L));
}
}