资讯专栏INFORMATION COLUMN

分布式工具的一次小升级⏫

AlexTuan / 2094人阅读

前言

之前在做 秒杀架构实践 时有提到对 distributed-redis-tool 的一次小升级,但是没有细说。

其实主要原因是:

</>复制代码

  1. 秒杀时我做压测:由于集成了这个限流组件,并发又比较大,所以导致连接、断开 Redis 非常频繁。
    最终导致获取不了 Redis connection 的异常。
池化技术

这就是一个典型的对稀缺资源使用不善导致的。

何为稀缺资源?常见的有:

线程

数据库连接

网络连接等

这些资源都有共同的特点:创建销毁成本较高

这里涉及到的 Redis 连接也属于该类资源。

我们希望将这些稀有资源管理起来放到一个池子里,当需要时就从中获取,用完就放回去,不够用时就等待(或返回)。

这样我们只需要初始化并维护好这个池子,就能避免频繁的创建、销毁这些资源(也有资源长期未使用需要缩容的情况)。

通常我们称这项姿势为池化技术,如常见的:

线程池

各种资源的连接池等。

为此我将使用到 Redis 的 分布式锁、分布式限流 都升级为利用连接池来获取 Redis 的连接。

这里以分布式锁为例:

将使用的 api 修改为:

原有:

</>复制代码

  1. @Configuration
  2. public class RedisLockConfig {
  3. @Bean
  4. public RedisLock build(){
  5. //Need to get Redis connection
  6. RedisLock redisLock = new RedisLock() ;
  7. HostAndPort hostAndPort = new HostAndPort("127.0.0.1",7000) ;
  8. JedisCluster jedisCluster = new JedisCluster(hostAndPort) ;
  9. RedisLock redisLock = new RedisLock.Builder(jedisCluster)
  10. .lockPrefix("lock_test")
  11. .sleepTime(100)
  12. .build();
  13. return redisLock ;
  14. }
  15. }

现在:

</>复制代码

  1. @Configuration
  2. public class RedisLockConfig {
  3. private Logger logger = LoggerFactory.getLogger(RedisLockConfig.class);
  4. @Autowired
  5. private JedisConnectionFactory jedisConnectionFactory;
  6. @Bean
  7. public RedisLock build() {
  8. RedisLock redisLock = new RedisLock.Builder(jedisConnectionFactory,RedisToolsConstant.SINGLE)
  9. .lockPrefix("lock_")
  10. .sleepTime(100)
  11. .build();
  12. return redisLock;
  13. }
  14. }

将以前的 Jedis 修改为 JedisConnectionFactory,后续的 Redis 连接就可通过这个对象获取。

并且显示的传入使用 RedisCluster 还是单机的 Redis。

所以在真正操作 Redis 时需要修改:

</>复制代码

  1. public boolean tryLock(String key, String request) {
  2. //get connection
  3. Object connection = getConnection();
  4. String result ;
  5. if (connection instanceof Jedis){
  6. result = ((Jedis) connection).set(lockPrefix + key, request, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, 10 * TIME);
  7. ((Jedis) connection).close();
  8. }else {
  9. result = ((JedisCluster) connection).set(lockPrefix + key, request, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, 10 * TIME);
  10. try {
  11. ((JedisCluster) connection).close();
  12. } catch (IOException e) {
  13. logger.error("IOException",e);
  14. }
  15. }
  16. if (LOCK_MSG.equals(result)) {
  17. return true;
  18. } else {
  19. return false;
  20. }
  21. }
  22. //获取连接
  23. private Object getConnection() {
  24. Object connection ;
  25. if (type == RedisToolsConstant.SINGLE){
  26. RedisConnection redisConnection = jedisConnectionFactory.getConnection();
  27. connection = redisConnection.getNativeConnection();
  28. }else {
  29. RedisClusterConnection clusterConnection = jedisConnectionFactory.getClusterConnection();
  30. connection = clusterConnection.getNativeConnection() ;
  31. }
  32. return connection;
  33. }

最大的改变就是将原有操作 Redis 的对象(T extends JedisCommands)改为从连接池中获取。

由于使用了 org.springframework.data.redis.connection.jedis.JedisConnectionFactory 作为 Redis 连接池。

所以需要再使用时构件好这个对象:

</>复制代码

  1. JedisPoolConfig config = new JedisPoolConfig();
  2. config.setMaxIdle(10);
  3. config.setMaxTotal(300);
  4. config.setMaxWaitMillis(10000);
  5. config.setTestOnBorrow(true);
  6. config.setTestOnReturn(true);
  7. RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
  8. redisClusterConfiguration.addClusterNode(new RedisNode("10.19.13.51", 7000));
  9. //单机
  10. JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(config);
  11. //集群
  12. //JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration) ;
  13. jedisConnectionFactory.setHostName("47.98.194.60");
  14. jedisConnectionFactory.setPort(6379);
  15. jedisConnectionFactory.setPassword("");
  16. jedisConnectionFactory.setTimeout(100000);
  17. jedisConnectionFactory.afterPropertiesSet();
  18. //jedisConnectionFactory.setShardInfo(new JedisShardInfo("47.98.194.60", 6379));
  19. //JedisCluster jedisCluster = new JedisCluster(hostAndPort);
  20. HostAndPort hostAndPort = new HostAndPort("10.19.13.51", 7000);
  21. JedisCluster jedisCluster = new JedisCluster(hostAndPort);
  22. redisLock = new RedisLock.Builder(jedisConnectionFactory, RedisToolsConstant.SINGLE)
  23. .lockPrefix("lock_")
  24. .sleepTime(100)
  25. .build();

看起比较麻烦,需要构建对象的较多。

但整合 Spring 使用时就要清晰许多。

配合 Spring

Spring 很大的一个作用就是帮我们管理对象,所以像上文那些看似很复杂的对象都可以交由它来管理:

</>复制代码

这个其实没多少好说的,就算是换成 SpringBoot 也是创建 JedispoolConfig,connectionFactory,redisTemplate 这些 bean 即可。

总结

换为连接池之后再进行压测自然没有出现获取不了 Redis 连接的异常(并发达到一定的量也会出错)说明更新是很有必要的。

推荐有用到该组件的朋友都升级下,也欢迎提出 Issues 和 PR。

项目地址:

https://github.com/crossoverJie/distributed-redis-tool

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69694.html

相关文章

  • 记一次小程序之旅

    摘要:用户绑定的逻辑主要复杂在既需要考虑微信本身的接口在不同情况下提供的数据不同,另外一方面就是考虑本身用户模块的业务逻辑问题。针对每一节课以及每一节系列课程生成小程序太阳码主要涉及到几个细节问题。 感觉已经好久没写程序了,最近这段时间,一方面是学习了python,然后折腾了scrapy框架,用python写了下守护进程程序监听任务以及用redis做队列任务通信,并开进程来处理爬虫任务。以上...

    不知名网友 评论0 收藏0
  • 阿里云南京云栖释放技术红利 核心产品最高降价50%

    摘要:在南京峰会上,阿里云产品宣布,包年包月实例租用费最高下调,存储价格不变。本次阿里云宣布所有规格整体降价,平均降幅达到。阿里云表示,经过不断的技术升级和资源优化,规模效应开始展现,这是今年持续大幅降价的基础。4月26日,在2018云栖大会·南京峰会上,阿里云宣布新一轮的价格调整。此次调整包含了Elasticsearch、分析型数据库、实人认证、开放搜索等多项产品,最高降幅达到50%。 ...

    MartinHan 评论0 收藏0
  • 构造函数与析构函数执行顺序,记一次小bug修复。

    摘要:执行构造函数执行析构函数第一次完毕第二次完毕执行输出执行构造函数第一次完毕执行构造函数执行析构函数第二次完毕执行析构函数终于逮到你了。。。这就导致了先执行构造函数,然后再执行析构函数。 class Test { protected $client; protected static $name; public function __construct() { ...

    xiao7cn 评论0 收藏0
  • 记一次小程序项目的开发心得

    摘要:前言这段时间一直负责公司的小程序的开发,总结了一些小程序的开发心得,方便自己以后的查阅也方便同仁少踩点坑。文章底部的技巧类小程序的识别小程序二维码功能,小程序的高斯模糊,都是自己填的坑。 前言:这段时间一直负责公司的小程序的开发,总结了一些小程序的开发心得,方便自己以后的查阅也方便同仁少踩点坑。文章底部的技巧类小程序的识别小程序二维码功能,小程序的高斯模糊,都是自己填的坑。欢迎交流。 ...

    you_De 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<