当前位置: 首页 > news >正文

【云原生|Kubernetes】07-Pod健康检查和服务可用性检查

【云原生|Kubernetes】07-Pod健康检查和服务可用性检查

文章目录

  • 【云原生|Kubernetes】07-Pod健康检查和服务可用性检查
    • 前言
    • Pod探针
      • Liveness(Pod存活探针)
      • Readiness(Pod服务就绪探针)
      • Startup(启动探针)
    • 定义Liveness存活探针
      • EXec探针
      • HTTP探针
      • TCP探针
      • gRPC探针
      • 使用命名端口
    • 定义startup启动探针
    • 定义Readiness就绪探针
    • 探针设置参数
      • 全局参数
      • HTTP 探测参数
      • TCP探针参数
      • 探针层面的 terminationGracePeriodSeconds
        • 什么是terminationGracePeriodSeconds
        • 示例:
        • 额外说明

前言

这篇文章介绍如何给容器配置存活(Liveness)、就绪(Readiness)和启动(Startup)探针。

Pod探针

Liveness(Pod存活探针)

  • kubelet 使用存活探针来确定什么时候要重启容器。 例如,存活探针可以探测到应用死锁(应用程序在运行,但是无法继续执行后面的步骤)情况。 重启这种状态下的容器有助于提高应用的可用性,即使其中存在缺陷。
  • 存活探针的常见模式是为就绪探针使用相同的低成本 HTTP 端点,但具有更高的 failureThreshold。 这样可以确保在硬性终止 Pod 之前,将观察到 Pod 在一段时间内处于非就绪状态。
  • 用于判断容器是否存活(Running状 态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容 器,并根据容器的重启策略做相应的处理。如果一个容器不包含 LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的 值永远是Success。

Readiness(Pod服务就绪探针)

  • kubelet 使用就绪探针可以知道容器何时准备好接受请求流量,当一个 Pod 内的所有容器都就绪时,才能认为该 Pod 就绪。 这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。 若 Pod 尚未就绪,会被从 Service 的负载均衡器中剔除。
  • 用于判断容器服务是否可用(Ready状 态),达到Ready状态的Pod才可以接收请求。对于被Service管理的 Pod,Service与Pod Endpoint的关联关系也将基于Pod是否Ready进行设 置。如果在运行过程中Ready状态变为False,则系统自动将其从Service 的后端Endpoint列表中隔离出去,后续再把恢复到Ready状态的Pod加回 后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到 服务不可用的Pod实例上。

Startup(启动探针)

  • kubelet 使用启动探针来了解应用容器何时启动。 如果配置了这类探针,你就可以控制容器在启动成功后再进行存活性和就绪态检查, 确保这些存活、就绪探针不会影响应用的启动。 启动探针可以用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉。

定义Liveness存活探针

  • Exec探针: Exec探针是一种通过在容器内部运行命令并检查其退出代码来检测容器是否处于活动状态的Liveness存活探针;
  • http探针:HTTP存活探针是一种用于检测Web服务器是否处于活动状态的探针;
  • TCP探针:TCP存活探针是一种用于检测TCP端口是否处于活动状态的探针;

EXec探针

  1. 在这个配置文件中,可以看到 Pod 中只有一个 ContainerperiodSeconds 字段指定了 kubelet 应该每 5 秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 5 秒。 kubelet 在容器内执行命令 cat /tmp/healthy 来进行探测。 如果命令执行成功并且返回值为 0,kubelet 就会认为这个容器是健康存活的。 如果这个命令返回非 0 值,kubelet 会杀死这个容器并重新启动它。
apiVersion: v1
kind: Pod
metadata:labels:test: livenessname: liveness-exec
spec:containers:- name: livenessimage: registry.k8s.io/busyboxargs:- /bin/sh- -c- touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600livenessProbe:exec:command:- cat- /tmp/healthyinitialDelaySeconds: 5periodSeconds: 5
  • periodSeconds : 指定了 kubelet 应该每 5 秒执行一次存活探测;
  • initialDelaySeconds: 指定了kubelet 在执行第一次探测前应该等待 5 秒;
  • timeoutSeconds: 探针执行超时时间,单位为秒。如果探针在指定的时间内没有返回结果,则认为探针失败。默认值为1;
  • successThreshold: 探针成功的阈值。如果连续多少次探针成功,则认为容器处于活动状态。默认值为1;
  • failureThreshold: 针失败的阈值。如果连续多少次探针失败,则认为容器不处于活动状态。默认值为3。

解析:

  1. 当容器启动时,执行如下的命令:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600"
  1. 这个容器生命的前 30 秒,/tmp/healthy 文件是存在的。 所以在这最开始的 30 秒内,执行命令 cat /tmp/healthy 会返回成功代码。 30 秒之后,执行命令 cat /tmp/healthy 就会返回失败代码。
  2. 在 30 秒内,查看 Pod 的事件;输出结果表明还没有存活探针失败:
kubectl describe pod liveness-exec
ype    Reason     Age   From               Message----    ------     ----  ----               -------Normal  Scheduled  11s   default-scheduler  Successfully assigned default/liveness-exec to node01Normal  Pulling    9s    kubelet, node01    Pulling image "registry.k8s.io/busybox"Normal  Pulled     7s    kubelet, node01    Successfully pulled image "registry.k8s.io/busybox"Normal  Created    7s    kubelet, node01    Created container livenessNormal  Started    7s    kubelet, node01    Started container liveness
  1. 35 秒之后,再来看 Pod 的事件;在输出结果的最下面,有信息显示存活探针失败了,这个失败的容器被杀死并且被重建了。
kubectl describe pod liveness-exec
Type     Reason     Age                From               Message----     ------     ----               ----               -------Normal   Scheduled  57s                default-scheduler  Successfully assigned default/liveness-exec to node01Normal   Pulling    55s                kubelet, node01    Pulling image "registry.k8s.io/busybox"Normal   Pulled     53s                kubelet, node01    Successfully pulled image "registry.k8s.io/busybox"Normal   Created    53s                kubelet, node01    Created container livenessNormal   Started    53s                kubelet, node01    Started container livenessWarning  Unhealthy  10s (x3 over 20s)  kubelet, node01    Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directoryNormal   Killing    10s                kubelet, node01    Container liveness failed liveness probe, will be restarted
  1. 再等 30 秒,确认这个容器被重启了;输出结果显示 RESTARTS 的值增加了 1。 请注意,一旦失败的容器恢复为运行状态,RESTARTS 计数器就会增加 1:
kubectl get pod liveness-exec
NAME            READY     STATUS    RESTARTS   AGE
liveness-exec   1/1       Running   1          1m

HTTP探针

  1. 另外一种类型的存活探测方式是使用 HTTP GET 请求。 下面是一个 Pod 的配置文件,其中运行一个基于 registry.k8s.io/liveness 镜像的容器。
apiVersion: v1
kind: Pod
metadata:labels:test: livenessname: liveness-http
spec:containers:- name: livenessimage: livenessargs:- /serverlivenessProbe:httpGet:path: /healthzport: 8080httpHeaders:- name: Custom-Headervalue: AwesomeinitialDelaySeconds: 3periodSeconds: 3
  • 在这个配置文件中,你可以看到 Pod 也只有一个容器。 periodSeconds 字段指定了 kubelet 每隔 3 秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 3 秒。 kubelet 会向容器内运行的服务(服务在监听 8080 端口)发送一个 HTTP GET 请求来执行探测。 如果服务器上 /healthz 路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的。 如果处理程序返回失败代码,则 kubelet 会杀死这个容器并将其重启。
  • 返回大于或等于 200 并且小于 400 的任何代码都标示成功,其它返回代码都标示失败。

解析:

  1. 可以访问 server.go 阅读服务的源码。 容器存活期间的最开始 10 秒中,/healthz 处理程序返回 200 的状态码。 之后处理程序返回 500 的状态码。
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {duration := time.Now().Sub(started)if duration.Seconds() > 10 {w.WriteHeader(500)w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))} else {w.WriteHeader(200)w.Write([]byte("ok"))}
})
  1. kubelet 在容器启动之后 3 秒开始执行健康检测。所以前几次健康检查都是成功的。 但是 10 秒之后,健康检查会失败,并且 kubelet 会杀死容器再重新启动容器。
  2. 10 秒之后,通过查看 Pod 事件来确认存活探针已经失败,并且容器被重新启动了。

