分布式调度方案:Elastic-Job
文章目录
- 一、什么是分布式调度
- 二、Elastic-Job 介绍
- 三、Elastic-Job 实战
- 3.1 环境搭建
- 3.1.1 本地部署
- 3.1.2 服务器部署
- 3.1.3 Zookeeper 管控台界面
- 3.2 入门案例
- 3.3 SpringBoot 集成 Elastic-Job
- 3.4 任务分片(★)
- 3.5 Dataflow 类型调度任务
一、什么是分布式调度
什么是任务调度?
我们可以思考一下下面业务场景的解决方案:
① 某电商平台需要每天上午10点,下午3点,晚上8点发放一批优惠券
② 某银行系统需要在信用卡到期还款日的前三天进行短信提醒
③ 某财务系统需要在每天凌晨0:10分结算前一天的财务数据,统计汇总
以上场景就是任务调度所需要解决的问题。
任务调度是为了自动完成特定任务,在约定的特定时刻去执行任务的过程
以上的场景可以使用定时任务注解 @Scheduled
贴在业务方法上,并在启动类上贴上 @EnableScheduling
注解,以实现任务调度。
@Scheduled(cron = "0/20 * * * * ? ")
public void doWork(){//doSomething
}
什么是分布式调度?
感觉 Spring 给我们提供的这个注解可以完成任务调度的功能,为什么还需要分布式呢?主要有如下这几点原因:
- 单机处理极限:原本 1 分钟内需要处理 1 万个订单,但是现在需要 1 分钟内处理 10 万个订单;原来一个统计需要1小时,现在业务方需要10分钟就统计出来。你也许会说,你也可以多线程、单机多进程处理。的确,多线程并行处理可以提高单位时间的处理效率,但是单机能力毕竟有限(主要是CPU、内存和磁盘),始终会有单机处理不过来的情况。
- 高可用:单机版的定式任务调度只能在一台机器上运行,如果程序或者系统出现异常就会导致功能不可用。虽然可以在单机程序实现的足够稳定,但始终有机会遇到非程序引起的故障,而这个对于一个系统的核心功能来说是不可接受的。
- 防止重复执行:在单机模式下,定时任务是没什么问题的。但当我们部署了多台服务,同时又每台服务又有定时任务时,若不进行合理的控制在同一时间,只有一个定时任务启动执行,这时,定时执行可能存在执复、混乱和错误的情况了。
这个时候就需要分布式的任务调度来实现了。
二、Elastic-Job 介绍
Elastic-Job 是一个分布式调度的解决方案,它由两个相互独立的子项目 Elastic-job-Lite 和 Elastic-Job-Cloud 组成,使用 Elastic-Job 可以快速实现分布式任务调度。
官方地址:https://shardingsphere.apache.org/elasticjob/
功能列表:
- 分布式调度协调:在分布式环境中,任务能够按照指定的调度策略执行,并且能够避免同一任务多实例重复执行。
- 丰富的调度策略:基于成熟的定时任务作业框架 Quartz cron 表达式执行定时任务。
- 弹性拓容缩容:当集群中增加一个实例,它应当能够被选举被执行任务;当集群减少一个实例时,他所执行的任务能被转移到别的示例中执行。
- 失效转移:某示例在任务执行失败后,会被转移到其他实例执行。
- 错过执行任务重触发:若因某种原因导致作业错过执行,自动记录错误执行的作业,并在下次作业完成后自动触发。
- 支持并行调度:支持任务分片,任务分片是指将一个任务分成多个小任务在多个实例同时执行。
- 作业分片一致性:当任务被分片后,保证同一分片在分布式环境中仅一个执行实例。
- 支持作业生命周期操作:可以动态对任务进行开启及停止操作,丰富的作业类型。
执行架构如下:
三、Elastic-Job 实战
3.1 环境搭建
zookeeper 可以理解为 elastic-job 的注册中心,分布式调度等功能由它实现,首先要下载资源。
csdn搜索资源: zookeeper-3.4.11.tar.gz
3.1.1 本地部署
将 zookeeper-3.4.11.tar.gz
解压,并将 conf 目录下 zoo_sample.cfg
拷贝一份命名成 zoo.cfg
其中 zookeeper 默认端口是 2181
切换到 bin 目录下,双击 zkServer.cmd
,即可启动 zookeeper
3.1.2 服务器部署
step1:将 zookeeper-3.4.11.tar.gz
上传到 /usr/local/software
目录下
step2:解压文件到指定目录
tar -zxvf /usr/local/software/zookeeper-3.4.11.tar.gz -C /usr/local/
step3:拷贝配置文件
cp /usr/local/software/zookeeper-3.4.11/conf/zoo_sample.cfg /usr/local/software/zookeeper-3.4.11/conf/zoo.cfg
step4:启动
/usr/local/zookeeper-3.4.11/bin/zkServer.sh start
step5:检查进程是否开启,需要查看到QuorumPeerMain
进程,如果存在则证明启动成功。
jps
zookeeper常用名称参考: linux下的zookeeper启动、停止 常用命令
注:如果启动显示 Starting zookeeper ... already running as process 7827
. 但是 jps
中没有 QuorumPeerMain
进程。则需查看 zookeeper_server.pid
文件的位置并删除。
# 查看该文件位置
find / -name "zookeeper_server.pid"
# 跳转到该文件的位置,并删除
rm -rf zookeeper_server.pid
另外:服务器需要暂时关闭防火墙 systemctl stop firewalld
,并可使用 firewall-cmd --state
查看防火墙状态。
具体可参考:Linux关闭防火墙命令
3.1.3 Zookeeper 管控台界面
搜索下载:zooInspector.zip
解压后进入 build 目录,运行 jar 包:java -jar zookeeper-dev-ZooInspector.jar
点击绿色按钮,输入连接的IP和端口号即可。
3.2 入门案例
版本要求:JDK 要求1.7 以上版本;Maven 要求 3.0.4 及以上版本;Zookeeper 要求 3.4.6 以上版本
1、引入 pom 依赖
<dependency><groupId>com.dangdang</groupId><artifactId>elastic-job-lite-core</artifactId><version>2.1.5</version>
</dependency>
2、调度任务类
public class MyElasticJob implements SimpleJob {@Overridepublic void execute(ShardingContext shardingContext) {System.out.println("执行任务:" + new Date());}
}
3、zookeeper 的配置类
启动类定义 JobScheduler 对象,里面传入两个对象:定时任务配置对象、注册中心配置,并调用 init() 方法完成初始化。
定时任务配置对象中要设置:任务名称、cron表达式和分片数量,并设置 任务对象的全路径类名。
注册中心配置对象中要设置:注册中心的地址、项目名以及节点的超时时间。
public class JobDemo {public static void main(String[] args) {new JobScheduler(createRegistryCenter(), createJobConfiguration()).init();}/*** Zookeeper注册中心配置** @return 注册中心配置对象*/private static CoordinatorRegistryCenter createRegistryCenter() {// ZookeeperConfiguration("zookeeper地址", "项目名")ZookeeperConfiguration configuration = new ZookeeperConfiguration("localhost:2181", "elastic-job");// 设置节点超时时间,即每隔一段时间查看当前节点是否下线configuration.setConnectionTimeoutMilliseconds(100);ZookeeperRegistryCenter center = new ZookeeperRegistryCenter(configuration);center.init();return center;}/*** 定时任务配置** @return 定时任务配置对象*/private static LiteJobConfiguration createJobConfiguration() {// 定义作业核心配置 newBuilder("任务名称", "corn表达式", "分片数量")JobCoreConfiguration simpleCoreConfig = JobCoreConfiguration.newBuilder("myElasticJob", "0/10 * * * * ?", 1).build();// 定义simple类型配置,MyElasticJob.class.getCanonicalName() 是获取MyElasticJob的全限定类名(全路径类名)SimpleJobConfiguration configuration = new SimpleJobConfiguration(simpleCoreConfig, MyElasticJob.class.getCanonicalName());// 定义Lite作业根配置,并返回// 设置overwrite(true),允许覆盖cron表达式(默认不允许,会每5s执行一次)return LiteJobConfiguration.newBuilder(configuration).overwrite(true).build();}
}
注: .overwrite(true)
如果不设置,默认 5 秒执行一次。
4、运行main方法。当开启第二个实例的时候,第一个实例停止打印,当关闭第二个实例的时候,第一个实例又重新开始运行。
3.3 SpringBoot 集成 Elastic-Job
1、添加 pom 依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.axy</groupId><artifactId>elastic-job-boot</artifactId><packaging>jar</packaging><version>1.0-SNAPSHOT</version><name>elastic-job-boot</name><url>http://maven.apache.org</url><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.dangdang</groupId><artifactId>elastic-job-lite-spring</artifactId><version>2.1.5</version></dependency>...</dependencies><build><finalName>elastic-job-boot</finalName></build>
</project>
2、因为配置中心的地址并不是固定的,所以我们应该把这个地址信息配置在配置文件中,所以在配置文件
application.yml 中添加配置如下:
zookeeper:url: localhost:2181groupName: elastic-job-boot
3、调度任务类交给 Spring 进行管理
@Component
public class MyElasticJob implements SimpleJob {@Overridepublic void execute(ShardingContext shardingContext) {System.out.println("定时调度:" + new Date());}
}
4、zookeeper 的配置类
elastic-job 集成 SpringBoot 以后,需要创建的不是 JobScheduler
对象,而是 SpringJobScheduler
对象,并交给 Spring 管理。其次,初始化该对象还需要传入需要分布式调度的任务对象当参数。
@Configuration
public class TestJobConfig {@Bean(initMethod = "init") // 创建bean后调用init方法public SpringJobScheduler testScheduler(MyElasticJob job, CoordinatorRegistryCenter registryCenter) {// 方法形参,自动会去spring的容器中寻找,首先会去看类型匹配,然后才会去看变量名,匹配方式和@Autowird一样LiteJobConfiguration configuration = createJobConfiguration(job.getClass(), "0/4 * * * * ?", 1);return new SpringJobScheduler(job, registryCenter, configuration);}@Beanpublic CoordinatorRegistryCenter registryCenter(@Value("${zookeeper.url}") String url,@Value("${zookeeper.groupName}") String groupName) {// ZookeeperConfiguration("zookeeper地址", "项目名")ZookeeperConfiguration configuration = new ZookeeperConfiguration(url, groupName);// 设置节点超时时间configuration.setConnectionTimeoutMilliseconds(100);ZookeeperRegistryCenter center = new ZookeeperRegistryCenter(configuration);center.init();return center;}/*** 定时任务配置* 这个定时任务使用的场景比较灵活,因此不建议放在spring的容器当中** @param clazz 定时任务的字节码* @param cron cron表达式* @param shardingCount 分片数量* @return 定时任务配置对象*/private static LiteJobConfiguration createJobConfiguration(Class clazz, String cron, int shardingCount) {// 定义作业核心配置 newBuilder("任务名称", "corn表达式", "分片数量")JobCoreConfiguration.Builder jobBuilder = JobCoreConfiguration.newBuilder(clazz.getSimpleName(), cron, shardingCount);JobCoreConfiguration simpleCoreConfig = jobBuilder.build();// 定义simple类型配置,MyElasticJob.class.getCanonicalName() 是获取MyElasticJob的全限定类名(全路径类名)System.out.println("MyElasticJob.class.getCanonicalName(): " + MyElasticJob.class.getCanonicalName());JobTypeConfiguration configuration;configuration = new SimpleJobConfiguration(simpleCoreConfig, clazz.getCanonicalName());// 定义Lite作业根配置,并返回// 设置overwrite(true),允许覆盖cron表达式(默认不允许)return LiteJobConfiguration.newBuilder(configuration).overwrite(true).build();}
}
5、启动项目
3.4 任务分片(★)
分片就是在就是在机器中分线程执行,分片的数量决定了最终分得线程的数量,将一个任务拆分为多个独立的任务项,然后由分布式的应用实例分别执行某一个或者几个分布项,下面以案例来逐步带入分片的概念。
现要处理下图表中数据的 backedUp 属性设置为 1。表一共有 20 条数据,根据 type 进行分类可以分成 text、image、radio 和 video 四类,那我们可以自定义任务分 4 片,分片索引分别为:0、1、2、3。
- 当只有一台机器的情况下,在机器 A 启动四个线程,分别处理四个分片的内容。
- 当有两台机器的情况下,机器 A 启动两个线程负责索引 0 1 的分片内容,机器 B 负责 2 3 的分片内容。
- 当有三台机器的情况下,机器 A 负责索引 0 1 的分片内容,机器 B 负责 2,机器 C 负责 3。
- 当有四台机器的情况下,机器 A 负责索引 0 的分片内容,机器 B 负责 1,机器 C 负责 2,机器 D 负责 3。
注:分片数建议等于机器个数的倍数。如:分片四个在两台机器上,那么就是每台机器分两个线程来执行任务。
如何实现上文的案例呢?这里我们忽略关于数据库层面的配置,主要的类与配置如下:
1、这里我们新建文件对象
@AllArgsConstructor
@NoArgsConstructor
@Data
public class FileCustom {// 唯⼀标识private Long id;//⽂件名private String name;//⽂件类型private String type;//⽂件内容private String content;// 是否已备份private Boolean backedUp = false;
}
2、这里我们先定义 zookeeper 的配置类
在初始化定时任务配置的时候,以字符串的形式传入分片参数,传入"0=text,1=image,2=radio,3=vedio"
,设置分片个数为 4,并添加分片功能 shardingItemParameters(...)
。
- 如果 分片个数 小于 分片参数,则取参数中前几个。如:分片取 2,则只会对
0=text,1=image
进行处理 - 如果 分片个数 大于 分片参数,则多出的参数补 null。如:分片取 5,则参数字符串会变为
0=text,1=image,2=radio,3=vedio,4=null
@Configuration
public class TestJobConfig {@Bean(initMethod = "init")public SpringJobScheduler fileScheduler(FileCustomElasticJob job, CoordinatorRegistryCenter registryCenter) {LiteJobConfiguration configuration = createJobConfiguration(job.getClass(), "0 0/1 * * * ?", 4, "0=text,1=image,2=radio,3=vedio");return new SpringJobScheduler(job, registryCenter, configuration);}@Beanpublic CoordinatorRegistryCenter registryCenter(@Value("${zookeeper.url}") String url, @Value("${zookeeper.groupName}") String groupName) {// ZookeeperConfiguration("zookeeper地址", "项目名")ZookeeperConfiguration configuration = new ZookeeperConfiguration(url, groupName);// 设置节点超时时间configuration.setConnectionTimeoutMilliseconds(100);ZookeeperRegistryCenter center = new ZookeeperRegistryCenter(configuration);center.init();return center;}/*** 定时任务配置* 这个定时任务使用的场景比较灵活,因此不建议放在spring的容器当中** @param clazz 定时任务的字节码* @param cron cron表达式* @param shardingCount 分片数量* @param shardingParam 分片参数* @return 定时任务配置对象*/private static LiteJobConfiguration createJobConfiguration(Class clazz, String cron, int shardingCount,String shardingParam) {// 定义作业核心配置 newBuilder("任务名称", "corn表达式", "分片数量")JobCoreConfiguration.Builder jobBuilder = JobCoreConfiguration.newBuilder(clazz.getSimpleName(), cron, shardingCount);if (!StringUtils.isEmpty(shardingParam)) {jobBuilder.shardingItemParameters(shardingParam); // 添加分片功能}JobCoreConfiguration simpleCoreConfig = jobBuilder.build();// 定义simple类型配置JobTypeConfiguration configuration;configuration = new SimpleJobConfiguration(simpleCoreConfig, clazz.getCanonicalName());// 定义Lite作业根配置,并返回// 设置overwrite(true),允许覆盖cron表达式(默认不允许)return LiteJobConfiguration.newBuilder(configuration).overwrite(true).build();}
}
3、文件对象的调度任务类
@Slf4j
@Component
public class FileCustomElasticJob implements SimpleJob {@Autowiredprivate FileCustomMapper fileCustomMapper;@Overridepublic void execute(ShardingContext shardingContext) {long threadId = Thread.currentThread().getId();System.out.printf("线程ID:{},任务的名称:{},任务参数:{},分片个数L:{},分片索引号:{},分片参数:{}\n",threadId,shardingContext.getJobName(),shardingContext.getJobParameter(),shardingContext.getShardingTotalCount(),shardingContext.getShardingItem(),shardingContext.getShardingParameter());doWorkByParameter(shardingContext.getShardingParameter());}/*** 根据类型查询出所有的备份任务** @param shardingParameter 线程对应处理的文件类型*/private void doWorkByParameter(String shardingParameter) {List<FileCustom> fileCustoms = fileCustomMapper.selectByType(shardingParameter);for (FileCustom fileCustom : fileCustoms) {backUp(fileCustom);}}/*** 模拟备份操作** @param fileCustom 备份对象*/private void backUp(FileCustom fileCustom) {System.out.println("备份的方法名:" + fileCustom.getName() + ",备份的类型:" + fileCustom.getType());System.out.println("==================================");try {TimeUnit.SECONDS.sleep(1); // 延时一秒} catch (InterruptedException e) {throw new RuntimeException(e);}fileCustomMapper.changeState(fileCustom.getId(), 1); // 修改数据的 backedUp}
}
4、这里我们模拟有两台机器,即两个实例。
从运行结果我们可以看出,机器 A 开启了两个线程来处理分片索引为 0 1 的分片内容,机器 B 开启了两个线程来处理分片索引为 2 3 的分片内容。
因此,通过对任务的合理分片化,可以达到任务并行处理的效果。分片的优点如下:
- 分片项与业务处理解耦:Elastic-ob并不直接提供数据处理的功能,框架只会将分片项分配至各个运行中的作业服务器,开发者需要自行处理分片项与真实数据的对应关系。
- 最大限度利用资源:将分片项设置大于服务器的数据,最好是大于服务器倍数的数量,作业将会合理利用分布式资源,动态的分配分片项。
3.5 Dataflow 类型调度任务
Dataflow 类型适用于要处理的数据量很大的情况,Dataflow
类型的定时任务需要实现 Datafowjob
接口,该接口提供 2 个方法供覆盖,分别用于抓取 fetchData
和处理 processData
数据,我们继续对例子进行改造。
Dataflow
类型用于处理数据流,他和 Simplejob
不同,它以数据流的方式执行,调用 fetchData
抓取数据,知道抓取不到数据才停止作业。
1、修改 zookeeper 配置类,增加数据类型判断和逻辑
@Configuration
public class TestJobConfig {@Bean(initMethod = "init")public SpringJobScheduler fileScheduler(FileDataFlowJob job, CoordinatorRegistryCenter registryCenter) {LiteJobConfiguration configuration = createJobConfiguration(job.getClass(), "0 0/1 * * * ?", 4, "0=text,1=image,2=radio,3=vedio", true);return new SpringJobScheduler(job, registryCenter, configuration);}@Beanpublic CoordinatorRegistryCenter registryCenter(@Value("${zookeeper.url}") String url, @Value("${zookeeper.groupName}") String groupName) {// ZookeeperConfiguration("zookeeper地址", "项目名")ZookeeperConfiguration configuration = new ZookeeperConfiguration(url, groupName);// 设置节点超时时间configuration.setConnectionTimeoutMilliseconds(100);ZookeeperRegistryCenter center = new ZookeeperRegistryCenter(configuration);center.init();return center;}/*** 定时任务配置* 这个定时任务使用的场景比较灵活,因此不建议放在spring的容器当中** @param clazz 定时任务的字节码* @param cron cron表达式* @param shardingCount 分片数量* @param shardingParam 分片参数* @param isDataFlow 是否是DataFlow类型* @return 定时任务配置对象*/private static LiteJobConfiguration createJobConfiguration(Class clazz, String cron, int shardingCount,String shardingParam, boolean isDataFlow) {// 定义作业核心配置 newBuilder("任务名称", "corn表达式", "分片数量")JobCoreConfiguration.Builder jobBuilder = JobCoreConfiguration.newBuilder(clazz.getSimpleName(), cron, shardingCount);if (!StringUtils.isEmpty(shardingParam)) {jobBuilder.shardingItemParameters(shardingParam); // 添加分片功能}JobCoreConfiguration simpleCoreConfig = jobBuilder.build();// 定义simple类型配置JobTypeConfiguration configuration;if (isDataFlow) {// true 代表流处理configuration = new DataflowJobConfiguration(simpleCoreConfig, clazz.getCanonicalName(), true);} else {configuration = new SimpleJobConfiguration(simpleCoreConfig, clazz.getCanonicalName());}// 定义Lite作业根配置,并返回// 设置overwrite(true),允许覆盖cron表达式(默认不允许)return LiteJobConfiguration.newBuilder(configuration).overwrite(true).build();}
}
2、定义新的 DataFlow 任务调度对象
@Component
public class FileDataFlowJob implements DataflowJob<FileCustom> {@Autowiredprivate FileCustomMapper fileCustomMapper;/*** 抓取数据** @param shardingContext* @return*/@Overridepublic List<FileCustom> fetchData(ShardingContext shardingContext) {// 取决于数据能否抓取到数据,有数据会继续调用该方法// 如果没数据就会停止,此次定时任务执行停止// 直到下次任务调度接着抓取System.out.println("开始抓取数据...");// select * from t_file_custom where backedUp = 0 and type = #{type} limit #{count}List<FileCustom> fileCustomList = fileCustomMapper.selectLimit(shardingContext.getShardingParameter(), 2); // 查找 backedUp=0 的前两条数据return fileCustomList; // 如果为null,则直接返回;如果不为null,则调用下方方法处理数据}/*** 处理数据** @param shardingContext* @param list*/@Overridepublic void processData(ShardingContext shardingContext, List<FileCustom> list) {for (FileCustom fileCustom : list) {backUp(fileCustom);}}/*** 模拟备份操作** @param fileCustom 备份对象*/private void backUp(FileCustom fileCustom) {System.out.println("备份的方法名:" + fileCustom.getName() + ",备份的类型:" + fileCustom.getType());System.out.println("==========================");try {TimeUnit.SECONDS.sleep(1); // 延时一秒} catch (InterruptedException e) {throw new RuntimeException(e);}fileCustomMapper.changeState(fileCustom.getId(), 1);}
}
3、启动项目发现,每次抓取两条数据,重复执行,有数据会继续调用该方法,如果没数据就会停止,此次定时任务执行停止。直至下次任务调度接着抓取。
文章参考:Java微服务商城高并发秒杀项目实战|Spring Cloud Alibaba真实项目实战+商城双11秒杀+高并发+消息+支付+分布式事物Seata
相关文章:

分布式调度方案:Elastic-Job
文章目录 一、什么是分布式调度二、Elastic-Job 介绍三、Elastic-Job 实战3.1 环境搭建3.1.1 本地部署3.1.2 服务器部署3.1.3 Zookeeper 管控台界面 3.2 入门案例3.3 SpringBoot 集成 Elastic-Job3.4 任务分片(★)3.5 Dataflow 类型调度任务 一、什么是分…...

网络安全工程师(白帽子)企业级学习路线
第一阶段:安全基础(入门) 第二阶段:Web渗透(初级网安工程师) 第三阶段:进阶部分(中级网络安全工程师)...

数据结构详细解释
数据结构 1. 线性数据结构 数组(Array) 定义:数组是一种固定大小的、元素类型相同的线性数据结构。元素在内存中是连续存储的,可以通过索引直接访问。 特点: 支持常数时间的随机访问(O(1))。…...

7.1图像平移
目录 实验原理 示例代码1 运行结果1 示例代码2 运行结果2 实验原理 OpenCV中,图像平移是一种基本的几何变换,指的是将图像中的每一个像素点沿着水平方向或垂直方向移动一定的距离。图像平移不改变图像…...

海外云手机是否适合运营TikTok?
随着科技的迅猛发展,海外云手机逐渐成为改变工作模式的重要工具。这种基于云端技术的虚拟手机,不仅提供了更加便捷、安全的使用体验,还在电商引流和海外社媒管理等领域展示了其巨大潜力。那么,海外云手机究竟能否有效用于运营TikT…...

IT 行业中常见的专业名称及其含义
API(Application Programming Interface) API 是应用程序编程接口,定义了不同软件系统之间如何互相通信的规则和方式。开发人员使用 API 将应用程序与外部服务集成,进行数据交换或调用外部功能。 IDE(Integrated Deve…...

全球开店,Shopee东南亚入驻指南|用友BIP电商通引领电商出海新潮流
在全球化的浪潮中,东南亚市场以其蓬勃的发展态势成为中国企业出海的首选之地。得益于其语言、物流、仓储、距离及政策的友好性,东南亚市场已成为企业海外拓展的必争之地。作为东南亚领先的电商平台,Shopee以其庞大的用户基础和高度的用户活跃…...

java当中什么是NIO
Java中的NIO(Non-blocking I/O)即非阻塞I/O,是Java 1.4中引入的一种新的I/O API,用于替代传统的I/O(即BIO, Blocking I/O)。与传统的阻塞式I/O相比,NIO提供了更高效的I/O操作,特别是…...

【基础】Three.js 自定义几何体和复制几何体
通过自定义顶点数据,可以创建任意的几何体。像threejs的长方体BoxGeometry、球体SphereGeometry等几何体都是基于BufferGeometry类构建的,它表示一个没有任何形状的空几何体。 1. 自定义点模型 通过javascript 类型化数组 Float32Array创建一组xyz坐标…...

如何使用ChatGPT进行高效的对话生成与优化
目录 一、对话生成的基础原理 二、如何优化对话生成的流畅性与上下文关联性 1. 提示词优化:明确上下文和期望目标 示例:提示词优化 2. 调整生成参数:控制生成长度与内容多样性 示例:调整生成参数 3. 上下文管理:…...

MySQL系列—8.存储结构
目录 1.系统表空间 ibdata 2.通用表空间 .ibd 3.独立表空间 4.Undo 表空间 5.临时表空间 6.Redo Log File 1.系统表空间 ibdata 系统表空间由参数innodb_data_file_path定义路径、初始化大小、自动扩展策略 如: innodb_data_file_path/dayta/mysql/ibdata1:…...

vue2、vue3生成二维码
Vue2版: 工具:使用 qrcodejs插件来生成二维码 安装:npm install qrcodejs2 qrcodejs官网地址: https://davidshimjs.github.io/qrcodejs/https://davidshimjs.github.io/qrcodejs/ 代码示例: <template><…...

Spring Cloud全解析:熔断之Hystrix线程隔离导致的问题
Hystrix线程隔离 在微服务框架中,可能一个服务需要调用多个微服务,在tomcat中运行时,tomcat只是分配了100个线程,由于多个服务之间调用的时间消耗过长,可能会导致线程耗尽,而在Hystrix中存在线程隔离&…...

网络编程项目(云词典项目)
目录 一、功能要求 服务器 用户客户端 二、演示效果 1.登录、注册功能 2. 查单词功能 3.查看历史纪录功能 三、项目代码 1.头文件 2.服务器 3.用户端 一、功能要求 仿照云词典的原理,实现云词典功能,用户可以查询输入的单词的英文解释&…...

Java Spring Boot 项目中的密码加密与验证开发案例手册
本手册主要针对Java项目中的账号密码加密与验证进行详细的步骤讲解和代码示例。适用于开发登录认证、用户管理等功能的场景。文档包含工具类的创建、数据库配置、服务层和控制器层的集成等常见操作。 1. 常用加密操作 在实现安全的登录功能时,密码加密与验证是不可…...

VueSax-解决Vue3报错问题,并支持typescript
以下为坑点 根据官方提示,本人在vue3typescript的项目中添加了vuesax的组件依赖 根据正常的导入依赖思路编写代码,发现typescript一直报 查询vuesax的目录文件发现存在ts文件,于是乎觉得是自己的问题,就查阅gpt与网上资料&#x…...

回归预测 | Matlab基于贝叶斯算法优化XGBoost(BO-XGBoost/Bayes-XGBoost)的数据回归预测+交叉验证
回归预测 | Matlab基于贝叶斯算法优化XGBoost(BO-XGBoost/Bayes-XGBoost)的数据回归预测交叉验证 目录 回归预测 | Matlab基于贝叶斯算法优化XGBoost(BO-XGBoost/Bayes-XGBoost)的数据回归预测交叉验证效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现基于贝叶…...

[数据集][目标检测]电动车入梯进电梯电单车入梯检测数据集VOC+YOLO格式7106张3类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):7106 标注数量(xml文件个数):7106 标注数量(txt文件个数):7106 标注…...

大数常用API
package API;public class BigNum {//如果普通的long和double的精度不足以满足要求,那么可以使用java.math包中的两个类//BigInteger和BigDecimal//前者实现任意精度的整数运算,后者实现任意精度的浮点数运算//BigInteger add(BigInteger other)//BigInt…...

Gartner发布ASCA自动化安全控制评估创新洞察:三年后40%的综合安全厂商都将提供ASCA功能
复杂的安全控制网络、技能差距和快速变化的攻击技术使维持技术安全控制的最佳配置的问题更加复杂。安全和风险管理领导者可以通过自动化安全控制评估来改善他们的安全状况。 主要发现 技术安全控制配置错误是与安全漏洞相关的长期问题。薄弱的安全默认值、配置漂移、为减少误报…...

使用lspci命令获取加速卡型号
文章目录 前言一、lspci -nn 获取具体厂商及设备ID二、使用步骤三、使用3080Ti再查询一下 前言 新到的实验机器和加速卡,安装好之后发现lspci命令没有显示型号,这里记录下使用 Vendor ID和Device ID 通过网页查询获取加速卡具体型号的过程。 一、lspci …...

php代码实例强制下载文件代码例子
php代码实例强制下载文件代码例子 $filename $_GET[file]; //Get the fileid from the URL // Query the file ID $query sprintf("SELECT * FROM tableName WHERE id %s",mysql_real_escape_string($filename)); $sql mysql_query($query); if(mysql_num_rows…...

Opencv中的直方图(3)直方图比较函数compareHist()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 比较两个直方图。 函数 cv::compareHist 使用指定的方法比较两个密集或两个稀疏直方图。 该函数返回 d ( H 1 , H 2 ) d(H_1, H_2) d(H1,H2…...

压力测试(内存、磁盘、网络、cpu)
压力测试 1. 内存压力测试工具stressmemtester 2. 磁盘压力测试工具fio (Flexible I/O Tester)dd (Data Duplicator) 3. 网络压力测试工具iperf3speedtest-cli 4. CPU压力测试工具stress-ng 为了满足更详细的需求,以下是针对内存、磁盘和网络压力测试工具的更深入介…...

ArcGIS JSAPI 高级教程 - ArcGIS Maps SDK for JavaScript - 原生代码实现动态扩散效果
ArcGIS JSAPI 高级教程 - ArcGIS Maps SDK for JavaScript - 原生代码实现动态扩散效果 核心代码完整代码:在线示例 ArcGIS Maps SDK for JavaScript 从 4.29 开始增加 RenderNode 类,可以添加数据以及操作 FBO(ManagedFBO)&#…...

Java 设计模式-代理模式
目录 概述 一. 什么是代理模式 1. 举例说明 二. 代理模式作用 1. 保护代理 2. 增强功能 3. 代理交互 4. 远程代理: 三. 代理模式3个角色 四. 静态代理 1. 代码示例: 五. JDK动态代理 1. 代码示例: 六. CGLIB 动态代理 1.代码示…...

CTF靶场之BUUCTF介绍
最后开始关注CTF,我们先了解一下什么CTF:CTF(Capture The Flag)中文一般译作夺旗赛,在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式,最后以夺取FLAG为成功。 从网上找了一个免费的靶场——BUUCTF…...

学会分析问题,画出分析图,解释问题过程,找出规律 ;整数数组分为左右2个部分,左边位奇数右边偶数
// 整数数组左边是奇数右边是偶数.cpp : Defines the entry point for the console application. //#include "stdafx.h" #include<stdio.h> void swap(int& a,int& b) {int tempa;ab;btemp; } int main(int argc, char* argv[]) {int a[7]{1,2,3,4,5,…...

数学基础 -- 线性代数正交多项式之勒让德多项式展开推导
勒让德多项式展开的详细过程 勒让德多项式是一类在区间 [ − 1 , 1 ] [-1, 1] [−1,1] 上正交的多项式,可以用来逼近函数。我们可以将一个函数表示为勒让德多项式的线性组合。以下是如何推导勒让德多项式展开系数 a n a_n an 的详细过程。 1. 勒让德展开的基本…...

Redis实战宝典:从主从模式、哨兵模式、集群模式一步步理解Redis集群
目录标题 Redis 集群的三种模式主从复制主从复制概念主从复制原理主从复制优缺点 哨兵集群哨兵概念哨兵功能下线判断主库选举故障转移哨兵模式优缺点 Cluser 集群Redis 集群的数据分片 Redis 集群的三种模式 在生产环境中,我们使用 Redis 通常采用集群模式…...