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

local-path-provisioner的使用(hostPath、local、local-path-provisioner三者对比)

前言

环境:k8s 1.22.17 、centos7.9
有时候,为了使用本地服务器上的磁盘存储资源,我们会使用hostPath这种方式来为k8s提供本地存储,本篇就来对比一下hostPath、local这两种使用本地服务器储存的方案,从而引出第三种local-path本地储存。

hostPath卷

hostPath 卷能将主机节点文件系统上的文件或目录挂载到你的 Pod 中,但是我们知道,pod重启后会随机调度,所以就需要为pod固定主机节点。下面仅演示hostPath的使用方法,挂载一个宿主机上的目录到pod中:

#hostPath示例一
#pod中直接使用hostPath卷
[root@matser data]# vim  nginx.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-179namespace: default
spec:replicas: 1selector:matchLabels:app: nginx-179template:metadata:labels:app: nginx-179spec:nodeName: master					#固定pod能调度的节点,确保pod重启后仍能访问之前的数据containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx-containerports:- containerPort: 80name: httpprotocol: TCPvolumeMounts:- mountPath: /var/log/nginx		#持久化日志name: hostpath-volumerestartPolicy: Alwaysvolumes:- name: hostpath-volumehostPath:						#hostPath卷path: /data/nginx				#使用宿主机上的/data/nginx目录type: DirectoryOrCreatekubectl  apply -f nginx.yaml
kubectl  delete  -f nginx.yaml
#hostPath示例二
#pod中使用pvc,pvc与pv关联,pv中定义hostPath,pod固定调度节点
[root@matser data]# cat hostPath.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:name: hostpath-pvlabels:type: local
spec:storageClassName: ""capacity:storage: 10GiaccessModes:- ReadWriteManyhostPath:path: "/data/nginx"type: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: hostpath-pvc
spec:accessModes:- ReadWriteManyresources:requests:storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-179namespace: default
spec:replicas: 1selector:matchLabels:app: nginx-179template:metadata:labels:app: nginx-179spec:nodeName: master					#固定pod能调度的节点,确保pod重启后仍能访问之前的数据containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx-containerports:- containerPort: 80name: httpprotocol: TCPvolumeMounts:- mountPath: /var/log/nginxname: hostpath-volumerestartPolicy: Alwaysvolumes:- name: hostpath-volumepersistentVolumeClaim:		#使用pvcclaimName: hostpath-pvc
[root@matser data]# 
#创建完成pv和pvc,当pvc与pv绑定之后发现并没有创建hostPath目录,只有当pod调度到节点上时才会真正创建hostPath目录。
#当pod重启之后,如果pod没有指定调度的节点,则仍然会在其他节点创建hostPath目录,所以为了使pod能访问之前的数据,都要把pod固定调度到指定节点。
#hostPath示例三
#pod中使用pvc,pvc与pv关联,pv中定义hostPath且定义节点亲和性#为节点打标签,只打了一个节点,如果是多个节点,那么pod会随机调度到这些节点数据就没有唯一性而言。
[root@matser data]# kubectl  label  nodes node2 storage=true
[root@matser data]# cat hostPath.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:name: hostpath-pvlabels:type: local
spec:storageClassName: ""capacity:storage: 10GiaccessModes:- ReadWriteManyhostPath:path: "/data/nginx"type: DirectoryOrCreatenodeAffinity:							#定义了节点亲和性required:nodeSelectorTerms:- matchExpressions:				- key: storageoperator: Invalues:- "true"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: hostpath-pvc
spec:accessModes:- ReadWriteManyresources:requests:storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-179namespace: default
spec:replicas: 1selector:matchLabels:app: nginx-179template:metadata:labels:app: nginx-179spec:					#pod中不在指定调度节点而是有pv中定义了节点亲和性,k8s会根据pv的节点亲和性来判断pod要调度到哪些节点containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx-containerports:- containerPort: 80name: httpprotocol: TCPvolumeMounts:- mountPath: /var/log/nginxname: hostpath-volumerestartPolicy: Alwaysvolumes:- name: hostpath-volumepersistentVolumeClaim:claimName: hostpath-pvc
[root@matser data]# 