TCP探针

  1. 第三种类型的存活探测是使用 TCP 套接字。 使用这种配置时,kubelet 会尝试在指定端口和容器建立套接字链接。 如果能建立连接,这个容器就被看作是健康的,如果不能则这个容器就被看作是有问题的。
apiVersion: v1
kind: Pod
metadata:name: goproxylabels:app: goproxy
spec:containers:- name: goproxyimage: registry.k8s.io/goproxy:0.1ports:- containerPort: 8080readinessProbe:tcpSocket:port: 8080initialDelaySeconds: 5periodSeconds: 10livenessProbe:tcpSocket:port: 8080initialDelaySeconds: 15periodSeconds: 20
  • 如你所见,TCP 检测的配置和 HTTP 检测非常相似。 下面这个例子同时使用就绪和存活探针。kubelet 会在容器启动 5 秒后发送第一个就绪探针。 探针会尝试连接 goproxy 容器的 8080 端口。 如果探测成功,这个 Pod 会被标记为就绪状态,kubelet 将继续每隔 10 秒运行一次探测。
  • 除了就绪探针,这个配置包括了一个存活探针。 kubelet 会在容器启动 15 秒后进行第一次存活探测。 与就绪探针类似,存活探针会尝试连接 goproxy 容器的 8080 端口。 如果存活探测失败,容器会被重新启动。

