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

kubernetes持久化存储卷

kubernetes持久化存储卷

  • kubernetes持久化存储卷
  • 一、存储卷介绍
  • 二、存储卷的分类
  • 三、存储卷的选择
  • 四、本地存储卷之emptyDir
  • 五、本地存储卷之 hostPath
  • 六、网络存储卷之nfs
  • 七、PV(持久存储卷)与PVC(持久存储卷声明)
    • 7.1 认识pv与pvc
    • 7.2 pv与pvc之间的关系
    • 7.3 实现nfs类型pv与pvc
    • 7.4 subpath使用
  • 八、存储的动态供给
    • 8.1 什么是动态供给
    • 8.2 使用NFS文件系统创建存储动态供给

kubernetes持久化存储卷

一、存储卷介绍

pod有生命周期,生命周期结束后 pod 里的数据会消失(如配置文件,业务数据等)。

解决: 我们需要将数据与pod分离,将数据放在专门的存储卷上

pod在k8s集群的节点中是可以调度的, 如果pod挂了被调度到另一个节点,那么数据和pod的联系会中断。

解决: 所以我们需要与集群节点分离的存储系统才能实现数据持久化

简单来说: volume提供了在容器上挂载外部存储的能力

二、存储卷的分类

kubernetes 支持的存储卷类型非常丰富,使用下面的命令查看:

# kubectl explain pod.spec.volumes

或者参考: https://kubernetes.io/docs/concepts/storage/

kubernetes支持的存储卷列表如下:

  • awsElasticBlockStore
  • azureDisk
  • azureFile
  • cephfs
  • cinder
  • configMap
  • csi
  • downwardAPI
  • emptyDir
  • fc (fibre channel)
  • flexVolume
  • flocker
  • gcePersistentDisk
  • gitRepo (deprecated)
  • glusterfs
  • hostPath
  • iscsi
  • local
  • nfs
  • persistentVolumeClaim
  • projected
  • portworxVolume
  • quobyte
  • rbd
  • scaleIO
  • secret
  • storageos
  • vsphereVolume

我们将上面的存储卷列表进行简单的分类:

  • 本地存储卷
    • emptyDir pod删除,数据也会被清除,用于数据的临时存储
    • hostPath 宿主机目录映射(本地存储卷)
  • 网络存储卷
    • NAS类 nfs等
    • SAN类 iscsi,FC等
    • 分布式存储 glusterfs,cephfs,rbd,cinder等
    • 云存储 aws,azurefile等

三、存储卷的选择

市面上的存储产品种类繁多,但按应用角度主要分为三类:

  • 文件存储 如:nfs,glusterfs,cephfs等
    • 优点: 数据共享(多pod挂载可以同读同写)
    • 缺点: 性能较差
  • 块存储 如: iscsi,rbd等
    • 优点: 性能相对于文件存储好
    • 缺点: 不能实现数据共享(部分)
  • 对象存储 如: ceph 对象存储
    • 优点: 性能好,数据共享
    • 缺点: 使用方式特殊,支持较少

面对kubernetes支持的形形色色的存储卷,如何选择成了难题。在选择存储时,我们要抓住核心需求:

  • 数据是否需要持久性
  • 数据可靠性 如存储集群节点是否有单点故障,数据是否有副本等
  • 性能
  • 扩展性 如是否能方便扩容,应对数据增长的需求
  • 运维难度 存储的运维难度是比较高的,尽量选择稳定的开源方案或商业产品
  • 成本

总之,存储的选择是需要考虑很多因素的,熟悉各类存储产品,了解它们的优缺点,结合自身需求才能选择合适自己的。

四、本地存储卷之emptyDir

  • 应用场景
    实现pod内容器之间数据共享

  • 特点
    随着pod被删除,该卷也会被删除

  1. 创建yaml文件
[root@k8s-master1 ~]# vim volume-emptydir.yml
apiVersion: v1
kind: Pod
metadata:name: volume-emptydir
spec:containers:- name: writeimage: centosimagePullPolicy: IfNotPresentcommand: ["bash","-c","echo haha > /data/1.txt ; sleep 6000"]volumeMounts:- name: datamountPath: /data- name: readimage: centosimagePullPolicy: IfNotPresentcommand: ["bash","-c","cat /data/1.txt; sleep 6000"]volumeMounts:- name: datamountPath: /data volumes:- name: dataemptyDir: {}
  1. 基于yaml文件创建pod
