Elastic-Job分布式任务调度(2):Elastic-Job快速入门

news2024/10/5 1:22:52

1 环境搭建

1.1 版本要求

JDK要求1.7及以上版本

Maven要求3.0.4及以上版本

zookeeper要求采用3.4.6及以上版本

1.2 Zookeeper安装&运行

自行查看我的zookeeper专题

ZooKeeper(3):ZooKeeper集群环境搭建_不死鸟.亚历山大.狼崽子的博客-CSDN博客

1.3 创建maven工程

创建maven工程elastic-job-quickstart,并导入以下依赖:

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.dangdang</groupId>
      <artifactId>elastic-job-lite-core</artifactId>
      <version>2.1.5</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.0</version>
    </dependency>
  </dependencies>

2 代码实现

2.1 编写定时任务类

此任务在每次执行时获取一定数目的文件,进行备份处理,由File实体类的backedUp属性来标识该文件是否已备份。

package org.example.elasticjob.quickstart.job;

import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;
import org.example.elasticjob.quickstart.model.FileCustom;

import java.lang.management.ManagementFactory;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class FileBackupJob implements SimpleJob {

    //每次任务执行要备份文件的数量
    private final int FETCH_SIZE = 1;
    //文件列表(模拟)
    public static List<FileCustom> files = new ArrayList<>();

    @Override
    public void execute(ShardingContext shardingContext) {
        //作业分片信息
        int shardingItem = shardingContext.getShardingItem();
        System.out.println(String.format("作业分片:%d",shardingItem));
        //获取未备份文件
        List<FileCustom> fileCustoms = fetchUnBackupFiles(FETCH_SIZE);
        //文件备份
        backupFiles(fileCustoms);
    }

    /**
     * 获取未备份的文件
     * @param count
     * @return
     */
    public List<FileCustom> fetchUnBackupFiles(int count) {
        List<FileCustom> fetchList = new ArrayList<>();
        int num = 0;
        for (FileCustom fileCustom : files) {
            if (num >= count) {
                break;
            }
            //未备份的文件则放入列表
            if (!fileCustom.getBackedUp()) {
                fetchList.add(fileCustom);
                num++;
            }
        }
        //ManagementFactory.getRuntimeMXBean()获取当前JVM进程的PID
        System.out.println(String.format("%sTime:%s,已获取%d文件",
                ManagementFactory.getRuntimeMXBean().getName(),new SimpleDateFormat("hh:mm:ss").format(new
                        Date()),num));
        return fetchList;
    }

    /**
     * 备份文件
     * @param files
     */
    public void backupFiles(List<FileCustom> files){
        for(FileCustom file : files){
        //标记文件数据为已备份
            file.setBackedUp(Boolean.TRUE);
            System.out.println(String.format("已备份文件:%s 文件类型:%s",file.getName(),file.getType()));
        }
    }

}

文件实体类如下:

package org.example.elasticjob.quickstart.model;

import lombok.Data;

@Data
public class FileCustom {

    /**
     * 标识
     */
    private String id;
    /**
     * 文件名
     */
    private String name;
    /**
     * 文件类型,如text、image、radio、vedio
     */
    private String type;
    /**
     * 文件内容
     */
    private String content;
    /**
     * 是否已备份
     */
    private Boolean backedUp = false;
    public FileCustom(String id,String name,String type,String content){
        this.id = id;
        this.name = name;
        this.type = type;
        this.content = content;
    }
}

2.2 编写启动类

package org.example.elasticjob.quickstart;

import com.dangdang.ddframe.job.config.JobCoreConfiguration;
import com.dangdang.ddframe.job.config.simple.SimpleJobConfiguration;
import com.dangdang.ddframe.job.lite.api.JobScheduler;
import com.dangdang.ddframe.job.lite.config.LiteJobConfiguration;
import com.dangdang.ddframe.job.reg.base.CoordinatorRegistryCenter;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;
import org.example.elasticjob.quickstart.job.FileBackupJob;
import org.example.elasticjob.quickstart.model.FileCustom;