hostPath卷总结:我们发现,无论是pod中直接使用hostPath,还是pod调用pvc,pvc调用pv,pv中使用hostPath,两者本质上没啥区别,示例1和实例2中都在pod中固定了调度节点,而实例3是在pv中定义了节点亲和性。

local卷

local 卷所代表的是某个被挂载的本地存储设备,例如磁盘、分区或者目录。
local 卷只能用作静态创建的持久卷。不支持动态配置。

与 hostPath 卷相比,local 卷能够以持久和可移植的方式使用,而无需手动将 Pod 调度到节点。系统通过查看 PersistentVolume 的节点亲和性配置,就能了解卷的节点约束。然而,local 卷仍然取决于底层节点的可用性,并不适合所有应用程序。 如果节点变得不健康,那么 local 卷也将变得不可被 Pod 访问。使用它的 Pod 将不能运行。 使用 local 卷的应用程序必须能够容忍这种可用性的降低,以及因底层磁盘的耐用性特征而带来的潜在的数据丢失风险。

下面是一个使用 local 卷和 nodeAffinity 的持久卷示例:

#local的使用和上面示例三hostPath卷的使用没多大区别,如下
[root@matser data]# cat local.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:name: local-pv
spec:capacity:storage: 10GivolumeMode: FilesystemaccessModes:- ReadWriteManypersistentVolumeReclaimPolicy: Retainlocal:								#这里定义的是local卷,path字段定义的是目录,这个目录必须先创建path: /data/nginxnodeAffinity:							#节点亲和性required:nodeSelectorTerms:- matchExpressions:- key: storageoperator: Invalues:- "true"          
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: local-pvc
spec:accessModes:- ReadWriteManyresources:requests:storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-179namespace: default
spec:replicas: 1selector:matchLabels:app: nginx-179template:metadata:labels:app: nginx-179spec:containers:					#没有定义节点选择器,k8s会根据pv定义的节点亲和性来调度pod- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx-containerports:- containerPort: 80name: httpprotocol: TCPvolumeMounts:- mountPath: /var/log/nginxname: local-volumerestartPolicy: Alwaysvolumes:- name: local-volumepersistentVolumeClaim:claimName: local-pvc
[root@matser data]# 
使用 local 卷时,你需要设置 PersistentVolume 对象的 nodeAffinity 字段。 Kubernetes 调度器使用 PersistentVolume 的 nodeAffinity 信息来将使用 local 卷的 Pod 调度到正确的节点。
PersistentVolume 对象的 volumeMode 字段可被设置为 "Block" (而不是默认值 "Filesystem"),以将 local 卷作为原始块设备暴露出来。
使用 local 卷时,建议创建一个 StorageClass 并将其 volumeBindingMode 设置为 WaitForFirstConsumer。要了解更多详细信息,请参考 local StorageClass 示例。 延迟卷绑定的操作可以确保 Kubernetes 在为 PersistentVolumeClaim 作出绑定决策时,会评估 Pod 可能具有的其他节点约束,例如:如节点资源需求、节点选择器、Pod 亲和性和 Pod 反亲和性。

总结:local卷和hostPath没啥区别,都可以通过在pv中定义节点亲和性,这样使用该pv的pod就会被k8s调度到指定的节点。唯一区别的是,local可以使用裸设备磁盘、分区、目录,而hostPath只能是文件或目录。

local-path-provisioner动态供给localPath或local卷

无论是hostPath卷还是local 卷,他们都不支持动态扩容,而local-path-provisioner很好的弥补了这一缺陷。

kubernetes-sigs版:https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner
注意kubernetes-sigs版不支持动态扩容/动态供给dynamically provisioning,所以建议使用rancher版。这里介绍的都是rancher版。
rancher版:https://github.com/rancher/local-path-provisioner

下载local-path-provisioner yml文件

# 进入https://github.com/rancher/local-path-provisioner,里面有很详细的安装教程
#安装local-path-provisioner
wget https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.24/deploy/local-path-storage.yaml

