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

006tNc79ly1fs2s4f0jf4j31g80ytn6i.jpg

前言

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

其实主要原因是:

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

池化技术

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

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

  • 线程
  • 数据库连接
  • 网络连接等

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

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

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

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

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

  • 线程池
  • 各种资源的连接池等。

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

这里以分布式锁为例:

将使用的 api 修改为:

原有:

@Configuration
public class RedisLockConfig {@Beanpublic RedisLock build(){//Need to get Redis connection RedisLock redisLock = new RedisLock() ;HostAndPort hostAndPort = new HostAndPort("127.0.0.1",7000) ;JedisCluster jedisCluster = new JedisCluster(hostAndPort) ;RedisLock redisLock = new RedisLock.Builder(jedisCluster).lockPrefix("lock_test").sleepTime(100).build();return redisLock ;}}

现在:

@Configuration
public class RedisLockConfig {private Logger logger = LoggerFactory.getLogger(RedisLockConfig.class);@Autowiredprivate JedisConnectionFactory jedisConnectionFactory;@Beanpublic RedisLock build() {RedisLock redisLock = new RedisLock.Builder(jedisConnectionFactory,RedisToolsConstant.SINGLE).lockPrefix("lock_").sleepTime(100).build();return redisLock;}
}

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

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

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

    public boolean tryLock(String key, String request) {//get connectionObject connection = getConnection();String result ;if (connection instanceof Jedis){result =  ((Jedis) connection).set(lockPrefix + key, request, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, 10 * TIME);((Jedis) connection).close();}else {result = ((JedisCluster) connection).set(lockPrefix + key, request, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, 10 * TIME);try {((JedisCluster) connection).close();} catch (IOException e) {logger.error("IOException",e);}}if (LOCK_MSG.equals(result)) {return true;} else {return false;}}//获取连接private Object getConnection() {Object connection ;if (type == RedisToolsConstant.SINGLE){RedisConnection redisConnection = jedisConnectionFactory.getConnection();connection = redisConnection.getNativeConnection();}else {RedisClusterConnection clusterConnection = jedisConnectionFactory.getClusterConnection();connection = clusterConnection.getNativeConnection() ;}return connection;}    

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

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

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

        JedisPoolConfig config = new JedisPoolConfig();config.setMaxIdle(10);config.setMaxTotal(300);config.setMaxWaitMillis(10000);config.setTestOnBorrow(true);config.setTestOnReturn(true);RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();redisClusterConfiguration.addClusterNode(new RedisNode("10.19.13.51", 7000));//单机JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(config);//集群//JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration) ;jedisConnectionFactory.setHostName("47.98.194.60");jedisConnectionFactory.setPort(6379);jedisConnectionFactory.setPassword("");jedisConnectionFactory.setTimeout(100000);jedisConnectionFactory.afterPropertiesSet();//jedisConnectionFactory.setShardInfo(new JedisShardInfo("47.98.194.60", 6379));//JedisCluster jedisCluster = new JedisCluster(hostAndPort);HostAndPort hostAndPort = new HostAndPort("10.19.13.51", 7000);JedisCluster jedisCluster = new JedisCluster(hostAndPort);redisLock = new RedisLock.Builder(jedisConnectionFactory, RedisToolsConstant.SINGLE).lockPrefix("lock_").sleepTime(100).build();

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

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

配合 Spring

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

   <!-- jedis 配置 --><bean id="JedispoolConfig" class="redis.clients.jedis.JedisPoolConfig"><property name="maxIdle" value="${redis.maxIdle}"/><property name="maxTotal" value="${redis.maxTotal}"/><property name="maxWaitMillis" value="${redis.maxWait}"/><property name="testOnBorrow" value="${redis.testOnBorrow}"/><property name="testOnReturn" value="${redis.testOnBorrow}"/></bean><!-- redis服务器中心 --><bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"><property name="poolConfig" ref="JedispoolConfig"/><property name="port" value="${redis.port}"/><property name="hostName" value="${redis.host}"/><property name="password" value="${redis.password}"/><property name="timeout" value="${redis.timeout}"></property></bean><bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"><property name="connectionFactory" ref="connectionFactory"/><property name="keySerializer"><bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/></property><property name="valueSerializer"><bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/></property></bean>

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

总结

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

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

项目地址:

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

转载于:https://www.cnblogs.com/crossoverJie/p/9385900.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/249850.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅谈vue $mount()

Vue 的$mount()为手动挂载&#xff0c;在项目中可用于延时挂载&#xff08;例如在挂载之前要进行一些其他操作、判断等&#xff09;&#xff0c;之后要手动挂载上。new Vue时&#xff0c;el和$mount并没有本质上的不同。 具体见代码&#xff1a; 顺便附上vue渲染机制流程图&a…

论一个程序员的自我修养-从一张图片说起

故事起源 本来今天想写.NET Core实战之CMS系统第十五篇文章的。哈&#xff0c;奈何今天在新生命人脉群里面看到石头哥分享的一张图片&#xff0c;然后大家就议论了起来&#xff0c;不过我看的很懵逼&#xff0c;这图什么意思啊&#xff1f;当一个朋友讲述了这个图片背后的故事的…

c/c++ 继承与多态 文本查询的小例子(非智能指针版本)

问题&#xff1a;在上一篇继承与多态 文本查询的小例子&#xff08;智能指针版本&#xff09;在Query类里使用的是智能指针&#xff0c;只把智能指针换成普通的指针&#xff0c;并不添加拷贝构造方法&#xff0c;会发生什么呢&#xff1f; 执行时&#xff0c;代码崩掉。 分析下…

HTML渲染过程详解

由于本人对http协议以及dns对url的解析问题并不了解&#xff0c;所以这里之探讨url请求加载到浏览器端时&#xff0c;浏览器对html的解析到呈现过程&#xff0c;后来经过几位道友分享&#xff0c;整理了一下url解析的过程&#xff0c;如下&#xff1a; 用户输入url地址&#x…

vue之router-view组件的使用

开发的时候有时候会遇到一种情况&#xff0c;比如 &#xff1a;点击这个链接跳转到其他组件的情况&#xff0c;通常会跳转到新的页面&#xff0c;蛋是&#xff0c;我们不想跳转到新页面&#xff0c;只在当前页面切换着显示&#xff0c;那么就要涉及到路由的嵌套了&#xff0c;也…

go 区分指针

先看一段代码 先放一段代码&#xff0c;人工运行一下&#xff0c;看看自己能做对几题&#xff1f; package mainimport "fmt"func main() {var a int 1 var b *int &a var c **int &b var x int *b fmt.Println("a ",a) fmt.Println("&a…

ajax和axios、fetch的区别

1.jQuery ajax $.ajax({type: POST,url: url,data: data,dataType: dataType,success: function () {},error: function () {} });传统 Ajax 指的是 XMLHttpRequest&#xff08;XHR&#xff09;&#xff0c; 最早出现的发送后端请求技术&#xff0c;隶属于原始js中&#xff0c…

函数函数sigaction、signal

函数函数sigaction 1. 函数sigaction原型&#xff1a; int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 分析&#xff1a; 参数 signum &#xff1a;要捕获的信号。参数act&#xff1a;truct sigaction 结构体&#xff0c;后面具体讲解传入…

关于固件

固件(Firmware)就是写入EROM或EPROM(可编程只读存储器)中的程序&#xff0c;通俗的理解就是“固化的软件”&#xff0c;台港澳称为“韧体”。更简单的说&#xff0c;固件就是BIOS的软件&#xff0c;但又与普通软件完全不同&#xff0c;它是固化在集成电路内部的程序代码&#x…

vue和element-ui使用

上一篇已经创建好一个vue项目。https://mp.csdn.net/postedit/80926242 这一篇主要是创建一个vue项目并结合饿了么框架element-ui。 1.先创建vue项目&#xff0c;我准备把项目放在e盘下&#xff1a;E:\Work\RegisterProject&#xff1b; 命令行进入这个目录&#xff1a; 创…

javaweb学习6——自定义标签

声明&#xff1a;本文只是自学过程中&#xff0c;记录自己不会的知识点的摘要&#xff0c;如果想详细学习JavaWeb&#xff0c;请到孤傲苍狼博客学习&#xff0c;JavaWeb学习点此跳转 本文链接&#xff1a;https://www.cnblogs.com/xdp-gacl/p/3916946.html https://www.cnblogs…

vscode配置vue环境

一、安装VSCode、NodeJS VSCode&#xff1a;https://code.visualstudio.com/ NodeJS&#xff1a;https://nodejs.org/en/ 二、打开VSCode&#xff0c;安装常用插件 如图所示&#xff08;安装后重新加载即可&#xff09;: 三、项目中添加.vscode文件夹&#xff0c;文件夹中添…

vue调用顺序(初学版) index.html → main.js → app.vue → index.js → components/组件 测试

关于它是怎么调用运作的&#xff1a;https://mp.csdn.net/postedit/86134414 一. 准备工作&#xff1a; 1.下载webstorm&#xff0c;安装vue。 2.创建项目&#xff0c;cd到要放项目的文件夹下 vue init webpack vue_test 3.安装各种包 npm install 4.运行 cd vue_test …

NO.8:自学python之路------并行socket网络编程

摘要 一到放假就杂事很多&#xff0c;这次的作业比较复杂&#xff0c;做了一个周&#xff0c;进度又拖了。不过结果还不错。 正文 粘包 在上一节中&#xff0c;如果连续发送过多数据&#xff0c;就可能发生粘包。粘包就是两次发送的数据粘在一起被接收&#xff0c;损坏了数据的…

vue项目中主要文件的加载顺序(index.html、App.vue、main.js)

先后顺序&#xff1a; index.html > App.vue的export外的js代码 > main.js > App.vue的export里面的js代码 > Index.vue的export外的js代码 测试的页面代码块&#xff1a; 文件的加载先后顺序&#xff1a; Index.vue的mounted()中的输出没有执行。why&#…

凸包算法

转载自&#xff1a;https://blog.csdn.net/bone_ace/article/details/46239187 凸包问题的五种解法 2015年05月29日 17:58:51 阅读数&#xff1a;33660前言&#xff1a; 首先&#xff0c;什么是凸包&#xff1f; 假设平面上有p0~p12共13个点&#xff0c;过某些点作一个多边形&a…

一个优雅的占位图解决方案。适用于 UITableView 和 UICollectionView。

FMListPlaceholder 项目地址&#xff1a;https://github.com/yfming93/FMListPlaceholder 一个优雅的占位图解决方案。适用于 UITableView 和 UICollectionView。 一行代码处理空列表占位图逻辑 0x001 与其他的同类三方库对比的优点&#xff1a; 首次进入列表占位图是不显示的。…

vue中 关于$emit的用法

1、父组件可以使用 props 把数据传给子组件。 2、子组件可以使用 $emit 触发父组件的自定义事件。 vm.$emit( event, arg ) //触发当前实例上的事件 vm.$on( event, fn );//监听event事件后运行 fn&#xff1b; 例如&#xff1a;子组件&#xff1a; <template><di…

vue-transition动画

demo点击显示与消失 <div id"demo"><button v-on:click"show !show">Toggle</button><transition name"fade"><p v-if"show">hello</p></transition> </div> <script> new V…

Java String:重要到别人只能当老二的字符串类

字符串&#xff0c;是Java中最重要的类。这句肯定的推断不是Java之父詹姆斯高斯林说的&#xff0c;而是沉默王二说的&#xff0c;因此你不必怀疑它的准确性。 关于字符串&#xff0c;有很多的面试题&#xff0c;但我总觉得理论知识绕来绕去没多大意思。你比如说&#xff1a;Str…