public class JobMain {
    //zookeeper端口
//    private static final int ZOOKEEPER_PORT = 2181;
    //zookeeper链接字符串 localhost:2181
//    private static final String ZOOKEEPER_CONNECTION_STRING = "192.168.222.130:" + ZOOKEEPER_PORT;
    private static final String ZOOKEEPER_CONNECTION_STRING = "192.168.222.130:2181,192.168.222.131:2181,192.168.222.132:2181" ;
    //定时任务命名空间
    private static final String JOB_NAMESPACE = "elastic‐job‐example‐java";
    //启动任务
    public static void main(String[] args) {
        //生成测试文件
        generateTestFiles();
        //配置zookeeper
        CoordinatorRegistryCenter registryCenter = setUpRegistryCenter();
        //启动任务
        startJob(registryCenter);
    }

    //生成测试文件
    private static void generateTestFiles(){
        for(int i=1;i<11;i++){
            FileBackupJob.files.add(new FileCustom(String.valueOf(i+10),"文件"+
                    (i+10),"text","content"+ (i+10)));
            FileBackupJob.files.add(new FileCustom(String.valueOf(i+20),"文件"+
                    (i+20),"image","content"+ (i+20)));
            FileBackupJob.files.add(new FileCustom(String.valueOf(i+30),"文件"+
                    (i+30),"radio","content"+ (i+30)));
            FileBackupJob.files.add(new FileCustom(String.valueOf(i+40),"文件"+
                    (i+40),"vedio","content"+ (i+40)));
        }
    }

    //注册中心配置
    private static CoordinatorRegistryCenter setUpRegistryCenter(){
        //注册中心配置
        ZookeeperConfiguration zookeeperConfiguration = new
                ZookeeperConfiguration(ZOOKEEPER_CONNECTION_STRING,JOB_NAMESPACE);
        //减少zk的超时时间
        zookeeperConfiguration.setSessionTimeoutMilliseconds(100);
        //创建注册中心
        CoordinatorRegistryCenter registryCenter = new
                ZookeeperRegistryCenter(zookeeperConfiguration);
        registryCenter.init();
        return registryCenter;
    }

    //配置并启动任务
    private static void startJob(CoordinatorRegistryCenter registryCenter) {
        //创建JobCoreConfiguration
        JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration.newBuilder("files‐job",
                "0/3 * * * * ?", 1)
                .build();
        //创建SimpleJobConfiguration
        SimpleJobConfiguration simpleJobConfiguration = new
                SimpleJobConfiguration(jobCoreConfiguration, FileBackupJob.class.getCanonicalName());
        //启动任务
        new JobScheduler(registryCenter,
                LiteJobConfiguration.newBuilder(simpleJobConfiguration).overwrite(true).build()).init();
    }
}

2.3 测试

(1)启动main方法查看控制台

作业分片:0
40200@MSITime:03:20:42,已获取1文件
已备份文件:文件11 文件类型:text
作业分片:0
40200@MSITime:03:20:45,已获取1文件
已备份文件:文件21 文件类型:image
作业分片:0
40200@MSITime:03:20:48,已获取1文件
已备份文件:文件31 文件类型:radio
作业分片:0
40200@MSITime:03:20:51,已获取1文件
已备份文件:文件41 文件类型:vedio
作业分片:0
40200@MSITime:03:20:54,已获取1文件
已备份文件:文件12 文件类型:text

定时任务每3秒批量执行一次,符合基础预期。

(2)测试窗口1不关闭,再次运行main方法观察控制台日志(窗口2)会出现以下两种情况:

        窗口1继续执行任务,窗口2不执行任务

        窗口2接替窗口1执行任务,窗口1停止执行任务

        可通过反复启停窗口2查看到以上现象。

(3)窗口1、窗口2同时运行的情况下,停止正在执行任务的窗口

        未停止的窗口开始执行任务。

分片测试:

当前作业没有被分片,所以多个实例共同执行时只有一个实例在执行,如果我们将作业分片执行,作业将被拆分为多个独立的任务项,然后由分布式的应用实例分别执行某一个或几个分片项。

修改上边的代码,改为作业分3片执行:

//创建JobCoreConfiguration
JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration.newBuilder("files‐job", "0/3 * * * * ?", 3).build();

同时启动三个JobMain:

每个JobMain窗口分别执行一片作业。

总结:

通过以上简单的测试,就可以看出Elastic-Job帮我们解决了分布式调度的以下三个问题:

1)多实例部署时避免任务重复执行,在任务执行时间到来时,从所有实例中选举出来一个,让它来执行任务,从而避免多个实例同时执行任务。

2)高可用,若某一个实例宕机,不影响其他实例来执行任务。

3)弹性扩容,当集群中增加某一个实例,它应当也能够被选举并执行任务,如果作业分片将参与执行某个分片作业。

3 Elastic-Job工作原理

3.1 Elastic-Job整体架构

App:应用程序,内部包含任务执行业务逻辑和Elastic-Job-Lite组件,其中执行任务需要实现ElasticJob接口完成与Elastic-Job-Lite组件的集成,并进行任务的相关配置。应用程序可启动多个实例,也就出现了多个任务执行实例。

Elastic-Job-Lite:Elastic-Job-Lite定位为轻量级无中心化解决方案,使用jar包的形式提供分布式任务的协调服务,此组件负责任务的调度,并产生日志及任务调度记录。

无中心化,是指没有调度中心这一概念,每个运行在集群中的作业服务器都是对等的,各个作业节点是自治的、平等的、节点之间通过注册中心进行分布式协调。

Registry:以Zookeeper作为Elastic-Job的注册中心组件,存储了执行任务的相关信息。同时,Elastic-Job利用该组件进行执行任务实例的选举。

Console:Elastic-Job提供了运维平台,它通过读取Zookeeper数据展现任务执行状态,或更新Zookeeper数据修改全局配置。通过Elastic-Job-Lite组件产生的数据来查看任务执行历史记录。

应用程序在启动时,在其内嵌的Elastic-Job-Lite组件会向Zookeeper注册该实例的信息,并触发选举(此时可能已经启动了该应用程序的其他实例),从众多实例中选举出一个Leader,让其执行任务。当到达任务执行时间时,Elastic-Job-Lite组件会调用由应用程序实现的任务业务逻辑,任务执行后会产生任务执行记录。当应用程序的某一个实例宕机时,Zookeeper组件会感知到并重新触发leader选举。

3.2 ZooKeeper

在学习Elastic-Job执行原理时,有必要大致了解一下ZooKeeper是用来做什么的,因为:

  • Elastic-Job依赖ZooKeeper完成对执行任务信息的存储(如任务名称、任务参与实例、任务执行策略等);
  • Elastic-Job依赖ZooKeeper实现选举机制,在任务执行实例数量变化时(如在快速上手中的启动新实例或停止实例),会触发选举机制来决定让哪个实例去执行该任务。

ZooKeeper是一个分布式一致性协调服务,它是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

咱们可以把ZooKeeper想象为一个特殊的数据库,它维护着一个类似文件系统的树形数据结构,ZooKeeper的客户端(如Elastic-Job任务执行实例)可以对数据进行存取:

每个子目录项如 /app1都被称作为 znode(目录节点),和文件系统一样,我们能够自由的增加、删除znode,在一 个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。

ZooKeeper为什么称之为一致性协调服务呢?因为ZooKeeper拥有数据监听通知机制,客户端注册监听它关心的 znode,当znode发生变化(数据改变、被删除、子目录节点增加删除)时,ZooKeeper会通知所有客户端。简单 来说就是,当分布式系统的若干个服务都关心一个数据时,当这个数据发生改变,这些服务都能够得知,那么这些服务就针对此数据达成了一致。

应用场景思考,使用ZooKeeper管理分布式配置项的机制:

假设我们的程序是分布式部署在多台机器上,如果我们要改变程序的配置文件,需要逐台机器去修改,非常麻烦, 现在把这些配置全部放到zookeeper上去,保存在 zookeeper 的某个目录节点中,然后所有相关应用程序作为 ZooKeeper的客户端对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 ZooKeeper的通知,从而获取新的配置信息应用到系统中。

3.2.1 Elastic-Job任务信息的保存

Elastic-Job使用ZooKeeper完成对任务信息的存取,任务执行实例作为ZooKeeper客户端对其znode操作,任务信息保存在znode中。

使用ZooInspector查看zookeeper节点

1、zookeeper图像化客户端工具的下载地址:

        https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip;

2、下载完后解压压缩包,双击地址为ZooInspector\build\zookeeper-dev-ZooInspector.jar的jar包;

