k8s工作负载控制器--Statefulset

news2024/11/23 1:56:11

文章目录

  • 一、概述
  • 二、引入"有状态"需求
    • 1、管理无状态服务的 Deployment 实现了什么
      • 1.1、创建 Deployment
      • 1.2、验证 Pod 数量
      • 1.3、配置更新策略(更新镜像版本)
      • 1.4、观察更新过程
      • 1.5、验证更新后 Pod 的状态
      • 1.6、回滚 Deployment
    • 2、新需求分析
  • 三、StatefulSet:面向有状态应用管理的控制器
    • 1、创建 Service、Statefulset
    • 2、Service、StatefulSet 状态
    • 3、Pod、PVC 状态
    • 4、Pod 的版本控制
    • 5、更新镜像
    • 6、查看新版本的状态
    • 7、如何查看 Pod 是否复用了之前的网络标识
    • 8、如何查看 Pod 是否复用了之前的存储盘
  • 四、架构设计
    • 1、管理模式
      • 1.1、ControllerRevision
      • 1.2、PVC
      • 1.3、Pod
    • 2、OwnerReference
      • 2.1、删除 StatefulSet
    • 3、StatefulSet 控制器工作流程
    • 4、扩容能力
    • 5、扩缩容管理策略
    • 6、发布模拟
  • 五、字段分析
    • 1、spec 字段解析
    • 2、升级策略字段解析

一、概述

StatefulSet 是 Kubernetes 中用于管理有状态应用程序的工作负载资源对象。它提供了一种管理有状态服务的方式,确保每个 Pod 都有一个唯一的、持久的身份,并支持持久化存储。它在 Kubernetes v1.9 版本中成为 GA 版本。StatefulSet 设计用于管理和部署有状态服务,其管理的 Pod 拥有固定的名称(通常是 - 形式)和有序的启动和停止顺序。

StatefulSet 中,Pod 名称可以用作网络标识符,并且通常与 Headless Service 结合使用。Headless Service 没有 Cluster IP,直接暴露 Pod 的 IP 地址或 DNS 名称。解析 Headless Service 的名称时,会返回所有 Pod 的 IP 地址或 DNS 名称。

此外,StatefulSet 在 Headless Service 的基础上为每个 Pod 创建了一个 DNS 域名,这些域名通常形如 ...svc.cluster.local。

StatefulSet 支持持久化存储,它可以使用多种持久化存储类型,包括本地存储、网络文件系统(NFS)等。

二、引入"有状态"需求

1、管理无状态服务的 Deployment 实现了什么

10400250317bt89glg2001gnmnc

首先它支持定义一组 Pod 的期望数量,Controller 会为我们维持 Pod 的数量在期望的版本以及期望的数量;

第二它支持配置 Pod 发布方式,配置完成后 Controller 会按照我们给出的策略来更新 Pod,同时在更新的过程中,也会保证不可用 Pod 数量在我们定义的范围内;

第三,如果我们在发布的过程中遇到问题,Deployment 也支持一键来回滚。

简单来说,**Deployment 认为:它管理的所有相同版本的 Pod 都是一模一样的副本。**也就是说,在 Deployment Controller 看来,所有相同版本的 Pod,不管是里面部署的应用还是行为,都是完全相同的。

1.1、创建 Deployment

cat >> web-app.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
      annotations:
        deployment.kubernetes.io/revision: "1"
    spec:
      containers:
      - name: web-server
        image: nginx:1.15.0
        ports:
        - containerPort: 80
EOF
kubectl apply -f web-app.yaml --record=true

1.2、验证 Pod 数量

通过 Deployment 控制器,我们可以验证 Pod 的数量是否维持在期望的数量(3 个)。

kubectl get pods -l app=web-app

img

1.3、配置更新策略(更新镜像版本)

kubectl set image deploy web-app web-server=nginx:1.16.0 --record=true

1.4、观察更新过程

kubectl rollout status deploy web-app

img

1.5、验证更新后 Pod 的状态

kubectl get pods -l app=web-app -o custom-columns='NAME:.metadata.name,IMAGE:.spec.containers[*].image,STATUS:.status.phase'

img

1.6、回滚 Deployment

以下就是回滚到指定版本的流程:

查看历史版本信息 --> 查看指定版本详细信息 --> 回滚到指定版本 --> 验证信息

kubectl rollout history deploy web-app

