K8s service 底层逻辑

文章目录

  • K8s service 底层逻辑
    • Kube-proxy 代理模式
    • Service 请求情况
      • Service-Iptables 模式
        • iptables 规则介绍
        • ClusterIP 模式分析
        • NodePort 模式分析
      • Service- IPVS 模式
    • 服务发现
      • 环境变量
      • CoreDNS
      • CoreDNS 策略
        • ClusterFirst(默认DNS策略)
        • CluterFirstWithHostNet
        • Default
        • None
    • HeadLess Service
      • Headless的作用
      • HeadLess 示例

K8s service 底层逻辑

Kube-proxy 代理模式

Kube-proxy 代理模式有一下三种

userSpace(已废弃)

userspace 模式下,kube-proxy 为Service IP 创建一个监听端口,当用户向ServiceIP 发送请求

  1. 首先请求会被Iptables规则拦截,然后重定向到Kube-Proxy对应的端口
  2. 然后Kube-Proxy 根据调度算法选择一个Pod,将请求调度到该Pod 上

总结:Pod请求ServiceIP时,会被Iptables将请求拦截给用户空间的Kube-Proxy,然后再经过内核空间路由到对应的Pod;

问题:但是该模式流量经过内核空间后,会送往用户空问kube-Proxy进程,而后又送回内核空间,发往调度分配的目标后端Pod;

iptables

iptables 模式下,kube-proxy 为Service后端的所有Pod创建对应的iptables规则,当用户向ServiceIP发送请求时

  1. 首先Iptables 会拦截用户请求
  2. 然后直接将请求调度到后端的Pod

总结:Pod请求Service IP时,Iptables 将请求拦截并直接完成调度,然后转发到对应的Pod,效率比userspace 高

问题:一个Service 会创建出大量的iptables规则,且不支持更高级的调度算法,当Pod 不可用也无法重试

IPVS

Itvs 模式和iptables类似,kube-proxy为service 后端的所有pod 创建对应的IPVS规则,一个Service只会生成一条规则,所以规模较大的场景下,应该使用IPVS模式。其次IPVS支持更高级的调度算法

Service 请求情况

访问Service会出现如下四种情况;

  1. Pod-A ->Service-> 调度 -> Pod-B/Pod-C
  2. Pod-A -> Service -> 调度 -> Pod-A
  3. Docker -> Service调度 -> pod-B/pod-c
  4. NodePort -> Service -> 调度-> pod-B/pod-C

Service-Iptables 模式

在这里插入图片描述

iptables 规则介绍
iptables中的四表五链1. 四个表具备某种功能的集合叫做表。filter:  负责做过滤功能呢	    nat:	 网络地址转换	      		mangle:	 负责修改数据包内容	      raw:	 负责数据包跟踪              2. 五个链在什么位置执行,能把表放在某个地方执行PREROUTING、INPUT、OUTPUT、FORWARD、POSTROUTING1) PREROUTING: 主机外报文进入位置,允许的表mangle, nat(目标地址转换,把本机地址转换为真正的目标机地址,通常指响应报文)2) INPUT:报文进入本机用户空间位置,允许的表filter, mangle3) OUTPUT:报文从本机用户空间出去的位置,允许filter, mangle, nat4) FOWARD:报文经过路由并且发觉不是本机决定转发但还不知道从哪个网卡出去,允许filter, mangle5) POSTROUTING:报文经过路由被转发出去,允许mangle,nat(源地址转换,把原始地址转换为转发主机出口网卡地址)流入本机: PREROUTING   --> INPUT --> PROCESS(进程)从本机流出:  PROCESS(进程)   --> OUTPUT   --> POSTROUTING经过本机: A ---> OUTPUT ---> POSTROUTING | ---> PREROUTING ---> FORWARD  ---> POSTROUTING ---> C ---> PREROUTING  ---> INPUT ---> B

更多iptables相关参考 Linux之Iptables. Linux之iptables使用 Linux之Iptables模块使用