如果双击没有反应?首先电脑要配好java环境,使用java -jar 再加上你的jar文件的路径 启动即可.

 

config节点内容如下:

{
    "jobName": "files‐job",
    "jobClass": "com.itheima.scheduling.job.FileBackupJob",
    "jobType": "SIMPLE",
    "cron": "0/3 * * * * ?",
    "shardingTotalCount": 1,
    "shardingItemParameters": "",
    "jobParameter": "",
    "failover": true,
    "misfire": true,
    "description": "",
    "jobProperties": {
        "job_exception_handler":
        "com.dangdang.ddframe.job.executor.handler.impl.DefaultJobExceptionHandler",
        "executor_service_handler":
        "com.dangdang.ddframe.job.executor.handler.impl.DefaultExecutorServiceHandler"
    },
    "monitorExecution": true,
    "maxTimeDiffSeconds": ‐1,
    "monitorPort": ‐1,
    "jobShardingStrategyClass": "",
    "reconcileIntervalMinutes": 10,
    "disabled": false,
    "overwrite": false
}

节点记录了任务的配置信息,包含执行类,cron表达式,分片算法类,分片数量,分片参数。默认状态下,如果你修改了Job的配置比如cron表达式,分片数量等是不会更新到zookeeper上去的,需要把LiteJobConfifiguration的参数overwrite修改成true,或者删除zk的结点再启动作业重新创建。

instances节点:

同一个Job下的elastic-job的部署实例。一台机器上可以启动多个Job实例,也就是Jar包。instances的命名是[IP+@-@+PID]。

leader节点:

任务实例的主节点信息,通过zookeeper的主节点选举,选出来的主节点信息。下面的子节点分为election,sharding和failover三个子节点。分别用于主节点选举,分片和失效转移处理。election下面的instance节点显式了当前主节点的实例ID:jobInstanceId。latch节点也是一个永久节点用于选举时候的实现分布式锁。

sharding节点下面有一个临时节点necessary,是否需要重新分片的标记,如果分片总数变化或任务实例节点上下 线,以及主节点选举,都会触发设置重分片标记,主节点会进行分片计算。

sharding节点:

任务的分片信息,子节点是分片项序号,从零开始,至分片总数减一。从这个节点可以看出哪个 分片在哪个实例上运行

3.2.2 Elastic-Job任务执行实例选举

Elastic-Job使用ZooKeeper实现任务执行实例选举,若要使用ZooKeeper完成选举,就需要了解ZooKeeper的znode类型了,ZooKeeper有四种类型的znode,客户端在创建znode时可以指定:

PERSISTENT-持久化目录节点

客户端创建该类型znode,此客户端与ZooKeeper断开连接后该节点依旧存在,如果创建了重复的key,比如/data,第二次创建会失败。

PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点

客户端与ZooKeeper断开连接后该节点依旧存在,允许重复创建相同key,Zookeeper给该节点名称进行顺序编号,如zk会在后面加一串数字比如 /data/data0000000001,如果重复创建,会创建一个/data/data0000000002节点(一直往后加1)

EPHEMERAL-临时目录节点

客户端与ZooKeeper断开连接后,该节点被删除,不允许重复创建相同key。

EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点

客户端与ZooKeeper断开连接后,该节点被删除,允许重复创建相同key,依然采取顺序编号机制。

实例选举实现过程分析:

每个Elastic-Job的任务执行实例作为ZooKeeper的客户端来操作ZooKeeper的znode

  1. 任意一个实例启动时首先创建一个 /server 的PERSISTENT节点
  2. 多个实例同时创建 /server/leaderEPHEMERAL子节点
  3. /server/leader子节点只能创建一个,后创建的会失败。创建成功的实例被选为leader节点 ,用来执行任务。
  4. 所有任务实例监听 /server/leader 的变化,一旦节点被删除,就重新进行选举,抢占式地创建 /server/leader节点,谁创建成功谁就是leader。

2.4 小结

通过本章,我们完成了对Elastic-Job技术的快速入门程序,并了解了Elastic-Job整体架构和工作原理。