kubectl rollout history deploy web-app --revision=1

kubectl rollout undo deploy web-app --to-revision=1

kubectl get pods -l app=web-app -o custom-columns='NAME:.metadata.name,IMAGE:.spec.containers[*].image,STATUS:.status.phase'

img

以上就是管理无状态服务的 Deployment 实现了什么功能展示


2、新需求分析

以下需求来自于一些有状态应用:

  • Pod 之间并非相同的副本,每一个 Pod 都有一个独立标识
  • Pod 独立标识要能够对应到一个固定的网络标识,并在发布升级后继续保持
  • 每一个 Pod 有一块独立的存储盘,并在发布升级后还能继续挂载原有的盘(保留数据)

这些有状态应用的需求都是 Deploment 无法满足的,因此引入了管理有状态应用的 StatefulSet

三、StatefulSet:面向有状态应用管理的控制器

img

  • 首先,每个 Pod 会有 Order 序号,会按照序号来创建,删除和更新 Pod;
  • 其次,通过配置一个 headless Service,使每个 Pod 有一个唯一的网络标识 (hostname);
  • 第三,通过配置 pvc 模板,就是 pvc template,使每个 Pod 有一块或者多块 pv 存储盘;
  • 最后,支持一定数量的灰度发布。比如现在有三个副本的 StatefulSet,我们可以指定只升级其中的一个或者两个,更甚至是三个到新版本。通过这样的方式,来达到灰度升级的目的。

1、创建 Service、Statefulset

cat >>service-nginx.yaml << EOF
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  clusterIP: None
  ports:
    - name: web
      port: 80
  selector:
    app: nginx
EOF

这是一个 Service 的配置,我们通过配置 headless Service,其实想要达到的目标是:期望 StatefulSet 里面的 Pod 有独立的网络标识。这里的 Service name 叫 nginx。

cat >> nginx-web.yaml << EOF
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nginx-web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.0
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www-storage
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www-storage
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi
EOF

这是一个 StatefulSet 的配置,在 spec 中有个 serviceName 也叫 nginx。通过这个 serviceName 来指定这个 StatefulSet 要对应哪一个 Service

这个 spec 中还定义了 selectortemplateselector 是一个标签选择器,selector 定义的标签选择逻辑,必须匹配 templatemetadatalabels 包含 app: nginx。在 template 中定义一个 nginx container,这个 container 用的 image 版本是 1.16.0 版本,对外暴露的 80 端口作为一个 web 服务。

最后,template.spec 里面定义了一个 volumeMounts,这个 volumeMounts 并不是来源于 spec 中的一个 Volumes,而是来自于 volumeClaimTemplates,也就是 pvc 模板。我们在 pvc 模板中定义了一个叫 www-storage 的 pvc 名称。这个 pvc 名称,我们也会写到 volumeMounts 作为一个 volume name,挂载到 /usr/share/nginx/html 这个目录下。通过这样的方式来达到每个 Pod 都有独立的一个 pvc,并且挂载到容器中对应目录的一个需求。

kubectl apply -f service-nginx.yaml -f nginx-web.yaml

2、Service、StatefulSet 状态

kubectl get svc nginx
 
kubectl get endpoints nginx
 
kubectl get sts nginx-web

img

通过将上文中的两个对象创建之后,我们可以通过 get 命令可以看到 Service nginx 资源已经创建成功。

同时可以通过查看 endpoints 看到,这个后端已经注册了三个 IP 和端口,这三个 IP 对应了 Pod 的 IP,端口对应了之前 spec 中配置的 80 端口。

最后通过 get sts (StatefulSet 缩写) nginx-web。从结果可以看到有一列 READY,值为 3/3。分母 3 是 StatefulSet 中期望的数量,而分子 3 表示 Pod 已经达到期望 READY 的状态数量。

3、Pod、PVC 状态

kubectl get pods -l app=nginx
 
kubectl get pvc

img

通过 get pvc 可以看到 NAME 那一列名称,前缀为 www-storage,中间是 nginx-web,后缀是一个序号。通过分析可以知道 www-storagevolumeClaimTemplates 中定义的 name,中间为 StatefulSet 定义的 name,末尾的序号对应着 Pod 的序号,也就是三个 PVC 分别被三个 Pod 绑定。通过这样一种方式,达到不同的 Pod 享有不同的 PVC;PVC 也会绑定相应的一个 PV, 来达到不同的 Pod 绑定不同 PV 的目的。

