经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Redis » 查看文章
springboot接入cachecloud redis示例实践
来源:jb51  时间:2019/10/28 11:02:17  对本文有异议

最近项目中需要接入  Redis CacheCloud,   CacheCloud是一个开源的 Redis 运维监控云平台,功能十分强大,支持Redis 实例自动部署、扩容、碎片管理、统计、监控等功能, 特别是支持单机、sentinel 、cluster三种模式的自动部署,搭建redis集群一步到位轻松搞定。

java项目中 接入 CacheCloud redis的方式主要有两种。

第一种就是在 CacheCloud 上创建好redis实例后将对应的IP,端口直接配置以配置形式应用到项目中,优点是通用性好,原有项目改造成本低,不过万一后期CacheCloud上对redis进行管理扩容,那只能手动把每个项目的redis配置都改一遍了。

第二种CacheCloud 上创建好实例后有一个对应的appId,程序调用CacheCloud 平台的rest接口通过 appId获取redis相关配置,将程序中的redis配置  统一交给CacheCloud平台去管理维护,后期管理和扩容及其方便,不过程序改造成本比较高。

现在采用第二种方式接入,工程采用springboot,redis采用哨兵模式,redis客户端主要用spring-data-redis和redisson,    接入流程如下:

添加配置到pom.xml文件

  1. <!--cachecloud 相关jar包-->
  2. <dependency>
  3. <groupId>com.sohu.tv</groupId>
  4. <artifactId>cachecloud-open-client-redis</artifactId>
  5. <version>1.0-SNAPSHOT</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.sohu.tv</groupId>
  9. <artifactId>cachecloud-open-client-basic</artifactId>
  10. <version>1.0-SNAPSHOT</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>com.sohu.tv</groupId>
  14. <artifactId>cachecloud-open-common</artifactId>
  15. <version>1.0-SNAPSHOT</version>
  16. </dependency>
  17. <!--spring redis 和 redisson-->
  18. <dependency>
  19. <groupId>org.springframework.boot</groupId>
  20. <artifactId>spring-boot-starter-data-redis</artifactId>
  21. <exclusions>
  22. <exclusion>
  23. <artifactId>jedis</artifactId>
  24. <groupId>redis.clients</groupId>
  25. </exclusion>
  26. </exclusions>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.redisson</groupId>
  30. <artifactId>redisson</artifactId>
  31. <version>3.9.0</version>
  32. </dependency>

准备配置文件  cacheCloudClient.properties,启动项目时  VM参数追加 -Dcachecloud.config= 配置文件路径

  1. http_conn_timeout = 3000
  2. http_socket_timeout = 5000
  3. client_version = 1.0-SNAPSHOT
  4. domain_url = http://192.168.33.221:8585 #cachecloud实际路径
  5. redis_cluster_suffix = /cache/client/redis/cluster/%s.json?clientVersion=
  6. redis_sentinel_suffix = /cache/client/redis/sentinel/%s.json?clientVersion=
  7. redis_standalone_suffix = /cache/client/redis/standalone/%s.json?clientVersion=
  8. cachecloud_report_url = /cachecloud/client/reportData.json

基本思路是先通过cachecloud的restapi接口获取并解析redis节点的配置信息,然后就可以按照传统的访问redis的方式进行初始化,获取RedisTemplate对象。

