当前位置:网站首页>Implementation of distributed scenario business operation log (based on redis lightweight)
Implementation of distributed scenario business operation log (based on redis lightweight)
2022-04-23 02:36:00 【Fat brother 1930】
order
I don't have time to write in detail today , Let's talk about the current demand scenario , I just want to insert the business operation log ,springCloud Environmental Science . then , Based on the results of my implementation , Let's say , Design has no formula , It's the foundation 、 Series connection of characteristics .
One 、 Design thinking
Through the analysis of , And find other groups of colleagues to learn from , The general design idea is not divided 3 class , as follows :
1、 Based on the section AOP
2、 Based on events ,EventBus or SpringBus
3、 Based on message oriented middleware
Two 、 Trade-off process
1. Based on the section ( House )
the reason being that springCloud Distributed scenarios , If cut , Then there is 2 A plan :
A、 Each service handles all aspects by itself
I don't think everyone wants to , This means that every service has to have a set AOP Cut code , Too complicated , In addition, you may need to insert a composite business operation log in the later stage of the business . Then the transmission parameters and everything may need to be changed , To transfer parameters of the business interface , The change is too big , The risk is too high , And complicated , House .
B、 Cut in the gateway
What the gateway does is no longer pure , Loss of understanding , For the composite business operation log to be inserted , You may also face the need to modify the parameters of the business interface ... House
2. Based on events ,EventBus or SpringBus( House )
Let's start with the scene , this 2 For a single service springBoot, It must be very fragrant . But here we have to compare their differences , Lose the conclusion directly :
Look at the official documents and you can roughly know , this 2 Neither way is suitable for SpringCloud Distributed scenarios .
3. Based on message oriented middleware
This is because the business operation log is a lightweight business scenario , Adopted redis Publish and subscribe to information .redis It has also been implemented before publishing and subscribing to , Here I will directly share the core code , With some business design .
RedisSubListenerConfig
import cn.hutool.core.util.ArrayUtil;
import com.fillersmart.fsihouse.commonservice.component.RedisReceiver;
import com.fillersmart.fsihouse.data.constant.ConstantsEnum.MsgType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.stereotype.Component;
/** * redis Subscription listening configuration * * @author zhengwen **/
@Component
public class RedisSubListenerConfig {
@Value("${redis.msg.topics}")
private String topics;
/** * Initialize listener * * @param connectionFactory Connection factory * @param listenerAdapter Monitor adapter * @return redis Listening container */
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
List<PatternTopic> topicList = new ArrayList<>();
// new PatternTopic(" Here is the name of the monitoring channel ") The channel should be consistent with that of the publisher
if (StringUtils.isNotBlank(topics)) {
String[] topisArr = topics.split(",");
if (ArrayUtil.isNotEmpty(topisArr)) {
Arrays.stream(topisArr).forEach(c -> {
PatternTopic topic = new PatternTopic(c);
topicList.add(topic);
});
}
}
// Enumerate information channels
Arrays.stream(MsgType.values()).forEach(m -> {
PatternTopic topic = new PatternTopic(m.getType());
topicList.add(topic);
});
container.addMessageListener(listenerAdapter, topicList);
return container;
}
/** * Binding message listener and receiving listener * * @param redisReceiver redis recipient * @return Information monitoring adapter */
@Bean
MessageListenerAdapter listenerAdapter(RedisReceiver redisReceiver) {
// redisReceiver Message Receiver
// receiveMessage The method after receiving the message
return new MessageListenerAdapter(redisReceiver, "receiveMessage");
}
@Bean
StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
/** * Registered subscribers * * @param latch CountDownLatch * @return RedisReceiver */
@Bean
RedisReceiver receiver(CountDownLatch latch) {
return new RedisReceiver(latch);
}
/** * Counter , Used to control threads * * @return CountDownLatch */
@Bean
CountDownLatch latch() {
// Number of times count specified 1
return new CountDownLatch(1);
}
}
RedisReceiver
import cn.hutool.json.JSONUtil;
import com.fillersmart.fsihouse.commonservice.service.CommonService;
import com.fillersmart.fsihouse.data.core.Result;
import com.fillersmart.fsihouse.data.vo.msgpush.RedisMsgVo;
import java.util.concurrent.CountDownLatch;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/*** * Message Receiver ( subscriber ) It needs to be injected into springboot in * @author zhengwen */
@Slf4j
@Component
public class RedisReceiver {
private CountDownLatch latch;
@Resource
private CommonService commonService;
@Autowired
public RedisReceiver(CountDownLatch latch) {
this.latch = latch;
}
/** * The method executed after receiving the message of the channel * * @param message */
public void receiveMessage(String message) {
// Here is the method to execute after receiving the channel's message
log.info("common General services received redis Information :" + message);
if (JSONUtil.isTypeJSON(message)) {
RedisMsgVo redisMsgVo = JSONUtil.toBean(message,RedisMsgVo.class);
Result<?> res = commonService.dealRedisMsg(redisMsgVo);
log.info("--redis Message processing results :{}",JSONUtil.toJsonStr(res));
}
latch.countDown();
}
}
The following is business related
dealRedisMsg Method
@Override
public Result<?> dealRedisMsg(RedisMsgVo redisMsgVo) {
log.info("-- General Services common Handle redis news --");
String queueName = redisMsgVo.getQueueName();
if (StringUtils.isBlank(queueName)) {
return ResultGenerator.genFailResult("redis The information queue name is empty ");
}
MsgType msgType = MsgType.getEnum(queueName);
if (msgType == null) {
return ResultGenerator.genFailResult(" Unknown redis Information queue name ");
}
String msgContent = redisMsgVo.getContent();
switch (msgType) {
case PAYED_MSG:
// Post payment information
break;
case BUSINESS_OPERATE_LOG_MSG:
// Business operation record
if (JSONUtil.isTypeJSON(msgContent)) {
BusinessOperateLogVo businessOperateLogVo = JSONUtil.toBean(msgContent,
BusinessOperateLogVo.class);
if (businessOperateLogVo == null) {
log.error(" Business operation record {} Convert to null ", msgContent);
} else {
businessOperateLogService.addBusLog(businessOperateLogVo);
}
}
break;
default:
break;
}
return ResultGenerator.genSuccessResult();
}
addBusLog Method
@Override
@Async
public Result<?> addBusLog(BusinessOperateLogVo businessOperateLogVo) {
// Parameter checking
Assert.notNull(businessOperateLogVo.getPlatform(), ResponseCodeI18n.PLATFORM_NULL.getMsg());
Assert.notNull(businessOperateLogVo.getOperateUserId(),
ResponseCodeI18n.OPERATE_USER_NULL.getMsg());
Assert.notNull(businessOperateLogVo.getBusinessId(),
ResponseCodeI18n.BUSINESS_ID_NULL.getMsg());
Assert.notNull(businessOperateLogVo.getCompanyId(), ResponseCodeI18n.PROJECT_ID_NULL.getMsg());
// Initial operator information
initOperateUserName(businessOperateLogVo);
// Initial business operation information
BusinessOperateLog operateLog = initBusinseeOperateLog(businessOperateLogVo);
businessOperateLogMapper.insert(operateLog);
return ResultGenerator.genSuccessResult();
}
Calling method
ThreadUtil.execAsync(() -> {
// Asynchronously convert and send redis Information
BusinessOperateVo businessOperateVo = new BusinessOperateVo(operateUserId.longValue(),DevicePlatformType.OPERATION_PC);
// Contract operation records
BusinessDataVo businessDataVo = new BusinessDataVo(JSONObject.parseObject(JSONObject.toJSONString(finalUserSubscribe)),
BusinessDataType.SUBSCRIBE_DATA,BusinessOperateType.BACK_APPLY,BusinessType.SUBSCRIBE);
businessOperateVo.getBusinessDataList().add(businessDataVo);
// The log of the rent return document
businessDataVo = new BusinessDataVo(JSONObject.parseObject(JSONObject.toJSONString(backApply)),
BusinessDataType.BACK_APPLY_DATA, BusinessOperateType.BACK_APPLY,BusinessType.BACK_APPLY);
businessOperateVo.getBusinessDataList().add(businessDataVo);
businessOperateLogRpcService.convertLogSendToRedis(businessOperateVo);
});
Supplementary table structure
CREATE TABLE `business_operate_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`company_id` int(11) DEFAULT NULL COMMENT ' project id',
`operate_type` int(2) DEFAULT NULL COMMENT ' Operation type ',
`operate_name` varchar(200) DEFAULT NULL COMMENT ' Operation name ',
`operate_time` datetime DEFAULT NULL COMMENT ' Operating time ',
`business_id` bigint(20) DEFAULT NULL COMMENT ' Business data primary key id',
`business_type` int(2) DEFAULT NULL COMMENT ' Business types ',
`operate_user_id` bigint(20) DEFAULT NULL COMMENT ' Operation user id',
`operate_user_name` varchar(200) DEFAULT NULL COMMENT ' Name of operator ( redundancy )',
`platform` int(1) DEFAULT NULL COMMENT ' Source of operating platform ',
`memo` varchar(500) DEFAULT NULL COMMENT ' remarks ',
`create_by` int(11) DEFAULT NULL COMMENT ' founder id',
`create_time` datetime DEFAULT NULL COMMENT ' Creation time ',
`is_deleted` int(1) DEFAULT NULL COMMENT ' Whether or not to delete ,0 no ,1 yes ',
PRIMARY KEY (`id`),
KEY `business_operate_log_company_id_IDX` (`company_id`) USING BTREE,
KEY `business_operate_log_business_type_IDX` (`business_type`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=246 DEFAULT CHARSET=utf8mb4 COMMENT=' Business logging ';
Screenshot of supplementary log storage
summary
1、ThreadUtil It's delicious (HuTool The toolkit ), Asynchronous does not affect interface performance
2、 The business trigger point only needs to pay attention to the key transmission parameters of the business operation log
3、 Scenarios run through distributed scenarios
Okay , Time is tight , So I'm going to go over here , I hope that helps , If you have any questions, please leave a message .
版权声明
本文为[Fat brother 1930]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204220822178570.html
边栏推荐
- Global, exclusive and local routing guard
- 在MySQL Workbench中执行外部的SQL脚本,报错
- SO库依赖问题
- 005_ redis_ Set set
- 智能辅助功能丰富,思皓X6安全配置曝光:将于4月23日预售
- C standard library - < time h>
- Water diversion into chengluo Valley p1514
- 001_ Redis set survival time
- VMware virtual machine installation openwrt as side route single arm route img image to vmdk
- 一个国产图像分割项目重磅开源!
猜你喜欢
一、序列模型-sequence model
认识进程(多线程_初阶)
SQL server2019 cannot download the required files, which may indicate that the version of the installer is no longer supported. What should I do
[xjtu Computer Network Security and Management] session 2 Cryptographic Technology
MySQL C language connection
每日一题冲刺大厂第十六天 NOIP普及组 三国游戏
The importance of ERP integration to the improvement of the company's system
Wechat public platform test number application, authorized login function and single sign on using hbuilder X and wechat developer tools
全局、獨享、局部路由守衛
R language advanced | generalized vector and attribute analysis
随机推荐
LeetCode 283. Move zero (simple, array) Day12
Preliminary understanding of stack and queue
Kubernetes cluster installation based on Kirin SP10 server version
PTA: 点赞狂魔
[XJTU计算机网络安全与管理]第二讲 密码技术
007_Redis_Jedis连接池
Hack the box optimum
SQL server2019无法下载所需文件,这可能表示安装程序的版本不再受支持,怎么办了
打靶narak
day18--栈队列
Solve the problem that the registered Google email Gmail mobile number cannot be used for verification
Web learning record (medium)
Summary of I / O knowledge points
高效音乐格式转换工具Music Converter Pro
Multithreading technology core
001_ Redis set survival time
RT_ Thread ask and answer
Global, exclusive, local Routing Guard
006_redis_jedis快速入门
Daily question (April 22, 2022) - rotation function