[root@k8s-master1 ~]# kubectl apply -f volume-emptydir.yml
pod/volume-emptydir created
  1. 查看pod启动情况
[root@k8s-master1 ~]# kubectl get pods |grep volume-emptydir
NAME                               READY   STATUS    RESTARTS   AGE
volume-emptydir                    2/2     Running   0          15s
  1. 查看pod描述信息
[root@k8s-master1 ~]# kubectl describe pod volume-emptydir | tail -10
Events:Type    Reason     Age   From               Message----    ------     ----  ----               -------Normal  Scheduled  50s   default-scheduler  Successfully assigned default/volume-emptydir to k8s-worker1Normal  Pulling    50s   kubelet            Pulling image "centos:centos7"Normal  Pulled     28s   kubelet            Successfully pulled image "centos:centos7" in 21.544912361sNormal  Created    28s   kubelet            Created container writeNormal  Started    28s   kubelet            Started container writeNormal  Pulled     28s   kubelet            Container image "centos:centos7" already present on machineNormal  Created    28s   kubelet            Created container readNormal  Started    28s   kubelet            Started container read
  1. 验证
[root@k8s-master1 ~]# kubectl logs volume-emptydir -c write
[root@k8s-master1 ~]# kubectl logs volume-emptydir -c read
haha

五、本地存储卷之 hostPath

  • 应用场景
    pod内与集群节点目录映射(pod中容器想访问节点上数据,例如监控,只有监控访问到节点主机文件才能知道集群节点主机状态)

  • 缺点
    如果集群节点挂掉,控制器在另一个集群节点拉起容器,数据就会变成另一台集群节点主机的了(无法实现数据共享)

  1. 创建yaml文件
[root@k8s-master1 ~]# vim volume-hostpath.yml
apiVersion: v1
kind: Pod
metadata:name: volume-hostpath
spec:containers:- name: busyboximage: busyboximagePullPolicy: IfNotPresentcommand: ["/bin/sh","-c","echo haha > /data/1.txt ; sleep 600"]volumeMounts:- name: datamountPath: /datavolumes:- name: datahostPath:path: /opttype: Directory
  1. 基于yaml文件创建pod
[root@k8s-master1 ~]# kubectl apply  -f volume-hostpath.yml
pod/volume-hostpath created[root@k8s-master1 ~]# kubectl get pods -o wide |grep volume-hostpath
volume-hostpath     1/1   Running   0    29s     10.224.194.120   k8s-worker1   <none>     <none>
可以看到pod是在k8s-worker1节点上
  1. 验证pod所在机器上的挂载文件
[root@k8s-worker1 ~]# cat /opt/1.txt
haha

六、网络存储卷之nfs

  1. 搭建nfs服务器
[root@nfsserver ~]# mkdir -p /data/nfs
[root@nfsserver ~]# vim /etc/exports
/data/nfs       *(rw,no_root_squash,sync)
[root@nfsserver ~]# systemctl restart nfs-server
[root@nfsserver ~]# systemctl enable nfs-server
  1. 所有node节点安装nfs客户端相关软件包
[root@k8s-worker1 ~]# yum install nfs-utils -y
[root@k8s-worker2 ~]# yum install nfs-utils -y
  1. 验证nfs可用性
[root@node1 ~]# showmount -e 192.168.10.129
Export list for 192.168.10.129:
/data/nfs *
[root@node2 ~]# showmount -e 192.168.10.129
Export list for 192.168.10.129:
/data/nfs *
  1. master节点上创建yaml文件
[root@k8s-master1 ~]# vim volume-nfs.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: volume-nfs
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.15-alpineimagePullPolicy: IfNotPresentvolumeMounts:- name: documentrootmountPath: /usr/share/nginx/htmlports:- containerPort: 80volumes:- name: documentrootnfs:server: 192.168.10.129path: /data/nfs
  1. 应用yaml创建
[root@k8s-master1 ~]#  kubectl apply -f volume-nfs.yml
deployment.apps/nginx-deployment created
  1. 在nfs服务器共享目录中创建验证文件