ClusterIP 模式分析
  1. 从Pod发出的请求会先经过 OUTPUT ,然后被转发到 KUBE-SERVICES 自定义规则链中

    [root@k8s-master ~]# iptables -t nat -S OUTPUT
    -P OUTPUT ACCEPT      # 默认通过
    -A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES  # 转发到 KUBE-SERVICES 
    
  2. KUBE-SERVICES 自定义规则链中,所有对nginx-svc发起的请求都会调度到KUBE-SVC- 链上

[root@k8s-master ~]# iptables -t nat -S KUBE-SERVICES
-N KUBE-SERVICES    # 创建自定义链
-A KUBE-SERVICES -d 10.107.78.95/32 -p tcp -m comment --comment "default/nginx-svc:http cluster IP" -m tcp --dport 80 -j KUBE-SVC-ELCM5PCEQWBTUJ2I  # 
...
  1. 查看 KUBE-SVC- 自定义链

    [root@k8s-master ~]# iptables -t nat -S KUBE-SVC-ELCM5PCEQWBTUJ2I
    -N KUBE-SVC-ELCM5PCEQWBTUJ2I   # 创建自定义链
    -A KUBE-SVC-ELCM5PCEQWBTUJ2I ! -s 10.244.0.0/16 -d 10.107.78.95/32 -p tcp -m comment --comment "default/nginx-svc:http cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ  处理
    # 来源地址不是 10.244.0.0/16(Pod ip网段) 访问 地址是 10.107.78.95/32 (nginx-svc Service ip) 的IP交给 KUBE-MARK-MASQ  处理
    -A KUBE-SVC-ELCM5PCEQWBTUJ2I -m comment --comment "default/nginx-svc:http" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-HCUFVO5PTBGTHQ3U  # 第一次 50% 几率(两个pod)
    -A KUBE-SVC-ELCM5PCEQWBTUJ2I -m comment --comment "default/nginx-svc:http" -j KUBE-SEP-7U4Y7ZRUZBRTYDGE  # 第二次100% 几率
    
  2. 查看任意一条 KUBE-SEP- 自定义链

    [root@k8s-master ~]# iptables -t nat -S KUBE-SEP-7U4Y7ZRUZBRTYDGE
    -N KUBE-SEP-7U4Y7ZRUZBRTYDGE  # 创建自定义链
    -A KUBE-SEP-7U4Y7ZRUZBRTYDGE -s 10.244.36.76/32 -m comment --comment "default/nginx-svc:http" -j KUBE-MARK-MASQ     # 请求ip如果是Pod 的IP,则交给  KUBE-MARK-MASQ 处理
    -A KUBE-SEP-7U4Y7ZRUZBRTYDGE -p tcp -m comment --comment "default/nginx-svc:http" -m tcp -j DNAT --to-destination 10.244.36.76:80  # 进行DNAT 地址替换, 将请求 ServiceIP 替换为后端的 PodIP,然后发出请求
    
  3. 查看 KUBE-MARK-MASQ

    [root@k8s-master ~]# iptables -t nat -S KUBE-MARK-MASQ 
    -N KUBE-MARK-MASQ   # 创建自定义链
    -A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000  # 给数据包打上 makr
    
  4. OUTPUT 处理完后,数据包会流入 POSTROUTING 链,由 POSTROUTING 链决定怎么发送数据包

    [root@k8s-master ~]# iptables -t nat -S POSTROUTING
    -P POSTROUTING ACCEPT  # 默认通过
    -A POSTROUTING -m comment --comment "cali:O3lYWMrLQYEMJtB5" -j cali-POSTROUTING
    # calico 网络插件,数据包跳转到  cali-POSTROUTING 自定义链处理
    -A POSTROUTING -s 172.20.0.0/16 ! -o docker0 -j MASQUERADE  # docker 默认规则不用管
    -A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
    # 数据包进入 KUBE-POSTROUTING  自定义链处理
    
  5. 查看 cali-POSTROUTING 数据链

    [root@k8s-master ~]#  iptables -t nat -S cali-POSTROUTING
    -N cali-POSTROUTING  # 创建自定义链
    -A cali-POSTROUTING -m comment --comment "cali:Z-c7XtVd2Bq7s_hA" -j cali-fip-snat
    # 转到 cali-fip-snat 链
    -A cali-POSTROUTING -m comment --comment "cali:nYKhEzDlr11Jccal" -j cali-nat-outgoing
    # 转到 cali-nat-outgoing 链
    -A cali-POSTROUTING -o tunl0 -m comment --comment "cali:JHlpT-eSqR1TvyYm" -m addrtype ! --src-type LOCAL --limit-iface-out -m addrtype --src-type LOCAL -j MASQUERADE
    # 匹配那些源地址不是从 tunl0 网卡输出出去的数据包,但是源地址是 tunl0 网段的数据包发送到目标ip[root@k8s-master ~]#  iptables -t nat -S cali-fip-snat
    -N cali-fip-snat  # 创建自定义链[root@k8s-master ~]#  iptables -t nat -S cali-nat-outgoing
    -N cali-nat-outgoing  # 创建自定义链
    -A cali-nat-outgoing -m comment --comment "cali:Dw4T8UWPnCLxRJiI" -m set --match-set cali40masq-ipam-pools src -m set ! --match-set cali40all-ipam-pools dst -j MASQUERADE
    # 源地址在 cali40masq-ipam-pools 集合中,且目标地址不在 cali40all-ipam-pools 集合中 发送到目标ip  tunl0 网卡,calico 创建的网卡  
    '''ClusterIP 类型走这条规则'''[root@k8s-master ~]# ipset list cali40masq-ipam-pools  # 查看ip网段
    Name: cali40masq-ipam-pools
    Type: hash:net
    Revision: 6
    Header: family inet hashsize 1024 maxelem 1048576
    Size in memory: 440
    References: 1
    Number of entries: 1
    Members:
    10.244.0.0/16
    
  6. 查看 KUBE-POSTROUTING 自定义链

    [root@k8s-master ~]# iptables -t nat -S KUBE-POSTROUTING
    -N KUBE-POSTROUTING # 创建自定义链
    -A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN
    # 如果没有匹配 0x4000/0x4000 就RETURN 回 POSTROUTING 继续处理
    -A KUBE-POSTROUTING -j MARK --set-xmark 0x4000/0x0
    # 如果匹配上一条就打上一个 标记   0x4000/0x0
    -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE
    # 对 源地址进行 SNAT, SNAT 节点去往目标IP最近的接口IP地址
    