4、Pod 的版本控制

不同于 Deployment 使用 ReplicaSet 来管理版本和维持副本数,StatefulSet controller 直接管理下属的 Pod ,而 Pod 中用一个 label 来标识版本

kubectl get pods -L controller-revision-hash

img

之前我们学到 Deployment 使用 ReplicaSet 来管理 Pod 的版本和所期望的 Pod 数量,但是在 StatefulSet 中,是由 StatefulSet Controller 来管理下属的 Pod,因此 StatefulSet 通过 Pod 的 label 来标识这个 Pod 所属的版本,这里叫 controller-revision-hash。这个 label 标识和 Deployment 以及 StatefulSet 在 Pod 中注入的 Pod template hash 是类似的。

如上图所示,通过 get pod 查看到 controller-revision-hash,这里的 hash 就是第一次创建 Pod 对应的 template 版本,可以看到后缀是6b558f6465。这里先记录一下,接下来会做 Pod 升级,再来看一下 controller-revision-hash 会不会发生改变。

5、更新镜像

img

kubectl set image statefulset nginx-web nginx=nginx:1.15.0

img

6、查看新版本的状态

kubectl get pods -L controller-revision-hash
 
kubectl get sts nginx-web -o json | jq '.status'

imgimg

通过 get pod 命令查询 Revision hash,可以看到三个 Pod 后面的 controller-revision-hash 都已经升级到了新的 Revision hash,后缀由6b558f6465 变成了 84d64959d6。通过这三个 Pod 创建的时间可以发现:序号为 2 的 Pod 创建的是最早的,之后是序号是 1 和 0。这表示在升级的过程中,真实的升级顺序为 2-1-0,通过这么一个倒序的顺序来逐渐把 Pod 升级为新版本,并且我们升级的 Pod,还复用了之前 Pod 使用的 PVC。所以之前在 PV 存储盘中的数据,仍然会挂载到新的 Pod 上。

通过在 StatefulSet 的 status 中看到的数据,这里有几个重要的字段:

  • currentReplica:表示当前版本的数量
  • currentRevision: 表示当前版本号
  • updateReplicas:表示新版本的数量
  • **updateRevision:**表示当前要更新的版本号

当然这里也能看到 currentReplicaupdateReplica,以及 currentRevisionupdateRevision 都是一样的,这就表示所有 Pod 已经升级到了所需要的版本。

7、如何查看 Pod 是否复用了之前的网络标识

其实 headless Service 配置的 hostname 只是和 Pod name 挂钩的,所以只要升级后的 Pod 名称和旧的 Pod 名称相同,那么就可以沿用之前 Pod 使用的网络标识。

8、如何查看 Pod 是否复用了之前的存储盘

kubectl get pvc

img

关于存储盘,可以查看 PVC 的状态,它们的创建时间一直没有改变,还是第一次创建 Pod 时的时间,所以现在升级后的 Pod 使用的还是旧 Pod 中使用的 PVC。

kubectl get pods nginx-web-0 -o yaml

img

或者可以查看其中的某一个 Pod,这个 Pod 里面同样有个声明的 volumes,这个 persistentVolumeClaim 里的名称 www-storage-nginx-web-0,对应着 PVC 列表中看到的序号为 0 的 PVC,之前是被旧的 Pod 所使用。升级过程中 Controller 删除旧 Pod,并且创建了一个同名的新 Pod,新的 Pod 仍然复用了旧 Pod 所使用的 PVC。

通过这种方式来达到升级前后,网络存储都能复用的目的。

四、架构设计

1、管理模式

StatefulSet 一般会创建三种类型的资源

1.1、ControllerRevision

通过这个资源,StatefulSet 可以很方便地管理不同版本的 template 模板。

kubectl get controllerrevision -l app=nginx
 
kubectl get pods -l app=nginx --show-labels

img

比如上面例子中的 container nginx,在创建之初拥有的第一个 template 版本,会创建一个对应的 ControllerRevision。而当修改了 image 版本之后,StatefulSet Controller 会创建一个新的 ControllerRevision,可以理解为每一个 ControllerRevision 对应了每一个版本的 Template,也对应了每一个版本的 ControllerRevision hash。其实在 Pod label 中定义的 ControllerRevision hash,就是 ControllerRevision 的名字。通过这个资源 StatefulSet Controller 来管理不同版本的 template 资源。

