万字长文 | Apache SeaTunnel 分离集群模式部署 K8s 集群实践

文章作者:雷宝鑫

整理排版:白鲸开源 曾辉

Apache SeaTunnel官网链接: https://seatunnel.apache.org/

Apache SeaTunnel(以下简称SeaTunnel)是一款新一代高性能、分布式的数据集成同步工具,正受到业界广泛关注和应用。SeaTunnel支持三种部署模式:本地模式(Local)、混合集群模式(Hybrid Cluster Mode)和分离集群模式(Separated Cluster Mode)。

本文尝试介绍如何在K8s上以分离集群模式部署SeaTunnel,为有相关需求的伙伴提供完整的部署流程和配置案例参考。

前期准备

在开始部署之前,需要确保以下环境和组件已经准备就绪:

  • Kubernetes集群环境
  • kubectl命令行工具
  • docker
  • helm (option)

对于熟悉和具有Helm环境的部署,可以直接参考官网中使用Helm部署教程:

  • https://seatunnel.apache.org/docs/2.3.10/start-v2/kubernetes/helm
  • https://github.com/apache/seatunnel/tree/dev/deploy/kubernetes/seatunnel

本文主要介绍基于Kubernetes环境和kubectl工具的方式实现部署。

构建SeaTunnel Docker镜像

目前官方已提供各版本的Docker镜像,可直接拉取,详细信息可参考官方文档:Set Up With Docker

docker pull apache/seatunnel:<version_tag>

由于我们需要部署的是集群模式,接下来需要配置集群间的网络通信。SeaTunnel集群的网络服务是通过Hazelcast实现的,所以接下来对这部分内容进行配置。

Hazelcast集群相关配置

Headless Service配置

Hazelcast 集群是由运行 Hazelcast 的集群成员组成的网络,集群成员自动联合起来形成一个集群,这种自动加入是通过集群成员用于查找彼此的各种发现机制实现的。

Hazelcast 支持以下发现机制:

  • 自动发现机制,支持以下环境:
    • AWS
    • Azure
    • GCP
    • Kubernetes
  • TCP
  • Multicast
  • Eureka
  • Zookeeper

在本文的集群部署中,我们基于HazelcastKubernetes自动发现机制来配置文件,详细的原理可以参考官网文档:Kubernetes Auto Discovery。

Hazelcast的k8s自动发现机制(DNS Lookup mode)需要借助于k8s的Headless Service功能来实现。

Headless Service在查询服务域名时,会将域名解析为所有匹配PodIP地址列表,以此来实现Hazelcast集群成员互相发现彼此。

为此,首先我们创建K8s Headless Service服务:

# use for hazelcast cluster join
apiVersion: v1
kind: Service
metadata:name: seatunnel-cluster
spec:type: ClusterIPclusterIP: Noneselector:app.kubernetes.io/instance: seatunnel-cluster-appapp.kubernetes.io/version: 2.3.10ports:- port: 5801name: hazelcast

上述配置中的关键部分:

  • metadata.name: seatunnel-cluster: 服务名称,Hazelcast 客户端/节点将通过该名称发现集群
  • spec.clusterIP: None:关键配置,声明为 Headless Service,不分配虚拟 IP
  • spec.selector: 选择器匹配的 Pod 标签,包含相应标签的pod会被该Service识别和代理
  • spec.port:Hazelcast的暴露端口

同时,为了能从系统外部利用rest api访问集群,我们定义另一个Service来包含Master的节点pod

# use for access seatunnel from outside system via rest api
apiVersion: v1
kind: Service
metadata:name: seatunnel-cluster-master
spec:type: ClusterIPclusterIP: Noneselector:app.kubernetes.io/instance: seatunnel-cluster-appapp.kubernetes.io/version: 2.3.10app.kubernetes.io/name: seatunnel-cluster-masterapp.kubernetes.io/component: masterports:- port: 8080name: "master-port"targetPort: 8080protocol: TCP

