關(guān)于緩存
- 最初開關(guān)和配置項(xiàng)是存放在內(nèi)存中的饺蔑,使用一個(gè)static final的currentmap存儲(chǔ),可以快速配置发皿,但是需要修改時(shí)穴墅,必須保證每臺(tái)服務(wù)器對(duì)應(yīng)的配置都同時(shí)生效…
- 一些不經(jīng)常變動(dòng)的查詢類數(shù)據(jù)温自,比如城市,站點(diǎn)松捉,司機(jī)信息等馆里,沒必要每次都去查詢數(shù)據(jù)庫(kù)也拜,即使做了索引和ibatis的緩存慢哈,也對(duì)db依然有壓力不是?
- 一個(gè)應(yīng)用部署在集群中時(shí)键俱,session維護(hù)是個(gè)比較關(guān)鍵的事情编振,當(dāng)然可以通過(guò)nginx的負(fù)載均衡策略來(lái)把相同ip請(qǐng)求過(guò)來(lái)的數(shù)據(jù)分配到同一臺(tái)服務(wù)器中踪央,不過(guò)這種方式就限定了負(fù)載均衡的配置策略健无,更靈活也更根本的方式的方式液斜,則是維護(hù)一份唯一的session臼膏,供多臺(tái)服務(wù)器共享
唧唧歪歪一大堆渗磅,不過(guò)是為了引入緩存服務(wù)器。這里使用redis风响,相對(duì)于memcache状勤,支持的數(shù)據(jù)類型更豐富;相對(duì)于mongodb,在使用上更容易上手葫盼。關(guān)于redis的介紹贫导,可以參照這里(http://redis.io ),而關(guān)于以上三種都可以作為緩存服務(wù)器的中間件對(duì)比峰档,可以參考這里(
http://www.cnblogs.com/94cool/p/3247307.html
http://stackoverflow.com/questions/10558465/memcached-vs-redis )讥巡,我就不重復(fù)造輪子啦
系統(tǒng)引入redis
添加依賴
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.6.2.RELEASE</version>
</dependency>-
加入對(duì)應(yīng)的配置
可以將配置信息放入對(duì)應(yīng)的redis.properties中归榕,在spring中引用此properties。不過(guò)我更習(xí)慣直接在spring中直接配置特石,結(jié)合maven的profile來(lái)指定不同環(huán)境的配置
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="600"/>
<property name="maxIdle" value="300"/>
<property name="minIdle" value="10"/>
<property name="maxWaitMillis" value="1000"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
</bean><bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis_url}"/> --在env.properties中設(shè)置對(duì)應(yīng)IP <property name="poolConfig" ref="poolConfig"/> <property name="usePool" value="true"/> --使用連接池芙委,提高連接利用率 <property name="port" value="6379"/> <property name="password" value="abcd@45435361094"/> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="connectionFactory"/> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property> </bean>
-
對(duì)應(yīng)的java代碼推捐,統(tǒng)一封裝在constantsDao中牛柒,統(tǒng)一維護(hù)db與redis中的數(shù)據(jù),保持兩者數(shù)據(jù)同步蛾魄。
@Repository("constantRedisDao")public class ConstantDaoImpl implements ConstantDao {
@Autowired
private ConfigMapper configMapper;
......//僅列出配置項(xiàng)相關(guān)代碼,其它需要放入redis的數(shù)據(jù),也類似的封裝對(duì)應(yīng)的方法。
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 對(duì)于列表數(shù)據(jù)膀篮,可以考慮<String,List>,依次類推@Override public String getConfigByKey(String key) throws YxBizException { ConfigDO configDO = null; configDO = queryConfigByKey(key); return configDO.getValue(); } @Override public ConfigDO queryConfigByKey(String key) { ConfigDO configDO = null; //判斷redis中是否有值 if (redisTemplate.hasKey(NonConfigYxConstants.Y_CONFIG + key)) { logger.debug("get config from redis:" + NonConfigYxConstants.Y_CONFIG + key); configDO = (ConfigDO) redisTemplate.opsForValue().get(NonConfigYxConstants.Y_CONFIG + key); } if (null == configDO) { //從數(shù)據(jù)庫(kù)中取值 logger.debug("get config from datasource:" + NonConfigYxConstants.Y_CONFIG + key); configDO = configMapper.queryConfigByKey(key); Preconditions.checkNotNull(configDO, ResultCodeEnum.CONFIG_INFO_NOT_EXIST.getType()); //存入redis中 redisTemplate.opsForValue().set(NonConfigYxConstants.Y_CONFIG + key, configDO); //設(shè)置失效時(shí)間 redisTemplate.expire(NonConfigYxConstants.Y_CONFIG + key, NonConfigYxConstants.EXPIRE, TimeUnit.DAYS); } return configDO; } @Override @Transactional(rollbackFor = Exception.class) public void addConfig(ConfigDO configDO) { configMapper.addConfig(configDO); } @Override @Transactional(rollbackFor = Exception.class) public void updateConfig(ConfigDO configDO) { //修改緩存中數(shù)據(jù) logger.debug("update config to redis:" + NonConfigYxConstants.Y_CONFIG + configDO.getConfigKey()); try { redisTemplate.opsForValue().set(NonConfigYxConstants.Y_CONFIG + configDO.getConfigKey(), configDO); //設(shè)置失效時(shí)間 redisTemplate.expire(NonConfigYxConstants.Y_CONFIG + configDO.getConfigKey(), NonConfigYxConstants.EXPIRE, TimeUnit.DAYS); } catch (Exception e) { //如果redis添加失敗拋出異常 添加失敗 throw new YxBizException(ResultCodeEnum.UPDATE_FAIL.getType()); } configMapper.updateConfig(configDO); } @Override @Transactional(rollbackFor = Exception.class) public void deleteConfig(ConfigDO configDO) { //刪除緩存中數(shù)據(jù) logger.debug("delete config to redis" + NonConfigYxConstants.Y_CONFIG + configDO.getConfigKey()); try { redisTemplate.delete(NonConfigYxConstants.Y_CONFIG + configDO.getConfigKey()); } catch (Exception e) { //如果redis刪除失敗拋出異常 添加失敗 throw new YxBizException(ResultCodeEnum.UPDATE_FAIL.getType()); } configMapper.deleteConfigs(configDO); }
-
將session統(tǒng)一放入redis中
為了統(tǒng)一維護(hù)session涧偷,確保在集群環(huán)境下session的唯一性,選擇將session統(tǒng)一放入redis中确封。有兩種方式:- 在代碼中手動(dòng)維護(hù),每次登陸與注銷時(shí)秉剑,去redis中更新對(duì)應(yīng)的存留信息;優(yōu)點(diǎn)是靈活性大种柑,可以自定義需要保存的信息,缺點(diǎn)是工作量比較大驶赏,且有比較多的代碼侵入。
- tomcat7有插件支持將session存入redis蚯姆,工作量比較小疙驾,無(wú)代碼侵入。
項(xiàng)目中采用了方式二扳肛,下面大概介紹下對(duì)應(yīng)的配置:
- 下載插件tomcat-redis-session-manager,并放入tomcat下lib目錄中旋讹,關(guān)于tomcat-redis-session-manager詳見:https://github.com/jcoleman/tomcat-redis-session-manager
- 同時(shí)將相關(guān)依賴的包jedis-2.5.2.jar commons-pool2-2.2.jar(包版本可以根據(jù)對(duì)應(yīng)的redis版本調(diào)整)也放入同一路徑害驹。
- 在tomcat\conf下的context.xml中加入配置葫松,注意valve一定要在manager之前定義(官方說(shuō)在server.xml中也會(huì)生效,實(shí)際測(cè)試并不成功珊擂,bs。。):
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="localhost"
port="6379"
database="1"
password="redispassword"
maxInactiveInterval="60"
sessionPersistPolicies="PERSIST_POLICY_1,PERSIST_POLICY_2,.."
sentinelMaster="SentinelMasterName"
sentinels="sentinel-host-1:port,sentinel-host-2:port,.." />
將每個(gè)tomcat實(shí)例都設(shè)置成上述配置锡搜,重啟生效凡傅。