Flink的简单学习(kafka)三

一 Kafka的介绍

1.kafka是一个高吞吐的分布式消息系统,是一个消息队列。

2.生产者负责生产数据 ,消费者负责消费数据

3.特点:

生存者消费者模型,FIFO

高性能:单节点支持上千个客户端,百MB/s吞吐

持久性:消息直接持久化在普通磁盘上且性能好

分布式:数据副本冗余、流量负载均衡、可扩展

很灵活:消息长时间持久化+Client维护消费状态

4.性能好的原因

kafka写磁盘是顺序的,所以不断的往前产生,不断的往后写

kafka还用了sendFile的0拷贝技术,提高速度

而且还用到了批量读写,一批批往里写,64K为单位

二 Kafka的搭建

2.1 上传解压修改环境变量

# 解压
tar -zxvf kafka_2.11-1.0.0.tgz -C ../
mv kafka_2.11-1.0.0 kafka-1.0.0# 配置环境变量
vim /etc/profileexport KAFKA_HOME=/usr/local/soft/kafka-1.0.0
export PATH=$PATH:$KAFKA_HOME/binsource /etc/profile

2.2 修改配置文件

1.修改config目录下的server.properties文件

broker.id=0 每一个节点broker.id 要不一样
zookeeper.connect=master:2181,node1:2181,node2:2181/kafka
log.dirs=/usr/local/soft/kafka-1.0.0/data   数据存放的位置

2.3 同步

# 同步kafka文件
scp -r kafka-1.0.0/ node1:`pwd`
scp -r kafka-1.0.0/ node2:`pwd`# 将master中的而环境变量同步到node1和node2中
scp /etc/profile node1:/etc/
scp /etc/profile node2:/etc/#  在ndoe1和node2中执行source
source /etc/profile

2.4 修改其他节点的文件

# node1
broker.id=1
# node2
broker.id=2

2.5 启动kafka

 1、需要启动zookeeper,  kafka使用zk保存元数据
 需要在每隔节点中执行启动的命令
 zkServer.sh start

2.每个节点中都要启动(去中心化的架构)
# -daemon后台启动

/usr/local/soft/kafka-1.0.0/config/server.properties:配置文件的路径要写全
kafka-server-start.sh -daemon /usr/local/soft/kafka-1.0.0/config/server.properties

3.测试 

任意一个节点输入

kafka-console-producer.sh --broker-list master:9092,node1:9092,node2:9092 --topic shujia

topic shujia:只是名字而已可以随便取

另一个节点输入

kafka-console-consumer.sh --bootstrap-server  master:9092,node1:9092,node2:9092 --from-beginning --topic shujia

但是主要最后这个节点后面的取名也跟前面的一样

4.数据存放在data目录下 但是不知道是哪个节点下的 

5.默认生产者产生的数据可以保存7天,消费者可以在这7天内使用这些数据,7天一过,数据自动销毁

三 Kafka的架构

3.1 基本概念

1.producer:消息生存者

2.consumer:消息消费者

3.broker:kafka集群的server:负责处理消息读、写请求,存储消息

4.topic:消息队列/分类

5.broker就是代理,在kafka cluster这一层这里,其实里面是有很多个broker

6.topic就相当于queue

3.2 消息存储和生产消费模型

1.一个topic分成多个partition。一个topic可以看成一张表,被分成多个分区。一个partition可以看作一个并行度。

2.每个partition内部消息强有序,其中的每个消息都有一个序号叫offset。每个分区内部的数据有有序的,先进先出,但是不同的partition里面的数据出来的顺序是随机的。

3.一个partition只对应一个broker,一个broker可以管多个partition。

4.消息不经过内存缓冲,直接写入文件。

5.根据时间策略删除,而不是消费完就删除

6.producer自己决定往哪个partition写消息,可以是轮询的负载均衡,或者是基于hash的partition策略

7.consumer自己维护消费到哪个offset

8.每个consumer都有对应的group

9.group内是queue消费模型 :

        各个consumer消费不同的partition

        因此一个消息在group内只消费一次

10.group间是publish-subscribe消费模型

        各个group各自独立消费,互不影响

        因此一个消息在被每个group消费一次

 

3.3 使用kafka

3.3.1  创建topic

1.输入命令

kafka-topics.sh --create --zookeeper master:2181,node1:2181,node2:2181/kafka --replication-factor 2 --partitions 3 --topic bigdata