gRPC探针

  • 特性状态:Kubernetes v1.24 [beta]

  • 如果你的应用实现了 gRPC 健康检查协议, kubelet 可以配置为使用该协议来执行应用存活性检查。 你必须启用 GRPCContainerProbe 特性门控 才能配置依赖于 gRPC 的检查机制。

  1. 这个例子展示了如何配置 Kubernetes 以将其用于应用程序的存活性检查。 类似地,你可以配置就绪探针和启动探针。
apiVersion: v1
kind: Pod
metadata:name: etcd-with-grpc
spec:containers:- name: etcdimage: registry.k8s.io/etcd:3.5.1-0command: [ "/usr/local/bin/etcd", "--data-dir",  "/var/lib/etcd", "--listen-client-urls", "http://0.0.0.0:2379", "--advertise-client-urls", "http://127.0.0.1:2379", "--log-level", "debug"]ports:- containerPort: 2379livenessProbe:grpc:port: 2379initialDelaySeconds: 10
  • 要使用 gRPC 探针,必须配置 port 属性。 如果要区分不同类型的探针和不同功能的探针,可以使用 service 字段。 你可以将 service 设置为 liveness,并使你的 gRPC 健康检查端点对该请求的响应与将 service 设置为 readiness 时不同。 这使你可以使用相同的端点进行不同类型的容器健康检查(而不需要在两个不同的端口上侦听)。 如果你想指定自己的自定义服务名称并指定探测类型,Kubernetes 项目建议你使用使用一个可以关联服务和探测类型的名称来命名。
  • 与 HTTP 和 TCP 探针不同,gRPC 探测不能使用按名称指定端口, 也不能自定义主机名。

使用命名端口

  • 对于 HTTP 和 TCP 存活检测可以使用命名的 port(gRPC 探针不支持使用命名端口)。
ports:
- name: liveness-portcontainerPort: 8080hostPort: 8080livenessProbe:httpGet:path: /healthzport: liveness-port

定义startup启动探针

有时候,会有一些现有的应用在启动时需要较长的初始化时间。 要这种情况下,若要不影响对死锁作出快速响应的探测,设置存活探测参数是要技巧的。 技巧就是使用相同的命令来设置启动探测,针对 HTTP 或 TCP 检测,可以通过将 failureThreshold * periodSeconds 参数设置为足够长的时间来应对糟糕情况下的启动时间。

ports:
- name: liveness-portcontainerPort: 8080hostPort: 8080livenessProbe:httpGet:path: /healthzport: liveness-portfailureThreshold: 1periodSeconds: 10startupProbe:httpGet:path: /healthzport: liveness-portfailureThreshold: 30periodSeconds: 10

幸亏有启动探测,应用程序将会有最多 5 分钟(30 * 10 = 300s)的时间来完成其启动过程。 一旦启动探测成功一次,存活探测任务就会接管对容器的探测,对容器死锁作出快速响应。 如果启动探测一直没有成功,容器会在 300 秒后被杀死,并且根据 restartPolicy 来执行进一步处置。