1.2、PVC

如果在 StatefulSet 中定义了 volumeClaimTemplates,StatefulSet 会在创建 Pod 之前,先根据这个模板创建 PVC,并把 PVC 加到 Pod volume 中。

如果用户在 spec 的 pvc 模板中定义了 volumeClaimTemplatesStatefulSet 在创建 Pod 之前,根据模板创建 PVC,并加到 Pod 对应的 volume 中。当然也可以在 spec 中不定义 pvc template,那么所创建出来的 Pod 就不会挂载单独的一个 pv。

1.3、Pod

StatefulSet 按照顺序创建、删除、更新 Pod,每个 Pod 有唯一的序号。

2、OwnerReference

StatefulSet Controller 是 Owned 三个资源:ControllerRevisionPodPVC

这里不同的地方在于,当前版本的 StatefulSet 只会在 ControllerRevisionPod 中添加 OwnerReference,而不会在 PVC 中添加 OwnerReference。拥有 OwnerReference 的资源,在管理的这个资源进行删除的默认情况下,会关联级联删除下属资源。因此默认情况下删除 StatefulSet 之后,StatefulSet 创建的 ControllerRevision 和 Pod 都会被删除,但是 PVC 因为没有写入 OwnerReference,PVC 并不会被级联删除。

10400250317c5m1qo0201ile94k

2.1、删除 StatefulSet

kubectl delete sts nginx-web
 
kubectl get pods -l app=nginx
 
kubectl get pvc
 
kubectl get controllerrevision -l app=nginx

img

可以看到由 StatefulSet 创建的 ControllerRevisionPod 均被删除,但是 PVC 未被删除

3、StatefulSet 控制器工作流程

10400250317c6hbpag202r992i0

首先通过注册 InformerEvent Handler(事件处理),来处理 StatefulSetPod 的变化。在 Controller 逻辑中,每一次收到 StatefulSet 或者是 Pod 的变化,都会找到对应的 StatefulSet 放到队列。紧接着从队列取出来处理后,先做的操作是 Update Revision,也就是先查看当前拿到的 StatefulSet 中的 template,有没有对应的 ControllerRevision。如果没有,说明 template 已经更新过,Controller 就会创建一个新版本的 Revision,也就有了一个新的 ControllerRevision hash 版本号。

然后 Controller 会把所有版本号拿出来,并且按照序号整理一遍。这个整理的过程中,如果发现有缺少的 Pod,它就会按照序号去创建,如果发现有多余的 Pod,就会按照序号去删除。当保证了 Pod 数量和 Pod 序号满足 Replica 数量之后,Controller 会去查看是否需要更新 Pod。也就是说这两步的区别在于,Manger pods in order 去查看所有的 Pod 是否满足序号;而后者 Update in order 查看 Pod 期望的版本是否符合要求,并且通过序号来更新。

Update in order 其更新过程如上图所示,其实这个过程比较简单,就是删除 Pod。删除 Pod 之后,其实是在下一次触发事件,Controller 拿到这个 success 之后会发现缺少 Pod,然后再从前一个步骤 Manger pod in order 中把新的 Pod 创建出来。在这之后 Controller 会做一次 Update status,也就是之前通过命令行看到的 status 信息。

通过整个这样的一个流程,StatefulSet 达到了管理有状态应用的能力。

4、扩容能力

10400250317c70sci02013q2ask

假设 StatefulSet 初始配置 replicas 为 1,有一个 Pod0。那么将 replicas 从 1 修改到 3 之后,其实我们是先创建 Pod1,默认情况是等待 Pod1 状态 READY 之后,再创建 Pod2。

通过上图可以看到每个 StatefulSet 下面的 Pod 都是从序号 0 开始创建的。因此一个 replicas 为 N 的 StatefulSet,它创建出来的 Pod 序号为 [0,N),也就是当 N>0 的时候,序号为 0 到 N-1。

5、扩缩容管理策略

StatefulSet.spec 中,有一个字段名为 podManagementPolicy ,可选策略为 OrderedReadyParallel,默认为前者

OrderedReady:扩缩容按照 order 顺序执行。扩容时,必须前面序号的 Pod 都 Ready 了才能扩下一个,缩容时按照倒序删除

Parallel:并行扩缩容,不需要等前面的 Pod Ready/删除后再处理下一个

