微服务原理篇(XXLJOB-幂等-MySQL)

简介: 本课程学习XXL-JOB任务调度核心技能:掌握其优势与架构组成,学会配置分布式调度任务,实现热点缓存更新;深入理解幂等性、数据库存储引擎、索引失效、回表、覆盖索引及SQL优化与分库分表方案。

学习目标

  1. 能够说出xxl-job任务调度的优势
  2. 能说出xxl-job的组成结构
  3. 能够编写热点商品更新缓存任务
  4. 能够说出什么是幂等,常见幂等解决方案
  5. 能够说出数据库常见存储引擎的核心区别
  6. 能够说出索引失效的场景
  7. 能够说出回表、覆盖索引
  8. 能够说出SQL调优的方案
  9. 能够说出常见分库分表的方案
    1 任务调度方案
    1.1 什么是任务调度
    1.1.1 概念
    我们可以先思考一下下面业务场景的解决方案:
    ● 某电商系统需要在每天上午10点,下午3点,晚上8点发放一批优惠券。
    ● 某银行系统需要在信用卡到期还款日的前三天进行短信提醒。
    ● 某财务系统需要在每天凌晨0:10结算前一天的财务数据,统计汇总。
    ● 12306会根据车次的不同,而设置某几个时间点进行分批放票。
    ● 某网站为了实现天气实时展示,每隔5分钟就去天气服务器获取最新的实时天气信息。
    以上场景就是任务调度所需要解决的问题。
    任务调度是指系统为了自动完成特定任务,在约定的特定时刻去执行任务的过程。有了任务调度即可解放更多的人 力由系统自动去执行任务。
    在解决缓存击穿方案中,通过缓存定时预热避免缓存击穿。
    1.1.2 技术方案
    如何实现任务调度?
    1、使用jdk提供的Timer定时器
    示例代码如下:
    每个Timer对应一个线程,可以同时启动多个Timer定时执行多个任务。
    public static void main(String[] args){
    Timer timer = new Timer();
    timer.schedule(new TimerTask(){
     @Override  
     public void run() {  
         //TODO:something
     }  
    
    }, 1000, 2000); //1秒后开始调度,每2秒执行一次
    }
    Time使用简单,可以实现每隔一定的时间去执行任务,但无法实现每天凌晨去执行任务,即在某个时间点去执行任务。
    2、使用第三方Quartz方式实现
    Quartz 是一个功能强大的任务调度框架(项目地址:链接 ),它可以满足更多更复杂的调度需求,Quartz 设计的核心类包括 Scheduler, Job 以及 Trigger。其中,Job 负责定义需要执行的任务,Trigger 负责设置调度策略,Scheduler 将二者组装在一起,并触发任务开始执行。Quartz支持简单的按时间间隔调度、还支持按日历调度方式,通过设置CronTrigger表达式(包括:秒、分、时、日、月、周、年)进行任务调度。
    虽然Quartz可以实现按日历调度的方式,但无法支持分布式环境下任务调度。分布式环境下通常一个服务部署多个实例即多个jvm进程,假设一个项目的微服务部署两个实例每个实例定时执行更新缓存的任务,两个实例就会重复执行。如下图:

3、使用分布式调度平台XXL-JOB
XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
官网:https://www.xuxueli.com/xxl-job/
文档:https://www.xuxueli.com/xxl-job/#%E3%80%8A%E5%88%86%E5%B8%83%E5%BC%8F%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E5%B9%B3%E5%8F%B0XXL-JOB%E3%80%8B
XXL-JOB主要有调度中心、执行器、任务:

调度中心:
负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码;
主要职责为执行器管理、任务管理、监控运维、日志管理等
任务执行器:
负责接收调度请求并执行任务逻辑;
主要职责是执行任务、执行结果上报、日志服务等
使用XXL-JOB可以解决多个jvm进程重复执行任务的问题,如下图:

