频道栏目
首页 > 资讯 > Java > 正文

memcached总结和与spring的集成

12-11-20        来源:[db:作者]  
收藏   我要投稿


         Memcached是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻硬盘数据库的负载,基于一个存储键/值对的hashmap,守护进程用c写的,客户端可用各种语言实现。
         特点有以下几个:
        1.暂无认证以及安全管制,也没有冗余备份机制,考虑到时内存数据库,也就无所谓了。
          2.Value大小 1.4.2以后可以到128M。
        3.节点之间不互相通信。
        4.c/s通信使用基于文本行的格式。
        5.使用LRU算法管理内存。
        6.客户端可以实现一致性哈希算法来决定数据在服务器节点的分布。
          7.Lazy Expiration,不主动检查数据的过期。
          原理图:

 
 
Perl:
整数哈希值根据余数计算分散
缺点:添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,从而影响缓存的命中率。
 
Php实现了Consistent Hashing:
 

 
首先求出memcached服务器(节点)的哈希值, 并将其配置到0~232的圆(continuum)上。add数据时,用同样的方法求出存储数据的键的哈希值,并映射到圆上。从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。 如果超过232仍然找不到服务器,就会保存到第一台memcached服务器上。
 

        上图可以看出增加服务器后受影响的只有部分区域,因为本来是属于node4的hash范围,加入机器后变为node5的范围。
 
memcached的监视工具可以用nagios,MemcachePHP
下面说明java客户端的用法,以跟spring集成为例:
 
          memcached的java客户端选用xmemcached,相关的包要下载下来。
一、客户端的bean配置:
[html] 
<!-- xMemcached集群配置 --> 
<bean id="cacheManager" class="com.cr.common.cache.base.CacheManager"> 
    <property name="clnt" ref="xMemcachedClient" /> 
    <property name="expire" value="3600" /> 
</bean> 
<bean name="memcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder"> 
    <constructor-arg> 
        <list> 
 
            <bean class="java.net.InetSocketAddress"> 
                <constructor-arg> 
                    <value>192.168.0.110</value> 
                </constructor-arg> 
                <constructor-arg> 
                    <value>11211</value> 
                </constructor-arg> 
            </bean> 
            <bean class="java.net.InetSocketAddress"> 
                <constructor-arg> 
                    <value>192.168.0.111</value> 
                </constructor-arg> 
                <constructor-arg> 
                    <value>11211</value> 
                </constructor-arg> 
            </bean> 
             
        </list> 
    </constructor-arg> 
    <constructor-arg> 
        <list> 
            <value>1</value> 
            <value>1</value> 
        </list> 
    </constructor-arg> 
    <property name="connectionPoolSize" value="30"></property> 
    <property name="commandFactory"> 
        <bean class="net.rubyeye.xmemcached.command.TextCommandFactory"></bean> 
    </property> 
    <property name="sessionLocator"> 
        <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"> 
            <constructor-arg index="0"> 
                <value>true</value> 
            </constructor-arg> 
        </bean> 
    </property> 
    <property name="transcoder"> 
        <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder"></bean> 
    </property> 
</bean> 
<bean name="xMemcachedClient" factory-bean="memcachedClientBuilder" 
    factory-method="build" destroy-method="shutdown"> 
    <property name="opTimeout" value="5000"></property> 
</bean> 

 
        memcachedClientBuilder完成MemcachedClientBuilder,在constructor-arg里面配置集群的节点。然后通过memcachedClient节点配置用于连接的client。
cacheManger是memcached的管理类,持有xMemcachedClient的实例,提供get,set操作,当然是通过bean注入的。
主要代码如下:
 
[java]
public <T> T getCache(String key) {        
        try {    
            log.info("get " + key); 
            return (T)(client.get(key)); 
        } catch (TimeoutException e) { 
            log.error(e.getMessage(), e); 
        } catch (InterruptedException e) { 
            log.error(e.getMessage(), e); 
        } catch (MemcachedException e) { 
            log.error(e.getMessage(), e); 
        } 
        return null; 
    } 
 
    public  <T> boolean setCache(String key, T value) { 
        try {            
            log.info("add cache:"+key); 
            return client.set(key, expire, value); 
        } catch (TimeoutException e) { 
            log.error(e.getMessage(), e); 
        } catch (InterruptedException e) { 
            log.error(e.getMessage(), e); 
        } catch (MemcachedException e) { 
            log.error(e.getMessage(), e); 
        } 
        return false; 
    } 

