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

kubernetes简单入门实战

本章将介绍如何在kubernetes集群中部署一个nginx服务,并且能够对其访问

Namespace

Namespace是k8s系统中一个非常重要的资源,它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。

默认情况下,k8s集群中的所有的Pod都是可以相互访问的。但是在实际中,可能不想让两个pod之间进行互相访问,那此时就可以将两个pod划分到不同的namespace下。k8s通过集群内部的资源分配到不同的namespace中,可以形成逻辑上的组,以方便不同的组的资源进行隔离使用和管理。

可以通过k8s的授权机制,将不同的namespace交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合k8s的资源配额机制,限定不同租户能占用的资源,例如CPU使用量,内存使用量等,来实现租户可用资源的管理。

image-20241112182312362

k8s在集群启动之后,会默认创建几个namespace

[root@k8s-master ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   11m
kube-node-lease   Active   11m
kube-public       Active   11m
kube-system       Active   11m
查看
#1.查看所有的ns
[root@k8s-master ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   11m
kube-node-lease   Active   11m
kube-public       Active   11m
kube-system       Active   11m#2.查看指定的ns
[root@k8s-master ~]# kubectl get ns default
NAME      STATUS   AGE
default   Active   18m#3.输出指定格式-o wide json yaml
[root@k8s-master ~]# kubectl get ns default -o yaml
apiVersion: v1
kind: Namespace
metadata:creationTimestamp: "2024-11-13T02:30:46Z"labels:kubernetes.io/metadata.name: defaultname: defaultresourceVersion: "206"uid: b80ba6be-a00f-42e7-868b-9319501d5cf9
spec:finalizers:- kubernetes
status:phase: Active#4.查看详情
[root@k8s-master ~]# kubectl describe ns default
Name:         default
Labels:       kubernetes.io/metadata.name=default
Annotations:  <none>
Status:       ActiveNo resource quota.No LimitRange resource.
创建
[root@k8s-master ~]# kubectl create ns dev
namespace/dev created
删除
[root@k8s-master ~]# kubectl delete ns dev
namespace "dev" deleted
配置方式

首先准备一个yaml配置文件,ns-dev.yaml

apiVersion: v1
kind: Namespace
metadata:name: dev

然后就可以执行对应的创建和删除

#创建
kubectl create -f ns-dev.yaml#删除
kubectl delete -f ns-dev.yaml

Pod

Pod是k8s集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在Pod中。Pod可以认为是容器的封装,一个Pod中可以存在一个或者多个容器

image-20241113110809293

k8s在集群启动后,集群中的各个组件也都是以Pod方式运行。可以通过下面命令查看

[root@k8s-master ns]# kubectl get pod -n kube-system
NAME                                     READY   STATUS    RESTARTS   AGE
calico-kube-controllers-cd8566cf-m7gzh   1/1     Running   0          4h5m
calico-node-2h55h                        1/1     Running   0          4h5m
calico-node-586wp                        1/1     Running   0          4h5m
calico-node-n5wk7                        1/1     Running   0          4h5m
coredns-6d8c4cb4d-66rzr                  1/1     Running   0          4h7m
coredns-6d8c4cb4d-8nsnk                  1/1     Running   0          4h7m
etcd-k8s-master                          1/1     Running   1          4h8m
kube-apiserver-k8s-master                1/1     Running   1          4h8m
kube-controller-manager-k8s-master       1/1     Running   18         4h8m
kube-proxy-2bxnm                         1/1     Running   0          4h7m
kube-proxy-qpvzh                         1/1     Running   0          4h7m
kube-proxy-tdrjj                         1/1     Running   0          4h7m
kube-scheduler-k8s-master                1/1     Running   18         4h8m
创建并运行

k8s没有提供单独运行Pod的命令,都是通过Pod控制器来实现

#命令格式:kubectl run (pod控制器名称)[参数]
#--image 指定pod的镜像
#--port 指定端口
#--namespace 指定namespace[root@k8s-master ns]# kubectl run nginx --image=nginx:1.17.1 --port=80 --namespace dev
pod/nginx created
查看pod信息
#查看pod基本信息
[root@k8s-master ns]# kubectl get pod -n dev
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          22s#查看pod的详细信息
[root@k8s-master ns]# kubectl get pod -n dev -o wide
NAME    READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          4m46s   10.244.169.129   k8s-node2   <none>           <none>
[root@k8s-master ns]# kubectl describe pod nginx -n dev
删除指定pod
[root@k8s-master ns]# kubectl delete pod nginx2 -n dev
pod "nginx2" deleted
配置操作

创建一个pod-nginx.yaml

apiVersion: v1
kind: Pod
metadata:name: nginxnamespace: dev
spec:containers:- image: nginx:1.17.1imagePullPolicy: IfNotPresentname: podports:- name: nginx-portcontainerPort: 80protocol: TCP

执行对应的创建和删除

#创建
kubectl create -f pod-nginx.yaml#删除
kubectl delete -f pod-nginx.yaml

Label

Label是k8s中一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择。

Label的特点:

  • 一个Label会以key/value键值对的形式附加到各个对象上,如Node、Pod、Service等
  • 一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源对象上去
  • Label通常在资源对象定义时确定,当然也可以在对象创建后动态添加或者删除

可以通过Label实现资源的多维度分组,一边灵活、方便地进行资源分配、调度、配置、部署等管理工作。

一些常用的Label实例如下:

  • 版本标签:“version”:“release”,“version”:“stable”…
  • 环境标签:“environment”:“dev”,“environment”:“test”,“environment”:“pro”
  • 架构标签:“tier”:“frontend”,“tier”:“backend”

标签定义完毕之后,还要考虑到标签的选择,这就要使用到Label Selector,即:

Label用于给某个资源对象定义标识

Label Selector用于查询和筛选拥有某些标签的资源对象

当前有两种Label Selector:

  • 基于等式的Label Selector

​ name=slave:选择所有包含Label中的key="name"且value="slave"的对象

​ env!=production:选择所有包括Label中的key="env"且value不等于"production"的对象

  • 基于合集的Label Selector

​ name in (master,slave):选择所有包含Label中的key="name"且value="master"或"slave"的对象

​ name not in (frontend):选择所有包含Label中的key="name"且value不等于"frontend"的对象

标签的选择条件可以使用多个,此时将多个Label Selector进行组合,使用逗号","进行分隔即可。例如:

name=slave,env!=production

name not in (frontend),env!=production

命令方式
#为pod资源打标签
[root@k8s-master pod]# kubectl label pod nginx version=1.0 -n dev
pod/nginx labeled#为pod资源更新标签
[root@k8s-master pod]# kubectl label pod nginx version=2.0 -n dev --overwrite
pod/nginx labeled#查看标签[root@k8s-master pod]# kubectl get pod nginx -n dev --show-labels
NAME    READY   STATUS    RESTARTS   AGE     LABELS
nginx   1/1     Running   0          2m20s   version=2.0#筛选标签
[root@k8s-master pod]# kubectl get pod -n dev -l version=2.0 --show-labels
NAME    READY   STATUS    RESTARTS   AGE     LABELS
nginx   1/1     Running   0          3m14s   version=2.0
[root@k8s-master pod]# kubectl get pod -n dev -l version!=2.0 --show-labels
No resources found in dev namespace.#删除标签
[root@k8s-master pod]# kubectl label pod nginx -n dev version-
pod/nginx unlabeled
配置方式
apiVersion: v1
kind: Pod
metadata:name: nginxnamespace: devlabels:version: "3.0"env: "test"
spec:containers:- image: nginx:1.17.1name: podports:- name: nginx-portcontainerPort: 80protocol: TCP

更新命令可以是:kubectl apply -f pod-nginx.yaml

Deployment

在k8s中,Pod是最小的控制单元,但是k8s很少直接控制pod,一般都是通过pod控制器来完成的。pod控制器用于pod的管理,确保pod资源符合预期的状态,当pod的资源出现故障时,会尝试进行重启或重建pod.

在k8s中pod控制器的种类有很多,现只介绍Deployment

配置方式

创建一个deployment-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:name: my-deploymentnamespace: dev
spec:replicas: 3selector:matchLabels:app: my-apptemplate:metadata:labels:app: my-appspec:containers:- name: my-containerimage: nginx:1.17.1ports:- containerPort: 80protocol: TCP

执行:kubectl create -f deployment-nginx.yaml

#查看deployment的信息
[root@k8s-master deployment]# kubectl get deployment -n dev
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
my-deployment   3/3     3            3           2m36s
[root@k8s-master deployment]# kubectl get deploy -n dev -o wide
NAME            READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS     IMAGES         SELECTOR
my-deployment   3/3     3            3           3m48s   my-container   nginx:1.17.1   app=my-app#删除deployment
[root@k8s-master deployment]# kubectl delete deployment my-deployment -n dev
deployment.apps "my-deployment" deleted

Service

虽然每个pod都会分配一个单独的pod ip,然而却存在如下问题:

  • pod ip会随着pod的重建产生变化
  • pod ip仅仅是集群内可见的虚拟ip,外部无法访问

这样对于访问这个服务带来的难度。因此,k8s设计了service来解决这个问题。

service可以看作是一组同类pod对外访问接口。借助service,应用可以方便地实现服务发现和负载均衡

image-20241114161727399

操作一:创建集群内部可访问的service

暴露service 绑定对应的deployment是解决如果deployment控制的pod如果重建会产生不同的ip不会影响到外部访问

#暴露service
[root@k8s-master deployment]# kubectl expose deploy my-deployment --name=svc-nginx --type=ClusterIP --port=80 --target-port=80 -n dev
service/svc-nginx exposed#查看service
[root@k8s-master deployment]# kubectl get service -n dev
NAME        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
svc-nginx   ClusterIP   10.108.254.244   <none>        80/TCP    9s
[root@k8s-master deployment]# kubectl get svc svc-nginx -n dev -o wide
NAME        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE   SELECTOR
svc-nginx   ClusterIP   10.108.254.244   <none>        80/TCP    69s   app=my-app#访问
[root@k8s-master deployment]# curl 10.108.254.244:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>
操作二:创建集群外部也可以访问的Service
#上面创建的Service的type类型为ClusterIP,这个ip地址只在集群内部可访问
#如果需要创建外部也可以访问的Service,需要修改type为NodePort
[root@k8s-master deployment]# kubectl expose deploy my-deployment --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev
service/svc-nginx2 exposed#查看
[root@k8s-master deployment]# kubectl get svc -n dev -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE   SELECTOR
svc-nginx    ClusterIP   10.108.254.244   <none>        80/TCP         51m   app=my-app
svc-nginx2   NodePort    10.100.160.81    <none>        80:30081/TCP   13s   app=my-app#在集群外通过节点IP:30081访问服务了
http://192.168.225.10:30081/
删除Service
[root@k8s-master deployment]# kubectl delete svc svc-nginx -n dev
service "svc-nginx" deleted
配置方式

创建一个svc-nginx.yaml

apiVersion: v1
kind: Service
metadata:name: svc-nginxnamespace: dev
spec:clusterIP: 10.109.179.231ports:- port: 80protocol: TCPtargetPort: 80selector:app: my-apptype: ClusterIP

执行创建和删除命令

kubectl create -f svc-nginx.yaml

kubectl delete -f svc-nginx.yaml

相关文章:

kubernetes简单入门实战

本章将介绍如何在kubernetes集群中部署一个nginx服务&#xff0c;并且能够对其访问 Namespace Namespace是k8s系统中一个非常重要的资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。 默认情况下&#xff0c;k8s集群中的所有的Pod都是可以相…...

Python连接Mysql、Postgre、ClickHouse、Redis常用库及封装方法

博主在这里分享一些常见的python连接数据库或中间件的库和封装方案&#xff0c;希望对大家有用。 Mysql封装 #!/usr/bin/python # -*- coding: utf-8 -*- import sys import pymysql from settings import MYSQL_DB, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_HOST, EN…...

如何修改npm包

前言 开发中遇到一个问题&#xff0c;配置 Element Plus 自定义主题时&#xff0c;添加了 ElementPlusResolver({ importStyle: "sass" }) 后&#xff0c;控制台出现报错&#xff0c;这是因为 Dart Sass 2.0 不再支持使用 !global 来声明新变量&#xff0c;虽然当前…...

Django 2024全栈开发指南(三):数据库模型与ORM操作(上篇)

目录 一、模型的定义二、数据迁移三、数据表关系四、数据表操作4.1 Shell工具4.2 数据新增4.3 数据修改4.4 数据删除4.5 数据查询 Django 对各种数据库提供了很好的支持&#xff0c;包括 PostgreSQL、MySQL、SQLite 和 Oracle&#xff0c;而且为这些数据库提供了统一的 API 方法…...

低代码可视化-uniapp开关选择组件-低码生成器

开关&#xff08;Switch&#xff09;选择组件是一种用户界面元素&#xff0c;允许用户在两种状态&#xff08;通常是开/关、是/否、启用/禁用等&#xff09;之间进行切换。这种组件在移动应用、桌面软件、网页以及物联网设备中广泛应用。以下是对开关Switch选择组件的详细介绍&…...

【arxiv‘24】Vision-Language Navigation with Continual Learning

论文信息 题目&#xff1a;Vision-Language Navigation with Continual Learning 视觉-语言导航与持续学习 作者&#xff1a;Zhiyuan Li, Yanfeng Lv, Ziqin Tu, Di Shang, Hong Qiao 论文创新点 VLNCL范式&#xff1a;这是一个新颖的框架&#xff0c;它使得智能体能够在适…...

如何在 Ubuntu 上安装 Jupyter Notebook

本篇文章将教你在 Ubuntu 服务器上安装 Jupyter Notebook&#xff0c;并使用 Nginx 和 SSL 证书进行安全配置。 我将带你一步步在云服务器上搭建 Jupyter Notebook 服务器。Jupyter Notebook 在数据科学和机器学习领域被广泛用于交互式编码、可视化和实验。在远程服务器上运行…...

免费申请 Let‘s Encrypt SSL 证书

免费申请 Lets Encrypt SSL 证书 在网络安全日益重要的今天&#xff0c;为网站启用 SSL 证书是保障数据安全和用户信任的关键。Lets Encrypt 提供的免费 SSL 证书是一个很好的选择。下面我们详细介绍如何为网站域名申请该证书。 一、准备工作 域名 确保已注册要使用 SSL 证书的…...

【JAVA】Java基础—面向对象编程:继承—重写父类方法

在Java开发中&#xff0c;重写&#xff08;Override&#xff09;是面向对象编程&#xff08;OOP&#xff09;中的一个重要概念。它允许子类提供父类方法的具体实现&#xff0c;从而改变或扩展父类的行为。重写是实现多态性的重要手段&#xff0c;使得程序在运行时能够根据对象的…...

【C++初阶】C++入门

1、C第一个程序 C是脱胎于C语言的&#xff0c;所以也包含了C语言绝大多数的内容&#xff0c;C兼容C语言绝大多数的语法,在C语言中能实现的程序在C中也是可以执行的&#xff0c;但需要将定义文件代码的后缀改为.cpp 就比如hello world程序 // test.cpp #include<stdio.h&g…...

自然推理系统:的拒取式的解析

要推导出 **"非A"** 的拒取式 (rejection form)&#xff0c;首先我们要理解逻辑推理中几个基本的概念。 假设我们有以下前提&#xff1a; 1. **A → B** &#xff08;如果A成立&#xff0c;那么B成立&#xff09; 2. **非B** &#xff08;B不成立&#xff09; 我们…...

OceanBase 分区表详解

1、分区表的定义 在OceanBase数据库中&#xff0c;普通的表数据可以根据预设的规则被分割并存储到不同的数据区块中&#xff0c;同一区块的数据是在一个物理存储上。这样被分区块的表被称为分区表&#xff0c;而其中的每一个独立的数据区块则被称为一个分区。 如下图所示&…...

Java中 LinkedList<>,ArrayDeque<>的区别 || Queue和Deque的区别

我是你爹 LinkedList<> 和 ArrayDeque<> 的区别Queue接口 和 Deque接口区别Queue 的用法Deque 的用法 LinkedList<> 和 ArrayDeque<> 的区别 1. 数据结构实现方式&#xff1a; LinkedList&#xff1a; 基于链表结构&#xff0c;是一个双向链表。每个…...

freemarker 读取template.xml ,通过response 输出文件,解决中文乱码问题

采用 try (Writer writer new OutputStreamWriter(os, “UTF-8”)) UTF-8 内容转换 public static void setResponseHeader(HttpServletResponse response, String fileName) {try {// fileName "中文.xls";try {fileName new String(fileName.getBytes(),"…...

arkUI:水果选择与管理:基于 ArkUI 的长按编辑功能实现

水果选择与管理&#xff1a;基于 ArkUI 的长按编辑功能实现 1 主要内容说明2 相关内容2.1 相关内容2.1.1 源码1内容的相关说明2.1.1.1 数据结构与状态管理2.1.1.2 添加水果功能2.1.1.3 水果列表展示2.1.1.4 长按进入编辑模式2.1.1.5 复选框的多选功能2.1.1.6 删除水果功能2.1.1…...

docker使用,docker图形化界面+docker详细命令

DockerUI进入 docker container run --rm --name docker.ui -v /var/run/docker.sock:/var/run/docker.sock -p 8999:8999 joinsunsoft/docker.ui访问8999端口就行&#xff0c;就可以图形化管理Docker了 常规使用 搭建 sudo docker-compose build #有一些需要这条命令 su…...

idea项目运行时 java: 错误: 不支持发行版本 21

java项目运行时&#xff0c;同样的项目别的都是正常运行&#xff0c;单个这个项目一直报 java: 错误: 不支持发行版本 21&#xff0c; 报错的解释 这个错误表明你正在尝试使用Java编译器编译一个类&#xff0c;但是编译器遇到了一个它不支持的版本号&#xff0c;在这个上下文…...

hive alter table add columns 是否使用 cascade 的方案

结论 alter table xxx add columns 时加上 cascade 时&#xff0c;会把所有的分区都加上此字段。如果不加则只有新的分区会加上此字段&#xff0c;旧的分区没有此字段&#xff0c;即便数据文件里有对应的数据&#xff0c;也不能显示内容。 如果分区都是 insert overwrite 生成…...

手机怎么玩steam游戏?随时随地远程串流玩steam游戏教程

喜欢在steam上玩游戏的玩家有没有想过&#xff0c;其实这些游戏也能在手机上玩呢&#xff1f;不管是探索的开放世界游戏&#xff0c;还是紧张刺激的射击游戏&#xff0c;还是丰富剧情的视觉小说等等&#xff0c;这些游戏你都可以通过远程串流软件&#xff0c;来帮你实现在手机上…...

【使用antv g6实现拓扑图】

使用antv g6实现拓扑图 安装antv g6创建一个 div&#xff0c;并制定必须的属性 id定义初始化方法定义node节点数据将获取到的数据渲染进页面 安装antv g6 npm install antv/g6 --save import G6 from antv/g6;创建一个 div&#xff0c;并制定必须的属性 id 定义好展示id&…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

Python常用模块:time、os、shutil与flask初探

一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...

Java并发编程实战 Day 11:并发设计模式

【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天&#xff0c;今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案&#xff0c;它们不仅提供了优雅的设计思路&#xff0c;还能显著提升系统的性能…...