• 【云原生 | 从零开始学istio】六、istio核心功能


    在这里插入图片描述

    istio 核心功能演示

    断路器

    断路器是创建弹性微服务应用程序的重要模式。断路器使应用程序可以适应网络故障和延迟等网络不良影响。

    测试断路器:
    1、在 k8s 集群创建后端服务

    [root@k8smaster ~]# cd istio-1.10.1 
    [root@k8smaster istio-1.10.1]# cat samples/httpbin/httpbin.yaml 
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: httpbin
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: httpbin
      labels:
        app: httpbin
        service: httpbin
    spec:
      ports:
      - name: http
        port: 8000
        targetPort: 80
      selector:
        app: httpbin
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: httpbin
          version: v1
      template:
        metadata:
          labels:
            app: httpbin
            version: v1
        spec:
          serviceAccountName: httpbin
          containers:
          - image: docker.io/kennethreitz/httpbin
            imagePullPolicy: IfNotPresent
            name: httpbin
            ports:
            - containerPort: 80
    #把 httpbin.tar.gz 上传到node1,手动解压: 
    [root@k8snode1 ~]# cd istio/
    [root@k8snode1 istio]# docker load -i httpbin.tar.gz 
    [root@k8smaster istio-1.10.1]# kubectl apply -f samples/httpbin/httpbin.yaml 
    #该 httpbin 应用程序充当后端服务。 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    2、配置断路器
    创建一个目标规则,在调用 httpbin 服务时应用断路器设置:

    [root@k8smaster istio-1.10.1]# vim destination.yaml 
    apiVersion:  networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: httpbin
    spec:
      host: httpbin
      trafficPolicy:
        connectionPool:
          tcp:
            maxConnections: 1
          http:
            http1MaxPendingRequests: 1
            maxRequestsPerConnection: 1
        outlierDetection:
          consecutiveGatewayErrors: 1
          interval: 1s
          baseEjectionTime: 3m
          maxEjectionPercent: 100
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    连接池(TCP | HTTP)配置,例如:连接数、并发请求等

    tcp:
    maxConnections: 1
    TCP 连接池中的最大连接请求数,当超过这个值,会返回 503 代码。如两个请求过来,就会有一个请求返回 503。

    http:
    http1MaxPendingRequests: 1
    连接到目标主机的最大挂起请求数,也就是待处理请求数。这里的目标指的是 virtualservice 路由规则中配置的 destination。

    maxRequestsPerConnection: 1
    连接池中每个连接最多处理 1 个请求后就关闭,并根据需要重新创建连接池中的连接

    outlierDetection:
    异常检测配置,传统意义上的熔断配置,即对规定时间内服务错误数的监测

    consecutiveGatewayErrors: 1
    #连续错误数 1,即连续返回 502-504 状态码的 Http 请求错误数

    interval: 1s
    错误异常的扫描间隔 1s,即在 interval(1s)内连续发生 consecutiveGatewayErrors(1)个错误,则触发服务熔断

    baseEjectionTime: 3m
    基本驱逐时间 3 分钟,实际驱逐时间为 baseEjectionTime*驱逐次数

    maxEjectionPercent: 100
    最大驱逐百分比 100%

    [root@k8smaster istio-1.10.1]# kubectl apply -f destination.yaml 
    
    • 1

    3、添加客户端访问 httpbin 服务
    创建一个客户端以将流量发送给 httpbin 服务。该客户端是一个简单的负载测试客户端,Fortio 可以控制连接数,并发数和 HTTP 调用延迟。使用此客户端来“跳闸”在 DestinationRule 中设置的断路器策略。看看熔断能不能启动。

    #通过执行下面的命令部署 fortio 客户端: 
    #把 fortio.tar.gz 上传到 node1 节点,手动解压: 
    [root@k8snode1 istio]# docker load -i fortio.tar.gz
    [root@k8smaster istio-1.10.1]# kubectl apply -f samples/httpbin/sample-client/fortio-deploy.yaml 
    
    #通过 kubectl 执行下面的命令,使用 fortio 客户端工具调用 httpbin: 
    [root@k8smaster istio-1.10.1]# kubectl get pods
    NAME                              READY   STATUS    RESTARTS   AGE
    appv1-6f7b58fd99-xb4br            2/2     Running   0          3h55m
    appv2-f78cb577-s6d4z              2/2     Running   0          3h55m
    details-v1-65bbfd4f58-7w985       2/2     Running   2          5h4m
    fortio-deploy-576dbdfbc4-hgfqj    2/2     Running   0          2m29s
    httpbin-74fb669cc6-b25f8          2/2     Running   0          15m
    productpage-v1-6b746f74dc-hxn89   2/2     Running   2          5h4m
    ratings-v1-b45758b-kz668          2/2     Running   2          5h4m
    reviews-v1-74894b48c8-g8nv8       2/2     Running   2          5h4m
    reviews-v2-f649764d-2lc54         2/2     Running   2          5h4m
    reviews-v3-6c675c6774-smbvr       2/2     Running   2          5h4m
    
    #进入fortio然后使用curl请求httpdbin
    [root@k8smaster istio-1.10.1]# kubectl exec fortio-deploy-5789d79849-4grn4 -c fortio -- /usr/bin/fortio curl http://httpbin:8000/get 
    #显示如下: 
    HTTP/1.1 200 OK 
    server: envoy 
    date: Mon, 08 Aug 2022 12:34:48 GMT
    content-type: application/json 
    content-length: 622
    access-control-allow-origin: * 
    access-control-allow-credentials: true 
    x-envoy-upstream-service-time: 2 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    4、触发断路器

    在 DestinationRule 设置中,指定了 maxConnections: 1 和 http1MaxPendingRequests: 1。这些规则表明,如果超过一个以上的连接并发请求,则 istio-proxy 在为进一步的请求和连接打开路由时,应该会看到下面的情况。
    模拟多个客户端发送请求,以两个并发连接(-c 2)和发送 20 个请求(-n 20)调用服务:

    [root@k8smaster istio-1.10.1]# kubectl exec -it fortio-deploy-576dbdfbc4-z28m7 -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get 
     
    #显示如下: 
    一大堆503
    Jitter: false 
    Code 200 : 4 (20.0 %) 
    Code 503 : 16 (80.0 %) 
    #只有20%成功了,其余的都断开了,每次请求都不一样,断路器触发了。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    超时

    在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性,Istio 使用虚拟服务来优雅实现超时处理。
    下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat。nginx 服务设置了超时时间为 2 秒,如果超出这个时间就不在等待,返回超时错误。tomcat 服务设置了响应时间延迟 10 秒,任何请求都需要等待 10 秒后才能返回。client 通过访问 nginx 服务去反向代理 tomcat 服务,由于 tomcat 服务需要 10 秒后才能返回,但 nginx 服务只等待 2 秒,所以客户端会提示超时错误。

    node1解压tomcat,nginx,busybox
    [root@k8snode1 ~]# docker load -i nginx
    [root@k8snode1 ~]# docker load -i busybox:1.2.8
    [root@k8snode1 ~]# docker load -i tomcat
    [root@k8smaster ~]# mkdir /root/timeout 
    [root@k8smaster ~]# cd /root/timeout/ 
    [root@k8smaster timeout~]# vim nginx-deployment.yaml 
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-tomcat
      labels:
        server: nginx
        app: web
    spec:
      replicas: 1
      selector:
        matchLabels:
          server: nginx
          app: web
      template:
        metadata:
          name: nginx
          labels: 
            server: nginx
            app: web
        spec:
          containers:
          - name: nginx
            image: nginx:latest
            imagePullPolicy: IfNotPresent
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: tomcat
      labels:
        server: tomcat
        app: web
    spec:
      replicas: 1
      selector:
        matchLabels:
          server: tomcat
          app: web
      template:
        metadata:
          name: tomcat
          labels: 
            server: tomcat
            app: web
        spec:
          containers:
          - name: tomcat
            image: docker.io/kubeguide/tomcat-app:v1 
            imagePullPolicy: IfNotPresent
    [root@k8smaster timeout]# vim nginx-tomcat-svc.yaml 
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-svc
    spec:
      selector:
        server: nginx
      ports:
      - name: http
        port: 80
        targetPort: 80
        protocol: TCP
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: tomcat-svc
    spec:
      selector:
        server: tomcat
      ports:
      - name: http
        port: 8080
        targetPort: 8080
        protocol: TCP
    [root@k8smaster timeout]# vim virtual-tomcat.yaml 
    ---
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: nginx-vs
    spec:
      hosts:
      - nginx-svc
      http:
      - route:
        - destination: 
            host: nginx-svc
        timeout: 2s
    ---
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: tomcat-vs
    spec:
      hosts:
      - tomcat-svc
      http:
      - fault:
          delay:
            percentage:
              value: 100
            fixedDelay: 10s
        route:
        - destination:
            host: tomcat-svc
    
    #virtual-tomcat.yaml 资源清单重点知识讲解 
    第一:故障注入
    http: 
    - fault: 
     delay: 
     percentage: 
     value: 100 
     fixedDelay: 10s 
    该设置说明每次调用 tomcat-svc 的 k8s service,都会延迟 10s 才会调用。 
    
    第二:调用超时
    hosts: 
    - nginx-svc 
     http: 
     - route: 
     - destination: 
     host: nginx-svc 
     timeout: 2s 
    该设置说明调用 nginx-svc 的 k8s service,请求超时时间是 2s。 
    
    #部署 tomcat、nginx 服务 
    需要对 nginx-deployment.yaml 资源文件进行 Istio 注入,将 nginx、tomcat 都放入到网格中,可以采用手工注入 Istio 方式。 
    [root@k8smaster timeout]# kubectl apply -f nginx-deployment.yaml 
    执行成功后,通过 kubectl get pods 查看 Istio 注入情况: 
    [root@k8smaster timeout]# kubectl get pods 
    NAME                              READY   STATUS    RESTARTS   AGE
    nginx-tomcat-7dd6f74846-48g9f     2/2     Running   0          5h15m
    tomcat-86ddb8f5c9-h6jdl           2/2     Running   0          5h15m
    
    #部署 nginx 和 tomcat 的 service 
    [root@k8smaster timeout]# kubectl apply -f nginx-tomcat-svc.yaml 
    #部署虚拟服务 
    [root@k8smaster timeout]# kubectl apply -f virtual-tomcat.yaml 
    
    #设置超时时间 
    [root@k8smaster timeout]# kubectl exec -it nginx-tomcat-7dd6f74846-48g9f -- sh 
    # apt-get update 
    # apt-get install vim -y 
    # vim /etc/nginx/conf.d/default.conf
    在location里把root和index注释掉,然后加下面两行反向代理的
    proxy_pass http://tomcat-svc:8080; 
    proxy_http_version 1.1; 
    编辑完后,再执行如下语句验证配置和让配置生效: 
    / # nginx -t 
    / # nginx -s reload 
    这样,整个样例配置和部署都完成了。 
     
    #验证超时 
    登录 client,执行如下语句: 
    [root@k8smaster timeout]# kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh 
    / # time wget -q -O - http://nginx-svc 
    #网关超时了
    wget: server returned error: HTTP/1.1 408 Request Timeout 
    Command exited with non-zero status 1 
    real 0m 2.02s 
    user 0m 0.00s 
    sys 0m 0.00s
    / # while true; do wget -q -O - http://nginx-svc; done 
    wget: server returned error: HTTP/1.1 504 Gateway Timeout 
    wget: server returned error: HTTP/1.1 504 Gateway Timeout 
    wget: server returned error: HTTP/1.1 504 Gateway Timeout 
    wget: server returned error: HTTP/1.1 504 Gateway Timeout 
    wget: server returned error: HTTP/1.1 408 Request Timeout 
    每隔 2 秒,由于 nginx 服务的超时时间到了而 tomcat 未有响应,则提示返回超时错误。 
    
    验证故障注入效果,执行如下语句: 
    / # time wget -q -O - http://tomcat-svc 
    wget: server returned error: HTTP/1.1 503 Service Unavailable 
    Command exited with non-zero status 1 
    real 0m 10.02s 
    user 0m 0.00s 
    sys 0m 0.01s 
    执行之后 10s 才会有结果 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189

    故障注入和重试

    Istio 重试机制就是如果调用服务失败,Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务,除非我们启动 Istio 重试机制。

    下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat。tomcat 通过故障注入而中止对外服务,nginx 设置如果访问 tomcat 失败则会重试 3 次。

    [root@k8smaster timeout]# kubectl delete -f . 
    [root@k8smaster timeout]# kubectl apply -f nginx-deployment.yaml 
    [root@k8smaster timeout]# kubectl apply -f nginx-tomcat-svc.yaml 
    [root@k8smaster timeout]# vim virtual-attempt.yaml 
    ---
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: nginx-vs
    spec:
      hosts:
      - nginx-svc
      http:
      - route:
        - destination: 
            host: nginx-svc
        retries:
          attempts: 3
          perTryTimeout: 2s
    ---
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: tomcat-vs
    spec:
      hosts:
      - tomcat-svc
      http:
      - fault:
          abort:
            percentage:
              value: 100
            httpStatus: 503
        route:
        - destination:
            host: tomcat-svc
    [root@k8smaster timeout]# kubectl apply -f virtual-attempt.yaml 
     
    虚拟服务资源清单解读: 
    第一:故障注入。该虚拟服务的作用对象就是 tomcat-svc。使用此故障注入后,在网格中该 tomcat 就是不可用的。 
    abort: 
     percentage: 
     value: 100 
     httpStatus: 503 
    abort 是模拟 tomcat 服务始终不可用,该设置说明每次调用 tomcat-svc 的 k8s service,100%都会返回错误状态码 503。 
    
    第二:调用超时: 
    hosts: 
    - nginx-svc 
     http: 
     - route: 
    - destination: 
     host: nginx-svc 
     reties: 
     attempts: 3 
     perTryTimeout: 2s 
    该设置说明调用 nginx-svc 的 k8s service,在初始调用失败后最多重试 3 次来连接到服务子集,每个重试都有 2 秒的超时。 
     
    [root@k8smaster timeout]# kubectl exec -it nginx-tomcat-3da6f82051-rdqqf -- /bin/sh 
    # apt-get update 
    # apt-get install vim -y 
    / # vim /etc/nginx/conf.d/default.conf
    在location里把root和index注释掉,然后加下面两行反向代理的
    proxy_pass http://tomcat-svc:8080; 
    proxy_http_version 1.1; 
    / # nginx -t 
    / # nginx -s reload 
    
    #验证重试是否生效 
    [root@k8smaster timeout]# kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh 
    / # wget -q -O - http://nginx-svc
    [root@xianchaomaster1 timeout]# kubectl logs -f nginx-tomcat-3da6f82051-rdqqf -c istio-proxy 
    可以看到重试三次
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    分布式追踪系统-jaeger

    1.什么是分布式追踪?

    分布式追踪最早由谷歌的 Dapper 普及开来,它本质上是具有在微服务的整个生命周期中追踪请求的能力。分布式追踪(Distributed Tracing)主要用于记录整个请求链的信息。

    2.为什么要分布式追踪?

    当业务微服务化后,一次业务请求,可能会涉及到多个微服务,分布式跟踪可以对跨多个分布式服务网格的 1 个请求进行追踪分析,并通过可视化的方式深入地了解请求的延迟,序列化和并发,充分地了解服务流量实况,从而快速地排查和定位问题。在微服务应用中,一个完整的业务往往需要调用多个服务才能完成,服务之间就产生了交互。当出现故障时,如何找到问题的根源非常重要。追踪系统可以清晰地展示出请求的整个调用链以及每一步的耗时,方便查找问题所在。

    3.分布式追踪系统-jaeger

    Jaeger 是一个开源的分布式追踪系统,它可以在复杂的分布式系统中进行监控和故障排查。Jaeger的主要功能包括分布式请求监控、性能调优、故障分析和服务依赖分析等。

    Jaeger 组件介绍:

    jaeger-agent:
    负责发送的进程,对 spans 进行处理并发送给 collector,监听 spans 的 UDP 发送。这层作为基础组件部署在主机上,Agent 将 Client Library 和 Collector 解耦,为 ClientLibrary 屏蔽了路由和发现 Collector 的细节。

    jaeger-collector:
    收集追踪 spans,并通过管道对追踪数据进行处理。当前的管道支持追踪的验证、索引、转换,最后存储数据。

    jaeger-query:
    从存储中检索追踪信息并通过 UI 展示

    data store:
    追踪信息的存储

    4.使用 jaeger

    kubectl get svc -n istio-system | grep jaeger 
    显示如下:
    jaeger-agent ClusterIP None <none> 5775/UDP,6831/UDP,6832/UDP 55d
    jaeger-collector ClusterIP 10.99.194.57 <none> 14267/TCP,14268/TCP,14250/TCP 55d
    jaeger-collector-headless ClusterIP None <none> 14250/TCP 55d
    jaeger-query ClusterIP 10.107.192.115 <none> 16686/TCP
    
    修改 jaeger-query 的 type 类型为 nodePort
    kubectl edit svc jaeger-query -n istio-system
    把 type: ClusterIP 变成 type: NodePort
    kubectl get svc -n istio-system | grep jaeger-query
    显示如下:
    jaeger-query NodePort 10.107.192.115 <none> 16686:31450/TCP 
    
    在浏览器访问:
    192.168.11.129:31450
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    5.追踪上下文传递

    Istio 利用 Envoy 的分布式追踪功能提供了开箱即用的追踪集成。确切地说,Istio 提供了安装各种追踪后端服务的选项,并且通过配置代理来自动发送追踪 span 到追踪后端服务。尽管 Istio 代理能够自动发送 span,但是他们需要一些附加线索才能将整个追踪链路关联到一起。所以当代理发送 span 信息的时候,应用需要附加适当的 HTTP 请求头信息,这样才能够把多个 span 正确的关联到同一个追踪上。
    要做到这一点,应用程序从传入请求到任何传出的请求中需要包含以下请求头参数:
    x-request-id
    x-b3-traceid
    x-b3-spanid
    x-b3-parentspanid
    x-b3-sampled
    x-b3-flags
    x-ot-span-context

    写在最后

    创作不易,如果觉得内容对你有帮助,麻烦给个三连关注支持一下我!如果有错误,请在评论区指出,我会及时更改!istio系列也算完结了,后面会补充一些k8s篇的遗漏知识点。

    感谢各位的观看,文章掺杂个人理解,如有错误请联系我指出~

  • 相关阅读:
    cherry-pick
    生命之水 I 永恒君主雪莉白兰地大师班
    力扣每日一题:808. 分汤 【dp动态规划】
    C++里sscanf()与swscanf()的使用
    React之Redux的使用配置
    储油罐北斗监测方案
    Windows10安装MySQL
    JVM 一些常见问题Q&A
    档案馆容灾备份案例分享
    M2 MacBookAir售价是多少 M2 MacBookAir配置如何
  • 原文地址:https://blog.csdn.net/qq_45400861/article/details/127879313