二、spring的AOP切面配置:
[html]
<span style="font-size:12px;"><bean id="systemContext" class="com.cr.common.utils.SystemContext" > 
        <property name="propertiesFile" 
            value="/WEB-INF/spring/SystemContext.properties" /> 
    </bean> 
    <!--BeanFactory 配置--> 
    <bean class="com.cr.common.utils.BeanFactory"></bean> 
        <!-- 日志切面 --> 
    <bean id="logAspect" 
        class="com.cr.common.log.LogAspect"> 
        <property name="orderValue" value="1" /> 
    </bean> 
        <!-- 缓存切面 --> 
    <bean id="cacheAspect" 
        class="com.cr.common.cache.core.CacheAspect"> 
        <property name="orderValue" value="2" /> 
        <property name="cacheManager" ref="cacheManager"/> 
    </bean> 
</span><span style="font-size:12px;">   <aop:aspectj-autoproxy> 
        <aop:include name="cacheAspect" /> 
        <aop:include name="logAspect" /> 
    </aop:aspectj-autoproxy></span> 
 
BeanFactory 类定义了通过名称获得Spring容器内的Bean实例:
[java]
<span style="font-size:12px;">public class BeanFactory implements ServletContextAware{ 
    private static ServletContext servletContext; 
    public static <T> T getBean(String beanName) { 
      WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); 
        return wac.getBean(beanName); 
    } 
 
    @Override 
    public void setServletContext(ServletContext servletContext) { 
        BeanFactory.servletContext = servletContext; 
    } 
}</span> 

为了记录浏览器端的访问记录可以写一个log切面,最后是切面的申明配置。
以上两个配置文件都是作为spring bean管理的。
 
三、缓存切面类:
[java] 
@Aspect 
public class CacheAspect implements Ordered { 
    private int orderValue = 2; 
    private Cache cacheManager; 
    private Logger log = Logger.getLogger(CacheAspect.class);  
 
    @Pointcut("@annotation(com.cr.common.cache.core.NeedCached)") 
    public void needCached() { 
 
    } 
 
    @Around("needCached() && args(filter,..)") 
    public Object aroundMethod(ProceedingJoinPoint pjp, QueryFilter filter) 
            throws Throwable { 
        if (filter.getValue() == null) { 
            return null; 
        }  www.2cto.com
        // 判断是否开启缓存 
        boolean cacheEnabled = CommonUtil.parseBoolean(ContextConfig.getProperty("cache.enabled"), false); 
 
        if (cacheEnabled) { 
            String md5key = MD5Util.getMD5(filter.getValue().toString()); 
            Object value = cacheManager.getCacheInfo(md5key); 
            boolean flag = false;           if (null != value)                          JSONObject json = new JSONObject(value.toString()); 
                return json; 
            } else if ("null".equals(value)) { 
                return null; 
            } else {    value = pjp.proceed(); 
                 
        if(null!=value){//此处省略若干业务码                                                                                                            cacheManager.setCacheInfo(md5key, value.toString()); 
                         
                        } 
                return value; 
            } 
        } else {// 未开启缓存,执行数据库查询 
            return pjp.proceed(); 
        } 
 
    } 
 
    public void setOrderValue(int orderValue) { 
        this.orderValue = orderValue; 
    } 
 
    public int getOrder() { 
        return orderValue; 
    } 
 
    public int getOrderValue() { 
        return orderValue; 
    } 
 
    public Cache getCacheManager() { 
        return cacheManager; 
    } 
 
    public void setCacheManager(Cache cacheManager) { 
        this.cacheManager = cacheManager; 
    } 

needCached是自定义注解,用于需要执行缓存切面的方法上,aroundMethod环绕在含有此注解,及方法参数含有filter的方法上面。由于本来的key超过了250,所以md5后作为key,value是jsonObect。
查询时,若缓存有,直接返回,没有则执行数据库查询,再设置缓存。

相关TAG标签
上一篇:ORA-01843与NLS_DATE_FORMAT问题分析
下一篇:MongoDB的授权和权限
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站