查看官方configmap解析

#local-path-storage.yaml中定义了一个configmap,我们先来看下官方样例中对这个cm的介绍.
provisioner的配置存储在一个configmap中,configmap包含1个json文件配置即config.json、1个Pod模板即helperPod.yaml、两个bash脚本即setup和teardown,如下所示:kind: ConfigMap
apiVersion: v1
metadata:name: local-path-confignamespace: local-path-storage
data:config.json: |-{"nodePathMap":[{"node":"DEFAULT_PATH_FOR_NON_LISTED_NODES","paths":["/opt/local-path-provisioner"]},{"node":"yasker-lp-dev1","paths":["/opt/local-path-provisioner", "/data1"]},{"node":"yasker-lp-dev3","paths":[]}]}setup: |-#!/bin/shset -eumkdir -m 0777 -p "$VOL_DIR"teardown: |-#!/bin/shset -eurm -rf "$VOL_DIR"helperPod.yaml: |-apiVersion: v1kind: Podmetadata:name: helper-podspec:containers:- name: helper-podimage: busyboxnodePathMap字段是一个数组,用于自定义在每个节点上存储数据的位置。
如果一个节点没有在nodePathMap上列出,而Kubernetes想要在它上面创建卷,那么default_path_for_non_listd_nodes中指定的路径将被用于分配。
如果nodePathMap上列出了一个节点,则将使用paths中指定的路径进行发放。
如果仅列出了节点,但路径设置为[],则提供程序将拒绝在该节点上提供服务。
如果节点上指定了多个路径,则在provision供给时将随机选择路径。
规则:路径必须是绝对路径,路径不能是根/,一个节点可以有多个不同的路径,不能重复列出节点,一个节点不能列出相同的路径。sharedFileSystemPath允许提供者使用同时挂载在所有节点上的文件系统。在这种情况下,支持所有访问模式:ReadWriteOnce, ReadOnlyMany和ReadWriteMany存储声明。
另外,volumeBindingMode: Immediate可以在StorageClass定义中使用。
请注意nodePathMap和sharedFileSystemPath是互斥的。如果使用sharedFileSystemPath,则nodePathMap必须设置为[]。setup脚本:在创建卷之前运行setup脚本来在节点上准备卷目录。
teardown脚本:删除卷后运行teardown脚本,清理节点上的卷目录。
helperPod.yaml模板:用于创建一个helper pod,用这个helper pod来执行setup和teardown脚本。provisioner支持自动热重载,即可以在线修改local-path-config配置,provisioner会自动生效配置,从local-path-provisioner pod中可以查看日志,如果provisioner生效失败,则provisioner仍然会保持上一个有效的local-path-config配置。
#指定local-path-provisioner创建的卷类型,可以通过以下2种方式指定local-path-provisioner要给你创建什么类型的卷
当你手动创建PVC时,在pvc的中添加以下注解:
annotations:volumeType: <local or hostPath>亦可以在存储类的定义中添加以下注解:
StorageClass:
annotations:defaultVolumeType: <local or hostPath>需要注意的是:StorageClass的注释将应用于使用它的所有卷,如果PVC提供了注释,则覆盖SC上的注释。如果这两个注解都没有提供,那么默认使用hostPath。

开始安装local-path-provisioner