[root@nfsserver ~]# echo "volume-nfs" > /data/nfs/index.html
  1. 验证pod
[root@k8s-master1 ~]# kubectl get pod |grep volume-nfs
volume-nfs-649d848b57-qg4bz   1/1     Running   0          10s
volume-nfs-649d848b57-wrnpn   1/1     Running   0          10s
[root@k8s-master1 ~]# kubectl exec -it volume-nfs-649d848b57-qg4bz -- /bin/sh
/ # ls /usr/share/nginx/html/
index.html
/ # cat /usr/share/nginx/html/index.html
volume-nfs										# 文件内容与nfs服务器上创建的一致
/ # exit
[root@k8s-master1 ~]# kubectl exec -it volume-nfs-649d848b57-wrnpn -- /bin/sh
/ # ls /usr/share/nginx/html/
index.html
/ # cat /usr/share/nginx/html/index.html
volume-nfs										# 文件内容与nfs服务器上创建的一致
/ # exit

七、PV(持久存储卷)与PVC(持久存储卷声明)

7.1 认识pv与pvc

kubernetes存储卷的分类太丰富了,每种类型都要写相应的接口与参数才行,这就让维护与管理难度加大。

persistenvolume(PV) 是配置好的一段存储(可以是任意类型的存储卷)

  • 也就是说将网络存储共享出来,配置定义成PV。

PersistentVolumeClaim(PVC)是用户pod使用PV的申请请求。

  • 用户不需要关心具体的volume实现细节,只需要关心使用需求。

7.2 pv与pvc之间的关系

  • pv提供存储资源(生产者)

  • pvc使用存储资源(消费者)

  • 使用pvc绑定pv

在这里插入图片描述

7.3 实现nfs类型pv与pvc

  1. 编写创建pv的YAML文件
[root@k8s-master1 ~]# vim pv-nfs.yml
apiVersion: v1
kind: PersistentVolume						# 类型为PersistentVolume(pv)
metadata:		name: pv-nfs								# 名称
spec:capacity:storage: 1Gi							# 大小accessModes:- ReadWriteMany							# 访问模式nfs:path: /data/nfs							# nfs共享目录server: 192.168.10.129					# nfs服务器IP

访问模式有3种 参考 链接

  • ReadWriteOnce 单节点读写挂载
  • ReadOnlyMany 多节点只读挂载
  • ReadWriteMany 多节点读写挂载

cephfs 存储卷3种类型都支持,我们要实现多个nginx跨节点之间的数据共享,所以选择ReadWriteMany模式。

  1. 创建pv并验证
[root@k8s-master1 ~]# kubectl apply -f pv-nfs.yml
persistentvolume/pv-nfs created
[root@k8s-master1 ~]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-nfs   1Gi        RWX            Retain           Available                                   81s

说明:

  • RWX为ReadWriteMany的简写
  • Retain是回收策略
    • Retain表示需要不使用了需要手动回收
    • 参考 回收策略
  1. 编写创建pvc的YAML文件
[root@k8s-master1 ~]# vim pvc-nfs.yml
apiVersion: v1
kind: PersistentVolumeClaim				# 类型为PersistentVolumeClaim(pvc)
metadata:name: pvc-nfs							# pvc的名称
spec:accessModes:- ReadWriteMany						# 访问模式resources:requests:storage: 1Gi						# 大小要与pv的大小保持一致
  1. 创建pvc并验证
[root@k8s-master1 ~]# kubectl apply -f pvc-nfs.yml
persistentvolumeclaim/pvc-nfs created
[root@k8s-master1 ~]# kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-nfs   Bound    pv-nfs   1Gi        RWX                           38s

注意: STATUS 必须为Bound状态 (Bound状态表示pvc与pv绑定OK)

  1. 编写deployment的YMAL
[root@k8s-master1 ~]# vim deploy-nginx-nfs.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: deploy-nginx-nfs
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80volumeMounts:- name: wwwmountPath: /usr/share/nginx/htmlvolumes:- name: wwwpersistentVolumeClaim:claimName: pvc-nfs
  1. 应用YAML创建deploment