XXL-JOB调度中心可以配置路由策略,比如:第一个、轮询策略、分片等,它们分别表示的意义如下:
● 第一个:即每次执行任务都由第一个执行器去执行。
● 轮询:即执行器轮番执行。
● 分片:每次执行任务广播给每个执行器让他们同时执行任务。
如果根据需求每次执行任务仅由一个执行器去执行任务可以设置路由策略:第一个、轮询。
如果根据需求每次执行任务由多个执行器同时执行可以设置路由策略为:分片。
xxl-job分布式任务调度系统具体有以下优势:
1、并行任务调度
并行任务调度实现靠多线程,如果有大量任务需要调度,此时光靠多线程就会有瓶颈了,因为一台计算机CPU的处理能力是有限的。
如果将任务调度程序分布式部署,每个结点还可以部署为集群,这样就可以让多台计算机共同去完成任务调度,我们可以将任务分割为若干个分片,由不同的实例并行执行,来提高任务调度的处理效率。
2、高可用
若某一个实例宕机,不影响其他实例来执行任务。
3、弹性扩容
当集群中增加实例就可以提高并执行任务的处理效率。
4、任务管理与监测
对系统中存在的所有定时任务进行统一的管理及监测。让开发人员及运维人员能够时刻了解任务执行情况,从而做出快速的应急处理响应。
5、避免任务重复执行
当任务调度以集群方式部署,同一个任务调度可能会执行多次,比如在上面提到的电商系统中到点发优惠券的例子,就会发放多次优惠券,对公司造成很多损失,所以我们需要控制相同的任务在多个运行实例上只执行一次。
1.1.3 小结
xxl-job任务调度与第三方Quartz或timer定时器实现任务调度有什么优势?
1.2 搭建XXL-JOB
1.2.1 组成结构
XXL-JOB由两部分组成:
● 调度模块(调度中心): 负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块; 支持可视化、简单且动态的管理调度信息,包括任务新建,更新,删除,GLUE开发和任务报警等,所有上述操作都会实时生效,同时支持监控调度结果以及执行日志,支持执行器Failover。
● 执行模块(执行器): 负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效; 接收“调度中心”的执行请求、终止请求和日志请求等。

1.2.2 部署调度中心
1.查阅xxl-job的源码
首先下载XXL-JOB
GitHub:https://github.com/xuxueli/xxl-job
码云:https://gitee.com/xuxueli0323/xxl-job
项目使用2.3.1版本: https://github.com/xuxueli/xxl-job/releases/tag/2.3.1
也可从课程资料目录获取,解压xxl-job-2.3.1.zip
使用IDEA打开解压后的目录

xxl-job-admin:调度中心
xxl-job-core:公共依赖
xxl-job-executor-samples:执行器Sample示例(选择合适的版本执行器,可直接使用)
:xxl-job-executor-sample-springboot:Springboot版本,通过Springboot管理执行器,推荐这种方式;
:xxl-job-executor-sample-frameless:无框架版本;
doc :文档资料,包含数据库脚本
在下发的虚拟机的MySQL中已经创建了xxl_job_2.3.1数据库
如下图:

安装xxl-job
没有使用下发虚拟机的同学请自行安装xxl-job。
拉取镜像:
docker pull xuxueli/xxl-job-admin:2.3.1
创建数据库:xxl_job_2.3.1
导入xxl_job_2.3.1.sql,如下:

创建目录:
/data/soft/xxl-job
/data/soft/xxl-job/applogs
创建配置文件:/data/soft/xxl-job/application.properties,内容如下:

web

server.port=8080
server.servlet.context-path=/xxl-job-admin

actuator

management.server.servlet.context-path=/actuator
management.health.mail.enabled=false

resources

spring.mvc.servlet.load-on-startup=0
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/

freemarker

spring.freemarker.templateLoaderPath=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.charset=UTF-8
spring.freemarker.request-context-attribute=request
spring.freemarker.settings.number_format=0.##########

mybatis

mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml

mybatis.type-aliases-package=com.xxl.job.admin.core.model

xxl-job, datasource

spring.datasource.url=jdbc:mysql://192.168.101.68:3306/xxl_job_2.3.1?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

datasource-pool

spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=HikariCP
spring.datasource.hikari.max-lifetime=900000
spring.datasource.hikari.connection-timeout=10000
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.validation-timeout=1000

xxl-job, email

spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=xxx@qq.com
spring.mail.from=xxx@qq.com
spring.mail.password=xxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory

xxl-job, access token

xxl.job.accessToken=default_token

xxl-job, i18n (default is zh_CN, and you can choose "zh_CN", "zh_TC" and "en")

xxl.job.i18n=zh_CN

xxl-job, triggerpool max size

xxl.job.triggerpool.fast.max=200
xxl.job.triggerpool.slow.max=100

xxl-job, log retention days