定义Readiness就绪探针

  • 有时候,应用会暂时性地无法为请求提供服务。 例如,应用在启动时可能需要加载大量的数据或配置文件,或是启动后要依赖等待外部服务。 在这种情况下,既不想杀死应用,也不想给它发送请求。 Kubernetes 提供了就绪探针来发现并缓解这些情况。 容器所在 Pod 上报还未就绪的信息,并且不接受通过 Kubernetes Service 的流量。
  • 注意:
    • 就绪探针在容器的整个生命周期中保持运行状态;
    • 存活探针不等待就绪性探针成功。 如果要在执行存活探针之前等待,应该使用 initialDelaySecondsstartupProbe
    • 就绪探针的配置和存活探针的配置相似。 唯一区别就是要使用 readinessProbe 字段,而不是 livenessProbe 字段。
  • 就绪和存活探测可以在同一个容器上并行使用。 两者共同使用,可以确保流量不会发给还未就绪的容器,当这些探测失败时容器会被重新启动。
  • LivenessProbe和ReadinessProbe均可配置以下三种实现方式。
    • EXec探针;
    • TCP探针
    • http探针

实现方式跟上面Liveness存活探针设置一样。

探针设置参数

全局参数

Probe有很多配置字段,可以使用这些字段精确地控制启动、存活和就绪检测的行为:

  • initialDelaySeconds:容器启动后要等待多少秒后才启动启动、存活和就绪探针, 默认是 0 秒,最小值是 0。

  • periodSeconds:执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。

  • timeoutSeconds:探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。

  • successThreshold:探针在失败后,被视为成功的最小连续成功数。默认值是 1。 存活和启动探测的这个值必须是 1。最小值是 1。

  • failureThreshold:探针连续失败了 failureThreshold 次之后, Kubernetes 认为总体上检查已失败:容器状态未就绪、不健康、不活跃。 对于启动探针或存活探针而言,如果至少有 failureThreshold 个探针已失败, Kubernetes 会将容器视为不健康并为这个特定的容器触发重启操作。 kubelet 会考虑该容器的 terminationGracePeriodSeconds 设置。 对于失败的就绪探针,kubelet 继续运行检查失败的容器,并继续运行更多探针; 因为检查失败,kubelet 将 Pod 的 Ready 状况设置为 false

  • terminationGracePeriodSeconds:为 kubelet 配置从为失败的容器触发终止操作到强制容器运行时停止该容器之前等待的宽限时长。 默认值是继承 Pod 级别的 terminationGracePeriodSeconds 值(如果不设置则为 30 秒),最小值为 1。

HTTP 探测参数

HTTP Probes允许针对 httpGet 配置额外的字段:

  • host:连接使用的主机名,默认是 Pod 的 IP。也可以在 HTTP 头中设置 “Host” 来代替。
  • scheme:用于设置连接主机的方式(HTTP 还是 HTTPS)。默认是 “HTTP”。
  • path:访问 HTTP 服务的路径。默认值为 “/”。
  • httpHeaders:请求中自定义的 HTTP 头。HTTP 头字段允许重复。
  • port:访问容器的端口号或者端口名。如果数字必须在 1~65535 之间。