定义好上述K8s的Service服务后,接下来根据Hazelcast的k8s发现机制来配置hazelcast-master.yamlhazelcast-worker.yaml文件。

Hazelcast master和worker的yaml配置

对于SeaTunnel分离集群模式来说,所有网络相关的配置都在hazelcast-master.yamlhazelcast-worker.yaml文件中。

hazelcast-master.yaml的配置如下所示:

hazelcast:cluster-name: seatunnel-clusternetwork:rest-api:enabled: trueendpoint-groups:CLUSTER_WRITE:enabled: trueDATA:enabled: truejoin:kubernetes:enabled: trueservice-dns: seatunnel-cluster.bigdata.svc.cluster.localservice-port: 5801port:auto-increment: falseport: 5801properties:hazelcast.invocation.max.retry.count: 20hazelcast.tcp.join.port.try.count: 30hazelcast.logging.type: log4j2hazelcast.operation.generic.thread.count: 50hazelcast.heartbeat.failuredetector.type: phi-accrualhazelcast.heartbeat.interval.seconds: 30hazelcast.max.no.heartbeat.seconds: 300hazelcast.heartbeat.phiaccrual.failuredetector.threshold: 15hazelcast.heartbeat.phiaccrual.failuredetector.sample.size: 200hazelcast.heartbeat.phiaccrual.failuredetector.min.std.dev.millis: 200

上述配置文件中的关键配置项如下:

cluster-name

该配置用于确定多个节点是否属于同一个集群,即只有相同cluster-name的节点才会属于同一个集群。如果两个节点之间的cluster-name名称不同,Hazelcast 将会拒绝服务请求。

网络配置
  • rest-api.enabled:在ST 2.3.10版本中Hazelcast REST 服务默认在配置中禁用,需要手动显式指定开启。
  • service-dns(必填):Headless Service 的完整域名,通常为 S E R V I C E − N A M E . {SERVICE-NAME}. SERVICENAME.{NAMESPACE}.svc.cluster.local。
  • service-port(可选):Hazelcast 端口;如果指定的值大于 0,则覆盖默认值(默认端口 = 5701)

使用上述基于k8s的join机制,在Hazelcast Pod启动时会解析service-dns,获取所有成员pod的IP列表(通过Headless Service),然后成员之间通过5801端口尝试建立TCP连接。

同样的,对于hazelcast-worker.yaml配置文件如下所示:

hazelcast:cluster-name: seatunnel-clusternetwork:rest-api:enabled: trueendpoint-groups:CLUSTER_WRITE:enabled: trueDATA:enabled: truejoin:kubernetes:enabled: trueservice-dns: seatunnel-cluster.bigdata.svc.cluster.localservice-port: 5801port:auto-increment: falseport: 5801properties:hazelcast.invocation.max.retry.count: 20hazelcast.tcp.join.port.try.count: 30hazelcast.logging.type: log4j2hazelcast.operation.generic.thread.count: 50hazelcast.heartbeat.failuredetector.type: phi-accrualhazelcast.heartbeat.interval.seconds: 30hazelcast.max.no.heartbeat.seconds: 300hazelcast.heartbeat.phiaccrual.failuredetector.threshold: 15hazelcast.heartbeat.phiaccrual.failuredetector.sample.size: 200hazelcast.heartbeat.phiaccrual.failuredetector.min.std.dev.millis: 200member-attributes:rule:type: stringvalue: worker

通过上述流程,我们就创建好了与Hazelcast集群相关的配置和服务,实现了Hazecast基于Kubernetes的集群成员发现。

接下来,继续完成有关SeaTunnel引擎的相关配置。

配置SeaTunnel引擎

SeaTunnel引擎的相关配置都在seatunnel.yaml文件中,下面给出seatunnel.yaml配置示例以供参考:

seatunnel:engine:history-job-expire-minutes: 1440backup-count: 1queue-type: blockingqueueprint-execution-info-interval: 60print-job-metrics-info-interval: 60classloader-cache-mode: truehttp:enable-http: trueport: 8080enable-dynamic-port: falseport-range: 100slot-service:dynamic-slot: truecheckpoint:interval: 300000timeout: 60000storage:type: hdfsmax-retained: 3plugin-config:namespace: /tmp/seatunnel/checkpoint_snapshotstorage.type: hdfsfs.defaultFS: hdfs://xxx:8020 # Ensure that the directory has written permissiontelemetry:metric:enabled: true

包含以下配置信息:

  • history-job-expire-minutes:任务历史记录保留时长为 24 小时(1440 分钟),超时自动清理。
  • backup-count: 1:任务状态备份副本数为 1。
  • queue-type: blockingqueue:使用阻塞队列管理任务,避免资源耗尽。
  • print-execution-info-interval: 60:每分钟打印一次任务执行状态。
  • print-job-metrics-info-interval: 60:每分钟输出一次任务指标(如吞吐量、延迟)。
  • classloader-cache-mode: true:启用类加载缓存,减少重复加载开销,提升性能。
  • dynamic-slot: true:允许根据负载动态调整任务槽(Slot)数量,优化资源利用率。
  • checkpoint.interval: 300000:每 5 分钟触发一次检查点(Checkpoint)。
  • checkpoint.timeout: 60000:检查点超时时间为 1 分钟。
  • telemetry.metric.enabled: true:启用任务运行指标采集(如延迟、吞吐量),便于监控。

创建k8s yaml文件部署应用

在完成上面的工作流程后,我们就可以进入到最后一步:创建Master和Worker节点的k8s yaml文件定义部署的相关配置。

为了将配置文件与应用程序解耦,我们将上文中列出的配置文件合并到一个ConfigMap中,并挂载到容器的配置路径下,便于对配置文件的统一管理和更新。

以下是针对 seatunnel-cluster-master.yamlseatunnel-cluster-worker.yaml 的配置示例,涵盖了配置 ConfigMap 挂载、容器启动命令以及部署资源定义等相关内容。

seatunnel-cluster-master.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:name: seatunnel-cluster-master
spec:replicas: 2  # modify replicas according to your casestrategy:type: RollingUpdaterollingUpdate:maxUnavailable: 25%maxSurge: 50%selector:matchLabels:app.kubernetes.io/instance: seatunnel-cluster-appapp.kubernetes.io/version: 2.3.10app.kubernetes.io/name: seatunnel-cluster-masterapp.kubernetes.io/component: mastertemplate:metadata:annotations:prometheus.io/path: /hazelcast/rest/instance/metricsprometheus.io/port: "5801"prometheus.io/scrape: "true"prometheus.io/role: "seatunnel-master"labels:app.kubernetes.io/instance: seatunnel-cluster-appapp.kubernetes.io/version: 2.3.10app.kubernetes.io/name: seatunnel-cluster-masterapp.kubernetes.io/component: masterspec:affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: nodeAffinity-keyoperator: Existscontainers:- name: seatunnel-masterimage: seatunnel:2.3.10imagePullPolicy: IfNotPresentports:- containerPort: 5801name: hazelcast- containerPort: 8080name: "master-port"command:- /opt/seatunnel/bin/seatunnel-cluster.sh- -r- masterresources:requests:cpu: "1"memory: 4GvolumeMounts:- mountPath: "/opt/seatunnel/config/hazelcast-master.yaml"name: seatunnel-configssubPath: hazelcast-master.yaml- mountPath: "/opt/seatunnel/config/hazelcast-worker.yaml"name: seatunnel-configssubPath: hazelcast-worker.yaml- mountPath: "/opt/seatunnel/config/seatunnel.yaml"name: seatunnel-configssubPath: seatunnel.yaml- mountPath: "/opt/seatunnel/config/hazelcast-client.yaml"name: seatunnel-configssubPath: hazelcast-client.yaml- mountPath: "/opt/seatunnel/config/log4j2_client.properties"name: seatunnel-configssubPath: log4j2_client.properties- mountPath: "/opt/seatunnel/config/log4j2.properties"name: seatunnel-configssubPath: log4j2.propertiesvolumes:- name: seatunnel-configsconfigMap:name: seatunnel-cluster-configs
部署策略
  • 采用多副本(replicas=2)部署确保服务高可用
  • 滚动更新策略(RollingUpdate)实现零停机部署:
    • maxUnavailable: 25%:保证更新期间至少75%的Pod保持运行
    • maxSurge: 50%:允许临时增加50%的Pod资源用于平滑过渡
