第三十九章 流量包模块+订单支付消息业务逻辑开发实战
第1集 MQ消费者开发-订单支付状态更新模块
简介:MQ消费者开发-订单支付状态更新模块
- 编码实战
public void handleProductOrderMessage(EventMessage eventMessage) {
String messageType = eventMessage.getEventMessageType();
try{
if(EventMessageType.PRODUCT_ORDER_NEW.name().equalsIgnoreCase(messageType)){
//关闭订单
this.closeProductOrder(eventMessage);
} else if(EventMessageType.PRODUCT_ORDER_PAY.name().equalsIgnoreCase(messageType)){
//订单已经支付,更新订单状态
String outTradeNo = eventMessage.getBizId();
Long accountNo = eventMessage.getAccountNo();
int rows = productOrderManager.updateOrderPayState(outTradeNo,accountNo,
ProductOrderStateEnum.PAY.name(),ProductOrderStateEnum.NEW.name());
log.info("订单更新成功:rows={},eventMessage={}",rows,eventMessage);
}
}catch (Exception e){
log.error("订单消费者消费失败:{}",eventMessage);
throw new BizException(BizCodeEnum.MQ_CONSUME_EXCEPTION);
}
}
第2集 账号服务-RabbitMQ相关配置开发实战
简介:账号服务-RabbitMQ相关配置开发实战
- 账号服务RabbitMQ配置
##----------rabbit配置--------------
spring.rabbitmq.host=120.79.150.146
spring.rabbitmq.port=5672
#需要手工创建虚拟主机
spring.rabbitmq.virtual-host=dev
spring.rabbitmq.username=admin
spring.rabbitmq.password=password
#消息确认方式,manual(手动ack) 和auto(自动ack); 消息消费重试到达指定次数进到异常交换机和异常队列,需要改为自动ack确认消息
spring.rabbitmq.listener.simple.acknowledge-mode=auto
#开启重试,消费者代码不能添加try catch捕获不往外抛异常
spring.rabbitmq.listener.simple.retry.enabled=true
#最大重试次数
spring.rabbitmq.listener.simple.retry.max-attempts=4
# 重试消息的时间间隔,5秒
spring.rabbitmq.listener.simple.retry.initial-interval=5000
- RabbitMQ配置
@Configuration
@Data
public class RabbitMQConfig {
/**
* 消息转换器
* @return
*/
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}
- 异常消息配置
@Configuration
@Slf4j
public class RabbitMQErrorConfig {
/**
* 异常交换机
*/
private String trafficErrorExchange = "traffic.error.exchange";
/**
* 异常队列
*/
private String trafficErrorQueue = "traffic.error.queue";
/**
* 异常routing.key
*/
private String trafficErrorRoutingKey = "traffic.error.routing.key";
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 创建异常交换机
* @return
*/
@Bean
public TopicExchange errorTopicExchange(){
return new TopicExchange(trafficErrorExchange,true,false);
}
/**
* 创建异常队列
* @return
*/
@Bean
public Queue errorQueue(){
return new Queue(trafficErrorQueue,true);
}
/**
* 建立绑定关系
* @return
*/
@Bean
public Binding bindingErrorQueueAndExchange(){
return BindingBuilder.bind(errorQueue()).to(errorTopicExchange()).with(trafficErrorRoutingKey);
}
/**
* 配置 RepublishMessageRecoverer
*
* 消费消息重试一定次数后,用特定的routingKey转发到指定的交换机中,方便后续排查和告警
*
* @return
*/
@Bean
public MessageRecoverer messageRecoverer(){
return new RepublishMessageRecoverer(rabbitTemplate,trafficErrorExchange,trafficErrorRoutingKey);
}
}
第3集 账号服务-流量包模块Manager层开发
简介: 账号服务-流量包模块Manager层开发
- 流量包基础模块接口开发
- 锻炼大家的发现问题能力(存在一些Bug,自己先找出)
- 除了学架构能力,还需要业务逻辑能力锻炼
- codeReview
- 锻炼大家的发现问题能力(存在一些Bug,自己先找出)
public interface TrafficManager {
/**
* 新增流量包
* @param trafficDO
* @return
*/
int add(TrafficDO trafficDO);
/**
* 分页查询可用的
* @param page
* @param size
* @param accountNo
* @return
*/
IPage<TrafficDO> pageAvailable(int page, int size, long accountNo);
/**
*
* @param currentTrafficId
* @param accountNo
* @param dayUsedTimes
*/
int addDayUsedTimes(Long currentTrafficId, long accountNo, int dayUsedTimes);
/**
* 查找流量包详情
* @param trafficId
* @param accountNo
* @return
*/
TrafficDO findByIdAndAccountNo(Long trafficId, long accountNo);
}
第4集 账号服务-流量包权益发放业务逻辑开发
简介: 账号服务-流量包权益发放业务逻辑开发
- 消费者开发
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
public void handleTrafficMessage(EventMessage eventMessage) {
String messageType = eventMessage.getEventMessageType();
if(EventMessageType.PRODUCT_ORDER_PAY.name().equalsIgnoreCase(messageType)){
//订单已经支付,新增流量
String content = eventMessage.getContent();
Map<String, Object> orderInfoMap = JsonUtil.json2Obj(content,Map.class);
//还原订单商品信息
Long accountNo = (Long)orderInfoMap.get("accountNo");
String outTradeNo = (String)orderInfoMap.get("outTradeNo");
Integer buyNum = (Integer)orderInfoMap.get("buyNum");
String productStr = (String) orderInfoMap.get("product");
ProductVO productVO = JsonUtil.json2Obj(productStr, ProductVO.class);
log.info("商品信息",productVO);
//流量包有效期
LocalDateTime expiredDateTime = LocalDateTime.now().plusDays(productVO.getValidDay());
Date date = Date.from(expiredDateTime.atZone(ZoneId.systemDefault()).toInstant());
//构建流量包对象
TrafficDO trafficDO = TrafficDO.builder()
.accountNo(accountNo)
.dayLimit(productVO.getDayTimes() * buyNum)
.dayUsed(0)
.totalLimit(productVO.getTotalTimes())
.pluginType(productVO.getPluginType())
.level(productVO.getLevel())
.productId(productVO.getId())
.outTradeNo(outTradeNo)
.expiredDate(date).build();
int rows = trafficManager.add(trafficDO);
log.info("消费消息新增流量包:rows={},trafficDO={}",rows,trafficDO);
}
}
第5集 账号服务-支付发放流量包消费者链路测试
简介:账号服务-支付发放流量包消费者链路测试
-
注意事项
- 支付参数是否过期
- 域名映射是否过期
- 清空历史数据
-
Bug修复
- 消费者缺少注解
-
链路测试(查看数据库数据)
- 下单
- 支付
- 订单更新
- 流量包记录新增
第四十章 流量包管理 +用户注册免费流量包发放开发实战
第1集 流量包管理相关API模块开发实战
简介:流量包管理相关API模块开发实战
- 分页API+详情API
/**
* 只能查看可用的流量包,不可用的需要去归档数据查
*
* @param page
* @param size
* @return
*/
@GetMapping("page")
public JsonData pageAvailable(
@RequestBody TrafficPageRequest request
) {
Map<String, Object> pageResult = trafficService.pageAvailable(request);
return JsonData.buildSuccess(pageResult);
}
/**
* 流量包详情
*
* @return
*/
@GetMapping("/detail/{trafficId}")
public JsonData detail(@PathVariable("trafficId") Long trafficId
) {
TrafficVO trafficVO = trafficService.detail(trafficId);
return JsonData.buildSuccess(trafficVO);
}
- 扣减流量包API骨架
第2集 新用户注册-拉新业务免费流量包发放解决方案对比
简介:新用户注册-免费流量包发放解决方案对比
- 需求
- 业务为了拉新,鼓励新用户注册,赠送一个免费流量包,每天允许有一定次免费创建短链的次数
通用项目模型
- 适合优惠券项目、新用户积分项目等
- 比如拼多多、淘宝特价版、滴滴、Uber、共享打车、当初应用刚上线,大量补贴新用户
- 基本互联网项目都离不开拉新用户,发放福利,然后激活,这类场景和免费流量包发放类似
解决方案你能想到几种
-
方式一
- 注册的时候直接调用操作数据库
- 调用商品服务,查询流量包详情
- 数据库新增一条用户流量包记录
- 缺点
- 接口性能不行
- 拓展性不强,比如新用户除了免费流量包,还需要做其他处理
- 优点
- 编码简单
-
方式二:
- 注册成功发送MQ消息,响应用户
- 消费端处理发放免费流量包
- 缺点
- 存在分布式事务问题
- 账号注册不成功,accountNo多1记录个也不影响,可以忽略
- 优点
- 接口性能高
- 拓展性强,类似注册发送一个广播事件,其他业务做监听处理即可
第3集 分库分表下-MQ消费者重复消费-发放流量包解决方案讲解
简介: 分库分表下-MQ消费者重复消费-发放流量包解决方案讲解
-
消息队列MQ面试核心
- 重复内容
- 投递(redis配置了限制,但还是不能百分百保证不重复)
- 消费
- 任何消息队列产品不保证消息不重复,如果你的业务需要保证严格的不重复消息,需要你自己在业务端去重
- kafka、rocketmq、rabbitmq等都是一样的
- 接口幂等性保障 ,消费端处理业务消息要保持幂等性
- 幂等性,通俗点说,就一个数据或者一个请求,给你重复来多次,你得确保对应的数据是不会改变的
- 重复内容
-
MQ消费端幂等性保障
- 分库分表情况下-同个accountNo路由到同个库表
- 付费流量包
- 采用订单号做唯一索引(accountNo + outTradeNo)
- 免费流量包
- 采用特定标识做唯一索引( accountNo + free_init )
-
库表设计增加了唯一索引
UNIQUE KEY `uk_trade_no` (`out_trade_no`,`account_no`) USING BTREE,
第4集 新用户注册-MQ生产者发送免费流量包开发实战
简介: 新用户注册-MQ生产者发送免费流量包开发实战
- RabbitMQ配置
//================流量包处理:用户初始化福利==================================
/**
* 交换机
*/
private String trafficEventExchange = "traffic.event.exchange";
/**
* 用户注册 免费流量包新增 队列
*/
private String trafficFreeInitQueue = "traffic.free_init.queue";
/**
* 用户注册 免费流量包新增 队列路由key
*
*/
private String trafficFreeInitRoutingKey = "traffic.free_init.routing.key";
/**
* 创建交换机 Topic类型
* 一般一个微服务一个交换机
* @return
*/
@Bean
public Exchange trafficEventExchange(){
return new TopicExchange(trafficEventExchange,true,false);
}
/**
* 队列的绑定关系建立:新用户注册免费流量包
* @return
*/
@Bean
public Binding trafficFreeInitBinding(){
return new Binding(trafficFreeInitQueue,Binding.DestinationType.QUEUE, trafficEventExchange,trafficFreeInitRoutingKey,null);
}
/**
* 免费流量包队列
*/
@Bean
public Queue trafficFreeInitQueue(){
return new Queue(trafficFreeInitQueue,true,false,false);
}
- 发送消息开发
/**
* 免费流量包ID
*/
private static final Long FREE_TRAFFIC_PRODUCT_ID = 1L;
/**
* 用户注册,初始化福利信息
* 注册成功后在发送
*
* (消费前查询下是否有这个用户,非必要)
* @param accountDO
*/
private void userRegisterInitTask(AccountDO accountDO,int productId) {
EventMessage freeTrafficEventMessage = EventMessage.builder()
.messageId(IDUtil.geneSnowFlakeID().toString())
.accountNo(accountDO.getAccountNo())
.eventMessageType(EventMessageType.TRAFFIC_FREE_INIT.name())
.bizId(FREE_TRAFFIC_PRODUCT_ID.toString())
.build();
rabbitTemplate.convertAndSend(rabbitMQConfig.getTrafficEventExchange(),
rabbitMQConfig.getTrafficFreeInitRoutingKey(), freeTrafficEventMessage);
}
第5集 新用户注册-MQ消费者开发+Feign调用流量包商品服务实战
简介: 新用户注册-MQ消费者开发+Feign调用流量包商品服务实战
- 消费者开发
else if (EventMessageType.TRAFFIC_FREE_INIT.name().equals(messageType)) {
//新用户注册初始化免费流量包 user_init 唯一索引,避免重复消费
Long productId = Long.valueOf(eventMessage.getBizId());
JsonData jsonData = productFeignService.detail(productId);
ProductVO productVO = jsonData.getData(new TypeReference<ProductVO>() {
});
TrafficDO trafficDO = TrafficDO.builder()
.accountNo(accountNo)
.dayLimit(productVO.getDayTimes())
.dayUsed(0)
.totalLimit(productVO.getTotalTimes())
.pluginType(productVO.getPluginType())
.level(PluginLevelEnum.FIRSR.name())
.productId(productVO.getId())
.expiredDate(new Date())
.outTradeNo("user_init")
.build();
trafficManager.add(trafficDO);
return true;
}
- Feign调用商品服务开发
@FeignClient(name = "dcloud-shop-service")
public interface ProductFeignService {
/**
* 获取商品详情
*
* @param product_id 商品id
* @return
*/
@GetMapping(value = "/api/product/v1/detail/{product_id}")
JsonData detail(@PathVariable("product_id") long productId);
}
第6集 新用户注册-发放免费流量包全链路测试实战
简介: 新用户注册-发放免费流量包全链路测试实战
- 链路测试
- 注册登录
- 短信选择申请接入阿里云市场:https://market.console.aliyun.com/imageconsole/index.htm
- 购买流量包
- 支付参数
- 回调域名
- 注册登录
第四十一章 新版分布式定时调度XXL-Job介绍和环境搭建
第1集 流量包过期业务需求和定时任务快速介绍
简介:流量包过期业务需求和解决方案讲解
-
需求
- 用户购买的流量包都是有时间限制,过期的流量包需要删除
- 逻辑删除、物理删除、或者转移到日志文件归档都行
- 我们这边直接使用物理删除,比数据过多
-
解决方式
-
使用定时任务删除
-
使用场景
- 某个时间定时处理某个任务、发邮件、短信等
-
消息提醒、订单通知、统计报表系
-
-
定时任务划分
- 单机定时任务
- 单机的容易实现,但应用于集群环境做分布式部署,就会带来重复执行
- 解决方案有很多比如加锁、数据库等,但是增加了很多非业务逻辑
- 分布式调度
- 把需要处理的计划任务放入到统一的平台,实现集群管理调度与分布式部署的定时任务 叫做分布式定时任务
- 支持集群部署、高可用、并行调度、分片处理等
- 单机定时任务
-
常见定时任务
-
单机:Java自带的java.util.Timer类配置比较麻烦,时间延后问题
-
单机:ScheduledExecutorService
- 是基于线程池来进行设计的定时任务类,在这里每个调度的任务都会分配到线程池里的一个线程去执行该任务,并发执行,互不影响
-
单机:SpringBoot框架自带
- SpringBoot使用注解方式开启定时任务
- 启动类里面 @EnableScheduling开启定时任务,自动扫描
- 定时任务业务类 加注解 @Component被容器扫描
- 定时执行的方法加上注解 @Scheduled(fixedRate=2000) 定期执行一次
-
分布式任务调度框架
- Elastic-Job
- XXL-Job
- Quartz
-
第2集 业界主流分布式任务调度框架介绍
简介:业界主流分布式任务调度框架介绍
-
常见分布式定时任务
-
Quartz
- Quartz关注点在于定时任务而并非是数据,并没有一套根据数据化处理而定的流程
- 虽然可以实现数据库作业的高可用,但是缺少了分布式的并行调度功能,相对弱点
- 不支持任务分片、没UI界面管理,并行调度、失败策略等也缺少
-
TBSchedule
- 这个是阿里早期开源的分布式任务调度系统,使用的是timer而不是线程池执行任务调度,使用timer在处理异常的时候是有缺陷的,但TBSchedule的作业类型比较单一,文档也缺失得比较严重
- 目前阿里内部使用的是ScheduleX
- 阿里云也有商业化版本: https://help.aliyun.com/product/147760.html
-
-
-
Elastic-job
- 当当开发的分布式任务调度系统,功能强大,采用的是zookeeper实现分布式协调,具有高可用与分片。
- 2020年6月,ElasticJob的四个子项目已经正式迁入Apache仓库
- 由 2 个相互独立的子项目 ElasticJob-Lite 和 ElasticJob-Cloud 组成
- ElasticJob-Lite 定位为轻量级无中心化解决方案,使用jar的形式提供分布式任务的协调服务;
- ElasticJob-Cloud 使用 Mesos 的解决方案,额外提供资源治理、应用分发以及进程隔离等服务
- 地址:https://shardingsphere.apache.org/elasticjob/index_zh.html
-
XXL-JOB
- 大众点评的员工徐雪里在15年发布的分布式任务调度平台,是轻量级的分布式任务调度框架,目标是开发迅速、简单、清理、易扩展; 老版本是依赖quartz的定时任务触发,在v2.1.0版本开始 移除quartz依赖
- 地址:https://www.xuxueli.com/xxl-job/
-
-
常规对比图
对比项 | XXL-JOB | elastic-job |
---|---|---|
并行调度 | 调度系统多线程并行 | 任务分片的方式并行 |
弹性扩容 | 使用Quartz基于数据库分布式功能 | 通过zookeeper保证 |
高可用 | 通过DB锁保证 | 通过zookeeper保证 |
阻塞策略 | 单机串行/丢弃后续的调度/覆盖之前的调度 | 执行超过zookeeper的session timeout时间的话,会被清除,重新进行分片 |
动态分片策略 | 以执行器为维度进行分片、支持动态的扩容 | 平均分配/作业名hash分配/自定义策略 |
失败处理策略 | 失败告警/失败重试 | 执行完毕后主动获取未分配分片任务 服务器下线后主动寻找可以用的服务器执行任务 |
监控 | 支持 | 支持 |
日志 | 支持 | 支持 |
如何选择哪一个分布式任务调度平台
- XXL-Job和Elastic-Job都具有广泛的用户基础和完善的技术文档,都可以满足定时任务的基本功能需求
- xxl-job侧重在业务实现简单和管理方便,容易学习,失败与路由策略丰富, 推荐使用在用户基数相对较少,服务器的数量在一定的范围内的场景下使用
- elastic-job关注的点在数据,添加了弹性扩容和数据分片的思路,更方便利用分布式服务器的资源, 但是学习难度较大,推荐在数据量庞大,服务器数量多的时候使用
第3集 快速入门分布式调度XXL-Job架构和概念说明
简介:快速入门分布式调度XXL-Job架构和概念说明
-
注意
- 这里只做快速入门讲解+回顾,深入看的话可以去小滴课堂看《XXL-Job分布式调度专题》
-
xxl-job的设计思想
- 将调度行为抽象形成“调度中心”公共平台,而平台自身并不承担业务逻辑,“调度中心”负责发起调度请求。
- 将任务抽象成分散的JobHandler,交由“执行器”统一管理
- “执行器”负责接收调度请求并执行对应的JobHandler中业务逻辑。
- 因此,“调度”和“任务”两部分可以相互解耦,提高系统整体稳定性和扩展性
-
架构系统组成
- 调度中心
- 负责管理调度的信息,按照调度的配置来发出调度请求
- 支持可视化、简单的动态管理调度信息,包括新建、删除、更新等,这些操作都会实时生效,同时也支持监控调度结果以及执行日志。
- 执行器
- 负责接收请求并且执行任务的逻辑。任务模块专注于任务的执行操作等等,使得开发和维护更加的简单与高效
- 调度中心
- XXL-Job具有哪些特性
- 调度中心HA(中心式):调度采用了中心式进行设计,“调度中心”支持集群部署,可保证调度中心HA
- 执行器HA(分布式):任务分布式的执行,任务执行器支持集群部署,可保证任务执行HA
- 触发策略:有Cron触发、固定间隔触发、固定延时触发、API事件触发、人工触发、父子任务触发
- 路由策略:执行器在集群部署的时候提供了丰富的路由策略,如:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用LFU、最久未使用LRU、故障转移等等
- 故障转移:如果执行器集群的一台机器发生故障,会自动切换到一台正常的执行器发送任务调度
- Rolling实时日志的监控:支持rolling方式查看输入的完整执行日志
- 脚本任务:支持GLUE模式开发和运行脚本任务,包括Shell、python、node.js、php等等类型脚本
第4集 分布式调度XXl-Job搭建-Docker部署服务端《上》
简介:分布式调度XXl-Job搭建-Docker部署服务端《上》
-
搭建XXL-Job相关环境
- 创建数据库脚本
- 部署XXL-Job服务端
- 客户端项目添加依赖
-
注意
- Client-Server通信,需要网络互通才行
- 所以不能一个是阿里云ECS,一个是本地电脑
- 建议:本地电脑安装Docker,或者本地Linux虚拟机安装Docker部署
-
步骤
- 步骤一:数据库脚本(使用mysql8)
- xxl_job 的数据库里有如下几个表
- xxl_job_group:执行器信息表,用于维护任务执行器的信息
- xxl_job_info:调度扩展信息表,主要是用于保存xxl-job的调度任务的扩展信息,比如说像任务分组、任务名、机器的地址等等
- xxl_job_lock:任务调度锁表
- xxl_job_log:日志表,主要是用在保存xxl-job任务调度历史信息,像调度结果、执行结果、调度入参等等
- xxl_job_log_report:日志报表,会存储xxl-job任务调度的日志报表,会在调度中心里的报表功能里使用到
- xxl_job_logglue:任务的GLUE日志,用于保存GLUE日志的更新历史变化,支持GLUE版本的回溯功能
- xxl_job_registry:执行器的注册表,用在维护在线的执行器与调度中心的地址信息
- xxl_job_user:系统的用户表
- 步骤一:数据库脚本(使用mysql8)
第5集 分布式调度XXl-Job搭建-Docker部署服务端《下》
简介:分布式调度XXl-Job搭建-Docker部署服务端《下》
-
步骤二:部署server
docker run -d -e PARAMS="--spring.datasource.url=jdbc:mysql://120.79.150.146:3306/xxl_job?Unicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai \ --spring.datasource.username=root \ --spring.datasource.password=class.net168 \ --xxl.job.accessToken=xdclass.net" \ -p 8080:8080 \ --name xxl-job-admin --restart=always xuxueli/xxl-job-admin:2.2.0
- 访问地址 http://127.0.0.1:8080/xxl-job-admin
- 默认登录账号 admin / 123456
第6集 分布式调度XXL-Job 可视化UI界面介绍
简介:分布式调度XXL-Job 可视化UI界面介绍
- 运行报表
- 以图形化来展示了整体的任务执行情况
- 任务数量:能够看到调度中心运行的任务数量
- 调度次数:调度中心所触发的调度次数
- 执行器数量:在整个调度中心中,在线的执行器数量有多少
- 以图形化来展示了整体的任务执行情况
- 任务管理
- 这里是配置执行任务/路由策略/Cron/JobHandler等
- 调度日志
- 这里是查看调度的日志,根据日志来查看任务具体的执行情况是怎样的
- 执行器管理
- 这里是配置执行器,等待执行器启动的时候都会被调度中心监听加入到地址列表
第四十二章 分布式定时调度XXL-Job和流量包过期业务整合
第1集 AlibabaCloud微服务整合XXL-Job依赖实战
简介:AlibabaCloud微服务整合XXL-Job依赖实战
- 聚合工程添加依赖
<xxl-job.version>2.2.0</xxl-job.version>
<!-- https://mvnrepository.com/artifact/com.xuxueli/xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${xxl-job.version}</version>
</dependency>
- common项目添加依赖
<!--分布式调度-->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
</dependency>
- 新增logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="1 seconds">
<contextName>logback</contextName>
<property name="log.path" value="./data/logs/xxl-job/app.log"/>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}.%d{yyyy-MM-dd}.zip</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n
</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</root>
</configuration>
- application.properties配置文件
#----------xxl-job配置--------------
logging.config=classpath:logback.xml
#调度中心部署地址,多个配置逗号分隔 "http://address01,http://address02"
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
#执行器token,非空时启用 xxl-job, access token
xxl.job.accessToken=class.net
# 执行器app名称,和控制台那边配置一样的名称,不然注册不上去
xxl.job.executor.appname=traffic-app-executor
# [选填]执行器注册:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。
#从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
xxl.job.executor.address=
#[选填]执行器IP :默认为空表示自动获取IP(即springboot容器的ip和端口,可以自动获取,也可以指定),多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务",
xxl.job.executor.ip=
# [选填]执行器端口号:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
xxl.job.executor.port=9999
#执行器日志文件存储路径,需要对该路径拥有读写权限;为空则使用默认路径
xxl.job.executor.logpath=./data/logs/xxl-job/executor
#执行器日志保存天数
xxl.job.executor.logretentiondays=30
- 编码
@Configuration
@Slf4j
public class XxlJobConfig {
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.executor.appname}")
private String appName;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
//旧版的有bug
//@Bean(initMethod = "start", destroyMethod = "destroy")
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
log.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appName);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
}
第2集 创建你的第一个XXL-Job分布式调度任务
简介:创建你的第一个XXL-Job分布式调度任务
-
Bug
- pom文件 版本使用2.2.0
-
注解介绍
- 在 Spring Bean 实例中,开发 Job 方法方式格式要求为
public ReturnT<String> execute(String param)
- 为 Job 方法添加注解 (注解value值是调度中心新建任务的 JobHandler 属性的值)
@XxlJob(value="自定义jobHandler名称", init = "handler初始化方法", destroy = "handler 销毁方法")
-
编写代码
@Component
@Slf4j
public class MyJobHandler {
@XxlJob(value = "demoJobHandler",init = "init",destroy = "destroy")
public ReturnT<String> execute(String param){
log.info( execute 任务方法触发成功");
return ReturnT.SUCCESS;
}
private void init(){
log.info(" MyJobHandler init >>>>>");
}
private void destroy(){
log.info("MyJobHandler destroy >>>>>");
}
}
- 执行器管理
- 到xxl-job调度中心里的执行器管理->新增
- Appname:是每一个执行器的唯一表示AppName,执行器会以周期性为appname进行注册,为任务调度的时候使用
- 名称:执行器的名称,因为appname有限制字母与数字等等组成,可读性不强,这个名称就是为了提高执行器的可读性
- 注册方式:调度中心获取执行器地址的方式
- 自动注册:执行器自动进行执行器的注册,通过底层的注册表可以动态的发现执行器机器的地址
- 手动录入:人工手动录入执行器的地址信息,多地址使用逗号进行分割,供调度中心使用
- 机器地址:“注册方式”为手动录入的时候才能使用,支持人工维护执行器的地址
- 点击保存后可能要等30S左右才回显示机器的地址
- 到xxl-job调度中心里的执行器管理->新增
- 任务管理
- 任务管理->选择所需要管理的执行器->新增执行器
- 任务管理-启动任务
- 任务管理的状态已经从STOP变更成RUNNING
- 调度日志
- 在调度日志里能够查看调度结果与日志的信息
第3集 付费流量包过期淘汰需求开发-整合分布式调度XXL-Job
简介:付费流量包过期淘汰需求开发-整合分布式调度XXL-Job
-
流量包删除接口
- 删除过期流量包记录
delete FROM traffic where expired_date <= now()
-
思考下有什么问题
第4集 海量数据处理维护三连问和流量包更新需求
简介:海量数据处理维护三连问和流量包更新需求
- 流量包更新维护需求
- 付费流量包:通过购买,然后每天都是有一定的使用次数
- 免费流量包:业务为了拉新,鼓励新用户注册,赠送一个免费流量包,每天允许有一定次免费创建短链的次数
怎么维护更新好流量包每天的次数呢