在这里插入图片描述

NodePort 模式分析
  1. NodePort 先要经过PREROUTING 链,然后将所有请转入KUBE-SERVICES自定义链

    [root@k8s-master ~]# iptables -t nat -S PREROUTING
    -P PREROUTING ACCEPT
    -A PREROUTING -m comment --comment "cali:6gwbT8clXdHdC1b1" -j cali-PREROUTING
    -A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
    -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER-INGRESS
    -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER# cali-PREROUTING 自定义链默认啥都没干,如果用的 flannel 网络组建,就直接转入 KUBE-SERVICES自定义链
    [root@k8s-master ~]# iptables -t nat -S cali-PREROUTING 
    -N cali-PREROUTING
    -A cali-PREROUTING -m comment --comment "cali:r6XmIziWUJsdOK6Z" -j cali-fip-dnat
    [root@k8s-master ~]# iptables -t nat -S cali-fip-dnat
    -N cali-fip-dnat
    
  2. 打印KUBE-SERVICE 自定链,过滤和nodeport 相关规则,规则调度到 KUBE-NODEPORTS

    [root@k8s-master ~]# iptables -t nat -S KUBE-SERVICES | grep nodeports
    -A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
    
  3. 打印 KUBE-NODEPORTS 自定义链, 后面就转入了 KUBE-SVC-

    [root@k8s-master ~]# iptables -t nat -S KUBE-NODEPORTS
    -N KUBE-NODEPORTS
    -A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx-sc:web" -m tcp --dport 31996 -j KUBE-SVC-IIUXE3BBFAXNZ4WP
    

在后面和 ClusterIP 流程类似,但是需要注意的是,数据包匹配的规则不一样,所以不能说后面就是 ClusterIP 的链路。

在这里插入图片描述