上面创建的例子,没有在 spec 中定义 podMangementPolicy。那么 Controller 默认 OrderedReady 作为策略,然后在 OrderedReady 情况下,扩缩容就严格按照 Order 顺序来执行,必须要等前面的 Pod 状态为 Ready 之后,才能扩容下一个 Pod。在缩容的时候,倒序删除,序号从大到小进行删除。

img

在这个例子中,从 Pod0 扩容到 Pod0、Pod1、Pod2 的时候,必须先创建 Pod1,等 Pod1 Ready 之后再创建 Pod2。其实还存在一种可能性:比如在创建 Pod1 的时候,Pod0 因为某些原因,可能是宿主机的原因或者是应用本身的原因,Pod0 变成 NotReady 状态。这时 Controller 也不会创建 Pod2,所以不只是我们所创建 Pod 的前一个 Pod 要 Ready,而是前面所有的 Pod 都要 Ready 之后,才会创建下一个 Pod。上图中的例子,如果要创建 Pod2,那么 Pod0、Pod1 都要 ready。

6、发布模拟

10400250317ccbdls0205g16o2g

假设这里的 StatefulSet template1 对应逻辑上的 Revision1,这时 StatefulSet 下面的三个 Pod 都属于 Revision1 版本。在我们修改了 template,比如修改了镜像之后,Controller 是通过倒序的方式逐一升级 Pod。上图中可以看到 Controller 先创建了一个 Revision2,对应的就是创建了 ControllerRevision2 这么一个资源,并且将 ControllerRevision2 这个资源的 name 作为一个新的 Revision hash。在把 Pod2 升级为新版本后,逐一删除 Pod0、Pod1,再去创建 Pod0、Pod1。

它的逻辑其实很简单,在升级过程中 Controller 会把序号最大并且符合条件的 Pod 删除掉,那么删除之后在下一次 Controller 在做 reconcile 的时候,它会发现缺少这个序号的 Pod,然后再按照新版本把 Pod 创建出来。

五、字段分析

git clone git@github.com:kubernetes/kubernetes.git

1、spec 字段解析

img

  • Replica 主要是期望的数量;
  • Selector 是事件选择器,必须匹配 spec.template.metadata.labels 中定义的条件;
  • Template:Pod 模板,定义了所要创建的 Pod 的基础信息模板;
  • VolumeClaimTemplates:PVC 模板列表,如果在 spec 中定义了这个,PVC 会先于 Pod 模板 Template 进行创建。在 PVC 创建完成后,把创建出来的 PVC name 作为一个 volume 注入到根据 Template 创建出来的 Pod 中。

img

  • ServiceName:对应 Headless Service 的名字。当然如果有人不需要这个功能的时候,会给 Service 定一个不存在的 value,Controller 也不会去做校验,所以可以写一个 fake 的 ServiceName。但是这里推荐每一个 Service 都要配置一个 Headless Service,不管 StatefulSet 下面的 Pod 是否需要网络标识;
  • PodMangementPolicy:Pod 管理策略。前面提到过这个字段的可选策略为 OrderedReadyParallel,默认情况下为前者;
  • UpdataStrategy:Pod 升级策略。
  • RevisionHistoryLimit:保留历史 ControllerRevision 的数量限制(默认为 10)。需要注意的一点是,这里清楚的版本,必须没有相关的 Pod 对应这些版本,如果有 Pod 还在这个版本中,这个 ControllerRevision 是不能被删除的。

2、升级策略字段解析

img

可以看到 StatefulSetUpdateStrategy 有个 type 字段,这个 type 定义了两个类型:一个是 RollingUpdate;一个是 OnDelete

  • RollingUpdate 其实跟 Deployment 中的升级是有点类似的,就是根据滚动升级的方式来升级;
  • OnDelete 是在删除的时候升级,叫做禁止主动升级,Controller 并不会把存活的 Pod 做主动升级,而是通过 OnDelete 的方式。比如说当前有三个旧版本的 Pod,但是升级策略是 OnDelete,所以当更新 spec 中镜像的时候,Controller 并不会把三个 Pod 逐一升级为新版本,而是当我们缩小 Replica 的时候,Controller 会先把 Pod 删除掉,当我们下一次再进行扩容的时候,Controller 才会扩容出来新版本的 Pod。

RollingUpdateStatefulSetSetStrategy 中,可以看到有个字段叫 Partition。这个 Partition 表示滚动升级时,保留旧版本 Pod 的数量。不是灰度新版本的数量