注意:

  • 对于 HTTP 探测,kubelet 发送一个 HTTP 请求到指定的路径和端口来执行检测。 除非 httpGet 中的 host 字段设置了,否则 kubelet 默认是给 Pod 的 IP 地址发送探测。 如果 scheme 字段设置为了 HTTPS,kubelet 会跳过证书验证发送 HTTPS 请求。 大多数情况下,不需要设置 host 字段。 这里有个需要设置 host 字段的场景,假设容器监听 127.0.0.1,并且 Pod 的 hostNetwork 字段设置为了 true。那么 httpGet 中的 host 字段应该设置为 127.0.0.1。 可能更常见的情况是如果 Pod 依赖虚拟主机,你不应该设置 host 字段,而是应该在 httpHeaders 中设置 Host

  • 针对 HTTP 探针,kubelet 除了必需的 Host 头部之外还发送两个请求头部字段: User-AgentAccept。这些头部的默认值分别是 kube-probe/{{ skew currentVersion >}} (其中 1.27 是 kubelet 的版本号)和 */*

你可以通过为探测设置 .httpHeaders 来重载默认的头部字段值;例如:

livenessProbe:httpGet:httpHeaders:- name: Acceptvalue: application/jsonstartupProbe:httpGet:httpHeaders:- name: User-Agentvalue: MyUserAgent

也可以通过将这些头部字段定义为空值,从请求中去掉这些头部字段。

livenessProbe:httpGet:httpHeaders:- name: Acceptvalue: ""startupProbe:httpGet:httpHeaders:- name: User-Agentvalue: ""

TCP探针参数

对于 TCP 探测而言,kubelet 在节点上(不是在 Pod 里面)发起探测连接, 这意味着你不能在 host 参数上配置服务名称,因为 kubelet 不能解析服务名称。

TCP探针可以针对tcpSocket配置的字段进行配置。以下是可以在tcpSocket字段中使用的可选参数:

  • host:要检测的TCP端口所在的主机。如果未指定该参数,则默认为Pod所在的主机。
  • port:要检测的TCP端口号。
  • sourceIPAddress:指定用于建立TCP连接的源IP地址。
  • sourcePort:指定用于建立TCP连接的源端口。
livenessProbe:tcpSocket:host: my-hostport: 8080sourceIPAddress: 10.0.0.1

探针层面的 terminationGracePeriodSeconds

  • 在 1.21 发行版之前,Pod 层面的 terminationGracePeriodSeconds 被用来终止存活探测或启动探测失败的容器。 这一行为上的关联不是我们想要的,可能导致 Pod 层面设置了 terminationGracePeriodSeconds 时容器要花非常长的时间才能重新启动。
  • 在 1.21 及更高版本中,用户可以指定一个探针层面的 terminationGracePeriodSeconds 作为探针规约的一部分。 当 Pod 层面和探针层面的 terminationGracePeriodSeconds 都已设置,kubelet 将使用探针层面设置的值。
  • 探针层面的 terminationGracePeriodSeconds 不能用于就绪态探针。

什么是terminationGracePeriodSeconds

  • 在Kubernetes中,terminationGracePeriodSeconds是一个用于控制Pod中容器终止行为的参数。当Pod中的一个容器被终止时,Kubernetes将等待一段时间来允许该容器完成尽可能多的工作,然后再强制终止该容器。terminationGracePeriodSeconds参数指定了Kubernetes要等待的时间长度,以秒为单位。

  • 如果在terminationGracePeriodSeconds时间内,容器仍未终止,则Kubernetes将发送SIGKILL信号来强制终止该容器,并释放该容器持有的所有资源。

  • 在探测器(livenessProbe、readinessProbe等)的情况下,如果容器在执行探测器时失败,则Kubernetes会杀死该容器,并在terminationGracePeriodSeconds时间后尝试重新启动该容器。如果容器在探测器超时之前重新启动,则可以避免在探测器失败时终止该容器。

  • 在探针层面添加terminationGracePeriodSeconds参数,可以确保在探测器失败时,Kubernetes等待一段时间来允许容器完成尽可能多的工作,以确保系统的可靠性。例如,如果在容器的livenessProbe中指定了一个较长的检测周期,那么在检测失败时,Kubernetes将等待一段时间,以便容器可以完成尽可能多的工作,然后再强制终止该容器。

示例:

  1. 在这个示例中,Pod的terminationGracePeriodSeconds参数被设置为3600秒,但是在容器的livenessProbe中,被重载为60秒。

  2. 此外,在该示例中,容器test中的端口被设置为8080,并且在livenessProbe中使用了HTTP探测器来检查容器的健康状况。如果HTTP探测器在60秒内无法访问/healthz路径,则认为容器处于不健康状态,将触发重启操作。

  3. 需要注意的是,在livenessProbe中再次设置terminationGracePeriodSeconds参数,将覆盖Pod级别的terminationGracePeriodSeconds参数,即容器将使用livenessProbe中设置的terminationGracePeriodSeconds参数。该示例中,容器的terminationGracePeriodSeconds参数被设置为60秒,这意味着如果容器在60秒内未能正常终止,则Kubernetes将发送SIGKILL信号来强制终止容器,并释放容器持有的所有资源。

    通过在Pod和容器级别设置terminationGracePeriodSeconds参数,可以确保Pod和容器在终止时能够完成尽可能多的工作,并避免数据丢失或其他不良影响。在实际应用中,可以根据不同的需求,适当调整terminationGracePeriodSeconds参数的值,以确保系统的稳定性和可靠性。

spec:terminationGracePeriodSeconds: 3600  # Pod 级别设置containers:- name: testimage: ...ports:- name: liveness-portcontainerPort: 8080hostPort: 8080livenessProbe:httpGet:path: /healthzport: liveness-portfailureThreshold: 1periodSeconds: 60# 重载 Pod 级别的 terminationGracePeriodSecondsterminationGracePeriodSeconds: 60

额外说明

从 Kubernetes 1.25 开始,默认启用 ProbeTerminationGracePeriod 特性。 选择禁用此特性的用户,请注意以下事项:

  • ProbeTerminationGracePeriod 特性门控只能用在 API 服务器上。 kubelet 始终优先选用探针级别 terminationGracePeriodSeconds 字段 (如果它存在于 Pod 上)。

  • 如果你已经为现有 Pod 设置了 terminationGracePeriodSeconds 字段并且不再希望使用针对每个探针的终止宽限期,则必须删除现有的这类 Pod。

  • 当你(或控制平面或某些其他组件)创建替换 Pod,并且特性门控 ProbeTerminationGracePeriod 被禁用时,即使 Pod 或 Pod 模板指定了 terminationGracePeriodSeconds 字段, API 服务器也会忽略探针级别的 terminationGracePeriodSeconds 字段设置。
    nGracePeriod` 特性。 选择禁用此特性的用户,请注意以下事项:

  • ProbeTerminationGracePeriod 特性门控只能用在 API 服务器上。 kubelet 始终优先选用探针级别 terminationGracePeriodSeconds 字段 (如果它存在于 Pod 上)。

  • 如果你已经为现有 Pod 设置了 terminationGracePeriodSeconds 字段并且不再希望使用针对每个探针的终止宽限期,则必须删除现有的这类 Pod。

  • 当你(或控制平面或某些其他组件)创建替换 Pod,并且特性门控 ProbeTerminationGracePeriod 被禁用时,即使 Pod 或 Pod 模板指定了 terminationGracePeriodSeconds 字段, API 服务器也会忽略探针级别的 terminationGracePeriodSeconds 字段设置。

相关文章:

【云原生|Kubernetes】07-Pod健康检查和服务可用性检查

【云原生|Kubernetes】07-Pod健康检查和服务可用性检查 文章目录 【云原生|Kubernetes】07-Pod健康检查和服务可用性检查前言Pod探针Liveness(Pod存活探针)Readiness(Pod服务就绪探针)Startup(启动探针) 定义Liveness存活探针EXec探针HTTP探针TCP探针gRPC探针使用命名端口 定义…...

jeecgboot使用的问题记录

最近使用jeecgboot些项目,总结使用过程中的问题。 form表单 1.下拉框 — 使用字典方式 {label: 工单状态,field: orderStatus,component: JDictSelectTag,componentProps: {dictCode: emergency_order_status,}, } 2.下拉框—使用接口获取数据方式 配置项 { l…...

【C++】数组 - 一维数组,二维数组

文章目录 1. 一维数组1.1 一维数组定义方式1.2 数组名1.3 冒泡排序 2. 二维数组2.1 二维数组定义方式2.2 数组名 所谓数组,就是一个集合,里边存放了相同类型的数据元素。 特点1:数组中的每个数据元素都是相同的数据类型 特点2:数…...

前端:使用rollup的简单记录

目录 rollup安装 简单使用 1、命令行打包 2、配置文件打包 问题 1、报错提示:(node:23744) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.(Use node --trace-warnings ... to sho…...

基于flask的web应用开发——接受post请求

目录 0. 前言1. 了解post方法2. 在flask中实现3. 具体讲解 0. 前言 操作系统:Windows10 家庭版 开发环境:Pycahrm Comunity 2022.3 Python解释器版本:Python3.8 第三方库:flask 1. 了解post方法 POST是HTTP协议定义的一种请…...

Linux源码包的安装与升级

文章目录 Linux源码包的安装与升级什么是源代码、编译器与可执行文件什么是函数库什么是make与configure什么是Tarball的软件如何安装与升级软件 Linux源码包的安装与升级 如果你想在自己的Linux服务器上运行网站,就需要安装一个Web服务器软件,否则无法…...

电子合同签署协议开源版系统开发

电子合同签署协议开源版系统开发 H5TP6mysqlphp 源码开源不加密 以下是电子合同系统可能包含的功能列表: 用户注册和登录:用户可以注册并登录系统,以便创建、签署和管理合同。合同创建:用户可以创建新合同,包括填写合…...

【每日一题Day221】LC2455可被三整除的偶数的平均值 | 模拟

可被三整除的偶数的平均值【LC2455】 给你一个由正整数组成的整数数组 nums ,返回其中可被 3 整除的所有偶数的平均值。 注意:n 个元素的平均值等于 n 个元素 求和 再除以 n ,结果 向下取整 到最接近的整数。 思路 遍历数组,如果某…...

NCI架构-1

1、NFCC和DH通过物理连线相连,物理连线对应为Transport Layer(传输层),支持SPI、I2C、UART、USB等; 2、DH中所有和NFC相关的应用程序都可视为DH-NFCEE(EE:Execution Enviroment),图左的NFCEE模块可运行一些…...

lambda使用场景

字符串转换为数组: [rootmaster pyflink]# cat t300.py f(lambda i: (i, 1)) x11 22 33 print(f(x)) [rootmaster pyflink]# python t300.py (11 22 33, 1) [rootmaster pyflink]# cat t301.py f(lambda i: i[0]) x(aa,11, 22, 33) print(f(x)) [rootmaster pyflink]# pyth…...

Python模拟Postgres数据库连接

psycopg2 psycopg2是一个Python库,用于在Python应用程序中连接和操作PostgreSQL数据库。它是PostgreSQL数据库的官方驱动程序之一,具有广泛的应用和支持。 以下是一些psycopg2的特点和功能: 连接到PostgreSQL数据库:psycopg2提供…...

(转载)基于粒子群算法的多目标搜索算法(matlab实现)

1 理论基础 在实际工程优化问题中,多数问题是多目标优化问题。相对于单目标优化问题,多目标优化问题的显著特点是优化各个目标使其同时达到综合的最优值。然而,由于多目标优化问题的各个目标之间往往是相互冲突的,在满足其中一个…...

皮卡丘存储型xss、DOM型xss、DOM型xss-x

1.存储型xss 看题目&#xff0c;我们先留言&#xff0c;看它的过滤机制 发现可以永久存储并输出我们的留言 之后插入payload: <script>alert(xss)</script> 成功弹窗&#xff01; 2.DOM型xss Dom型xss&#xff0c;简单的说&#xff0c;就是向文档对象传入xss参…...

ThreadLocal源码

介绍 ThreadLocal是一个线程的本地变量&#xff0c;也就意味着这个变量是线程独有的&#xff0c;是不能与其他线程共享的。这样就可以避免资源竞争带来的多线程的问题。 但是&#xff0c;这种解决多线程安全问题的方式和加锁方式&#xff08;synchronized、Lock) 是有本质的区…...

Hive学习---3、DML(Data Manipulation Language)数据操作、查询

1、DML&#xff08;Data Manipulation Language&#xff09;数据操作 1.1 Load load语句可将文件导入到Hive表中 1、语法 load data [local] inpath filepath [overwrite] into table tablename [partition(partcol1val1,partcol2val2...)]2、关键字说明 &#xff08;1&…...

chatgpt赋能python:Python去除重复元素的几种方法

Python去除重复元素的几种方法 在Python编程中&#xff0c;去除列表、集合、字典等数据结构中的重复元素是一个常见的操作。本文将介绍Python中去除重复元素的几种方法&#xff0c;并分析它们的优缺点。 方法一&#xff1a;使用set去重 Set是Python中的一种集合类数据结构&a…...

2年测试我迷茫了,软件测试大佬都会哪些技能?我的测试进阶之路...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…...

21天学会C++:Day7----auto关键字

CSDN的uu们&#xff0c;大家好。这里是C入门的第七讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 知识引入 2. auto的使用 2.1 auto与指针和引用结合起来使用 2.2 在同一…...

Vue3 + ElementPlus实战学习——模拟简单的联系人列表管理后台

文章目录 &#x1f4cb;前言&#x1f3af;demo 介绍&#x1f3af;功能分析&#x1f9e9;数据的展示与分页功能&#x1f9e9;编辑功能&#x1f9e9;删除功能 &#x1f3af;部分代码分析&#x1f3af;完整代码&#x1f4dd;最后 &#x1f4cb;前言 这篇文章介绍一下基于 Vue3 和…...

【Go语言从入门到实战】并发篇

Go语言从入门到实战 — 并发篇 协程 Thread vs Groutine 相比之下&#xff0c;协程的栈大小就小很多了&#xff0c;创建起来也会更快&#xff0c;也更节省系统资源。 一个 goroutine 的栈&#xff0c;和操作系统线程一样&#xff0c;会保存其活跃或挂起的函数调用的本地变量…...

img标签请求 添加自定义header(二)

之前写过一篇关于img添加自定义请求头的处理方式&#xff08;点击这里&#xff09;&#xff0c;那么本篇我们来看另外几种实现方法。 自定义指令 以Vue为例&#xff0c;我们可以定义一个全局指令&#xff0c;对img标签进行一些处理。 <template><img :src"src…...

Set和weakSet Map和WeakMap

Set和weakSet的用法和区别 1.Set 和weakSet 它是类似于数组&#xff0c;且成员值都是唯一的&#xff0c; 2.Set有 add has delete clear size keys values forEach entries 3.weakSet 有add has delete 4.WeakSet中只能存放对象类型&#xff0c;不能存放基本类型 5.WeakSet它是…...

Qt基础之三十六:异常处理

本文将介绍如何在Qt中使用try...catch和调试dump文件来处理异常。 Qt版本5.12.6 一.使用try...catch 一段简单的捕获异常的代码,新建一个控制台工程,pro文件不用修改 #include <QCoreApplication> #include <QDebug>int main(int argc, char *argv[]) {QCoreA…...

【HMS Core】【ML Kit】活体检测FAQ合集

【问题描述1】 使用示例代码集成活体检测SDK时&#xff0c;报错state code -7001 【解决方案】 使用示例代码前请详细阅读示例工程中的“README”文件。您需要完成以下操作后才可以运行示例代码。 在AppGallery Connect网站下载自己应用的“agconnect-services.json”文件&a…...

ChatGPT:使用OpenAI创建自己的AI网站,使用 flask web框架快速搭建网站主体

使用OpenAI创建自己的AI网站 如果你还是一个OpenAI的小白&#xff0c;有OpenAI的账号&#xff0c;但想调用OpenAI的API搞一些有意思的事&#xff0c;那么这一系列的教程将仔细的为你讲解如何使用OpenAI的API制作属于自己的AI网站。 使用 flask web框架快速搭建网站主体 之前…...

后端(一):Tomcat

我们之前的前端是被我们一笔带过的&#xff0c;那不是我们要讲的重点&#xff0c;而这里的后端则是重点。本章先来认识认识后端的基础。 Tomcat 是什么 我们先来聊聊什么叫做tomcat&#xff0c;我们熟悉的那个是汤姆猫&#xff1a; 这和我们Java世界中的Tomcat 不是同一只猫&…...

华为OD机试之最小调整顺序次数、特异性双端队列(Java源码)

最小调整顺序次数、特异性双端队列 题目描述 有一个特异性的双端队列&#xff0c;该队列可以从头部或尾部添加数据&#xff0c;但是只能从头部移出数据。 小A依次执行2n个指令往队列中添加数据和移出数据。其中n个指令是添加数据&#xff08;可能从头部添加、也可能从尾部添加…...

2023年武汉住建厅七大员怎么报名?报名流程?精准题库一次过??

2023年武汉住建厅七大员怎么报名?报名流程&#xff1f;精准题库一次过&#xff1f;&#xff1f; 2023年武汉住建厅七大员是指施工员、质量员、资料员、材料员、机械员、标准员、劳务员&#xff0c;报的最多的可能就是施工员&#xff0c;质量员和资料员 报名流程&#xff1a; 1…...

Rust每日一练(Leetday0014) 组合总和II、缺失正数、接雨水

目录 40. 组合总和 II Combination Sum II &#x1f31f;&#x1f31f; 41. 缺失的第一个正数 First Missing Positive &#x1f31f;&#x1f31f;&#x1f31f; 42. 接雨水 Trapping Rain Water &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题…...

EnjoyVIID部署

1、下载 git clone https://gitee.com/tsingeye/EnjoyVIID.git 2、导入数据库 创建表enjoyviid 导入数据库(修改数据库文件里的编码) EnjoyVIID/sql/tsingeye-viid.sql 3、修改配置 vim EnjoyVIID/tsingeye-admin/src/main/resources/application-dev.yml 修改数据库连接、re…...