Service- IPVS 模式

  1. IPVS 会在每个节点上创建一个名为kube-ipvs0的虛拟接口,并将集群所有Service对象的ClusterIP都配置在该接口
  2. Kube-Proxy将每个Service生成一个虚拟服务器VirtualServer的定义(集群ip,集群对应后端的ip)

注意:ipvs仅需要借助极少量的iptables规则完成源地址转换、源端口转换等;

设置集群为IPVS模式:

[root@k8s-master ~]# kubectl edit cm kube-proxy -n kube-system  # 修改 kube-proxy 配置文件ipvs:excludeCIDRs: nullminSyncPeriod: 0sscheduler: ""strictARP: falsesyncPeriod: 0stcpFinTimeout: 0stcpTimeout: 0sudpTimeout: 0skind: KubeProxyConfigurationmetricsBindAddress: ""mode: "ipvs"  # 该为 ipvs 即可nodePortAddresses: nulloomScoreAdj: null# 删除原来的 kube-proxy pod ,重启更新配置
[root@k8s-master ~]# kubectl  delete po -l k8s-app=kube-proxy -n kube-system# 下载 ipvsadm
[root@k8s-master ~]# yum install -y ipvsadm# 通过 ipvsadm 查看 
[root@k8s-master ~]# ipvsadm -Ln# 并且会加上一个 kube-ipvs0 网卡
[root@k8s-master ~]# ip addr | grep kube-ipvs0

在这里插入图片描述
在这里插入图片描述

服务发现

当Pod需要访问Service时,通过Service提供的ClusterIP就可以实现了,但是有几个问题;

  1. Service的IP不稳定,删除重建会发生变化;
  2. ServiceIP难以记忆,如果能通过一个固定的名称访问就好了;

为了解决这样的问题,kubernetes引入了环境变量和DNS两种方案来解决这样的问题;

  1. 环境变量方式:通过特定的名称将环境变量注入到Pod内部;
  2. DNS方式:通过APIServer来监视Service变动,而后动态创建对应Service名称与ServiceIP的域名解析记录;

环境变量

每个 Pod 启动的时候,会通过环境变量的方式将Service的IP以及Port信息注入进去,这样 Pod 中的应用可以通过读取环境变量来获取对应service服务的地址信息,这种方法使用起来相对简单但是也存在一定的问题。就是Pod所依赖的Service必须优Pod启动,否则无法注入到环境变量中。

在这里插入图片描述

CoreDNS

在安装Kubernetes集群时,CoreDNS作为附加组件,用来为Pod提供DNS域名解析。CoreDNs监视 Kubernetes API 中的新service, 并为每个service名称创建一组DNS 记录。这样我们就可以通过固定的Service名称来转换出不固定ServiceIP