举个例子:假设当前有个 replicas 为 10 的 StatefulSet,当我们更新版本的时候,如果 Partition 是 8,并不是表示要把 8 个 Pod 更新为新版本,而是表示需要保留 8 个 Pod 为旧版本,只更新 2 个新版本作为灰度。当 Replica 为 10 的时候,配置 Partition 为 8 的时候,其实还是保留 [0,8) 这 8 个 Pod 为旧版本,只有 [8,10) 进入新版本。

总结一下,假设 replicas=NPartition=M (M<N) ,则最终旧版本 Pod 为 [0,M) ,新版本 Pod 为 [M,N)。通过这样一个 Partition 的方式来达到灰度升级的目的,这是目前 Deployment 所不支持的。

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

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

相关文章

iptable 理解

iptable 理解 这个当初我理解不了&#xff0c;主要是没把netfilter理解清楚。 Netfilter是集成在内核中的&#xff0c;用来定义存储各种规则的。Iptalbe是修改这些规则的工具&#xff0c;修改后存在netfilter里面。 数据包进入LINUX服务器时&#xff0c;先进入服务器的netfilt…

Leetcode 72. 编辑距离 动态规划 优化 C++实现

Leetcode 72.编辑距离 问题&#xff1a;给你两个单词 word1 和 word2&#xff0c; 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作&#xff1a;插入一个字符&#xff0c;删除一个字符&#xff0c;替换一个字符。 算法1&#xff1a;递…

9-6springboot该如何学习

这阶段如何学习 javase&#xff1a;面向对象OOP mysql:持久化 htmlcssjsjquery框架&#xff1a;视图&#xff08;框架不熟练&#xff09;&#xff0c;css不好 javaweb&#xff1a;独立开发MVC三层架构的网站&#xff1a;原始 ssm&#xff1a;框架&#xff1a;简化了我们的…

【课程学习】信号检测与估计

文章目录 3.7-CRB延展到向量的形式3.8-参数变换形式的CRB CRB for transformation, pp45-463.9-高斯分布 CRLB for the General Gaussian Case3.7-CRB延展到向量的形式 0904 向量和变换形式的CRLB形式 估计参数真实值 θ \theta θ,估计值 θ ^ \hat \theta θ^ 与信号与系统…

AcWing算法基础课-786第k个数-Java题解

大家好&#xff0c;我是何未来&#xff0c;本篇文章给大家讲解《AcWing算法基础课》786 题——第 k 个数。本篇文章详细解析了如何使用 Java 实现快速排序算法&#xff0c;以解决查找数组中第 k 个元素的问题。通过深入浅出的讲解&#xff0c;展示了从输入读取到快速排序实现的…

Java程序打jar包(包含作者各种踩坑案例,力求为大家避雷)

一、诉求 将一个spring boot项目打包成一个jar包&#xff0c;直接在windows或者linux系统下直接命令行运行。 二、配置步骤 1、编写assembly.xml配置文件&#xff08;放在pom.xml同级目录&#xff09; <?xml version"1.0"?> <assembly><id>T…

GAN生成器好坏之评价方法

我们产生出来的生成器它好或者是不好。要 评估一个生成器的好坏&#xff0c;最直觉的做法也许是找人来看生成器产生出来的图片到底像不像真 实的图片。所以其实很长一段时间&#xff0c;尤其是人们刚开始研究生成式技术的时候&#xff0c;很长一段时间 没有好的评估方法。那时候…

群晖NAS安装(一)

主要教程参考 https://zhuanlan.zhihu.com/p/515187738?utm_id0&wd&eqide69f50bb0000263900000006645b5680 系统是DS3617xs DSM6.1.3 一 准备工作 旧16G U盘一个 软件: diskgenius 分区工具 win32diskimager 写入工具 chipeasy或者chipgenius 识别工具 二 安装 分区…

log4j2 与 log4j使用时的几点小区别 - log4j2上手说明

虽然log4j2 目前还是beta版&#xff0c;不过OneCoder已经忍不住要尝试一下。跟使用log4j 比起来&#xff0c;上手上主要的区别有。 1、依赖的jar包。使用slf4jlog4j2 时&#xff0c;依赖的jar包如下&#xff1a;( gradle配置&#xff0c;Maven对照修改即可) dependencies{ com…

