给土豆做的网站要做集群. 众所周知,集群服务器之间的Session共享是一个致命的问题.而Acegi使用的基于Session内存的实现机制使得问题难以调和.
正好最近在看程序员增刊--Web2.0.其中强烈推荐了分布式的缓存服务器memcached.感觉能解决目前的问题.所以就打算研究一下.
1 memcached 的安装
memcached的下载
www.danga.com/memcached/
memcached的安装
ttitfly.javaeye.com/blog/110112
这篇文章比较细致.也遇到了其中说得找不到.so文件的错误,建立一个link就搞定了.
2 Java memcached client
memcached Java Client API
www.danga.com/memcached/apis.bml
我使用了Dustin Sallings写的Improved API
bleu.west.spy.net/~dustin/projects/memcached/
下载memcached client, spy 两个jar包.
然后安装简要说明就可以实现了.
3 Ruby memcached client
1)下载memcached client
gem install memcache-client
2)sample code
我使用的是Aptana IDE,对RoR集成得非常好.参照memcached client的Rdoc,创建了一个HelloWorld.rb.
require 'memcache'
cache = MemCache::new '10.0.0.15:11211',
:debug => true,
:c_threshold => 100_000,
:compression => false,
:namespace => 'foo'
# Cache simple values with simple String or Symbol keys
cache["my_key"] = "Some value"
cache[:other_key] = "Another value"
# ...or more-complex values
cache["object_key"] = { 'complex' => [ "object", 2, 4 ] }
# ...or more-complex keys
cache[ Time::now.to_a[1..7] ] ||= 0
val = cache["my_key"] # => "Some value"
val = cache["object_key"] # => {"complex" => ["object",2,4]}
print val['complex'][2] # => 4
4 acegi + memcached ( to be continued )
参考文章
www.java-asp.net/java/200512/t_48588.html
www.springside.org.cn/docs/reference/Acegi4.htm
如同第一篇文章中作者所说的,acegi基于spring以及interface的设计确实非常的灵活方便.
只需要实现org.acegisecurity.providers.dao.UserCache这个接口,就可以轻松的集成acegi +memcached.(想想而已,晚上回家实现一把)
昨晚想的还是太简单了,按照第一篇文章说的,确实能够实现分布式缓存.但是只能实现登陆信息数据库的分布式缓存.
也就是说如果我下次登陆被负载均衡分配到了另外一台陌生的服务器,系统同样可以从缓存而不是数据库读取权限信息.这与我的初衷还是有所不同的,使用了acegi自带的acegi-security-sample-tutorial.war,实现如下.
/**
*
*/
package com.xiuxiu.acegimemcached.cache;
import net.spy.memcached.MemcachedClient;
import org.acegisecurity.providers.dao.UserCache;
import org.acegisecurity.userdetails.UserDetails;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.util.Assert;
/**
* @author Xiu
*
*/
public class MemcachedUserCache implements UserCache, InitializingBean {
private static final Log logger = LogFactory.getLog(MemcachedUserCache.class);
private static int EXP = 3000;
private MemcachedClient memcachedClient;
public MemcachedUserCache(){
}
/**
* @return the cache
*/
public MemcachedClient getMemcachedClient() {
return memcachedClient;
}
/**
* @param cache the cache to set
*/
public void setMemcachedClient(MemcachedClient memcachedClient) {
this.memcachedClient = memcachedClient;
}
/* (non-Javadoc)
* @see org.acegisecurity.providers.dao.UserCache#getUserFromCache(java.lang.String)
*/
public UserDetails getUserFromCache(String username) {
Object element = null;
try {
element = memcachedClient.get(username);
} catch (RuntimeException cacheException) {
throw new DataRetrievalFailureException("Cache failure: " + cacheException.getMessage());
}
if (logger.isDebugEnabled()) {
logger.debug("Cache hit: " + (element != null) + "; username: " + username);
}
if (element == null) {
return null;
} else {
return (UserDetails) element;
}
}
/* (non-Javadoc)
* @see org.acegisecurity.providers.dao.UserCache#putUserInCache(org.acegisecurity.userdetails.UserDetails)
*/
public void putUserInCache(UserDetails user) {
if (logger.isDebugEnabled()) {
logger.debug("Cache put: " + user.getUsername());
}
memcachedClient.set(user.getUsername(), EXP, user);
}
/* (non-Javadoc)
* @see org.acegisecurity.providers.dao.UserCache#removeUserFromCache(java.lang.String)
*/
public void removeUserFromCache(String username) {
memcachedClient.delete(username);
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
Assert.notNull(memcachedClient, "cache mandatory");
}
}
<bean id="memcachedClient" class="net.spy.memcached.MemcachedClient">
<constructor-arg>
<bean class="java.net.InetSocketAddress">
<constructor-arg type="java.lang.String" value="192.168.1.3"/>
<constructor-arg type="int" value="11211"/>
</bean>
</constructor-arg>
</bean>
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService"/>
<property name="userCache">
<bean class="com.xiuxiu.acegimemcached.cache.MemcachedUserCache">
<property name="memcachedClient" ref="memcachedClient"/>
</bean>
</property>
</bean>