--replication-factor  ---每一个分区的副本数量, 同一个分区的副本不能放在同一个节点,副本的数量不能大于kafak集群节点的数量
--partition   --分区数,  根据数据量设置
--zookeeper zk的地址,将topic的元数据保存在zookeeper中

2.在生产和消费数据时,如果topic不存在会自动创建一个分区为1,副本为1的topic

3.3.2 查看topic描述信息

1.输入命令

kafka-topics.sh --describe  --zookeeper master:2181,node1:2181,node2:2181/kafka --topic bigdata

partition的数字是分区编号,leader后面的数字是节点,后面是存储的分区编号,但是不是匹配的,这里的leader0的分区编号是0与1,leader1的分区编号是1与2,leader2的分区是0与2.

3.3.3 获取所有topic

kafka-topics.sh --list  --zookeeper  master:2181,node1:2181,node2:2181/kafka

2.__consumer_offsetsL kafka用于保存消费便宜量的topic

3.3.4 创建控制台生产者

kafka-console-producer.sh --broker-list master:9092,node1:9092,node2:9092 --topic bigdata

3.3.5 创建控制台消费者

kafka-console-consumer.sh --bootstrap-server  master:9092,node1:9092,node2:9092 --from-beginning --topic bigdata

3.3.6 数据保存的方式

# 1、保存的文件
/usr/local/soft/kafka_2.11-1.0.0/data# 2,每一个分区每一个副本对应一个目录# 3、每一个分区目录中可以有多个文件, 文件时滚动生成的
00000000000000000000.log
00000000000000000001.log
00000000000000000002.log# 4、滚动生成文件的策略
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000# 5、文件删除的策略,默认时7天,以文件为单位删除
log.retention.hours=168

3.3.7 删除topic

1.先在配置文件vim config/server.properties加一行代码delete.topic.enable=true

再执行命令:

kafka-topics.sh --delete --topic students_hash --zookeeper master:2181,node1:2181,node2:2181/kafka

 四 JavaAPI

4.1 producer

1.先需要创建Properties对象,并设置broker列表以及kv的数据类型

Properties properties = new Properties();//指定broker列表properties.setProperty("bootstrap.servers", "master:9092,node2:9092,node2:9092");//指定key和value的数据格式properties.setProperty("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");properties.setProperty("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

2.创建KafkaProducer对象,泛型是上面kv的数据类型,里面传入Properties的对象

 Producer<String, String> producer = new KafkaProducer<String, String>(properties);

3.生产数据:使用KafkaProducer对象中的send方法,里面传入ProducerRecord的对象。前面是topic,后面是数据

producer.send(new ProducerRecord<>("words","java"));

4.刷新并关闭

5.查看去命令行查看,相关命令去看使用Kafka

6.全部代码

