本人菜鸟一名,刚毕业出来没多久,在上海一家公司工作,公司有算上我有3个java程序员,其他两个有两到三年的工作经验,他们负责APP的接口开发,我一个人负责后台管理接口开发,公司项目框架是用Spring搭建的,开发工具也是Spring的,持久层集成了Spring data jap和Mybatis,控制层用的是Spring MVC ,对于刚出校园的我来说觉得这框架塔的特别牛。由于项目的权限做的有点复杂,而且查询的地方特别多,网页加载速度特别慢,老大说把那些权限判断放我缓存里,让我去做,我当时就楞住了,我刚从学校出来,只知道hibernate二级缓存,老大让我在memcached和redis中选一个,还要做集群模式的,我那时还是试用期,为了突显自己的能力,就硬着头皮答应下来了。现在就写下我学习这两个缓存的路程。
redis sentinel 介绍:(此处copy)
Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance),该系统执行以下三个任务:
- 监控(Monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
- 提醒(Notification):当被监控的某个 Redis 服务器出现问题时,Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
- 自动故障迁移(Automatic failover):当一个主服务器不能正常工作时,Sentinel 会开始一次自动故障迁移操作,它会将失效主服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器;当客户端试图连接失效的主服务器时,集群也会向客户端返回新主服务器的地址,使得集群可以使用新主服务器代替失效服务器。
首先介绍redis sentinel服务端配置
这是端口号为6479的redis主服务器
##redis.conf
##redis-0,默认为def_master
port 6479
##授权密码,请各个配置保持一致
requirepass 123456
masterauth 123456
##暂且禁用指令重命名
##rename-command
##开启AOF,禁用snapshot
appendonly yes
save 900 1
save 300 10
save 60 10000
##slaveof no one
slave-read-only yes
这是端口号为6480的从服务器
##redis.conf
##redis-0,默认为def_master
port 6480
slaveof 127.0.0.1 6479
##授权密码,请各个配置保持一致
requirepass 123456
masterauth 123456
##暂且禁用指令重命名
##rename-command
##开启AOF,禁用snapshot
appendonly yes
save 900 1
save 300 10
save 60 10000
##slaveof no one
slave-read-only yes
这是sentinel 集群管理器sentinel.conf配置
##redis-0
##sentinel实例之间的通讯端口
port 26379
##指定sentinel使用的端口,不能与redis-server运行实例的端口冲突,1表示至少一台从服务器发现主服务器故障就会自动主从切换
sentinel monitor def_master 127.0.0.1 6479 1
##连接redis服务密码
sentinel auth-pass def_master 123456
##表示如果5s内mymaster没响应,就认为主服务器发生故障
sentinel down-after-milliseconds def_master 50000
##表示如果master重新选出来后,其它slave节点能同时并行从新master同步缓存的台数有多少个,显然该值越大,所有slave节点完成同步切换的整体速度越快,但如果此时正好有人在访问这些slave,可能造成读取失败,影响面会更广。最保定的设置为1,只同一时间,只能有一台干这件事,这样其它slave还能继续服务,但是所有slave全部完成缓存更新同步的进程将变慢。
sentinel parallel-syncs def_master 1
表示如果90秒后,mysater仍没活过来,则启动failover(故障转移),从剩下的slave中选一个升级为master
sentinel failover-timeout def_master 900000
配置写好后就开始启动reids服务,我这是在Windows环境下测试的,在linux下命令有所不同。
输入cmd命令进入控制台,
打开redis文件位置,输入redis-server.exe redis6479.conf启动reids主服务器。
然后打开从服务器位置,输入redis-server.exe redis6480.conf启动reids从服务器。
然后启动sentinel,打开文件位置输入redis-server sentinel.conf --sentinel启动管理器。
完了之后服务端就开启成功。
一下是客户端连接服务端代码编写:
Spring提供了Spring data redis这个子项目,本人用的就是Spring data redis
spring的配置文件:
spring-data-redis.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"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<context:component-scan base-package="org.tht.service"/>
<cache:annotation-driven></cache:annotation-driven>
<bean id="redisSentinelConfiguration"
class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
<!--这里的def_master就是集群管理器的名字,我们在客户端只需连接sentinel,sentinel会帮我们去管理redis服务器 -->
<property name="def_master ">
<bean class="org.springframework.data.redis.connection.RedisNode">
<property name="name" value="mymaster"></property>
</bean>
</property>
<property name="sentinels">
<set>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"/>
<constructor-arg name="port" value="26379"/>
</bean>
</set>
</property>
</bean>
<bean id="jeidsConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="password" value="123456"></property>
<constructor-arg ref="redisSentinelConfiguration"/>
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jeidsConnectionFactory"/>
<bean
id="cacheManager"
class="org.springframework.data.redis.cache.RedisCacheManager"
c:template-ref="redisTemplate"/>
</beans>
现在我们写方法:
@Cacheable(value="messageCache",key="#name")
public String getMessage(String name) {
return userService.findByName(name);
}
这是查询方法,@Cacheable(value="messageCache",key="#name")
这个注解是查询redis缓存,value:命名空间,key:返回数据对应的键。如果缓存中没有这个key就会去查询数据库,并将返回的值存入redis,有则直接从缓存中读取数据。
//更新缓存
@CachePut(value="messageCache",key="#name")
public String updateMessage(String name) {
return userService.findByName(name);
}
这个注解是修改redis缓存@CachePut(value="messageCache",key="#name")
//清空命名空间为messageCache下的所有缓存
@CacheEvict(value="messageCache",allEntries=true)
public void deleteOperationAuthByPageUrlCache() {
}
//清空命名空间为messageCache下key为name的缓存
@CacheEvict(value="messageCache",allEntries=true,key="#name")
public void deleteOperationAuthByPageUrlCache() {
}
以上代码经过本人测试过,没问题,当主服务器发生故障时从服务器会自动升为主服务器,两台redis服务器的数据会同步,这种集群模式无需担心服务器挂掉之后数据的丢失。
在学校redis之前本人也学习了memcached,之说以选择redis下面会说明原因。
以下是memcached基于客户端分布式代码:
谷歌提供了memcached与Spring集成的组件simple spring memcached,一下是spring-memcache.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
">
<context:component-scan base-package="org.tht.service"/>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<import resource="simplesm-context.xml" />
<!-- 默认一个client -->
<bean name="defaultMemcachedClient" class="com.google.code.ssm.CacheFactory">
<property name="cacheClientFactory">
<bean name="cacheClientFactory" class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl" />
</property>
<property name="addressProvider">
<bean class="com.google.code.ssm.config.DefaultAddressProvider">
<!--服务器地址,在这里实现分布式 -->
<property name="address" value="127.0.0.1:11211,192.168.1.227:12677" />
</bean>
</property>
<!-- 一致性hash ~。~ -->
<property name="configuration">
<bean class="com.google.code.ssm.providers.CacheConfiguration">
<property name="consistentHashing" value="true" />
</bean>
</property>
</bean>
<bean class="com.google.code.ssm.Settings">
<property name="order" value="500" />
</bean>
</beans>
一下是方法:
/**
* 当执行getUserById查询方法时,系统首先会从缓存中获取id对应的实体
* 如果实体还没有被缓存,则执行查询方法并将查询结果放入缓存中
*/
@ReadThroughSingleCache(namespace = "test")
public CacheBean getUserById(@ParameterValueKeyProvider String userId) throws Exception{
System.out.println("没有缓存命中");
CacheBean cacheBean=new CacheBean();
cacheBean.setUserId(userId);
cacheBean.setUserName("赵六");
return cacheBean;
}
/**
* 当执行delete方法时,系统会删除缓存中id对应的实体
*/
@InvalidateSingleCache(namespace="test")
public void delete(@ParameterValueKeyProvider Integer userId){
System.out.println(userId);
}
/**
* 当执行update方法时,系统会更新缓存中id对应的实体
* 将实体内容更新成@*DataUpdateContent标签所描述的实体
*/
@UpdateSingleCache(namespace="test")
public void update(@ParameterValueKeyProvider @ParameterDataUpdateContent CacheBean cacheBean){
System.out.println(cacheBean.getUserName());
}
现在就开始说说redis和memcached的区别:
在此之前你可能在网上查看了很多关于两者的区别,在此我只说我在用这两个缓存的心得与体会。
区别1:memcached的分布式是基于客户端的(下面会介绍),而redis的分布式是基于服务端的(上面已经写的很清楚了)
区别2:redis可以根据命名空间删除该命名空间下的所有key,而memcached必须得指定key(想删除命名空间下的所有key,只能先将该命名空间下的所有key查出来再进行删除)
区别3:Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而memcached服务器重启后所有缓存数据都会清空。
以上3个区别是我的切身体会,还有很多区别在这里就不一一说明了,在网上都可以查到。
本人菜鸟一枚,大神勿喷,以上只是本人学习的一点小体会,也只是懂了点皮毛,也有很多不懂得地方,希望可以和你们一起交流,共同进步。