标签选择器
  • 采用Kubernetes推荐的标准标签体系
  • spec.selector.matchLabels: 根据标签定义Deployment管理Pod的范围
  • spec.template.labels: 定义新创建Pod的标签,标识Pod的元数据。
节点亲和性
  • 配置affinity属性指定Pod调度的节点,需要根据自己k8s环境的节点标签进行替换。
配置文件挂载
  • 核心配置文件统一管理在ConfigMap中,便于管理以及与应用程序解耦
  • 通过subPath指定挂载的单个文件

seatunnel-cluster-worker.yaml配置文件如下:

apiVersion: apps/v1
kind: Deployment
metadata:name: seatunnel-cluster-worker
spec:replicas: 3  # modify replicas according to your casestrategy:type: RollingUpdaterollingUpdate:maxUnavailable: 25%maxSurge: 50%selector:matchLabels:app.kubernetes.io/instance: seatunnel-cluster-appapp.kubernetes.io/version: 2.3.10app.kubernetes.io/name: seatunnel-cluster-workerapp.kubernetes.io/component: workertemplate:metadata:annotations:prometheus.io/path: /hazelcast/rest/instance/metricsprometheus.io/port: "5801"prometheus.io/scrape: "true"prometheus.io/role: "seatunnel-worker"labels:app.kubernetes.io/instance: seatunnel-cluster-appapp.kubernetes.io/version: 2.3.10app.kubernetes.io/name: seatunnel-cluster-workerapp.kubernetes.io/component: workerspec:affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: nodeAffinity-keyoperator: Existscontainers:- name: seatunnel-workerimage: seatunnel:2.3.10imagePullPolicy: IfNotPresentports:- containerPort: 5801name: hazelcastcommand:- /opt/seatunnel/bin/seatunnel-cluster.sh- -r- workerresources:requests:cpu: "1"memory: 10GvolumeMounts:- mountPath: "/opt/seatunnel/config/hazelcast-master.yaml"name: seatunnel-configssubPath: hazelcast-master.yaml- mountPath: "/opt/seatunnel/config/hazelcast-worker.yaml"name: seatunnel-configssubPath: hazelcast-worker.yaml- mountPath: "/opt/seatunnel/config/seatunnel.yaml"name: seatunnel-configssubPath: seatunnel.yaml- mountPath: "/opt/seatunnel/config/hazelcast-client.yaml"name: seatunnel-configssubPath: hazelcast-client.yaml- mountPath: "/opt/seatunnel/config/log4j2_client.properties"name: seatunnel-configssubPath: log4j2_client.properties- mountPath: "/opt/seatunnel/config/log4j2.properties"name: seatunnel-configssubPath: log4j2.propertiesvolumes:- name: seatunnel-configsconfigMap:name: seatunnel-cluster-configs

定义好上述master和worker的yaml文件后,就可以执行以下命令进行部署到k8s集群了:

kubectl apply -f seatunnel-cluster-master.yaml
kubectl apply -f seatunnel-cluster-worker.yaml

正常情况下会看到SeaTunnel集群中共有2个master节点和3个worker节点:

$ kubectl get pods | grep seatunnel-clusterseatunnel-cluster-master-6989898f66-6fjz8                        1/1     Running                0          156m
seatunnel-cluster-master-6989898f66-hbtdn                        1/1     Running                0          155m
seatunnel-cluster-worker-87fb469f7-5c96x                         1/1     Running                0          156m
seatunnel-cluster-worker-87fb469f7-7kt2h                         1/1     Running                0          155m
seatunnel-cluster-worker-87fb469f7-drm9r                         1/1     Running                0          156m