java代码如下:

  1. import com.alibaba.fastjson.JSONObject;
  2. import com.sohu.tv.cachecloud.client.basic.heartbeat.ClientStatusEnum;
  3. import com.sohu.tv.cachecloud.client.basic.util.ConstUtils;
  4. import com.sohu.tv.cachecloud.client.basic.util.HttpUtils;
  5. import com.sohu.tv.cachecloud.client.jedis.stat.ClientDataCollectReportExecutor;
  6. import lombok.Getter;
  7. import lombok.Setter;
  8. import org.apache.commons.lang3.tuple.Pair;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11. import org.springframework.beans.factory.annotation.Value;
  12. import org.springframework.stereotype.Component;
  13. import javax.annotation.PostConstruct;
  14. import java.util.HashSet;
  15. import java.util.Random;
  16. import java.util.Set;
  17. import java.util.concurrent.TimeUnit;
  18. import java.util.concurrent.locks.Lock;
  19. import java.util.concurrent.locks.ReentrantLock;
  20. @Component
  21. public class RedisProperties {
  22. public static Logger logger = LoggerFactory.getLogger(RedisProperties.class);
  23. /**
  24. * 构建锁
  25. */
  26. private static final Lock LOCK = new ReentrantLock();
  27. @Value("${cacheCloud.appId}") //cahcecloud 开通redis实例 应用id
  28. private Integer appId;
  29. @Getter
  30. @Setter
  31. private String masterName;
  32. @Getter
  33. @Setter
  34. private Set<Pair<String, String>> sentinelSet = new HashSet<>();
  35. private Boolean clientStatIsOpen=true;
  36. @Getter
  37. @Setter
  38. private String password;
  39. private Boolean getConfigSuccess = false;
  40. @PostConstruct
  41. public void init() {
  42. while (true) {
  43. try {
  44. LOCK.tryLock(10, TimeUnit.MILLISECONDS);
  45. if (!getConfigSuccess) {
  46. /**
  47. * http请求返回的结果是空的;
  48. */
  49. String response = HttpUtils.doGet(String.format(ConstUtils.REDIS_SENTINEL_URL, appId));
  50. if (response == null || response.isEmpty()) {
  51. logger.warn("get response from remote server error, appId: {}, continue...", appId);
  52. continue;
  53. }
  54. /**
  55. * http请求返回的结果是无效的;
  56. */
  57. JSONObject jsonObject = null;
  58. try {
  59. jsonObject = JSONObject.parseObject(response);
  60. } catch (Exception e) {
  61. logger.error("heartbeat error, appId: {}. continue...", appId, e);
  62. }
  63. if (jsonObject == null) {
  64. logger.error("get sentinel info for appId: {} error. continue...", appId);
  65. continue;
  66. }
  67. int status = jsonObject.getIntValue("status");
  68. String message = jsonObject.getString("message");
  69. /** 检查客户端版本 **/
  70. if (status == ClientStatusEnum.ERROR.getStatus()) {
  71. throw new IllegalStateException(message);
  72. } else if (status == ClientStatusEnum.WARN.getStatus()) {
  73. logger.warn(message);
  74. } else {
  75. logger.info(message);
  76. }
  77. /**
  78. * 有效的请求:取出masterName和sentinels;
  79. */
  80. masterName = jsonObject.getString("masterName");
  81. String sentinels = jsonObject.getString("sentinels");
  82. for (String sentinelStr : sentinels.split(" ")) {
  83. String[] sentinelArr = sentinelStr.split(":");
  84. if (sentinelArr.length == 2) {
  85. sentinelSet.add(Pair.of(sentinelArr[0], sentinelArr[1]));
  86. }
  87. }
  88. //收集上报数据
  89. if (clientStatIsOpen) {
  90. ClientDataCollectReportExecutor.getInstance();
  91. }
  92. password = jsonObject.getString("password");
  93. getConfigSuccess = true;
  94. return;
  95. }
  96. } catch (Throwable e) {//容错
  97. logger.error("error in build, appId: {}", appId, e);
  98. } finally {
  99. LOCK.unlock();
  100. }
  101. try {
  102. TimeUnit.MILLISECONDS.sleep(200 + new Random().nextInt(1000));//活锁
  103. } catch (InterruptedException e) {
  104. logger.error(e.getMessage(), e);
  105. }
  106. }
  107. }
  108. }
  1. import com.shunwang.buss.dispatchPay.provider.config.PropertiesUtil;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.redisson.Redisson;
  4. import org.redisson.api.RedissonClient;
  5. import org.redisson.config.Config;
  6. import org.redisson.config.ReadMode;
  7. import org.redisson.config.SentinelServersConfig;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.context.annotation.Primary;
  12. import org.springframework.data.redis.connection.RedisConnectionFactory;
  13. import org.springframework.data.redis.connection.RedisNode;
  14. import org.springframework.data.redis.connection.RedisSentinelConfiguration;
  15. import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
  16. import org.springframework.data.redis.core.RedisTemplate;
  17. import org.springframework.data.redis.serializer.StringRedisSerializer;
  18. import redis.clients.jedis.JedisPoolConfig;
  19. import java.net.UnknownHostException;
  20. import java.util.List;
  21. import java.util.Set;
  22. import java.util.stream.Collectors;
  23. import static java.util.stream.Collectors.toList;
  24. @Configuration
  25. public class RedisConfig {
  26. /**
  27. * JedisPoolConfig 连接池
  28. */
  29. @Bean
  30. public JedisPoolConfig jedisPoolConfig(RedisProperties properties) {
  31. JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
  32. // 最大空闲数
  33. jedisPoolConfig.setMaxIdle(20);
  34. // 连接池的最大数据库连接数
  35. jedisPoolConfig.setMaxTotal(20);
  36. // 最大建立连接等待时间
  37. jedisPoolConfig.setMaxWaitMillis(3000);
  38. return jedisPoolConfig;
  39. }
  40. /**
  41. * 配置redis的哨兵
  42. */
  43. @Bean
  44. public RedisSentinelConfiguration sentinelConfiguration(RedisProperties properties) {
  45. RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
  46. // 配置redis的哨兵sentinel
  47. Set<RedisNode> redisNodeSet = properties.getSentinelSet().stream()
  48. .map(pair -> new RedisNode(pair.getLeft(), Integer.parseInt(pair.getRight())))
  49. .collect(Collectors.toSet());
  50. redisSentinelConfiguration.setSentinels(redisNodeSet);
  51. redisSentinelConfiguration.setMaster(properties.getMasterName());
  52. return redisSentinelConfiguration;
  53. }
  54. /**
  55. * 配置工厂
  56. */
  57. @Bean
  58. public RedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig, RedisSentinelConfiguration sentinelConfig) {
  59. JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(sentinelConfig, jedisPoolConfig);
  60. return jedisConnectionFactory;
  61. }
  62. @Bean
  63. public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
  64. throws UnknownHostException {
  65. RedisTemplate template = new RedisTemplate();
  66. template.setConnectionFactory(redisConnectionFactory);
  67. FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
  68. // 设置值(value)的序列化采用FastJsonRedisSerializer。
  69. template.setValueSerializer(fastJsonRedisSerializer);
  70. template.setHashValueSerializer(fastJsonRedisSerializer);
  71. // 设置键(key)的序列化采用StringRedisSerializer。
  72. template.setKeySerializer(new StringRedisSerializer());
  73. template.setHashKeySerializer(new StringRedisSerializer());
  74. template.afterPropertiesSet();
  75. return template;
  76. }
  77. /**
  78. * Redisson 配置
  79. */
  80. @Bean
  81. public RedissonClient redissonClient(RedisProperties properties) {
  82. Config config = new Config();
  83. List<String> newNodes = properties.getSentinelSet().stream()
  84. .map(pa -> "redis://" + pa.getLeft() + ":" + pa.getRight()).collect(toList());
  85. SentinelServersConfig serverConfig = config.useSentinelServers()
  86. .addSentinelAddress(newNodes.toArray(new String[newNodes.size()]))
  87. .setMasterName(properties.getMasterName())
  88. .setReadMode(ReadMode.SLAVE);
  89. if (StringUtils.isNotBlank(properties.getPassword())){
  90. serverConfig.setPassword(properties.getPassword());
  91. }
  92. return Redisson.create(config);
  93. }
  94. }

到这里我们已经在Spring中 生成了RedisTemplate 和  RedissonClient 对象,无论是基本数据结构操作  还是分布式锁  都已经轻松支持了,具体使用就不展开了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号