[root@k8s-master ~]# kubectl get cm  coredns -n kube-system -o yaml 
apiVersion: v1
data:Corefile: |.:53 {errors      # 错误记录health {     # 健康检查lameduck 5s    }readykubernetes cluster.local in-addr.arpa ip6.arpa {    # 用于解析kubernets 集群内域名pods insecurefallthrough in-addr.arpa ip6.arpattl 30}prometheus :9153             # 监控端口forward . /etc/resolv.conf {    # 如果请求非kubernetes 域名,则用节点resolv.conf 中的dns解析max_concurrent 1000}cache 30       # 缓存所有内容loopreload          # 支持热更新loadbalance     # 负载均衡,默认轮询}
kind: ConfigMap

CoreDNS 之所以是固定IP 以及固定的搜索域。是因为kubelet 将 --cluster-dns=、 --cluster-domain= 对应的配置传递给了每个容

[root@k8s-master ~]# cat /var/lib/kubelet/config.yaml 
apiVersion: kubelet.config.k8s.io/v1beta1
...
clusterDNS:
- 10.96.0.10             # DNS 固定的ServiceIP
clusterDomain: cluster.local   # 域名
...[root@k8s-master ~]# kubectl exec -it nginx-sc-0   -- bash
root@nginx-sc-0:/# cat /etc/resolv.conf 
nameserver 10.96.0.10    # pod 里面默认配置的 dns   把这个配置到节点中,就能在节点上通过域名访问pod了
search default.svc.cluster.local svc.cluster.local cluster.local   # dns 解析器会依次尝试在这个列表中的每个域名后缀前加上这个短域名,并查询新构造的完整域名
options ndots:5

CoreDNS 策略

DNS策略可以单独对Pod进行设定,在创建Pod时可以为其指定DNS策略,最终配置会落在Pod的/etc/resolv.conf 文件中,可以通过 pod.spec.dnsPolicy 字段设置DNS的策略

ClusterFirst(默认DNS策略)

Pod 内的DNS使用集群中配置的DNS服务,简单来说就是使用Kubernets 中的 coredns 服务进行域名解析。如果不成功, 会使用当前Pod 所在的宿主机DNS 进行解析

apiVersion: v1
kind: Pod
metadata:name: dns-example-1
spec:dnsPolicy: ClusterFirstcontainers:- name: toolsimage: nginx:1.7.9ports:- containerPort: 8899
CluterFirstWithHostNet

在某些场景下,我们的 Pod是用HostNetwork 模式启动的,一旦使用HostNetwork 模式,那该Pod则会使用当前宿主机的/etc/resolv.conf、来进行 DNS 查询,但如果任然想继续使用Kubernetes 的DNS服务,那就将dnsPolicy 设置为ClusterFirstWithHostNet

apiVersion: v1
kind: Pod
metadata:name: dns-example-2
spec:hostNetwork: true             # 与宿主机共享网络名称空间 如果只设置这个,就不会使用coredns服务,无法通过域名解析找到对应的poddnsPolicy: ClusterFirstWithHostNet  containers:- name: toolsimage: nginx:1.7.9imagePullPolicy: IfNotPresentports:- containerPort: 8899
Default

默认使用宿主机的 /etc/resolv.conf 但可以使用kubelet 的 --resolv-conf=/etc/resolv.conf 来指定DNS 解析文件地址

None

空的DNS设置,这种方式一般用于自定义 DNS 配置的场景, 往往需要和dnsConfig 一起使用才能达到自定义DNS的目录

apiVersion: v1
kind: Pod
metadata:name: dns-example-4
spec:containers:- name: toolsimage: nginx:1.7.9imagePullPolicy: IfNotPresentports:- containerPort: 8899dnsPolicy: NonednsConfig:nameservers:- 10.96.0.10- 114.114.114.114searches:- cluster.local- svc.cluster.local- default.svc.cluster.local options:- name: ndotsvalue: "5"

HeadLess Service

HeadlessService也叫无头服务,就是创建的Service没有ClusterIP,而是为Service所匹配的每个Pod都创建一条DNS的解析记录,这样每个Pod都有一个唯一的DNS名称标识身份,访问的格式如下

( s e r v i c e n a m e ) . (service_name). (servicename).(namespace).svc.clustter.local

在这里插入图片描述

Headless的作用

像elasticsearch,mongodb, kafka 等分布式服务,在做集群初始化时,配置文件中要写上集群中所有节点的工P(或是域名)但Pod是没有固定IP的,所以配置文件里写DNS名称是最合适的。

那为什么不用Service, 因为 Service 作为 Pod 前置的负载均衡,一般是为一组相同的后端 Pod 提供访问入口,而且 Service的selector也没有办法区分同一组Pod的不同身份。

但是我们可以使用 Statefulset控制器,它在创建每个Pod的时候,能为每个 Pod 做一个编号,就是为了能区分这一组Pod的不同角色,各个节点的角色不会变得混乱,然后再创建 headless service 资源,集群内的节点通过Pod名称+序号.Service名称,来进行彼此问通信的,只要序号不变,访问就不会出错。

当 statefulset.spec.serviceName 配置与headless service相同时,可以通过 thostName}.theadless service} .{namespace}.svc.cluster.local 解析出节点IP。hostName 由{statefulset name}-{编号} 组成。

HeadLess 示例