xxl.job.logretentiondays=30
创建容器:
docker run -d -e \
--restart=always \
-v /data/soft/xxl-job/applogs:/data/applogs \
-v /data/soft/xxl-job/application.properties:/application.properties \
-p 8088:8080 \
--name xxl-job-admin \
xuxueli/xxl-job-admin:2.3.1
启动成功进入管理界面:
http://192.168.101.68:8088/xxl-job-admin
账号/密码:admin/123456
2.启动xxl-job
执行docker start xxl-job-admin 启动xxl-job
访问:http://192.168.101.68:8088/xxl-job-admin/
账号和密码:admin/123456
1.2.3 执行器
1.添加执行器依赖
下边配置执行器,执行器负责与调度中心通信接收调度中心发起的任务调度请求,执行器负责执行微服务中定义的任务,执行器程序由xxl-job提供,在微服务中引入下边的依赖即加入了执行器的程序。
我们在商品服务中引入xxl-job执行器依赖。


com.xuxueli
xxl-job-core
2.3.0

参考源代码中的XxlJobConfig去编写xxl-job的配置类,此配置类已提供,将课程资料中xxl-job下的配置类和模型类拷贝到商品服务的config包下:

2.配置xxl-job
在application.yaml下配置xxl-job
xxl-job:
enable: true
port: 11603
access-token: default_token
admin:
address: http://192.168.101.68:8088/xxl-job-admin
executor:
appName: ${spring.application.name}

#ip: 172.17.0.170
port: ${xxl-job.port}
# 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能
log-retention-days: 30

说明:
address:调度中心的地址
appName:执行器名称,spring.application.name表示微服务的名称(在bootstrap.yml中配置)
port:执行器端口号,通过xxl-job.port配置,执行器通过此端口与调度中心通信。

  1. 下边进入调度中心添加执行器
    启动商品服务即启动了xxl-job执行器。
    进入调度中心,进入执行器管理界面,如下图:

点击新增,填写执行器信息

AppName:执行名称, appName: ${spring.application.name}表示指定执行器名称就是微服务的应用名。
名称:取一个中文名称。
注册方式:自动注册,只要执行器和调度中心连通执行器会自动注册到调度中心
机器地址:自动注册时不用填写。
添加成功:

启动item-service,查看item-service的控制台:

xxl-job remoting server start success, nettype = class com.xxl.job.core.server.EmbedServer, port = 11603 说明执行器启动成功。
稍等片刻进入 xxl-job调度中心,进入执行器管理界面,执行器注册成功:

点击“查看(1)”,查看执行器的地址,如下图:

1.2.4 小结
项目为什么要用xxl-job?
能说出xxl-job的组成部分。
1.3 XXL-JOB任务入门
1.3.1 编写测试任务
定时执行任务就需要编写任务方法,此任务方法由执行器去调用。
可以参考xxl-job源码去编写任务方法,从源码目录中找到执行器示例代码:
xxl-job-2.3.1\xxl-job-executor-samples\xxl-job-executor-sample-springboot\src\main\java\com\xxl\job\executor\service\jobhandler\SampleXxlJob.java

部分示例代码如下:下边代码中demoJobHandler()就是一个任务方法,需要使用@XxlJob注解标识,所在类需要由spring去管理,所以加了@Component注解。
将源代码中的SampleXxlJob类拷贝到商品服务的job包下,修改代码如下:
package com.hmall.item.job;
...
@Component
@Slf4j
public class SampleXxlJob {
private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);

/**
 * 1、简单任务示例(Bean模式)
 */
@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
    log.info("XXL-JOB, Hello World.");

    for (int i = 0; i < 5; i++) {
        log.info("beat at:" + i);
        TimeUnit.SECONDS.sleep(2);
    }
    // default success
}


/**
 * 2、分片广播任务
 */
@XxlJob("shardingJobHandler")
public void shardingJobHandler() throws Exception {

    // 分片参数
    int shardIndex = XxlJobHelper.getShardIndex();
    int shardTotal = XxlJobHelper.getShardTotal();

    log.info("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);

    // 业务逻辑
    for (int i = 0; i < shardTotal; i++) {
        if (i == shardIndex) {
            log.info("第 {} 片, 命中分片开始处理", i);
        } else {
            log.info("第 {} 片, 忽略", i);
        }
    }

}

}
1.3.2 配置任务
下边在调度中心配置任务。
进入任务管理,新增任务:

填写任务信息:

说明:
调度类型:

固定速度指按固定的间隔定时调度。
Cron,通过Cron表达式实现更丰富的定时调度策略。
Cron表达式是一个字符串,通过它可以定义调度策略,格式如下:
{秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}
Cron 的各个域的定义如下表格所示:

xxl-job提供图形界面去配置:

一些例子如下:
0 0 0 ? 每天0点触发
30 10 1 ? 每天1点10分30秒触发
0/30 ? 每30秒触发一次

  • 0/10 ? 每10分钟触发一次
    为了方便测试这里第5秒执行一次,设置为:0/5
    ?
    cron 表达式的难点在于通配符,下边的内容请自行阅读
    ● , 这里指的是在两个以上的时间点中都执行,如果我们在 “分” 这个域中定义为 8,12,35 ,则表示分别在第8分,第12分 第35分执行该定时任务。
    ● - 这个比较好理解就是指定在某个域的连续范围,如果我们在 “时” 这个域中定义 1-6,则表示在1到6点之间每小时都触发一次,用 , 表示 1,2,3,4,5,6
    表示所有值,可解读为 “每”。 如果在“日”这个域中设置 ,表示每一天都会触发。
    ● ? 表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的8号触发一个操作,但不关心是周几,我们可以这么设置 0 0 0 8
    ?
    ● / 在某个域上周期性触发,该符号将其所在域中的表达式分为两个部分,其中第一部分是起始值,除了秒以外都会降低一个单位,比如 在 “秒” 上定义 5/10 表示从 第 5 秒开始 每 10 秒执行一次,而在 “分” 上则表示从 第 5 秒开始 每 10 分钟执行一次。
    ● L 表示英文中的LAST 的意思,只能在 “日”和“周”中使用。在“日”中设置,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年), 在“周”上表示周六,相当于”7”或”SAT”。如果在”L”前加上数字,则表示该数据的最后一个。例如在“周”上设置”7L”这样的格式,则表示“本月最后一个周六”
    ● W 表示离指定日期的最近那个工作日(周一至周五)触发,只能在 “日” 中使用且只能用在具体的数字之后。若在“日”上置”15W”,表示离每月15号最近的那个工作日触发。假如15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果是 “1W” 就只能往本月的下一个最近的工作日推不能跨月往上一个月推。
    ● # 表示每月的第几个周几,只能作用于 “周” 上。例如 ”2#3” 表示在每月的第三个周二。
    运行模式有BEAN和GLUE,bean模式较常用就是在项目工程中编写执行器的任务代码,GLUE是将任务代码编写在调度中心。
    JobHandler即任务方法名,填写任务方法上边@XxlJob注解中的名称。
    路由策略:
    第一个:即每次执行任务都由第一个执行器去执行。
    轮询:即执行器轮番执行。
    分片:每次执行任务广播给每个执行器让他们同时执行任务。
    详细说明xxl-job源码中的doc目录下的文档:

1.3.3 启动任务并测试
任务配置完成,下边启动任务

启动成功:

我们在任务方法上打断点跟踪,任务方法被执行,如下图:

相关文章
|
13天前
|
数据采集 人工智能 安全
|
8天前
|
编解码 人工智能 自然语言处理
⚽阿里云百炼通义万相 2.6 视频生成玩法手册
通义万相Wan 2.6是全球首个支持角色扮演的AI视频生成模型,可基于参考视频形象与音色生成多角色合拍、多镜头叙事的15秒长视频,实现声画同步、智能分镜,适用于影视创作、营销展示等场景。
661 4
|
8天前
|
机器学习/深度学习 人工智能 前端开发
构建AI智能体:七十、小树成林,聚沙成塔:随机森林与大模型的协同进化
随机森林是一种基于决策树的集成学习算法,通过构建多棵决策树并结合它们的预测结果来提高准确性和稳定性。其核心思想包括两个随机性:Bootstrap采样(每棵树使用不同的训练子集)和特征随机选择(每棵树分裂时只考虑部分特征)。这种方法能有效处理大规模高维数据,避免过拟合,并评估特征重要性。随机森林的超参数如树的数量、最大深度等可通过网格搜索优化。该算法兼具强大预测能力和工程化优势,是机器学习中的常用基础模型。
350 164
|
7天前
|
机器学习/深度学习 自然语言处理 机器人
阿里云百炼大模型赋能|打造企业级电话智能体与智能呼叫中心完整方案
畅信达基于阿里云百炼大模型推出MVB2000V5智能呼叫中心方案,融合LLM与MRCP+WebSocket技术,实现语音识别率超95%、低延迟交互。通过电话智能体与座席助手协同,自动化处理80%咨询,降本增效显著,适配金融、电商、医疗等多行业场景。
359 155