[root@k8s-master1 ~]# kubectl apply -f deploy-nginx-nfs.yml
deployment.apps/deploy-nginx-nfs created
  1. 验证pod
[root@k8s-master1 ~]# kubectl get pod |grep deploy-nginx-nfs
deploy-nginx-nfs-6f9bc4546c-gbzcl   1/1     Running   0          1m46s
deploy-nginx-nfs-6f9bc4546c-hp4cv   1/1     Running   0          1m46s
  1. 验证pod内卷的数据
[root@k8s-master1 ~]# kubectl exec -it deploy-nginx-nfs-6f9bc4546c-gbzcl -- /bin/sh
/ # ls /usr/share/nginx/html/
index.html
/ # cat /usr/share/nginx/html/index.html
volume-nfs
/ # exit[root@k8s-master1 ~]# kubectl exec -it deploy-nginx-nfs-6f9bc4546c-hp4cv -- /bin/sh
/ # ls /usr/share/nginx/html/
index.html
/ # cat /usr/share/nginx/html/index.html
volume-nfs
/ # exit

7.4 subpath使用

subpath 是指可以把相同目录下不同子目录挂载到容器中不同的目录中使用的方法。以下通过案例演示:

编辑文件
# vim 01_create_pod.yaml编辑后查看,保持内容一致即可
# cat 01_create_pod.yaml
apiVersion: v1
kind: Pod
metadata:name: pod1
spec:containers:- name: c1image: busyboxcommand: ["/bin/sleep","100000"]volumeMounts:- name: datamountPath: /opt/data1subPath: data1- name: datamountPath: /opt/data2subPath: data2volumes:- name: datapersistentVolumeClaim:claimName: pvc-nfs执行文件,创建pod
# kubectl apply -f 01_create_pod.yaml
pod/pod1 created
编辑文件
# vim 02_create_pvc.yaml查看编辑后文件,保持内容一致即可
# cat 02_create_pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim                             # 类型为PersistentVolumeClaim(pvc)
metadata:name: pvc-nfs                                                 # pvc的名称
spec:accessModes:- ReadWriteMany                                             # 访问模式resources:requests:storage: 1Gi                                              # 大小要与pv的大小保持一致
执行文件,创建pvc
# kubectl apply  -f 02_create_pvc.yaml
persistentvolumeclaim/pvc-nfs created
编辑文件
# vim 03_create_pv_nfs.yaml查看编辑后文件,保持内容一致,注意修改nfs服务器及其共享的目录
# cat 03_create_pv_nfs.yaml
apiVersion: v1
kind: PersistentVolume                                           # 类型为PersistentVolume(pv)
metadata:name: pv-nfs                                                   # 名称
spec:capacity:storage: 1Gi                                                 # 大小accessModes:- ReadWriteMany                                              # 访问模式nfs:path: /sdb                                                   # nfs共享目录server: 192.168.10.214
执行文件,创建pv
# kubectl apply -f 03_create_pv_nfs.yaml
persistentvolume/pv-nfs created在nfs服务器查看pod中目录是否自动添加到nfs服务器/sdb目录中
[root@nfsserver ~]# ls /sdb
data1  data2

八、存储的动态供给

8.1 什么是动态供给

每次使用存储要先创建pv, 再创建pvc,真累!所以我们可以实现使用存储的动态供给特性。

  • 静态存储需要用户申请PVC时保证容量和读写类型与预置PV的容量及读写类型完全匹配,而动态存储则无需如此。
  • 管理员无需预先创建大量的PV作为存储资源

Kubernetes从1.4 版起引入了一个新的资源对象 StorageClass,可用于将存储资源定义为具有显著特性的类(Class)而不是具体的PV。用户通过PVC直接向意向的类别发出申请,匹配由管理员事先创建的PV,或者由其按需为用户动态创建PV,这样就免去了需要先创建PV的过程。

8.2 使用NFS文件系统创建存储动态供给

PV对存储系统的支持可通过其插件来实现,目前,Kubernetes支持如下类型的插件。

官方地址:https://kubernetes.io/docs/concepts/storage/storage-classes/

官方插件是不支持NFS动态供给的,但是我们可以用第三方的插件来实现

第三方插件地址: https://github.com/kubernetes-retired/external-storage

  1. 下载并创建storageclass
