memcached下集合对象的缓存

本文介绍了一种使用Memcached缓存粒度更细的有效方法,通过将传统的key-value(list)结构转变为key_index-list[index]的方式,解决了修改list内单一元素的问题,并提供了一种利用计数器维护index的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

memcached作为当下比较流行的缓存利器,有很多很多优点,也有一些自身的缺点。
很多时候,需要缓存一个list,可是Memcached颗粒度并不支持修改其中的元素,所以只能采用replace,就是把list整个取出,然后add/remove/modify之类再set回去。
这种解决方案不是很好,比如list增长的很大,又比如list内的对象都比较大。
很多时候可能存在这样的需求,list内的对象都有一定时效,比如30分钟,如果整个list存入memcached显然很难做到这一点,随着set整个List操作,list的时效会恢复成30分钟,虽然可能list内的部分元素你已经不再需要了,可是怎么把它们remove是个问题,这个问题可以在把整个List取出来进行一堆复杂算法之后可以实现,不过这种方法显然很糟糕。
这里提供了一种方法,可以尝试一下。
原本的数据结构式key-value(list);
现修改为 key_index - list[index]。
很显然这样设计的话,需要维护这个index。可能你觉得可以用List下标来实现。可是随着里面元素的增加修改删除或者失效,这样并不起作用,而且运用于分布式系统下这种方法并不明智。
这样的话我们需要一个东西来存储index。 memcached自身提供了一个counter功能。我们可以利用起来。
另外如果批量存进去之后,如何批量取出又是个问题了。还好memcached为我们提供了get(Collection)方法。

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;

import net.rubyeye.xmemcached.Counter;
import net.rubyeye.xmemcached.GetsResponse;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.exception.MemcachedException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MemcachedClientManager{

private static final MemcachedClientManager instance = new MemcachedClientManager();

private static final int storeTime = 5 * 60;

//待更新列表保存时效
private static final String updateObjKey = "UpdateObj_";

private static MemcachedClient memcachedClient;
private static final long counterInitValue = 1;
private static final long maxavilableValue = 10000;

private static final String UpdateObjCounter = "UpdateObjCounter";

public static List<String> UpdateObjList = new ArrayList<String>((int)maxavilableValue);

static{
for( long i = counterInitValue ; i <= maxavilableValue ; i++ ){
UpdateObjList.add(new StringBuffer(updateObjKey).append(i).toString());
}
}

private MemcachedClientManager()
{
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
memcachedClient = (MemcachedClient) app.getBean("memcachedClient");
}

public static MemcachedClientManager getInstance()
{
return instance;
}

/**
* 封装delete方法
*/
public void delete(String arg0) {

try {
memcachedClient.deleteWithNoReply(arg0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MemcachedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

/**
* 封装gets方法
*/
public <T> T get(String arg0) {

try {
return memcachedClient.get(arg0);
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MemcachedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

public void replace(String arg0, int arg1, Object arg2) {
try {
memcachedClient.replaceWithNoReply(arg0, arg1, arg2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MemcachedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public void set(String arg0, int arg1, Object arg2) {
try {
memcachedClient.setWithNoReply(arg0, arg1, arg2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MemcachedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public <T> Map<String, GetsResponse<T>> gets(Collection<String> arg0) {
// TODO Auto-generated method stub
try {
return memcachedClient.gets(arg0);
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MemcachedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

/**
* 计数器取值,支持分布式系统
*/
private long getCount(long min,long max,String key) {
long count = min;
Counter counter = memcachedClient.getCounter(key);
try {
count = counter.incrementAndGet();
if(count > max){
counter.set(min);
count = min;
}
} catch (MemcachedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return count;
}

/**
* 存入list_index-value
*/
public void storeUpdateList(Bean obj)
{
try {
long count = getCount(counterInitValue,maxavilableValue,UpdateObjCounter);
String key = new StringBuffer(updateObjKey).append(count).toString();
memcachedClient.setWithNoReply(key, storeTime, obj);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MemcachedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

/**
* 根据键集获取值集
*/
@SuppressWarnings("unchecked")
public <T> List<T> getKeys(List<String> keylist){
List<T> rt = new ArrayList<T>();
Map<String, GetsResponse<Object>> map = gets(keylist);
if( null != map && map.size() > 0 )
{
List<GetsResponse<Object>> list = new ArrayList<GetsResponse<Object>>(map.values());
for(GetsResponse<Object> temp : list){
T t = (T) temp.getValue();
rt.add(t);
}
}
return rt;
}
}


application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- http://code.google.com/p/xmemcached/wiki/Spring_Integration -->
<context:property-placeholder location="memcache.properties" />
<bean
id="memcachedClientBuilder"
class="net.rubyeye.xmemcached.XMemcachedClientBuilder"
p:connectionPoolSize="${memcached.connectionPoolSize}"
p:failureMode="${memcached.failureMode}"
p:healSessionInterval="${memcached.healSessionInterval}">
<!-- XMemcachedClientBuilder have two arguments.First is server list,and
second is weights array. -->
<constructor-arg>
<list>
<bean class="java.net.InetSocketAddress">
<constructor-arg>
<value>${memcached.server1.host}</value>
</constructor-arg>
<constructor-arg>
<value>${memcached.server1.port}</value>
</constructor-arg>
</bean>
<!-- <bean class="java.net.InetSocketAddress">
<constructor-arg>
<value>${memcached.server2.host}</value>
</constructor-arg>
<constructor-arg>
<value>${memcached.server2.port}</value>
</constructor-arg>
</bean> -->
</list>
</constructor-arg>
<constructor-arg>
<list>
<value>${memcached.server1.weight}</value>
<!-- <value>${memcached.server2.weight}</value> -->
</list>
</constructor-arg>
<property name="commandFactory">
<bean class="net.rubyeye.xmemcached.command.TextCommandFactory" />
</property>
<property name="sessionLocator">
<bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator" />
</property>
<property name="transcoder">
<bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />
</property>
</bean>
<!-- Use factory bean to build memcached client -->
<bean
id="memcachedClient"
factory-bean="memcachedClientBuilder"
factory-method="build"
destroy-method="shutdown" />
</beans>


memcache.properties

#连接池大小即客户端个数
memcached.connectionPoolSize=50
memcached.failureMode=true
memcached.healSessionInterval=60000
#server1
memcached.server1.host=127.0.0.1
memcached.server1.port=11211
memcached.server1.weight=6
#server2
#memcached.server2.host=127.0.0.1
#memcached.server2.port=11212
#memcached.server2.weight=4


附上测试代码

public static void main(String[] args) {
long beginTime = System.currentTimeMillis();
MemcachedClientManager manager = MemcachedClientManager.getInstance();
for( int i = 0 ; i< 12000 ; i ++ ){
Bean obj = new Bean();
obj.setName(String.valueOf(i));
manager.storeUpdateList(obj);
}

List<Bean> rtList = manager.getKeys(MemcachedClientManager.UpdateObjList);

long endTime = System.currentTimeMillis();

//因为keylist设置了10000个 counter最大值也是10000 所以取出的列表最大为10000个
System.out.println(rtList.size());
System.out.println(endTime - beginTime);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值