springboot接入cachecloud redis示例实践
最近项目中需要接入 RedisCacheCloud, CacheCloud是一个开源的Redis运维监控云平台,功能十分强大,支持Redis实例自动部署、扩容、碎片管理、统计、监控等功能,特别是支持单机、sentinel、cluster三种模式的自动部署,搭建redis集群一步到位轻松搞定。
java项目中接入CacheCloudredis的方式主要有两种。
第一种就是在CacheCloud上创建好redis实例后将对应的IP,端口直接配置以配置形式应用到项目中,优点是通用性好,原有项目改造成本低,不过万一后期CacheCloud上对redis进行管理扩容,那只能手动把每个项目的redis配置都改一遍了。
第二种CacheCloud上创建好实例后有一个对应的appId,程序调用CacheCloud平台的rest接口通过appId获取redis相关配置,将程序中的redis配置 统一交给CacheCloud平台去管理维护,后期管理和扩容及其方便,不过程序改造成本比较高。
现在采用第二种方式接入,工程采用springboot,redis采用哨兵模式,redis客户端主要用spring-data-redis和redisson, 接入流程如下:
添加配置到pom.xml文件
com.sohu.tv cachecloud-open-client-redis 1.0-SNAPSHOT com.sohu.tv cachecloud-open-client-basic 1.0-SNAPSHOT com.sohu.tv cachecloud-open-common 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-data-redis jedis redis.clients org.redisson redisson 3.9.0
准备配置文件 cacheCloudClient.properties,启动项目时 VM参数追加-Dcachecloud.config=配置文件路径
http_conn_timeout=3000 http_socket_timeout=5000 client_version=1.0-SNAPSHOT domain_url=http://192.168.33.221:8585#cachecloud实际路径 redis_cluster_suffix=/cache/client/redis/cluster/%s.json?clientVersion= redis_sentinel_suffix=/cache/client/redis/sentinel/%s.json?clientVersion= redis_standalone_suffix=/cache/client/redis/standalone/%s.json?clientVersion= cachecloud_report_url=/cachecloud/client/reportData.json
基本思路是先通过cachecloud的restapi接口获取并解析redis节点的配置信息,然后就可以按照传统的访问redis的方式进行初始化,获取RedisTemplate对象。
java代码如下:
importcom.alibaba.fastjson.JSONObject;
importcom.sohu.tv.cachecloud.client.basic.heartbeat.ClientStatusEnum;
importcom.sohu.tv.cachecloud.client.basic.util.ConstUtils;
importcom.sohu.tv.cachecloud.client.basic.util.HttpUtils;
importcom.sohu.tv.cachecloud.client.jedis.stat.ClientDataCollectReportExecutor;
importlombok.Getter;
importlombok.Setter;
importorg.apache.commons.lang3.tuple.Pair;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.stereotype.Component;
importjavax.annotation.PostConstruct;
importjava.util.HashSet;
importjava.util.Random;
importjava.util.Set;
importjava.util.concurrent.TimeUnit;
importjava.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
@Component
publicclassRedisProperties{
publicstaticLoggerlogger=LoggerFactory.getLogger(RedisProperties.class);
/**
*构建锁
*/
privatestaticfinalLockLOCK=newReentrantLock();
@Value("${cacheCloud.appId}")//cahcecloud开通redis实例应用id
privateIntegerappId;
@Getter
@Setter
privateStringmasterName;
@Getter
@Setter
privateSet>sentinelSet=newHashSet<>();
privateBooleanclientStatIsOpen=true;
@Getter
@Setter
privateStringpassword;
privateBooleangetConfigSuccess=false;
@PostConstruct
publicvoidinit(){
while(true){
try{
LOCK.tryLock(10,TimeUnit.MILLISECONDS);
if(!getConfigSuccess){
/**
*http请求返回的结果是空的;
*/
Stringresponse=HttpUtils.doGet(String.format(ConstUtils.REDIS_SENTINEL_URL,appId));
if(response==null||response.isEmpty()){
logger.warn("getresponsefromremoteservererror,appId:{},continue...",appId);
continue;
}
/**
*http请求返回的结果是无效的;
*/
JSONObjectjsonObject=null;
try{
jsonObject=JSONObject.parseObject(response);
}catch(Exceptione){
logger.error("heartbeaterror,appId:{}.continue...",appId,e);
}
if(jsonObject==null){
logger.error("getsentinelinfoforappId:{}error.continue...",appId);
continue;
}
intstatus=jsonObject.getIntValue("status");
Stringmessage=jsonObject.getString("message");
/**检查客户端版本**/
if(status==ClientStatusEnum.ERROR.getStatus()){
thrownewIllegalStateException(message);
}elseif(status==ClientStatusEnum.WARN.getStatus()){
logger.warn(message);
}else{
logger.info(message);
}
/**
*有效的请求:取出masterName和sentinels;
*/
masterName=jsonObject.getString("masterName");
Stringsentinels=jsonObject.getString("sentinels");
for(StringsentinelStr:sentinels.split("")){
String[]sentinelArr=sentinelStr.split(":");
if(sentinelArr.length==2){
sentinelSet.add(Pair.of(sentinelArr[0],sentinelArr[1]));
}
}
//收集上报数据
if(clientStatIsOpen){
ClientDataCollectReportExecutor.getInstance();
}
password=jsonObject.getString("password");
getConfigSuccess=true;
return;
}
}catch(Throwablee){//容错
logger.error("errorinbuild,appId:{}",appId,e);
}finally{
LOCK.unlock();
}
try{
TimeUnit.MILLISECONDS.sleep(200+newRandom().nextInt(1000));//活锁
}catch(InterruptedExceptione){
logger.error(e.getMessage(),e);
}
}
}
}
importcom.shunwang.buss.dispatchPay.provider.config.PropertiesUtil;
importorg.apache.commons.lang3.StringUtils;
importorg.redisson.Redisson;
importorg.redisson.api.RedissonClient;
importorg.redisson.config.Config;
importorg.redisson.config.ReadMode;
importorg.redisson.config.SentinelServersConfig;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.context.annotation.Primary;
importorg.springframework.data.redis.connection.RedisConnectionFactory;
importorg.springframework.data.redis.connection.RedisNode;
importorg.springframework.data.redis.connection.RedisSentinelConfiguration;
importorg.springframework.data.redis.connection.jedis.JedisConnectionFactory;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.data.redis.serializer.StringRedisSerializer;
importredis.clients.jedis.JedisPoolConfig;
importjava.net.UnknownHostException;
importjava.util.List;
importjava.util.Set;
importjava.util.stream.Collectors;
importstaticjava.util.stream.Collectors.toList;
@Configuration
publicclassRedisConfig{
/**
*JedisPoolConfig连接池
*/
@Bean
publicJedisPoolConfigjedisPoolConfig(RedisPropertiesproperties){
JedisPoolConfigjedisPoolConfig=newJedisPoolConfig();
//最大空闲数
jedisPoolConfig.setMaxIdle(20);
//连接池的最大数据库连接数
jedisPoolConfig.setMaxTotal(20);
//最大建立连接等待时间
jedisPoolConfig.setMaxWaitMillis(3000);
returnjedisPoolConfig;
}
/**
*配置redis的哨兵
*/
@Bean
publicRedisSentinelConfigurationsentinelConfiguration(RedisPropertiesproperties){
RedisSentinelConfigurationredisSentinelConfiguration=newRedisSentinelConfiguration();
//配置redis的哨兵sentinel
SetredisNodeSet=properties.getSentinelSet().stream()
.map(pair->newRedisNode(pair.getLeft(),Integer.parseInt(pair.getRight())))
.collect(Collectors.toSet());
redisSentinelConfiguration.setSentinels(redisNodeSet);
redisSentinelConfiguration.setMaster(properties.getMasterName());
returnredisSentinelConfiguration;
}
/**
*配置工厂
*/
@Bean
publicRedisConnectionFactoryjedisConnectionFactory(JedisPoolConfigjedisPoolConfig,RedisSentinelConfigurationsentinelConfig){
JedisConnectionFactoryjedisConnectionFactory=newJedisConnectionFactory(sentinelConfig,jedisPoolConfig);
returnjedisConnectionFactory;
}
@Bean
publicRedisTemplate
到这里我们已经在Spring中生成了RedisTemplate和 RedissonClient对象,无论是基本数据结构操作 还是分布式锁 都已经轻松支持了,具体使用就不展开了
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。