至此,我们已成功在Kubernetes环境中以分离集群模式部署了SeaTunnel集群。

如今,集群已就绪,如何在客户端向其提交任务呢?

客户端提交任务到集群

使用命令行工具提交任务

有关SeaTunnel客户端的配置都在hazelcast-client.yaml文件中。

首先需要在客户端本地下载二进制安装包(包含bin、config文件),并保证SeaTunnel的安装路径与服务端一致,这也就是官网中所说的:Setting the SEATUNNEL_HOME the same as the server,否则,可能会导致出现诸如无法在服务器端找到连接器插件路径等错误(因为服务端插件路径与客户端路径不一致)。

进入安装路径下,只需要修改config/hazelcast-client.yaml文件,配置指向刚刚创建的Headless Service服务地址即可:

hazelcast-client:cluster-name: seatunnel-clusterproperties:hazelcast.logging.type: log4j2connection-strategy:connection-retry:cluster-connect-timeout-millis: 3000network:cluster-members:- seatunnel-cluster.bigdata.svc.cluster.local:5801

客户端配置完成后,即可将任务提交至集群执行。任务提交时的JVM参数配置方式主要有两种:

  • config/jvm_client_options文件中配置任务提交时的JVM参数

    此方法配置的JVM参数将应用于所有通过seatunnel.sh提交的任务,无论运行于本地模式还是集群模式。所有提交的任务都将共享相同的JVM参数配置。

  • 在提交任务的命令行中指定JVM参数。

    使用seatunnel.sh提交任务时,可在命令行中直接指定JVM参数,例如:sh bin/seatunnel.sh --config $SEATUNNEL_HOME/config/v2.batch.config.template -DJvmOption=-Xms2G -Xmx2G。此方法允许为每个提交的任务独立配置JVM参数。

接下来通过一个案例来演示客户端提交任务至集群执行的完整流程:

env {parallelism = 2job.mode = "STREAMING"checkpoint.interval = 2000
}source {FakeSource {parallelism = 2plugin_output = "fake"row.num = 16schema = {fields {name = "string"age = "int"}}}
}sink {Console {}
}

在客户端使用以下命令提交任务:

sh bin/seatunnel.sh --config config/v2.streaming.example.template -m cluster -n st.example.template -DJvmOption="-Xms2G -Xmx2G"

在Master节点,使用如下命令列出正在运行的任务列表:

$ sh bin/seatunnel.sh -lJob ID              Job Name             Job Status  Submit Time              Finished Time            
------------------  -------------------  ----------  -----------------------  -----------------------  
964354250769432580  st.example.template  RUNNING     2025-04-15 10:39:30.588  

可以看到,我们刚刚向集群中提交的st.example.template任务已经处于RUNNING状态了。现在我们可以在Worker节点日志中看到如下日志打印:

2025-04-15 10:34:41,998 INFO  [.a.s.c.s.c.s.ConsoleSinkWriter] [st-multi-table-sink-writer-1] - subtaskIndex=0  rowIndex=1:  SeaTunnelRow#tableId=fake SeaTunnelRow#kind=INSERT : bdaUB, 110348049
2025-04-15 10:34:41,998 INFO  [.a.s.c.s.c.s.ConsoleSinkWriter] [st-multi-table-sink-writer-1] - subtaskIndex=1  rowIndex=1:  SeaTunnelRow#tableId=fake SeaTunnelRow#kind=INSERT : mOifY, 1974539087
2025-04-15 10:34:41,999 INFO  [.a.s.c.s.c.s.ConsoleSinkWriter] [st-multi-table-sink-writer-1] - subtaskIndex=0  rowIndex=2:  SeaTunnelRow#tableId=fake SeaTunnelRow#kind=INSERT : jKFrR, 1828047742
2025-04-15 10:34:41,999 INFO  [.a.s.c.s.c.s.ConsoleSinkWriter] [st-multi-table-sink-writer-1] - subtaskIndex=1  rowIndex=2:  SeaTunnelRow#tableId=fake SeaTunnelRow#kind=INSERT : gDiqR, 1177544796
2025-04-15 10:34:41,999 INFO  [.a.s.c.s.c.s.ConsoleSinkWriter] [st-multi-table-sink-writer-1] - subtaskIndex=0  rowIndex=3:  SeaTunnelRow#tableId=fake SeaTunnelRow#kind=INSERT : bCVxc, 909343602
...