package com.shujia.kafka;import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Properties;public class Demo2StudentToKafka {public static void main(String[] args)throws Exception {Properties properties = new Properties();//指定broker列表properties.setProperty("bootstrap.servers", "master:9092,node2:9092,node2:9092");//指定key和value的数据格式properties.setProperty("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");properties.setProperty("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");Producer<String, String> producer = new KafkaProducer<String, String>(properties);BufferedReader br = new BufferedReader(new FileReader("flink/data/students.csv"));String line =null;while ((line=br.readLine())!=null){producer.send(new ProducerRecord<>("students",line));producer.flush();}br.close();producer.close();}
}

 7.hash分区代码

这个分区是先在命令行中已经分好的,然后通过某一个字段的哈希值值分组

kafka-topics.sh --create --zookeeper master:2181,node1:2181,node2:2181/kafka --replication-factor 2 --partitions 3 --topic students_hash

package com.shujia.kafka;import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Properties;public class Demo4StudentToKafka {public static void main(String[] args)throws Exception {Properties properties = new Properties();//指定broker列表properties.setProperty("bootstrap.servers", "master:9092,node2:9092,node2:9092");//指定key和value的数据格式properties.setProperty("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");properties.setProperty("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");Producer<String, String> producer = new KafkaProducer<String, String>(properties);BufferedReader br = new BufferedReader(new FileReader("flink/data/students.csv"));String line =null;while ((line=br.readLine())!=null){//通过hash分区,hash分区就是将那个字段的hash值对分区数取余String clazz = line.split(",")[4];int partition = Math.abs(clazz.hashCode()) % 3;//kafka-topics.sh --create --zookeeper master:2181,node1:2181,node2:2181/kafka --replication-factor 2 --partitions 3 --topic students_hash//ProducerRecord(String topic, Integer partition, K key, V value)producer.send(new ProducerRecord<>("students_hash",partition,null,line));producer.flush();}br.close();producer.close();}
}

4.2 consume

1. 先需要创建Properties对象,并设置broker列表,kv的数据类型,读取的方式,以及指定消费者组

其中的earliest是全局消费,latest是提交一次offset消费一次,如果不指定,默认是latest

Properties properties = new Properties();//kafka 集群列表properties.setProperty("bootstrap.servers", "master:9092,node2:9092,node2:9092");//读取数据的格式properties.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");properties.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");/** earliest* 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费* latest  默认* 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产认值生的该分区下的数据* none* topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常**/properties.setProperty("auto.offset.reset", "earliest");//指定消费者组,一条数据在一个组内只消费一次properties.setProperty("group.id", "asdsada");

2.创建KafkaConsume对象,泛型是上面kv的数据类型,里面传入Properties的对象

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);

3.订阅topic,封装成一个集合。再使用KafkaConsume对象的subscribe方法,里面传入的是集合

        //订阅topicArrayList<String> topics = new ArrayList<>();topics.add("students");//subscribe方法里面传的是一个集合,所以要把topic封装成一个集合对象consumer.subscribe(topics);

4.设置消费的间隔时间,获取一个迭代器

        ConsumerRecords<String, String> consumerRecords = consumer.poll(1000);

5.遍历迭代器获取里面的元素,包括topic,partition,offset,value,timestamp等等

 for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {String topic = consumerRecord.topic();int partition = consumerRecord.partition();long offset = consumerRecord.offset();String value = consumerRecord.value();long timestamp = consumerRecord.timestamp();System.out.println(topic + "\t" + offset + "\t" + partition + "\t" + value + "\t" + timestamp);}

6.一般一组只能取500个,想获取完要么改分组名,要么改成死循环,让他一直消费,只要有数据产生,就能一直消费

7.一直取的代码

package com.shujia.kafka;import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;import java.util.ArrayList;
import java.util.Properties;public class Demo3Consumer {public static void main(String[] args) {Properties properties = new Properties();//kafka 集群列表properties.setProperty("bootstrap.servers", "master:9092,node2:9092,node2:9092");//读取数据的格式properties.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");properties.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");/** earliest* 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费* latest  默认* 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产认值生的该分区下的数据* none* topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常**/properties.setProperty("auto.offset.reset", "earliest");//指定消费者组,一条数据在一个组内只消费一次properties.setProperty("group.id", "asdsada");//创建消费者KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);//订阅topicArrayList<String> topics = new ArrayList<>();topics.add("students");//subscribe方法里面传的是一个集合,所以要把topic封装成一个集合对象consumer.subscribe(topics);while (true){ConsumerRecords<String, String> consumerRecords = consumer.poll(1000);for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {String topic = consumerRecord.topic();int partition = consumerRecord.partition();long offset = consumerRecord.offset();String value = consumerRecord.value();long timestamp = consumerRecord.timestamp();System.out.println(topic + "\t" + offset + "\t" + partition + "\t" + value + "\t" + timestamp);}}}
}

五 Flink On Kafka

5.1 kafka source

1.见代码

package com.shujia.flink.kafka;import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.connector.kafka.source.KafkaSource;
import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;public class Demo1KafkaSource {public static void main(String[] args) throws Exception {StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();//创建kafka sourceKafkaSource<String> source = KafkaSource.<String>builder().setBootstrapServers("master:9092,node1:9092,node2:9092")//kafka集群列表.setTopics("students")//指定消费的topic// 从消费组提交的位点开始消费,如果提交位点不存在,使用最早位点//.setStartingOffsets(OffsetsInitializer.committedOffsets(OffsetResetStrategy.EARLIEST))// 从最早位点开始消费//.setStartingOffsets(OffsetsInitializer.earliest())// 从最末尾位点开始消费
//                .setStartingOffsets(OffsetsInitializer.latest()).setStartingOffsets(OffsetsInitializer.earliest()).setValueOnlyDeserializer(new SimpleStringSchema())//指定读取数据的格式.build();//使用kafka sourceDataStreamSource<String> studentsDS = env.fromSource(source, WatermarkStrategy.noWatermarks(), "Kafka Source");studentsDS.print();env.execute();}
}

5.2 kafka sink

package com.shujia.flink.kafka;import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.connector.base.DeliveryGuarantee;
import org.apache.flink.connector.kafka.sink.KafkaRecordSerializationSchema;
import org.apache.flink.connector.kafka.sink.KafkaSink;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;public class Demo2KafkaSink {public static void main(String[] args) throws Exception{StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();DataStream<String> carsDS = env.readTextFile("flink/data/cars_sample.json");//创建kafka sinkKafkaSink<String> sink = KafkaSink.<String>builder().setBootstrapServers("master:9092,node1:9092,node2:9092")//kafka集群列表.setRecordSerializer(KafkaRecordSerializationSchema.builder().setTopic("cars")//指定topic.setValueSerializationSchema(new SimpleStringSchema())//指定数据格式.build())//指定数据处理的语义.setDeliverGuarantee(DeliveryGuarantee.AT_LEAST_ONCE).build();//使用kafka sinkcarsDS.sinkTo(sink);env.execute();}
}

5.3 代码打包到服务器运行

1.导入依赖,将flink-sql-connector-kafka-1.15.2.jar放到flink/lib目录下

2.执行命令随便选一个

flink run-application -t yarn-application -c com.shujia.flink.kafka.Demo3Cars flink-1.0.jar 
 

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

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

相关文章

【Spring Cloud Alibaba】开源组件Sentinel

目录 什么是Sentinel发展历史与Hystrix的异同 Sentinel可以做什么&#xff1f;Sentinel的功能Sentinel的开源生态Sentinel的用户安装Sentinel控制台预备环境准备Sentinel 分为两个部分:下载地址 项目集成Sentinel创建项目修改依赖信息添加启动注解添加配置信息在控制器类中新增…

一条sql的执行流程

文章地址 https://blog.csdn.net/qq_43618881/article/details/118657040 连接器 请求先走到连接器&#xff0c;与客户端建立连接、获取权限、维持和管理连接 mysql缓存池 如果要查找的数据直接在mysql缓存池里面就直接返回数据 分析器 请求已经建立了连接&#xff0c;现在…

MySql索引的数据结构

mysql索引是什么&#xff1f; 想象一下&#xff0c;你手上有一本数学教材&#xff0c;但是目录被别人给撕掉了&#xff0c;现在要你翻到三三角函数的那一页&#xff0c;该怎么办&#xff1f; 没有了目录&#xff0c;就只有两种方法&#xff0c;要么一页一页翻&#xff0c;要么…

反激电源的类型与特点

主要分为 1 固定频率&#xff08;CCMDCM&#xff09; 2 可变频率控制&#xff08;CRM电流临界模式&#xff09; 这三种模式是很好辨别的&#xff0c;首先我们看左边的连续模式&#xff0c;Vds能看到他有一些尖峰毛刺&#xff0c;这是场效应管关闭的时候&#xff0c;LRC谐振导…

合势而上 聚力成峰 |“我店平台616购物嘉年华发布会”圆满落幕

引言 合势而上&#xff0c;聚力成峰&#xff1b;我店力量&#xff0c;势如破竹。 6月2日&#xff0c;“合势而上聚力成峰——我店平台616购物嘉年华发布会”于杭州顺利举办。会上&#xff0c;我店平台董事长肖翰成携手公司一众高管&#xff0c;正式启动“我店平台616购物嘉年华…

Java中getBytes()方法

我以为旅人将我 热情都燃尽 —— 24.6.4 String.getBytes(String decode)方法会根据指定的decode编码返回某字符串在该编码下的byte数组表示 而与getBytes相对的&#xff0c;可以通过new String(byte[], decode)的方式来还原这个“深”字时&#xff0c;这个new String(byte[],…

屏幕录制工具分享6款,附上详细电脑录屏教程(2024全新)

当你即将参加一个重要的在线会议或一堂关键的直播课&#xff0c;但又担心错过关键点或无法及时做笔记时&#xff0c;屏幕录制无疑是最好的方法之一。屏幕录制是一项非常有价值的技能&#xff0c;它能让你出于各种目的捕捉屏幕上的活动。无论你的目的是创建教程、演示软件功能、…

HiveMetastore

HiveMetastore 背后的存储 select * from DBS; select * from TBLS; select * from TABLE_PARAMS; 查找出没有 totalSize stats 的table SELECT DBS.NAME,t.TBL_NAME from DBS inner join (select DB_ID,TBL_NAME from TBLS where TBLS.TBL_ID not in(select TBL_ID from T…

家里总是“飞尘、毛絮”多怎么办?用这个东西教你轻松解决难题

每次清洁家里卫生的时候&#xff0c;都会发现家里空气中飘浮着毛毛和灰尘&#xff0c;地板上、沙发套、床单被罩都是毛毛。明明每天清洁&#xff0c;为什么家里还有这么多“飞尘、毛絮”呢&#xff1f;如果不将这些“飞尘、毛絮”清洁干净&#xff0c;空气中的飞尘、毛絮进入我…

任务3.3 学生喂养三种宠物:猫、狗和鸟

本任务旨在通过Java面向对象编程中的多态性和方法重载概念&#xff0c;实现一个学生喂养三种不同宠物&#xff08;猫、狗、鸟&#xff09;的程序。 定义基类和派生类 创建一个Animal基类&#xff0c;包含所有动物共有的属性和方法&#xff0c;如name、age、speak()、move()和ea…

一篇文章讲透排序算法之归并排序

0.前言 本篇文章将详细解释归并排序的原理&#xff0c;以及递归和非递归的代码原理。 一.概念 归并排序是建立在归并操作上的一种有效的排序算法&#xff0c;该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使…

虚拟机Ubuntu 22.04上搭建GitLab操作步骤

GitLab是仓库管理系统&#xff0c;使用Git作为代码管理工具。GitLab提供了多个版本&#xff0c;包括社区版(Community Edition)和企业版(Enterprise Edition)。实际应用场景中要求CPU最小4核、内存最小8GB&#xff0c;非虚拟环境。 以下是在虚拟机中安装社区版步骤&#xff1a;…

git获取的项目无法运行

一、Unsupported engine 问题&#xff1a;在使用命令npm install下载依赖项的时候就遇到了这个问题&#xff0c;有帖子说多试几次&#xff0c;其实这是提示node版本问题&#xff0c;版本的更新出现兼容性问题&#xff0c;多试几次也没用。 解决方案&#xff1a; 更新node.js的…

Paper速读-[Visual Prompt Multi-Modal Tracking]-Dlut.edu-CVPR2023

文章目录 简介关于具体的思路问题描述算法细节实验结果模型的潜力模型结果 论文链接&#xff1a;Visual Prompt Multi-Modal Tracking 开源代码&#xff1a;Official implementation of ViPT 简介 这篇文章说了个什么事情呢&#xff0c;来咱们先看简单的介绍图 简单来说&…

【玩转C语言】第一讲--->C语言概念

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 引言&#xff1a; 1. C语言是什么 2. C语言的辉煌历史 3. 第一个C语言程序 4. main()函数 5. printf() 函数 6. 库函数 6.1 库函数概念 7. 关键字介绍 …

工具:一键采集 平台:TB+PDD+JD...

什么是数据集&#xff1f; 电商商品数据集通常是指收集自电子商务平台的商品信息的结构化数据集合。这些数据包括但不限于商品名称、价格、描述、用户评价、分类标签、卖家信息、销售量、库存量、图片链接等。数据集可以由电商平台公开提供&#xff0c;也可以通过网络爬虫等技术…

沟通技巧(Communication Skills 业务分析能力)

背景 业务分析的胜任力模型&#xff0c;有六大部分&#xff0c;今天我们看第二部分&#xff0c;业务知识 Analytical Thinking and Problem Solving &#xff1a;分析判断及问题解决能力Behavioural Characteristics&#xff1a; 行为特质&#xff08;责任、道德、适应性等等…

Kubernetes小记

Kubernetes 集群 架构 一个有效的 Kubernetes 部署称为集群&#xff0c;可以将 Kubernetes 集群分为两个部分&#xff1a;控制平面与计算设备&#xff08;或称为节点&#xff09;控制组件 控制平面 K8s 集群的神经中枢,负责处理重要的工作&#xff0c;以确保容器以足够的数量…

GCN 代码解析(一) for pytorch

Graph Convolutional Networks 代码详解 前言一、数据集介绍二、文件整体架构三、GCN代码详解3.1 utils 模块3.2 layers 模块3.3 models 模块3.4 模型的训练代码 总结 前言 在前文中&#xff0c;已经对图卷积神经网络&#xff08;Graph Convolutional Neural Networks, GCN&am…

小程序CI/CD之自动化打包预览并钉钉通知发布进程

小程序打包方式分为两种&#xff1a;手动打包、自动打包 那如何实现 自动打包 呐&#xff1f;我们今天就来聊一聊&#xff01; 首先&#xff0c;很重要&#xff0c;看 官方文档 这里提到今天我们要聊的“主角” miniprogram-ci miniprogram-ci 是从微信开发者工具中抽离的关于…