对于应用程序,只需要将任务执行细节包装为ElasticJob接口的实现类并对任务细节进行配置即可完成与Elastic-Job的集成,而Elastic-Job需要依赖Zookeeper进行执行任务信息的存取,执行任务实例的选举。通过对快速入门程序的测试,我们可以看到Elastic-Job确实解决了分布式任务调度的核心问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/136520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python代理IP的使用和代理池的设置

熟悉python的人都知道为了python的正常请求&#xff0c;维持数据的稳定获取&#xff0c;都会用到代理IP。代理IP不仅可以用来规避IP在单位时间的请求次数&#xff0c;还可以借助代理来隐藏真实的IP&#xff0c;避免出现“IP请求过于频繁”&#xff0c;“403”等报错。今天就带大…

甲方安全之仿真钓鱼演练(邮件+网站钓鱼)

文章目录一、简介1.1 前言1.2 整体思路1.3 演练所需1.4 各邮件厂商日群发上限二、钓鱼平台搭建及配置2.1 gophish平台搭建2.2 收件目标配置&#xff08;User & Groups&#xff09;2.3 发信邮箱配置&#xff08;Sending Profiles&#xff09;2.4 邮件模版配置&#xff08;Em…

Windows下socket网络编程,C++,Email的客户端程序(支持邮件基于SMTP的发送和POP3的接收)

阅读前请看一下&#xff1a;我是一个热衷于记录的人&#xff0c;每次写博客会反复研读&#xff0c;尽量不断提升博客质量。文章设置为仅粉丝可见&#xff0c;是因为写博客确实花了不少精力。不用担心你关注我而我却不关注你&#xff0c;因为我是个诚信互关的人&#xff01;&…

linux--管道

这里写自定义目录标题基本概念管道特征编写模型有名管道模型示例demowrite.cread.c结果无名管道基本概念 进程间存在天然的壁垒,进程间通信(Interperocess Communication,IPC)是指二个或者多个进程之间进行数据交换的过程 管道特征 管道是进程间通讯的一种常用方法。管道分为…

MyISAM 引擎和 InnoDB 引擎中索引存储的区别

一、MyISAM 引擎下的索引 MyISAM 存储引擎不支持行级锁&#xff0c;只有表级锁&#xff1b;不支持事务&#xff0c;也不支持外键&#xff0c;主要面向 OLAP 应用&#xff0c;是 MySQL 数据库5.5.8 版本之前默认的存储引擎&#xff0c;MyISAM 适用于不需要关心事务&#xff0c;…

实时即未来,大数据项目车联网之原始数据实时ETL任务HBase调优【九】

1. 原始数据实时ETL任务HBase调优 1.1 数据写入hbase优化 上一节写入数据,一条条数据put到表中,对于大量数据的写入,效率极低,因此针对此项进行优化 使用hbase客户端写缓存进行批量写入数据到hbase中 hbase客户端写缓存对象:BufferedMutator hbase的每一次put操作写入数据…

CSS权威指南(二)选择符

1.样式的基本规则 CSS的一个核心优势就是可以为文档中某种种类的元素全部应用相同的样式规则。CSS样式便于修改和编辑&#xff0c;而且能应用到指定的所有文本元素上。 &#xff08;1&#xff09;元素选择符 即直接使用元素的名称进行选择&#xff0c;类似于p{ font-size:10px…

Lc.152 乘积最大子数组

题目链接1 前言翻译成大白话&#xff1a;就是找一个数组&#xff0c;其连续子数组的乘积最大值。2 算法思路&#xff1a;一般求最值的问题首选动态规划。这道题与[LC.53 最大子序和]很类似。我们假设状态转移方程为:它表示以第 i 个元素结尾乘积最大子数组的乘积可是在这里&…

异步通信技术AJAX | AJAX实现省市联动、AJAX跨域问题

目录 一&#xff1a;异步通信技术AJAX | 快速搞定AJAX&#xff08;第四篇&#xff09; 1、AJAX实现省市联动 2、超链接、form表单和JS代码跨域 3、AJAX跨域问题 &#xff08;1&#xff09;测试Ajax跨域访问 &#xff08;2&#xff09;同源 & 不同源 &#xff08;3&a…

可以通过哪些方式了解量化接口level2?