apiVersion: v1
kind: Service
metadata:name: myapp
spec:clusterIP: "None" # 设置为None 表示无头服务selector:app: nginx-headports:- port: 80targetPort: 80---
apiVersion: apps/v1
kind: StatefulSet
metadata:name: web-head
spec:serviceName: "myapp"replicas: 3selector:matchLabels:app: nginx-headtemplate:metadata:labels:app: nginx-headspec:containers:- name: nginx-sts-headimage: nginx:1.7.9imagePullPolicy:  IfNotPresentports:- containerPort: 80

查看创建的pod

[root@k8s-master demo]# kubectl get po
NAME                                               READY   STATUS    RESTARTS   AGE
web-head-0                                         1/1     Running   0          2m23s
web-head-1                                         1/1     Running   0          2m20s
web-head-2                                         1/1     Running   0          2m19s

测试

[root@k8s-master demo]# kubectl exec -it nginx-sc-0 -- bash  # 随便找一个pod 进去root@nginx-sc-0:/# ping web-head-0.myapp.default.svc.cluster.local
PING web-head-0.myapp.default.svc.cluster.local (10.244.235.199): 48 data bytes
56 bytes from 10.244.235.199: icmp_seq=0 ttl=63 time=0.193 ms
56 bytes from 10.244.235.199: icmp_seq=1 ttl=63 time=0.198 ms
56 bytes from 10.244.235.199: icmp_seq=2 ttl=63 time=0.191 msroot@nginx-sc-0:/# ping web-head-1.myapp.default                  
PING web-head-1.myapp.default.svc.cluster.local (10.244.36.100): 48 data bytes
56 bytes from 10.244.36.100: icmp_seq=0 ttl=62 time=1.367 msroot@nginx-sc-0:/# ping web-head-2.myapp
PING web-head-2.myapp.default.svc.cluster.local (10.244.235.203): 48 data bytes
56 bytes from 10.244.235.203: icmp_seq=0 ttl=63 time=0.138 ms
56 bytes from 10.244.235.203: icmp_seq=1 ttl=63 time=0.234 ms

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

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

相关文章

gcc编译器

预处理gcc -E b.c -o g.i -S -s -c -o gcc a.c -L acc.c指导路径 3 /

0041__在VC中链接动态链接库(DLL)的方法

在VC中链接动态链接库(DLL)的方法_vc如何链接dll库-CSDN博客

创新入门|营销中的视频内容:不可或缺的策略

视频在营销中日益重要。你是否也发现,视频内容最近似乎无处不在?它占据着社交媒体的推文、网站首页,甚至电子邮件中的位置。事实上,并不是你一个人有这样的感受。在过去十年中,视频作为一种营销手段日益成熟和强大。这是因为,人类天生就是视觉动物。我们大脑处理视觉信息的速度…

基于EasyX的贪吃蛇小游戏 - C语言

游戏基本功能演示: 1.主菜单界面 2.自定难度界面 在这里可以自行设定游戏的难度,包括蛇的移动速度,初始节数,以及默认模式,参考线(网格)。这些设定的数据都会在右上角的游戏属性栏中实时显示。…

图解Mysql索引原理

概述 是什么 索引像是一本书的目录列表,能根据目录快速的找到具体的书本内容,也就是加快了数据库的查询速度索引本质是一个数据结构索引是在存储引擎层,而不是服务器层实现的,所以,并没有统一的索引标准,…

[AI资讯·0605] GLM-4系列开源模型,OpenAI安全疑云,ARM推出终端计算子系统,猿辅导大模型备案……

AI资讯 1毛钱1百万token,写2遍红楼梦!国产大模型下一步还想卷什么?AI「末日」突然来临,公司同事集体变蠢!只因四大聊天机器人同时宕机OpenAI员工们开始反抗了!AI手机PC大爆发,Arm从软硬件到生态…

esp32s3 nvs 存储过程中使用malloc和free函数的一点困惑

我的项目中,大量使用了malloc()和free()函数,在使用nvs存储之前没有出现问题。 esp32厂家nvs的blob存储的例程中,有使用malloc()和free(),我参照例程写了自己的blob存储函数f,一开始是可以正常使用的,后来…

【Git】Git 的基本操作 -- 详解

