一、背景
同样是在海口的项目的文书平台,项目涉及到的技术和中间件主要有springboot+mysql+redis等,其中的一个文书的生成环节,涉及到的操作过多(文书生成(从xml->doc->pdf),文书信息入库,模版状态的更改、操作日志记录等等),导致测试在进行压测(50/S,100/S,200/S)的时候,接口执行时间过长🤓,所以要进行优化。
二、优化路线
对于CRUD的语句优化得不能再优化后,主要耗时的部分在于模版转化文书的过程(从xml->doc->pdf),在确保每条sql执行不会出现异常情况下(除非宕机),将流程拆分为异步处理(主要的削峰)。由于是分布式的情况下,单体应用的队列就不考虑了,所以考虑到的是阿里的RocketMQ,其中的消息顺序消费也是符合需求的。但海口的其它项目组并没有使用到MQ,又不能自己申请一个😫,加上个人不太在项目引入过多的中间件(运维成本和项目风险),现在能使用的也就Redis,而且之前引入Redisson,所以采用了Redisson的消息队列。
三、集成Redisson消息队列
1、引入redisson(跟上篇一样🙄)
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>版本号</version></dependency>
2、redisson配置
publicclassRedissonConfig { "${spring.redis.host}") (privateStringhost; "${spring.redis.port}") (privateStringport; "${spring.redis.password}") (privateStringpassword; publicRedissonClientgetRedisson() { Configconfig=newConfig(); config.useSingleServer() .setAddress("redis://"+host+":"+port) .setTcpNoDelay(true) .setConnectTimeout(30000) .setSubscriptionsPerConnection(5) .setKeepAlive(true) .setSubscriptionConnectionPoolSize(50) .setPingConnectionInterval(60000); // 添加主从配置// config.useMasterSlaveServers().setMasterAddress("").setPassword("").addSlaveAddress(new String[]{"",""});returnRedisson.create(config); } }
3、主要代码块
执行器
3) (publicclassQueueRunnerimplementsCommandLineRunner { privateExecutorServicequeueThreadPool=newThreadPoolExecutor(4, 8, 1000, TimeUnit.MILLISECONDS, newLinkedBlockingDeque<>(8), newThreadPoolExecutor.CallerRunsPolicy()); QueueHandlerqueueHandler; publicvoidrun(String... args) { queueThreadPool.execute(queueHandler); } }
监听器
publicclassQueueHandlerimplementsRunnable { RedissonClientredissonClient; publicvoidrun() { // 添加topic监听RTopictopic=redissonClient.getTopic(CommonConstant.REDISSION_SYS_TOPIC, newSerializationCodec()); topic.addListener(SystemMessage.class, (CharSequencecharSequence, SystemMessagereportMessage) -> { executeTask(reportMessage); }); } /*** 处理队列信息* 由于队列是异步的,无法获取SessionUtils的用户信息,需要手动回传** @param systemMessage*/privatevoidexecuteTask(SystemMessagesystemMessage) { switch (systemMessage.getModelEnum()) { casePARAMS: // 业务逻辑break; default: break; } } // 省略。。。}
四、压测结果
经过采用异步处理,文书生成接口通过测试的压测(50/S,100/S,200/S)。
五、没demo,参考资料
https://blog.csdn.net/u011663149/article/details/88855849
https://blog.csdn.net/CharlesYooSky/article/details/101701690