可以通过哪些方式了解量化接口level2&#xff1f;大家可以去百查看关于量化交易接口的信息&#xff0c;根据小编对市场上大多数的level2接口了解发现既有要收费的也有免费的&#xff0c;一般来说第三方软件公司提供的都是收费的居多&#xff0c;一些正规券商提供的就是免费的居…

一文读懂自动驾驶汽车:软硬结合 造就未来出行体验(下篇)

在上篇&#xff0c;我们回顾了自动驾驶汽车的发展历史&#xff0c;介绍了自动驾驶汽车的工作原理。得益于 AI 技术的突破&#xff0c;自动驾驶汽车飞速发展&#xff0c;运算速度也从 2007 年的 230 FLOPS 跃升至 2022 年的 254 TOPS&#xff0c;向软件定义汽车发展。现在&#…

数据结构-考研难点代码突破 (C++实现有向无环图的拓扑排序)

文章目录1. AOE网2. 拓扑排序C代码1. AOE网 AOV网∶若用DAG 图&#xff08;有向无环图&#xff09;表示一个工程&#xff0c;其顶点表示活动&#xff0c;用有向边<Vi&#xff0c;Vj>表示活动 Vi必须先于活动Vj进行的这样一种关系&#xff0c;则将这种有向图称为顶点表示…

基于主从博弈的智能小区代理商定价策略及电动汽车充电管理(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

C语言贪吃蛇大作战

C语言贪吃蛇大作战 贪吃蛇大作战 1997 年&#xff0c;诺基亚公司发布了贪吃蛇游戏&#xff0c;并将其内置于诺基亚 6110 手机中&#xff0c;使这款游戏迅速风靡全球&#xff0c;成为一代经典。一般的观点认为&#xff0c;贪吃蛇是手机游戏的鼻祖。 与传统单人贪吃蛇不同的是&…

【时间之外】系统管人,能行?(冷眼旁观连载之一)

目录 写作初心 在用工具 某微 某道 某书 工具痛点 某微痛点 某道痛点 某书痛点 总结一下&#xff1a;功能复杂 2023年观察计划 最大痛点 效果跟踪 未完待续 写作初心 2022年应该是这一生中值得纪念的一年&#xff0c;疫情封控自不必说&#xff0c;对于个人而言&a…

traefik gateway api

背景 在使用istio后开始考虑网关了&#xff0c;istio已经有自己的网关&#xff0c;为什么还要另外找一个别的网关&#xff0c;参考了好几个文章大致结论是&#xff0c;istio的网关功能不够强大&#xff0c;下图红色的部分是istio网关暂时缺失的&#xff0c;所以我的结论是在is…

Monorepo 下 Git 工作流的最佳实践

作者&#xff1a;林宜丙 背景 没有哪一种 Git 工作流是银弹&#xff0c;合适的 Git 工作流往往取决于项目的代码规模、协作人数、应用场景等&#xff1b;本次分享先从适合小型 Monorepo 的 Feature branch 工作流开始分享&#xff0c;接着分享适用于中大型 Monorepo 的 Trunk…

头歌:Ping客户端创建原始套接字(底部附全关完整答案)

头歌实践教学平台 (educoder.net)为Ping客户端创建一个原始类型的套接字原始套接字套接字&#xff08;socket&#xff09;是一个抽象层网络应用程序可以通过它发送或接收数据&#xff0c;可对其进行像文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中&a…

<C++>二叉树进阶

文章目录为什么要学这一节1. 二叉搜索树1.1 二叉搜索树概念1.2 二叉搜索树操作1.3 二叉搜索树的实现1.4 二叉搜索树的应用1.5 二叉搜索树的性能分析2. 经典题目2.1 最近公共祖先2.2 从前序与中序遍历序列构造二叉树2.3 二叉树的前序遍历&#xff08;非递归&#xff09;为什么要…

计算机组成原理复习:数据的表示和运算

计算机组成原理复习&#xff1a;数据的表示和运算2. 数据的表示和运算2.1 数制与编码2.1.1 数制&#xff1a;进位计数制及其相互转换2.1.2 编码&#xff1a;数值数据的编码与表示2.1.2.1 逻辑型数据2.1.2.2 字符型数据 之 ASCII码2.1.2.3 数值型数据 之 BCD码2.1.3 校验码——奇…