[root@k8s-master1 ~]# wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/class.yaml
[root@k8s-master1 ~]# mv class.yaml storageclass-nfs.yml[root@k8s-master1 ~]# cat storageclass-nfs.yml
apiVersion: storage.k8s.io/v1
kind: StorageClass				# 类型
metadata:name: nfs-client				# 名称,要使用就需要调用此名称
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner 	# 动态供给插件
parameters:archiveOnDelete: "false"		# 删除数据时是否存档,false表示不存档,true表示存档
[root@k8s-master1 ~]# kubectl apply -f storageclass-nfs.yml
storageclass.storage.k8s.io/managed-nfs-storage created[root@k8s-master1 ~]# kubectl get storageclass
NAME         PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-client   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  10s# RECLAIMPOLICY pv回收策略,pod或pvc被删除后,pv是否删除还是保留。
# VOLUMEBINDINGMODE Immediate 模式下PVC与PV立即绑定,主要是不等待相关Pod调度完成,不关心其运行节点,直接完成绑定。相反的 WaitForFirstConsumer模式下需要等待Pod调度完成后进行PV绑定。
# ALLOWVOLUMEEXPANSION pvc扩容
  1. 下载并创建rbac

因为storage自动创建pv需要经过kube-apiserver,所以需要授权。