说明我们的任务成功提交至所创建的SeaTunnel集群,并且确认其正常运行。

使用Rest Api接口提交任务

SeaTunnel提供了通过Rest Api接口的方式来查询运行作业的状态和统计信息,以及提交/停止作业等操作。

在上文中我们配置了只包含Master节点的Headless Service,并指定暴露的端口为8080。因此,我们就可以在客户端使用Rest API接口的方式来实现任务的提交。

SeaTunnel Rest API接口提供了通过上传配置文件来提交任务,命令如下:

 $ curl 'http://seatunnel-cluster-master.bigdata.svc.cluster.local:8080/submit-job/upload' --form 'config_file=@"/opt/seatunnel/config/v2.streaming.example.template"' --form 'jobName=st.example.template'{"jobId":"964553575034257409","jobName":"st.example.template"}

如果作业提交成功,会返回jobIdjobName,如上所示。

接下来,通过Rest API接口获取集群正在运行的所有任务,观察刚刚提交的任务信息:

curl 'http://seatunnel-cluster-master.bigdata.svc.colo.gzgalocal:8080/running-jobs'
[{"jobId":"964553575034257409","jobName":"st.example.template","jobStatus":"RUNNING","envOptions":{"job.mode":"STREAMING","checkpoint.interval":"2000","parallelism":"2"}, ...]

可以看到接口返回显示了任务状态和其他额外的元数据信息,说明我们通过Rest Api接口提交任务的方式也成功执行。更多Rest Api接口介绍可以参考官网:RESTful API V2

总结

本文着重介绍了如何以推荐的分离集群模式(Separated Cluster Mode)部署k8s集群的实践,总结下来,部署过程主要包含以下步骤:

  1. 准备 Kubernetes 环境

    确保已搭建并运行一个可用的 Kubernetes 集群,并安装所有必要的组件。

  2. 构建 SeaTunnel Docker 镜像

    如果没有二次开发需求,可直接使用官方提供的镜像。否则,在本地编译打包后,编写 Dockerfile 并构建 SeaTunnel 镜像。

  3. 配置Headless Service和Hazelcast集群

    Hazelcast的k8s自动发现机制的DNS Lookup模式是基于k8s的Headless Service功能来实现的,因此首先创建Headless Service服务,并在hazelcast的yaml配置文件中通过service-dns来指定服务地址。

    Headless Service会在域名解析时解析成所包含pod的IP地址集合,以此实现hazelcast集群成员之间的彼此发现。

  4. 配置 SeaTunnel 引擎

    修改seatunnel.yaml文件,配置SeaTunnel引擎参数。

  5. 创建k8s yaml部署文件

    分别创建Master和Worker的k8s yaml文件,配置节点标签、启动命令、资源和数据卷挂载等内容,最终将其部署到k8s集群。

  6. 配置 SeaTunnel 客户端

    在客户端安装SeaTunnel,并确保客户端的安装路径 (SEATUNNEL_HOME) 与服务端一致。修改 hazelcast-client.yaml 文件,配置客户端连接到集群Service服务的地址。

  7. 任务提交与执行:

    完成以上步骤后,即可在客户端提交任务并由 SeaTunnel 集群执行。

本文上述配置案例仅供参考,可能仍有很多配置项和配置内容未涉及,欢迎各位补充与讨论,希望有各位有所帮助!

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

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

相关文章

深入解析YOLO v1:实时目标检测的开山之作

目录 YOLO v1 算法详解​ ​1. 核心思想​ ​2. 算法优势​ ​3. 网络结构&#xff08;Unified Detection&#xff09;​​ ​4. 关键创新​ ​5. 结构示意图&#xff08;Fig1&#xff09;​ Confidence Score 的计算​ 类别概率与 Bounding Box 的关系​ 后处理&…

信令与流程分析

WebRTC是h5支持的重要特征之一&#xff0c;有了它&#xff0c;不再需要借助音视频相关的客户端&#xff0c;直接通过浏览器的Web页面就可以实现音视频聊天功能。 WebRTC项目是开源的&#xff0c;我们可以借助WebRTC&#xff0c;构建自己的音视频聊缇娜功能。无论是前端JS的Web…

BIOS主板(非UEFI)安装fedora42的方法

BIOS主板(非UEFI)安装fedora42的方法 现实困难&#xff1a;将Fedora-Workstation-Live-42-1.1.x86_64.iso写入U盘制作成可启动U盘启动fedora42&#xff0c;按照向导将fedora42安装到真机的sda7分区中得到报错如下内容&#xff1a; /boot/efi 必需的 /boot/efi必须位于格式化为e…

安卓 Compose 相对传统 View 的优势

安卓 Compose 相对传统 View 的优势 文章目录 安卓 Compose 相对传统 View 的优势1. 引言2. 核心概念&#xff1a;Compose的革新性设计2.1 Jetpack Compose2.2 传统安卓View系统 3. 开发体验&#xff1a;Compose大幅提升效率3.1 使用Jetpack Compose构建UI3.2 使用传统View系统…

SIEMENS PLC 程序 GRAPH 程序解读 车型入库

1、程序载图1 2、程序截图2 3、程序解释 这是一个基于西门子 GRAPH 编程的车型 1 入库顺序控制流程图&#xff0c;通过状态机结构&#xff08;状态框 S 与转移条件 T&#xff09;描述完整工作流程&#xff0c;具体如下&#xff1a; 整体流程概述 初始化&#xff1a;从 S1&am…

VuePress可以做什么?

VuePress 可以做什么 VuePress 是一个基于 Vue.js 的静态站点生成器,专注于文档和内容展示。它结合了 Markdown 的简洁性和 Vue 的灵活性,适合多种场景的开发需求。以下是 VuePress 的主要用途和功能: 1. 技术文档网站 VuePress 最初是为编写 Vue.js 官方文档而设计的,因…

架构-系统可靠性分析与设计

一、可靠性相关基本概念 1. 可靠性与可用性 可靠性&#xff1a;软件系统在遇到错误、意外操作或系统故障时&#xff0c;仍能维持自身功能特性的能力。 举例&#xff1a;手机银行APP在用户误操作&#xff08;如快速点击多次转账&#xff09;时&#xff0c;仍能正确处理交易并避…

再谈String

1、字符串常量池 1.1 创建对象的思考 下面是两种创建字符串对象的代码 public static void main1(String[] args) {String s1 "hello";String s2 "hello";System.out.println(s1 s2);//trueString s3 new String("hello");String s4 new …

《深入浅出ProtoBuf:从环境搭建到高效数据序列化》​

ProtoBuf详解 1、初识ProtoBuf2、安装ProtoBuf2.1、ProtoBuf在Windows下的安装2.2、ProtoBuf在Linux下的安装 3、快速上手——通讯录V1.03.1、步骤1&#xff1a;创建.proto文件3.2、步骤2&#xff1a;编译contacts.proto文件&#xff0c;生成C文件3.3、步骤3&#xff1a;序列化…

基于PHP+Uniapp的互联网医院源码:电子处方功能落地方案

随着“互联网医疗”政策红利持续释放&#xff0c;互联网医院已成为推动医疗数字化转型的重要方向。在这一趋势下&#xff0c;电子处方功能模块作为核心环节&#xff0c;不仅直接关系到线上问诊闭环的实现&#xff0c;也成为系统开发中技术难度较高、业务逻辑最为复杂的一部分。…

ARM Cortex-M (STM32)如何调试HardFault

目录 步骤 1: 实现一个有效的 HardFault 处理程序 步骤 2: 复现 HardFault 并使用调试器分析 步骤 3: 解读故障信息 步骤 4: 定位并修复源代码 HardFault 是 ARM Cortex-M 处理器中的一种异常。当处理器遇到无法处理的错误&#xff0c;或者配置为处理特定类型错误&#xff…

基于归纳共形预测的大型视觉-语言模型中预测集的**数据驱动校准**

摘要 本研究通过分离共形预测&#xff08;SCP&#xff09;框架&#xff0c;解决了大型视觉语言模型&#xff08;LVLMs&#xff09;在视觉问答&#xff08;VQA&#xff09;任务中幻觉缓解的关键挑战。虽然LVLMs在多模态推理方面表现出色&#xff0c;但它们的输出常常表现出具有…

LangChain4j 搭配 Kotlin:以协程、流式交互赋能语言模型开发

Kotlin 支持 | LangChain4j Kotlin 是一种面向 JVM&#xff08;及其他平台&#xff09;的静态类型语言&#xff0c;能够实现简洁优雅的代码&#xff0c;并与 Java 库无缝互操作。 LangChain4j 利用 Kotlin 扩展和类型安全构建器来增强 Java API&#xff0c;为其增添特定于 Ko…

正大模型视角下的市场结构判断逻辑

正大模型视角下的市场结构判断逻辑 在多数交易策略中&#xff0c;结构识别往往先于方向判断。以正大的数据研判风格为例&#xff0c;其核心逻辑是&#xff1a;价格行为不能孤立解读&#xff0c;必须结合时间与成交效率来判断当前结构的有效性。 例如&#xff0c;一个上涨过程&…

Django 入门实战:从环境搭建到构建你的第一个 Web 应用

Django 入门实战&#xff1a;从环境搭建到构建你的第一个 Web 应用 恭喜你选择 Django 作为你学习 Python Web 开发的起点&#xff01;Django 是一个强大、成熟且功能齐全的框架&#xff0c;非常适合构建中大型的 Web 应用程序。本篇将通过一个简单的例子&#xff0c;带你走完…

Unity 打包后 无阴影 阴影不显示

在项目设置里面->质量 这里面显示的是打包之后的质量 PS:注意运行质量 点击左键选择运行质量,这俩不一致就会导致,运行有阴影但是打包出来的平台没有阴影,原因就在这. 质量等级选择好之后 往下滑,在这里打开阴影,如果距离过远不显示阴影,就增加阴影距离.

python——面向对象编程

一、编程思想 面向过程编程&#xff08;典型&#xff1a;c语言&#xff09;&#xff1a;是一种以过程为中心的编程思想。它强调流程化、线性化、步骤化的思考方式&#xff0c;实现思路就是函数。 面向对象编程&#xff1a;强调整体性和差异性。它将任何事物看做一个统一整个&…

宿主机和容器 ping 不通域名解决方法

目录 一、问题描述 二、宿主机解决方法 三、容器解决办法 一、问题描述 宿主机是Ubuntu&#xff0c;在宿主机上 ping 不通域名&#xff1a;xxxx.cn&#xff0c;但是个人电脑能 ping 通。 同时宿主机上的启动的k8s容器也无法ping通。 二、宿主机解决方法 ①编辑文件&#xff…

windows作业job介绍

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、作业job是什么&#xff1f;二、使用步骤1.代码示例 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; winapi网站&#xff1a; h…

ESG跨境电商如何为国内的跨境电商企业打开国外的市场

现在不管是国内还是国外&#xff0c;做电商的企业都非常的多&#xff0c;那么既然有这么多大电商公司&#xff0c;就要有为这些电商公司提供服务的公司&#xff0c;这就是ESG&#xff0c;它是专门为跨境电商服务的公司&#xff0c;那么这家公司的主要业务是什么呢&#xff1f;它…