#查看修改local-path-storage.yaml内容
[root@matser data]# cat local-path-storage.yaml 
apiVersion: v1
kind: Namespace
metadata:name: local-path-storage
---
apiVersion: v1
kind: ServiceAccount
metadata:name: local-path-provisioner-service-accountnamespace: local-path-storage
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: local-path-provisioner-role
rules:- apiGroups: [ "" ]resources: [ "nodes", "persistentvolumeclaims", "configmaps" ]verbs: [ "get", "list", "watch" ]- apiGroups: [ "" ]resources: [ "endpoints", "persistentvolumes", "pods" ]verbs: [ "*" ]- apiGroups: [ "" ]resources: [ "events" ]verbs: [ "create", "patch" ]- apiGroups: [ "storage.k8s.io" ]resources: [ "storageclasses" ]verbs: [ "get", "list", "watch" ]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: local-path-provisioner-bind
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: local-path-provisioner-role
subjects:- kind: ServiceAccountname: local-path-provisioner-service-accountnamespace: local-path-storage
---
apiVersion: apps/v1
kind: Deployment
metadata:name: local-path-provisionernamespace: local-path-storage
spec:replicas: 1selector:matchLabels:app: local-path-provisionertemplate:metadata:labels:app: local-path-provisionerspec:serviceAccountName: local-path-provisioner-service-accountcontainers:- name: local-path-provisionerimage: rancher/local-path-provisioner:v0.0.24imagePullPolicy: IfNotPresentcommand:- local-path-provisioner- --debug- start- --config- /etc/config/config.jsonvolumeMounts:- name: config-volumemountPath: /etc/config/env:- name: POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespacevolumes:- name: config-volumeconfigMap:name: local-path-config
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: local-pathannotations:					#添加了注释,表示StorageClass提供哪些卷类型,可以是hostPath和local,默认值为hostPathvolumeType: hostPath
provisioner: rancher.io/local-path
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain			#修改为Retain,原来默认是Delete
allowVolumeExpansion: true		#允许扩容
---
kind: ConfigMap
apiVersion: v1
metadata:name: local-path-confignamespace: local-path-storage
data:config.json: |-{"nodePathMap":[{"node":"DEFAULT_PATH_FOR_NON_LISTED_NODES",	#指定其它节点使用/data/local-path-provisioner目录作为存储"paths":["/data/local-path-provisioner"]	#存储目录,会自动创建},{"node":"master",			#指定使用master节点的/opt/local-path-provisioner目录作为存储"paths":["/opt/local-path-provisioner"]		#存储目录,会自动创建}	#如果不想让指定节点作为存储节点,则需显示的列出来,并且将该节点的path设置[]]}setup: |-#!/bin/shset -eumkdir -m 0777 -p "$VOL_DIR"teardown: |-#!/bin/shset -eurm -rf "$VOL_DIR"helperPod.yaml: |-apiVersion: v1kind: Podmetadata:name: helper-podspec:containers:- name: helper-podimage: busyboximagePullPolicy: IfNotPresent
[root@matser data]# kubectl apply -f  local-path-storage.yaml

创建pod、pvc进行验证

[root@matser data]# cat local-path.yaml 
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: local-path-pvc
spec:storageClassName: local-pathaccessModes:- ReadWriteOnceresources:requests:storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-179namespace: default
spec:replicas: 1selector:matchLabels:app: nginx-179template:metadata:labels:app: nginx-179spec:containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx-containerports:- containerPort: 80name: httpprotocol: TCPvolumeMounts:- mountPath: /usr/share/nginx/htmlname: local-path-volumerestartPolicy: Alwaysvolumes:- name: local-path-volumepersistentVolumeClaim:claimName: local-path-pvc
[root@matser data]# kubectl apply -f  local-path.yaml#验证发现,pod随机调度到node2节点,并且已经自动创建了/data/local-path-provisioner/目录,并且存在权限是777的pvc-e04ceb06-1a30-4b83-8215-7786850f3d93_default_local-path-pvc目录,所有动态分配pv验证成功了。
#验证过程中发现,pv其实还是具有节点亲和性的,这说明,当节点挂掉的时候,pod无法重新调度到其他节点,因为pod使用的pv定义节点亲和性,
#这也难怪,provisioner创建的卷类型本身就是hostPath或local卷。
[root@matser data]# kubectl  get pv pvc-0926a91c-854a-400f-be54-ad3fdd5e0051  -oyaml
apiVersion: v1
kind: PersistentVolume
metadata:........hostPath:				#其实卷的类型仍是hostPathpath: /opt/local-path-provisioner/pvc-0926a91c-854a-400f-be54-ad3fdd5e0051_default_local-path-pvctype: DirectoryOrCreatenodeAffinity:			#具有节点亲和性required:nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/hostnameoperator: Invalues:- master
........

存在的问题

#发现如果在pod中定义nodeName想让pod调度到某台节点,pod会无法调度,pod的events报错如下:
[root@matser data]# kubectl  describe  pod nginx-1791-5d444554cb-b2mvq 
Events:Type     Reason       Age   From     Message----     ------       ----  ----     -------Warning  FailedMount  6s    kubelet  Unable to attach or mount volumes: unmounted volumes=[local-path-volume], unattached volumes=[local-path-volume kube-api-access-c7h9m]: error processing PVC default/local-path-pvc1: PVC is not bound
查看pvc的报错如下:
[root@matser data]# kubectl  describe  pvc local-path-pvc1
Events:Type    Reason                Age               From                         Message----    ------                ----              ----                         -------Normal  WaitForFirstConsumer  5s (x2 over 15s)  persistentvolume-controller  waiting for first consumer to be created before binding这是怎么回事呢?pod显示pvc没有绑定,pvc又在等待pod来消费,这不是死循环吗。如果pod中不指定nodeName,让pod随机调度,是能正常创建的,但是一旦定义了nodeName就不能正常了,这是什么回事呢?

local-path-provisioner仅支持ReadWriteOnce访问模式

在写pvc的时候,如果将accessModes写成 ReadWriteMany,则pvc将一直处于penging状态,查看local-path-provisioner pod的日志或kubectl describe pvc local-path-pvc 发现了以下报错:

 Type     Reason                Age                  From                                                                                                Message----     ------                ----                 ----                                                                                                -------Normal   WaitForFirstConsumer  11m                  persistentvolume-controller                                                                         waiting for first consumer to be created before bindingNormal   ExternalProvisioning  102s (x42 over 11m)  persistentvolume-controller                                                                         waiting for a volume to be created, either by external provisioner "rancher.io/local-path" or manually created by system administratorNormal   Provisioning          52s (x7 over 11m)    rancher.io/local-path_local-path-provisioner-6464fcbd8b-bhmqs_d68778ed-2a18-4f48-9788-1b2dc0f2b88f  External provisioner is provisioning volume for claim "default/local-path-pvc"Warning  ProvisioningFailed    52s (x7 over 11m)    rancher.io/local-path_local-path-provisioner-6464fcbd8b-bhmqs_d68778ed-2a18-4f48-9788-1b2dc0f2b88f  failed to provision volume with StorageClass "local-path": Only support ReadWriteOnce access mode
[root@matser data]# kubectl  describe  pvc local-path-pvc 
#怎么local-path-provisioner创建的pv仅支持ReadWriteOnce访问模式而已的呢?

卸载local-path-provisioner

#1、手动删除pv,确保已经没有pv是使用local-path 这个存储类的
#2、kubectl delete  -f local-path-storage.yaml
#3、手动删除节点上的目录

总结

1、pod中直接使用hostPath来挂载宿主机的指定目录,但是为了防止pod重启后没有调度到上一次调度的宿主机节点,所以pod中需要定义nodeName指定调度主机。
2、可以在pv中使用hostPath,然后创建pvc与pv进行绑定,然后pod中使用pvc即可,pod中仍需要定义nodeName指定调度主机。
3、可以在pv中使用hostPath并且pv中定义节点亲和性,然后创建pvc与pv进行绑定,然后pod中使用pvc即可,此时pod中不需要定义nodeName指定调度主机,k8s会根据pv中定义的节点亲和性来选择调度pod,这样其实也是间接的指定了pod要调度的主机。
4、local的使用和上面第3点相同,都是在pv中定义节点亲和性,local与hostPath的区别在于,local可以使用裸设备、目录、分区,而hostPath只能是目录或文件。
5、local和hostPath都没有动态供给,都是手动的。
6、引入local-path-provisioner只是为了实现local或hostPath的动态供给。
7、创建一个local-path-provisioner 的pod、存储类、cm、服务账号等资源对象来实现动态供给。
8、本质上local-path-provisioner提供的卷仍是hostPath或local,所以local-path-provisioner提供的pv仍是具有节点亲和性的,这就说明当宿主机挂机了的时候,由于pod绑定的pv具有节点亲和性,所以pod无法在其他节点重新调度,pod就会存在故障。这其实就是hostPath、local卷的劣势。
9、使用local-path-provisioner动态供给pv,发现pod无法使用nodeName节点选择器,这一点有待研究。
10、使用local-path-provisioner动态供给pv,pvc只能是ReadWriteOnce,因为local-path-provisioner pod显示StorageClass "local-path": Only support ReadWriteOnce access mode

相关文章:

local-path-provisioner的使用(hostPath、local、local-path-provisioner三者对比)

前言 环境&#xff1a;k8s 1.22.17 、centos7.9 有时候&#xff0c;为了使用本地服务器上的磁盘存储资源&#xff0c;我们会使用hostPath这种方式来为k8s提供本地存储&#xff0c;本篇就来对比一下hostPath、local这两种使用本地服务器储存的方案&#xff0c;从而引出第三种lo…...

命令行快捷键Mac Iterm2

原文:Jump forwards, backwards and delete a word in iTerm2 on Mac OS iTerm2并不允许你使用 ⌥← 或 ⌥→ 来跳过单词。 你也不能使用 ⌥backspace 来删除整个单词。 下面是在Mac OS上如何配置iTerm2以便能做到这一点的方法。 退格键 首先&#xff0c;你需要将你的左侧 ⌥…...

无涯教程-Lua - Modules(模块)

模块就像可以使用 require 加载的库&#xff0c;并且具有包含Table的单个全局名称&#xff0c;该模块可以包含许多函数和变量。 Lua 模块 其中一些模块示例如下。 -- Assuming we have a module printFormatter -- Also printFormatter has a funtion simpleFormat(arg) -- …...

url重定向

不安全的url跳转 不安全的url跳转问题可能发生在一切执行了url地址跳转的地方。 如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地,而又没有做判断的话 就可能发生"跳错对象"的问题。 url跳转比较直接的危害是…...

Linux 查看IP地址、子网掩码和网关的配置信息

使用以下命令来查看IP地址、子网掩码和网关的配置信息&#xff1a; 1&#xff0c;使用ifconfig命令&#xff1a; ifconfig 在输出中&#xff0c;找到你正在使用的网络接口的配置信息。你将看到类似以下的内容&#xff1a; eth0: flags4163<UP,BROADCAST,RUNNING,MULTICA…...

token

token验证流程&#xff1a; ①客户端使用用户名和密码请求登录。 ②服务端收到请求&#xff0c;验证用户名和密码。 ③验证成功后&#xff0c;服务端会生成一个token&#xff0c;然后把这个token发送给客户端。 ④客户端收到token后把它存储起来&#xff0c;可以放在cookie…...

利用awk筛选给定时间范围内的日志

文章目录 筛选给定时间范围内的日志时间时间戳什么是时间戳&#xff1f; 系统时间 筛选日志时间示例简单示例mktime()函数是什么 进阶示例 筛选给定时间范围内的日志 时间 时间的表示方法&#xff1a; 时间戳系统时间&#xff08;年月日时间&#xff09; 时间戳 什么是时间…...

ORACLE字符集概念学习

1、字符集的一些基本知识 字符集有很多种&#xff0c;最初的字符集是ASCII&#xff0c;由于ASCII支持的字符很有限&#xff0c;因此随后又出现了很多的编码方案&#xff0c;这些编码方案大部分都是包括了ASCII 的。EBCDIC编码是另一个比较基本的编码&#xff0c;它的部分字符采…...

时间复杂度、空间复杂度实践练习(力扣OJ)

目录 文章目录 前言 题目一&#xff1a;轮转数组 思路一&#xff1a; 思路二&#xff1a; 思路三&#xff1a; 题目二&#xff1a;消失的数字 思路一&#xff1a; 思路二&#xff1a; 思路三&#xff1a; 题目三&#xff1a;移除元素 思路&#xff1a; 总结 前言 想要编写高效的…...

JMeter(二十四)、使用吞吐量控制器实现不同的用户操纵不同的业务

一、需求 需求&#xff1a;博客系统&#xff0c;模拟用户真实行为&#xff0c;80%的用户阅读文章&#xff0c;20%的用户创建文章&#xff0c;创建文章的用户随机的删除或者修改文章。 二、脚本实现 80%的用户查看文章 20%用户创建文章 根据post_id是否能整除2&#xff0c;决…...

8.1Jmeter5.1:Jmeter SSL

Jmeter配置证书请求双向认证SSL的web接口 需求:需要通过Jmeter配置证书请求双向认证SSL的web接口 提供的证书:P12格式 备注:Jmeter需要导入的证书是keystore证书 那么要先把P12转成keystore文件 1、使用p12生成keystore文件 keytool介绍 这里需要提到提到jdk自带的key…...

7-7 找最小的字符串 (15 分)

7-7 找最小的字符串 &#xff08;15 分) 本题要求编写程序&#xff0c;针对输入的N个字符串&#xff0c;输出其中最小的字符串。 输入格式&#xff1a; 输入第一行给出正整数N&#xff1b;随后N行&#xff0c;每行给出一个长度小于80的非空字符串&#xff0c;其中不会出现换行…...

Red Hat 安装MySQL 8.0与 Navicat

目录 Red Hat 安装 MySQL 8.0 1、更新软件包列表 2、安装MySQL服务器和客户端 3、启动MySQL服务 4、确保MySQL服务器正在运行 5、root 用户的密码 6、登录MySQL&#xff0c;输入mysql密码 7、MySQL默认位置 Red Hat 安装 Navicat 1、下载 Navicat 2、执行命令 Red H…...

17游刃有余:动手实现自己的RPC框架(三)

这篇文章我们来实现跨语言的网络通信。 跨语言RPC框架的必要性主要体现在以下几个方面: 解决不同语言之间的互操作性。不同语言使用的数据类型和序列化方式可能不同,跨语言 RPC 框架可以提供通用的编解码库和语言适配器,以便将不同语言的数据转换为通用的格式进行通信。实现…...

c语言——求n之内的素数和

//求n之内的素数和 //列如&#xff1a;2、3、5等 #include<stdio.h> #include<math.h> int main() {int i,j,k,n0;scanf("%d",&n);for(i2;i<n;i){k(int)sqrt(i);for(j2;j<k;j)if(i%j0)break;if(j>k){printf("%d,",i);n;if(n%50)p…...

【M波段2D双树(希尔伯特)小波多分量图像去噪】基于定向M波段双树(希尔伯特)小波对多分量/彩色图像进行降噪研究(Matlab代码实现)

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

unity TextMeshPro 富文本

<b>粗体标签</b> <i>斜体标签</i> <u>下划线标签</u> <s>删除线标签</s> <sup>上标标签</sup>前面后边上标签 5<sup>。</sup>C <sub>下标标签&#xff0c;如&#xff1a;</sub>H<sub&…...

【PyTorch】PyTorch、Cuda 的安装和使用

原文作者&#xff1a;我辈李想 版权声明&#xff1a;文章原创&#xff0c;转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、Anaconda 中安装 PyTorch 和 CUDA二、检查PyTorch和CUDA版本三、PyTorch的基本使用四、PyTorch调用cuda五、Matplotlib绘制Pytorch损…...

1.初识typescript

在很多地方的示例代码中使用的都是ts而不是js&#xff0c;为了使用那些示例&#xff0c;学习ts还是有必要的 JS有的TS都有&#xff0c;JS与TS的关系很像css与less ts在运行前需要先编译为js&#xff0c;浏览器不能直接运行ts 目录 1 编译TS的工具包 1.1 安装 1.2 基本…...

iPhone 6透明屏是什么?原理、特点、优势

iPhone 6透明屏是一种特殊的屏幕技术&#xff0c;它能够使手机屏幕变得透明&#xff0c;让用户能够透过屏幕看到手机背后的物体。 这种技术在科幻电影中经常出现&#xff0c;给人一种未来科技的感觉。下面将介绍iPhone 6透明屏的原理、特点以及可能的应用。 iPhone 6透明屏的原…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...