SAP与湃睿PLM系统集成案例

一、项目背景 浙江某家用电机有限公司, 该公司的产品涵盖洗衣机、‌空调、‌冰箱及厨房用具等家电电机的制造&#xff0c;‌具备年产4600万台电机的生产能力&#xff0c;‌是中国最大的家电电机生产基地之一。 为确保工艺路线信息在设计与生产执行层面的无缝传递&#xff0…

python多进程

文章目录 1、前言2、示例3、参考 1、前言 python中使用多进程&#xff0c;可以加快代码的运行速度&#xff0c;更高效地进行相关工作。 2、示例 使用蒙特卡洛方法计算 π \pi π来进行使用多进程前后代码运行速率的对比&#xff1b; import random import multiprocessing as…

信也科技基于 Apache SeaTunnel金融场景的应用实践探索

前言 作者&#xff1a;朱俊&#xff0c;信也科技&#xff0c;数据开发专家 离线开发一直是数据仓库建设中重要的一个环节。信也科技之前基于Azkaban构建了离线任务调度与开发平台&#xff0c;承载了公司90%以上的离线任务调度需求&#xff0c;以及玄策变量平台的每日变量跑批产…

爵士编曲:如何编写爵士鼓

音源选取 使用ssd鼓写爵士乐&#xff0c;使用其中的豪华爵士音源&#xff0c;然后选其中的第一个或第二个都可以。 或者用add鼓studio drummer中的爵士鼓也可以 ​Cubase图示 用swing的律动把叮叮镲写上 然后第三拍加上踩镲

【截图服务 +打包】pkg打包 puppeteer

目录 最后结论 遇到的问题与解决 版本匹配问题 参考文档 最后结论 pkg -t win --public ./screenshots.js --output ./dist/screen.exe 服务启动&#xff1a; postman调用 &#xff1a; 遇到的问题与解决 版本匹配问题 pkg 这里说的是v3.5,实际装的是5.8.1&#xff0c;…

【ArcGIS Pro实操第二期】最小成本路径(Least-cost path)原理及实操案例

ArcGIS Pro实操第一期&#xff1a;最小成本路径原理及实操案例 概述&#xff08;Creating the least-cost path&#xff09;1.1 原理介绍1.2 实现步骤1.3 应用案例 2 GIS实操2.1 工具箱简介2.1.1 成本路径&#xff08;Cost path&#xff09;2.1.2 成本距离&#xff08;Cost dis…

Cesium 展示——格式化时间控件信息

文章目录 需求分析需求 如图,我们在 Cesium 初始化后如图一展示,展示的是UTC的时间,而且是英文,如何将该控件进行格式化一下,展示当前的北京时间呢?分析 初始化 Cesiumconst fetchData = () => {

【LabVIEW学习篇 - 20】:人机界面交互设计04

文章目录 声音播放自定义控件自定义控件创建过程演示 选项卡、子面板、分隔栏 声音播放 有时系统检测到某些事件发生时&#xff0c;需要通过声音去传递信息&#xff0c;因此播放声音也是一种重要的交互方式&#xff0c;如系统检测到异常报警时&#xff0c;需要放报警声音来通知…

flutter Image

Flutter中&#xff0c;Image是一个用于显示图片的控件&#xff0c;可以显示网络图片、本地图片以及Asset中的图片。Image控件支持多种常见的图片格式&#xff0c;例如PNG、JPEG、GIF等。 const Image({super.key,required this.image,this.frameBuilder,this.loadingBuilder,th…

用“黑科技”书写“黑神话” | 基于RK3576核心板的三维扫描仪应用方案

《黑神话&#xff1a;悟空》作为国内首款3A游戏大作&#xff0c;上线仅10天全球发行量就已超过1700万份&#xff0c;不论您是否是游戏玩家&#xff0c;相信您都能在各种新闻、宣传和活动中感受到这款游戏的热度。在游戏的众多亮点中&#xff0c;“细腻的场景设计与对名胜古迹的…

3个永不过时的妙招,恢复苹果手机视频不是问题

苹果手机的视频功能较为出色&#xff0c;使用苹果手机拍摄的视频更加真实、清晰&#xff0c;因此许多人会选择使用苹果手机来记录生活点滴。但是&#xff0c;如果我们不小心删除了苹果手机视频&#xff0c;有什么方法可以让这些“生活的回忆”重现呢&#xff1f;别担心&#xf…