[root@k8s-master1 ~]# wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml
[root@k8s-master1 ~]# mv rbac.yaml storageclass-nfs-rbac.yaml[root@k8s-master1 ~]# cat storageclass-nfs-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:name: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: nfs-client-provisioner-runner
rules:- apiGroups: [""]resources: ["persistentvolumes"]verbs: ["get", "list", "watch", "create", "delete"]- apiGroups: [""]resources: ["persistentvolumeclaims"]verbs: ["get", "list", "watch", "update"]- apiGroups: ["storage.k8s.io"]resources: ["storageclasses"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["events"]verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: run-nfs-client-provisioner
subjects:- kind: ServiceAccountname: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
roleRef:kind: ClusterRolename: nfs-client-provisioner-runnerapiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: leader-locking-nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
rules:- apiGroups: [""]resources: ["endpoints"]verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: leader-locking-nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
subjects:- kind: ServiceAccountname: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
roleRef:kind: Rolename: leader-locking-nfs-client-provisionerapiGroup: rbac.authorization.k8s.io
[root@k8s-master1 ~]# kubectl apply -f rbac.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
  1. 创建动态供给的deployment
    需要一个deployment来专门实现pv与pvc的自动创建
[root@k8s-master1 ~]# vim deploy-nfs-client-provisioner.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: nfs-client-provisioner
spec:replicas: 1strategy:type: Recreateselector:matchLabels:app: nfs-client-provisionertemplate:metadata:labels:app: nfs-client-provisionerspec:serviceAccount: nfs-client-provisionercontainers:- name: nfs-client-provisionerimage: registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0volumeMounts:- name: nfs-client-rootmountPath: /persistentvolumesenv:- name: PROVISIONER_NAMEvalue: k8s-sigs.io/nfs-subdir-external-provisioner- name: NFS_SERVERvalue: 192.168.10.129- name: NFS_PATHvalue: /data/nfsvolumes:- name: nfs-client-rootnfs:server: 192.168.10.129path: /data/nfs
[root@k8s-master1 ~]# kubectl apply -f deploy-nfs-client-provisioner.yml
deployment.apps/nfs-client-provisioner created[root@k8s-master1 ~]# kubectl get pods |grep nfs-client-provisioner
nfs-client-provisioner-5b5ddcd6c8-b6zbq   1/1     Running   0          34s
测试存储动态供给是否可用
# vim nginx-sc.yaml
---
apiVersion: v1
kind: Service
metadata:name: nginxlabels:app: nginx
spec:ports:- port: 80name: webclusterIP: Noneselector:app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:name: web
spec:selector:matchLabels:app: nginxserviceName: "nginx"replicas: 2template:metadata:labels:app: nginxspec:imagePullSecrets:- name: huoban-harborterminationGracePeriodSeconds: 10containers:- name: nginximage: nginx:latestports:- containerPort: 80name: webvolumeMounts:- name: wwwmountPath: /usr/share/nginx/htmlvolumeClaimTemplates:- metadata:name: wwwspec:accessModes: [ "ReadWriteOnce" ]storageClassName: "nfs-client"resources:requests:storage: 1Gi
[root@k8s-master1 nfs]# kubectl get pods
NAME                                     READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-9c988bc46-pr55n   1/1     Running   0          95s
web-0                                    1/1     Running   0          95s
web-1                                    1/1     Running   0          61s[root@nfsserver ~]# ls /data/nfs/
default-www-web-0-pvc-c4f7aeb0-6ee9-447f-a893-821774b8d11f  default-www-web-1-pvc-8b8a4d3d-f75f-43af-8387-b7073d07ec01 

扩展:

批量下载文件:
# for file in class.yaml deployment.yaml rbac.yaml  ;
do wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/nfs-client/deploy/$file ; 
done

相关文章:

kubernetes持久化存储卷

kubernetes持久化存储卷 kubernetes持久化存储卷一、存储卷介绍二、存储卷的分类三、存储卷的选择四、本地存储卷之emptyDir五、本地存储卷之 hostPath六、网络存储卷之nfs七、PV(持久存储卷)与PVC(持久存储卷声明)7.1 认识pv与pvc7.2 pv与pvc之间的关系7.3 实现nfs类型pv与pvc…...

【Rust笔记】意译解构 Object Safety for trait

意译解构Object Safety for trait 借助【虚表vtable】对被调用成员函数【运行时内存寻址】的作法允许系统编程语言Rust模仿出OOP高级计算机语言才具备的【专用多态Ad-hoc Polymorphism】特性。 计算机高级语言中的“多态”术语是一个泛指。它通常可被细化为 基于继承关系的“子…...

Spring Boot单元测试入门指南

Spring Boot单元测试入门指南 JUnit是一个成熟和广泛应用的Java单元测试框架&#xff0c;它提供了丰富的功能和灵活的扩展机制&#xff0c;可以帮助开发人员编写高质量的单元测试。通过JUnit&#xff0c;开发人员可以更加自信地进行重构、维护和改进代码&#xff0c;同时提高代…...

《面试1v1》如何能从Kafka得到准确的信息

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…...

2023秋招面试题持续更新中。。。

目录 1.八股文渐进式MVVM三次握手&#xff0c;四次挥手viteajax组件化和模块化虚拟dom原理流程浏览器内核浏览器渲染过程回流和重绘nextTick 2.项目相关1.声明式导航和编程式导航重写push和replace方法&#xff1a;性能优化图片懒加载路由懒加载 http请求方式 1.八股文 渐进式…...

Java | 数组排序算法

一、冒泡排序 冒泡排序的基本思想是对比相邻的元素值&#xff0c;如果满足条件就交换元素值&#xff0c;把较小的元素移到数组前面&#xff0c;把较大的元素移到数组后面&#xff08;也就是交换两个元素的位置&#xff09;&#xff0c;这样较小的元素就像气泡一样从底部升到顶…...

android studio 连接SQLite数据库并实现增删改查功能

功能代码及调试代码 package com.example.bankappdemo;import android.annotation.SuppressLint; import android.content.ContentValues; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.util.Log; import android.view.View; im…...

跑步适合戴什么样的耳机、最好的跑步耳机推荐

每个人对于运动的方式都不尽相同&#xff0c;但大多数热爱运动的朋友都离不开音乐的陪伴。运动和带有节奏感的音乐能够激发我们更多的热情和动力。特别是在夏日的时候&#xff0c;我非常喜欢跑步。在酷热的天气里&#xff0c;如果没有音乐的伴随&#xff0c;跑步会变得单调乏味…...

物联网的通信协议

物联网的通信协议 目录 物联网的通信协议一、UART串口通信1.1 串口通信1.2 异步收发1.3 波特率1.4 串口通信协议的数据帧1.5 优缺点1.5.1 优点1.5.2 缺点 二、I^2^C2.1 I^2^C2.2 I^2^C2.3 数据有效性2.4 起始条件S和停止条件P2.5 数据格式2.6 协议数据单元PDU2.7 优缺点2.7.1 优…...

【业务功能篇56】SpringBoot 日志SLF4J Logback

3.5.1 日志框架分类与选择 3.5.1.1 日志框架的分类 日志门面 (日志抽象)日志实现JCL(Jakarta Commons Logging) SLF4J(Simple Logging Facade for Java)Jul(Java Util Logging) , Log4j , Log4j2 , Logback 记录型日志框架 Jul (Java Util Logging)&#xff1a;JDK中的日志…...

leetcode 53. 最大子数组和

2023.7.28 要求找最大和的 连续子数组&#xff0c; 我的思路是用一个temp记录局部最优值&#xff0c;用ans记录全局最优值。 然后在每次for循环进行一个判断&#xff1a;当前遍历元素temp值 是否大于当前遍历元素的值&#xff0c;如果大于&#xff0c;说明temp值是帮了正忙的&a…...

js 下载url返回的excel数据,并解析为json

XLSX GitHub地址&#xff1a;https://github.com/SheetJS/sheetjs/blob/github/dist/xlsx.full.min.js 需要先引入&#xff1a;XLSX.full.min.js // 下载文件的请求 fetch(downloadFileUrl).then(response > {return rsp.blob() }).then(data > {let reader new FileR…...

图文教程:使用 Photoshop、3ds Max 和 After Effects 创建被风暴摧毁的小屋

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 在 Photoshop 中设置图像 步骤 1 打开 Photoshop。 打开 Photoshop 步骤 2 我已经将小屋的图像导入到Photoshop中以演示 影响。如果您愿意&#xff0c;可以使用其他图像。 图片导入 步骤 3 由于小…...

学习Maven Web 应用

Maven Web 应用 本章节我们将学习如何使用版本控制系统 Maven 来管理一个基于 web 的项目&#xff0c;如何创建、构建、部署已经运行一个 web 应用。 创建 Web 应用 我们可以使用 maven-archetype-webapp 插件来创建一个简单的 Java web 应用。 打开命令控制台&#xff0c;…...

page allocation stalls for 问题调研

一.现象分析和内存管理基本概念介绍 最近有一台linux出现卡死的状态,系统不反应,无法ssh登录,只能通过电源关机重启操作恢复,重启后登录系统后台,拉取kernel日志,如下 Jul 12 18:48:06 kernel: [141294.374983] send process: page allocation stalls for 10108ms, orde…...

JUC并发工具类

一、ReentrantLock 特点&#xff1a;独占、可重入、公平/非公平、可中断、支持多个条件变量 1、常用api ReentrantLock实现了Lock接口&#xff0c;Lock类规范定义了如下方法 lock()&#xff1a;获取锁&#xff0c;调用该方法的线程会获取锁&#xff0c;当锁获得后&#xff0…...

【雕爷学编程】MicroPython动手做(10)——零基础学MaixPy之神经网络KPU

早上百度搜“神经网络KPU”&#xff0c;查到与非网的一篇文章《一文读懂APU/BPU/CPU/DPU/EPU/FPU/GPU等处理器》&#xff0c;介绍各种处理器非常详细&#xff0c;关于“KPU”的内容如下&#xff1a; KPU Knowledge Processing Unit。 嘉楠耘智&#xff08;canaan&#xff09;号…...

MySQL~SQL语句

一、SQL 1.什么是SQL&#xff1f; Structured Query Language&#xff1a;结构化查询语言 每一种数据库操作的方式存在不一样的地方&#xff0c;称为“方言”。 2.SQL通用语法 SQL 语句可以单行或多行书写&#xff0c;以分号结尾 可使用空格和缩进来增强语句的可读性 MyS…...

从零开始构建基于YOLOv5的目标检测系统

本博文从零开始搭建基于YOLOv5模型的目标检测系统&#xff08;具体系统参考本博主的其他博客&#xff09;&#xff0c;手把手保姆级完成环境的搭建。 &#xff08;1&#xff09;首先Windows R输入cmd命令后打开命令窗口&#xff0c;进入项目目录&#xff0c;本博文以野生动物…...

PDF尺寸修改:等比绽放(标准面单100*150mm)

PDF修改尺寸 需要注意&#xff1a;第一个方法返回的是转换后PDF的base64。第二个方法返回的是文件流&#xff0c;这个方法才是转的核心。 /*** 修改PDF尺寸** param pdfUrl PDF链接* param pdfWidthInMillimeters 指定宽 mm* param pdfHeightInMillimeters 指…...

C++ - list介绍 和 list的模拟实现

list介绍 list 是一个支持在常数范围内&#xff0c;任意位置进行插入删除的序列式容器&#xff0c;且这个容器可以前后双向迭代。我们可以把 list 理解为 双向循环链表的结构。 于其他结构的容器相比&#xff0c;list在 任意位置进行插入和函数的效率要高很多&#xff1b;而li…...

干翻Dubbo系列第四篇:Dubbo3第一个应用程序细节补充

前言 不从恶人的计谋&#xff0c;不站罪人的道路&#xff0c;不坐亵慢人的座位&#xff0c;惟喜爱耶和华的律法&#xff0c;昼夜思想&#xff0c;这人便为有福&#xff01;他要像一棵树栽在溪水旁&#xff0c;按时候结果子&#xff0c;叶子也不枯干。凡他所做的尽都顺利。 如…...

深度学习初探

1.深度学习模型训练过程 1&#xff09;数据&#xff08;数据清洗标注&#xff09; 2&#xff09;模型&#xff08;模型的构建和初始化&#xff09; 3&#xff09;损失&#xff08;前向传播的过程&#xff0c;得到模型的输出和真实标签的差异值&#xff0c;称之为损失&#x…...

nn.BCELoss与nn.CrossEntropyLoss

BCELoss与CrossEntropyLoss都是用于分类问题。可以知道&#xff0c;BCELoss是Binary CrossEntropyLoss的缩写&#xff0c;BCELoss是CrossEntropyLoss的一个特例&#xff0c;只用于二分类问题&#xff0c;而CrossEntropyLoss可以用于二分类&#xff0c;也可以用于多分类&#xf…...

CSDN浏览如何解决

一、对于平时我们苦恼csdn数据不够好看 当面试等各个场合需要我们装*或者秀技术无法拿出亮眼的时候&#xff0c;刚好我闲时间编译的在线模块适合你 二、如何操作&#xff08;虚拟平台我已给大家放到最后直接使用即可&#xff09; 重点&#xff1a;pc端必须拥有python环境 win…...

web前端开发小知识

当今互联网技术迅猛发展&#xff0c;web前端开发也成为了非常热门的职业之一。作为一个web前端开发者&#xff0c;不仅需要掌握各种前端开发技术&#xff0c;还需要了解一些小技巧和小知识。下面&#xff0c;我们将介绍一些web前端开发小知识&#xff0c;希望对你的工作有所帮助…...

Java泛型的简单认识

泛型的认识 自定义泛型&#xff0c;定义了String类型&#xff0c;随后这个泛型就是String类型 于是他的方法都是字符串的类型 泛型接口 泛型方法 所有车可以进行比赛&#xff0c;定义了一个BMW和BENZ两个车类&#xff0c;都继承car&#xff0c;当使用泛型的 如果你顶一个狗对象…...

视频转化为图片或灰度视频

1.视频转化为图片 import cv2video_pathr"D:\Dataset\video/7.mp4" capturecv2.VideoCapture(video_path) # print(capture.get(5))if capture.isOpened():ret,imgcapture.read()index0while ret:if index%200:imgidr"D:\Dataset\image/6/""%07d&quo…...

【动态规划刷题 2】使⽤最⼩花费爬楼梯 解码⽅法

使⽤最⼩花费爬楼梯 746 . 使用最小花费爬楼梯 链接: 746 . 使用最小花费爬楼梯 给你一个整数数组 cost &#xff0c;其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用&#xff0c;即可选择向上爬一个或者两个台阶。 你可以选择从下标为 0 或下标为 …...

Python的基本语法

“有人说&#xff0c;写python就像是坐在一个没有安全带的车上&#xff0c; 我认为这个说法很欠妥当&#xff0c; 应该是一辆没有外壳和座椅&#xff0c; 只有发动机和轮子的车&#xff0c; 并且车上摆满了轮子” python既然是作为一个工具&#xff0c;那么就不需要去深入…...