掌柜大作战(2):京东Redis服务的使用
来源:互联网 发布:linux rsyslog配置 编辑:程序博客网 时间:2024/04/28 13:07
京东内部,封装了Redis,可以用来缓存关键数据,内部通常叫做“Jim”或“jimClient”。
对外的Redis缓存服务和具体用法,请参考京东云官网:
https://www.jcloud.com/products/redis
本篇简要介绍下,Jim在内部项目中的配置和使用方式。
1、Spring上下文spring-applicationContext.xml
<bean id="propertyConfigurer" class="PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:redis.properties</value>
</list>
</property>
</bean>
<import resource="classpath:spring-redis.xml" />
2、Redis属性文件redis.properties
redis.configId=jim://abc123/def456
redis.token=jim:///abc123/def456
3、Reids相关bean配置spring-redis.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">
<bean id="jimClient" class="JimClientFactoryBean">
<!-- 配置拥有集群的客户端配置ID(必选)-->
<property name="configId" value="${redis.configId}"/>
<!-- 配置拥有集群的客户端配置Token(必选)-->
<property name="token" value="${redis.token}"/>
</bean>
<!--redis统一封装类-->
<bean id="redisClient" class="com.jd.RedisClient"/>
<bean id="cacheUtil" class="CacheUtil"/>
</beans>
4、RedisClient
import com.jd.jim.cli.Cluster;
/**
* redis的封装类,redis实例的统一出口,
* 此类可以封装多个实例的客户端,保证接口的统一化
*/
public class RedisClient {
private Cluster jimClient; //jedis
public Cluster getClientInstance(){
return jimClient;
}
public void setJimClient(Cluster jimClient) {
this.jimClient = jimClient;
}
public Cluster getJimClient() {
return jimClient;
}
}
5、Cluster 底层实现
6、CacheUtil
缓存工具类,根据RedisClient 底层的Jim接口,提供项目需要的功能,一般会增加“日志监控”和“异常处理”功能。UmpProfiler是京东内部的“统一监控服务”。
public class CacheUtil {
private final static Log log = LogFactory.getLog(CacheUtil.class);
private RedisClient redisClient;
public void setRedisClient(RedisClient redisClient) {
this.redisClient = redisClient;
}
/**
* 获取读缓存开关
*/
public Boolean getReadCacheSwitch() {
String value = this.redisClient.getClientInstance().get(SwitchConstants.Test.READ_CACHE_SWITCH);
if (StringUtils.isEmpty(value) || value.equals("1")) {
return true;
}
return false;
}
/**
* 获取写缓存开关
*/
public Boolean getWriteCacheSwitch() {
String value = this.redisClient.getClientInstance().get(SwitchConstants.Test.WRITE_CACHE_SWITCH);
if (StringUtils.isEmpty(value) || value.equals("1")) {
return true;
}
return false;
}
/**
* 设置缓存
*/
public void setString(String key, String cacheContent) {
CallerInfo callerInfo = UmpProfiler.methodReg(UmpKeyConstants.METHOD.REDIS_STATUS_WRITE);
try {
if (StringUtils.isNotEmpty(key)) {
redisClient.getClientInstance().set(key, cacheContent);
UmpProfiler.methodRegEnd(callerInfo);
}
} catch (Exception e) {
log.error("#设置set---key=" + key + "-->>>>>", e);
UmpProfiler.funcError(callerInfo);
}
}
}
7、实际使用
a.先检查是否使用缓存。
b.如果使用,从缓存中查询值value。
c.如果value不为null,直接返回。
d.如果value为null,调用方法查询,然后缓存,保证下次直接从缓存中能查询到。
补充:代码中存在不严谨的地方,如果isUseCache 为false,不使用缓存get查询,
但是却使用cacheUtil.setString缓存数据。难道是为了方便调试?
@Service
public class UserServiceImpl implements UserService{
@Resource
private CacheUtil cacheUtil;
@Resource
private ConfigUtil configUtil ;
/**
* 检查是否存在用户
*/
public boolean isExistBpin(String pin) {
CallerInfo callerInfo = UmpProfiler.methodReg(UmpKeyConstants.UserService.IS_EXISTS_BPIN); //ump监控
Boolean result = false;
String keyBak = EasyUtils.addSperator(RedisConstants.User.IS_EXIST_BPIN_BAK , pin);
String value = null;
try {
String key = EasyUtils.addSperator(RedisConstants.User.IS_EXIST_BPIN , pin);
Boolean isUseCache = configUtil.getSwitch(ConfigConstants.User.USER_SERVICE_IS_EXIST_BPIN_SWITCH);
if (isUseCache){
value = cacheUtil.getString(key);
log.info("#isExistBpin读取缓存["+key+"="+value+"]");
}
if (StringUtils.isBlank(value)) {
log.info("#isExistBpin读取接口");
result = this.userRpc.isExistBpin(pin);
if (result != null) {
if (result) {//如果存在再进行缓存数据
value = String.valueOf(result);
Long timeout = configUtil.getLong(ConfigConstants.User.USER_SERVICE_IS_EXIST_BPIN_TIMEOUT, 10L);
cacheUtil.setStringEx(key, value, timeout, TimeUnit.MINUTES);
cacheUtil.setString(keyBak, value);
}
}
}
} catch (Exception e) {
log.error("#[" + pin + "]isExistBpin.error", e);
UmpProfiler.funcError(callerInfo);
} finally {
if (StringUtils.isBlank(value)) {
value = cacheUtil.getString(keyBak);
}
if (StringUtils.isNotBlank(value)) {
result = Boolean.parseBoolean(value);
}
UmpProfiler.methodRegEnd(callerInfo);
}
return result;
}
}
8、总结
很多项目都需要缓存服务,因此可以定义CacheUtil和set和get等接口,然后实现该接口。
接口的底层数据存储,可以使用Redis、Memcache、本地Map等。
如果是Redis,可以是本地安装1个Redis、京东内部的Redis私有云服务、京东云的Redis公有云服务。
如果是中小型创业公司,也可以选择阿里云的Redis缓存云。
具体到阿里内部,猜测下:内部开发有私有云和公有云(阿里云)2种选择。
9、思考
实际项目中,因为有了统一的Redis封装,开发者(软件工程师、程序员、码农)更加侧重应用开发、业务实现和API接口调用,对底层实现关注的不多。知道底层实现,可能有2个作用。
a、实际价值
偶尔会遇到一些问题,知道原理,可以快速定位问题,从而解决它。
b、面试
比较侧重技术的面试官,可能会问你底层原理。
如果啥都不懂,可能就GG了。
阅读全文
0 0
- 掌柜大作战(2):京东Redis服务的使用
- 掌柜大作战(9):京东分布式服务框架JSF的配置和使用,一步步让你成为“技术傻瓜”
- 掌柜大作战(5):使用AOP,统一记录方法执行所花的时间
- 掌柜大作战(8):京东消息中间件JMQ的配置和使用
- 掌柜大作战(12):京东统一监控平台UMP的配置、使用和实现原理
- 掌柜大作战(13):京东统一日志平台Logbook的使用和实现原理
- 掌柜大作战(25):健身房签到系统,多线程使用不当造成的1个严重bug
- 掌柜大作战(1):人民的美梦,群众的水乡
- 掌柜大作战(14):京东Web安全经验总结-客户端安全
- 掌柜大作战(23):京东Me,移动办公,应有尽有
- 掌柜大作战(4):京东统一登录服务,外网和内网
- 掌柜大作战(17):Spring事务的原理,用自己的语言描述自己的理解
- 掌柜大作战(10):人脸识别和图像识别,Java程序员的宿命
- 掌柜大作战(22):京东商城系统之间的通信和合作,技术探讨
- 掌柜大作战(15):营业执照图片识别,有点尴尬
- 掌柜大作战(19):京东和企业信息化
- 掌柜大作战(21):京东线上数据库管理
- 掌柜大作战(24):京东红绿灯监控报警系统
- git的使用
- c++栈
- Linux系统虚拟机管理(创建,安装,快照,删除)
- deeplearning _Initialization
- 使用STL map应该注意什么
- 掌柜大作战(2):京东Redis服务的使用
- 网页静态服务器-1-显示固定的页面
- OBIEE Quick LDAP Configuration
- 欢迎使用 MWeb
- 设计模式之单例模式
- Tensorflow报错tensorflow.python.framework.errors_impl.InvalidArgumentError exception str() failed原因
- Android 判断网络是否正常
- mysql查询一个表自增主键的下一个主键值:
- Android_Dialog