一、创建 Git 本地仓库 要提前说的是,仓库是进行版本控制的一个文件目录。我们要想对文件进行版本控制,就必须先创建一个仓库出来。 创建⼀个 Git 本地仓库对应的命令为 git init ,注意命令要在文件目录下执行,例如:…

HCIP-Datacom-ARST自选题库_10_多种协议多选【24道题】

1.如图所示,PE1和PE2之间通过LoopbackO接口建立MP-BGP邻居关系,在配完成之后,发现CE1和CE2之间无法互相学习路由,下列哪些选项会造成该问题的出现? PE1或PE2未在BGP-VPNV4单播地址族视图使能邻居A PE1或PE2上的VPN实例参数配置错…

windows系统 flutter 开发环境配置

1、管理员运行powershell,安装:Chocolatey 工具,粘贴复制运行下列脚本: Chocolatey 官方安装文档 Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol [System.Net.ServicePointManage…

CSS函数:scale、scale3d函数的使用

CSS函数scale()主要是为了实现元素的放大和缩小效果,使用的是元素的变换效果。使用的是元素的转换属性:transform的,该函数可以实现指定X轴和Y轴的放大、缩小效果。除此之外,我们还可以通过如下两种方式实现指定方向的转换&#x…

【Java】国密SM3/SM4(附工具类)

目录 前言国密算法SM1对称加密算法SM1算法的基本原理SM1算法的应用场景SM1算法的优势代码示例 SM2非对称加密算法SM2算法的基本原理SM2算法的应用场景SM2算法的优势代码示例依赖代码 SM3杂凑算法SM4分组密码算法 SM3、SM4工具类示例依赖SM3工具类SM4工具类CBCECB 前言 目前形式…

[论文笔记]Mixtral of Experts

引言 今天带来大名鼎鼎的Mixtral of Experts的论文笔记,即Mixtral-8x7B。 作者提出了Mixtral 8x7B,一种稀疏专家混合(Sparse Mixture of Experts,SMoE)语言模型。Mixtral与Mistral 7B具有相同的架构,不同之处在于每个层由8个前馈…

SpringCache 缓存 - @Cacheable、@CacheEvict、@CachePut、@Caching、CacheConfig 以及优劣分析

目录 SpringCache 缓存 环境配置 1)依赖如下 2)配置文件 3)设置缓存的 value 序列化为 JSON 格式 4)EnableCaching 实战开发 Cacheable CacheEvict CachePut Caching CacheConfig SpringCache 的优势和劣势 读操作…

Flask 实现增改及分页查询的完整 Demo

Flask 实现增改及分页查询的完整 Demo 简介 本文将通过一个 Flask Demo 来展示如何使用 Flask 框架实现 RESTful API,包括增加、修改用户信息以及分页查询功能。我们将使用 Flask 的扩展 SQLAlchemy 来处理数据库操作。 环境准备 首先,确保你已安装 …

【Android面试题】请你分别采用递归和非递归对二叉树进行遍历?

请你分别采用递归和非递归对二叉树进行遍历? 这道题想考察什么? 1、二叉树的基本原理和遍历的方法? 考察的知识点 二叉树遍历的基本概念、二叉树的基本原理 考生如何回答 二叉树的基本概念 当然可以! 二叉树是一种常见的数据结构,它由一组称为节点的元素构成。每个…

地平线x3派开启core文件存储奔溃日志

开发环境 ubuntu22 ros humble c11 程序奔溃后core文件存储设置 1. 确保系统允许生成core文件 首先,检查和设置系统的core文件生成限制: 检查当前core文件大小限制 使用以下命令检查当前core文件大小限制: ulimit -c如果输出为 0&am…

reduce过滤递归符合条件的数据

图片展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head><…

Python 实现乘数加密法

乘数加密是简单代替密码的一种。乘数加密法脱胎于凯撒加密法,加密和解密符号设计把他们转换成数字,加上或者减去密钥,然后把新的数字转换回符号,当我们把加减密钥变成乘以密钥,就是乘法加密法。有关凯撒加密法可以看之前的文章《Python实现凯撒加解密》。 加密过程 乘数加…