【完全揭秘】Traefik云原生网关——助力你的业务破万QPS

news2024/12/26 2:58:30

Traefik 是一款开源的反向代理和负载均衡软件,可以自动地为多个微服务实例进行负载均衡,并提供 HTTP/HTTPS/TCP/UDP 等协议支持。

Traefik 具有简单易用、自动发现服务、动态配置、可插拔的中间件等特点,被广泛应用于云原生和容器化场景中,介绍中也是表明自己是一个云原生网关。

Traefik 支持多种后端服务,包括 Kubernetes、Docker Swarm、Mesos、Consul、Etcd、Zookeeper、Redis 等,同时也提供了丰富的 API 和 Dashboard 等管理工具,使得用户能够方便地对反向代理和负载均衡进行配置和监控。

基本概念

Traefik 有 4 个基本概念,EntryPoints、Routers、Middlewares、Services。(官方图已经很清晰明了了,就不多画图了)

bec821f0deb432de039409f4a0e8e262.png
架构

EntryPoints

网络入口点,配置端口、协议,包括 HTTP、HTTPS、TCP 和 UDP,每个入口点都有一个唯一标识符,并可以配置不同的访问规则和路由策略。

73e06348684a965c4f606c907c23c80f.png

针对http、https 和 udp 不同的配置方式:

## Static configuration
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
  streaming:
    address: ":1704/udp"

Routers

路由,负责将传入的请求连接到可以处理它们的服务,在这个过程中,路由可以使用一些中间件来修改请求的一些信息。

cfc9427c0cef97e7a5c7435d0afaad7a.png

配置/foo开始的请求路由到的后端服务。

## Dynamic configuration
http:
  routers:
    my-router:
      rule: "Path(`/foo`)"
      service: service-foo

路由可以配置不同的的规则,比如针对请求 host 和请求路径进行匹配。

rule = "Host(`example.com`) || (Host(`example.org`) && Path(`/traefik`))"
规则描述
Headers(keyvalue)请求头校验规则
HeadersRegexp(keyregexp)请求头校验规则,value 正则匹配
Host(example.com, ...)请求域名校验规则
HostRegexp(example.com{subdomain:[a-z]+}.example.com, ...)请求域名正则匹配规则
Method(GET, ...)请求方法校验规则,支持GET\POST\PUT\DELETE\PATCH\HEAD
Path(/path/articles/{cat:[a-z]+}/{id:[0-9]+}, ...)请求路径匹配规则,精确匹配,支持正则
PathPrefix(/products//articles/{cat:[a-z]+}/{id:[0-9]+})请求路径前缀匹配规则,支持正则
Query(foo=barbar=baz)请求参数匹配规则
ClientIP(10.0.0.0/16::1)请求 IP 匹配规则

Middlewares

中间件,用于对请求进行处理和转换,类似过滤器、拦截器,有些人可能把他理解成很多网关中的插件,但是其实在 Traefik 里面也有插件的概念,并且可以发布分享,可以参考 https://plugins.traefik.io/create。

Traefik 提供了多种内置的中间件,比如日志记录、重定向、身份验证和限流等第,此外,也可以根据需要自定义中间件。

621396d61942a2b68dc19e9a76b40f83.png

配置方式:

# As a Docker Label
whoami:
  #  A container that exposes an API to show its IP address
  image: traefik/whoami
  labels:
    #  `foo-add-prefix` 中间件
    - "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo"
    - "traefik.http.routers.router1.middlewares=foo-add-prefix@docker"

列出一些 HTTP 中间件列表,其实很多一看名字基本就知道是干嘛用的,基本上基础的网关鉴权、熔断、限流都有默认的插件。

中间件描述
AddPrefix路径添前缀
BasicAuth鉴权
Buffering缓冲
Chain中间件链,可以定义可重用的中间件组合
CircuitBreaker熔断
Compress压缩
Headers请求头操作,可以添加、删除请求头
IPWhiteListIP 白名单
RateLimit限流
Retry重试

Services

服务指的是 Traefik 服务,每个服务都有一个唯一标识符,并可以配置不同的负载均衡规则和健康检查策略。

需要注意的是这里的服务指的是 Traefik 自身的 service,并非是我们自己的服务。

41f7a3923e9ce9039b5ec3b62cbd2129.png

配置示例:

## Dynamic configuration
http:
  services:
    my-service:
      loadBalancer:
        servers:
        - url: "http://<private-ip-server-1>:<private-port-server-1>/"
        - url: "http://<private-ip-server-2>:<private-port-server-2>/"

根据以上的概念,实际上在 Traefik 中一个请求的流程:

  • • 当客户端发送请求时,请求首先会被协议处理器接收并解析。

  • • 然后,请求会被路由器匹配到相应的路由规则,并根据规则将请求转发给相应的中间件链。

  • • 中间件链会按照顺序执行各个中间件,并根据需要对请求进行处理和转换。

  • • 处理完请求后,请求会被转发给相应的后端服务器。

  • • 后端服务器将处理完请求后的响应返回给 Traefik。

  • • 最后,Traefik 将响应返回给客户端。

负载均衡

Traefik 的负载均衡功能通过负载均衡器来实现,支持多种负载均衡策略,包括轮询、随机、加权轮询和加权随机等。

当 Traefik 接收到请求时,根据路由规则将请求转发给相应的后端服务器。如果后端服务器有多个,Traefik 就需要使用负载均衡算法来选择一个服务器处理请求。具体流程如下:

  1. 1. Traefik 会先根据配置的路由规则,将请求匹配到对应的前端入口点

  2. 2. 针对该入口点,Traefik 会获取所有与之关联的后端服务列表

  3. 3. 根据负载均衡策略,在可用的后端服务器中选择一个服务

  4. 4. 将请求转发给所选择的后端服务

  5. 5. 如果后端服务出现故障或者不可用,Traefik 会将其从服务器列表中移除,并选择另外一个可用的服务器来处理请求。

目前来说,官方支持轮询和加权轮询策略。

加权轮询

比如配置 v1 版本权重为3,v2版本权重为1,可用于灰度流量,配置方式如下。

## Dynamic configuration
http:
  services:
    app:
      weighted:
        services:
        - name: appv1
          weight: 3
        - name: appv2
          weight: 1

    appv1:
      loadBalancer:
        servers:
        - url: "http://private-ip-server-1/"

    appv2:
      loadBalancer:
        servers:
        - url: "http://private-ip-server-2/"

流量复制

另外还有一个比较特殊的是镜像请求,镜像能够将发送到一个服务的请求镜像到其他服务,或者我们叫做流量复制更好。

比如针对 appv1的请求,配置 percent 10,那么 10% 的流量就会被打到 appv2 服务上,配置方式如下:

## Dynamic configuration
http:
  services:
    mirrored-api:
      mirroring:
        service: appv1
        # maxBodySize is the maximum size allowed for the body of the request.
        # If the body is larger, the request is not mirrored.
        # Default value is -1, which means unlimited size.
        maxBodySize: 1024
        mirrors:
        - name: appv2
          percent: 10

    appv1:
      loadBalancer:
        servers:
        - url: "http://private-ip-server-1/"

    appv2:
      loadBalancer:
        servers:
        - url: "http://private-ip-server-2/"

健康检查&故障转移

Traefik 要做负载均衡同样是需要健康检查的机制,健康检查需要配置健康检查的路径、请求频率(默认30秒)、超时时间(默认5秒),但是 K8S 有自己的健康检查机制,会移除失效的 pod,所以这里的健康检查对 K8S CRD 和 K8SIngress 无效。

故障转移只是依赖健康检查做正常的负载均衡而已,配置方式如下:

## Dynamic configuration
http:
  services:
    app:
      failover:
        service: main
        fallback: backup

    main:
      loadBalancer:
        healthCheck:
          path: /status
          interval: 10s
          timeout: 3s
        servers:
        - url: "http://private-ip-server-1/"

    backup:
      loadBalancer:
        servers:
        - url: "http://private-ip-server-2/"

部署

接下来通过 Docker 和 K8S 方式了解一下基本的使用。

Docker

首先下载镜:

docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.yml:/etc/traefik/traefik.yml traefik:v2.10

创建配置文件:

version: '3'

services:
  whoami:
    # A container that exposes an API to show its IP address
    image: traefik/whoami
    labels:
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
  reverse-proxy:
    # The official v2 Traefik docker image
    image: traefik:v2.10
    # Enables the web UI and tells Traefik to listen to docker
    command: --api.insecure=true --providers.docker
    ports:
      # The HTTP port
      - "80:80"
      # The Web UI (enabled by --api.insecure=true)
      - "8080:8080"
    volumes:
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock

启动:

docker-compose up -d reverse-proxy
docker-compose up -d whoami

服务创建成功,自动服务发现 whoami,并且存在规则,请求头带 Host 请求可以访问到 whoami 的服务。

392c529f97871e2f20f40ead43ca1ed0.png

测试请求http://localhost可以得到响应

6aac9eb7772d12771b15db07d5547e7f.png

同时,可以使用命令扩容:

docker-compose up -d --scale whoami=2

发现启动了两个 whoami 的实例

5fbf3a75650a2ff71ff9b463b62e5af1.png

再次请求会发现响应的 IP 会发生变化 IP: 172.18.0.4或者 IP: 172.18.0.3,从后台也可以看到两个实例

f17651b1a60bcbb2c87abf23af932cfb.png

K8S

Traefik 结合 K8S 首先需要 K8S 的环境,Mac 下直接使用 Docker Desktop 还是比较方便的。

Mac K8S 环境搭建

首先,下载 Docker Desktop,下载好之后是自带 K8S 的,我们只要在设置中开启即可。

ecdb071fcbcde4bcc80a7176dd5001fb.png

开启之后需要等待一段时间,需要去拉取相关依赖的镜像,国内可能需要自己科学上网,OK 之后可以看到 K8S 已经启动成功。

14880372d4fca56e8389f6ddb5b09ce0.png

到这里那其实已经就好了,顺便可以安装一下Kubernetes Dashboard,默认情况下不会部署控制台,使用命令部署:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

运行结果:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created

然后,使用 kubectl 命令行工具来启用 Dashboard 访问。

kubectl proxy

启动成功之后访问 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ ,进入控制台页面,然后需要我们去配置 token,目前只能通过这种方式去访问。

a1a9eb09576888feb2a6adf15c879149.png

按照官网文档:https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md,配置一个账户和集群角色,复制到一个文件就行,不需要做修改,保存文件为 k8s-admin.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard

使用命令创建服务:

kubectl create -f k8s-admin.yaml

执行命令,生成 token:

kubectl -n kubernetes-dashboard create token admin-user
f87f20c1eb909d37f4c66b1729e1cc30.png

然后填入 token,就可以正常访问 dashboard 了。

7f814c8e1eabf9134b07ce054b903cd3.png

Traefik 部署

参考官方文档:https://doc.traefik.io/traefik/getting-started/quick-start-with-kubernetes/

Traefik 使用 Kubernetes API 来做服务发现,为了使用 Kubernetes API,Traefik 需要一些权限,首先是创建角色,创建 ClusterRole 角色:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: traefik-role

rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
      - networking.k8s.io
    resources:
      - ingresses
      - ingressclasses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
      - networking.k8s.io
    resources:
      - ingresses/status
    verbs:
      - update

然后创建用于 traefik 的账户:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: traefik-account

然后,在账户上绑定角色以应用权限和规则:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: traefik-role-binding

roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: traefik-role
subjects:
  - kind: ServiceAccount
    name: traefik-account
    namespace: default

这样角色和账户的配置已经完成了,接下来需要配置 Traefik 的服务信息和 Dashboard 控制台,其中 args 参数是 traefik 的启动静态配置参数。

kind: Deployment
apiVersion: apps/v1
metadata:
  name: traefik-deployment
  labels:
    app: traefik

spec:
  replicas: 1
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik-account
      containers:
        - name: traefik
          image: traefik:v2.10
          args:
            - --api.insecure
            - --providers.kubernetesingress
          ports:
            - name: web
              containerPort: 80
            - name: dashboard
              containerPort: 8080

创建 Traefik 的服务资源:

apiVersion: v1
kind: Service
metadata:
  name: traefik-dashboard-service

spec:
  type: LoadBalancer
  ports:
    - port: 8080
      targetPort: dashboard
  selector:
    app: traefik
---
apiVersion: v1
kind: Service
metadata:
  name: traefik-web-service

spec:
  type: LoadBalancer
  ports:
    - targetPort: web
      port: 80
  selector:
    app: traefik

最终,我们可以根据这些配置统一到一个配置文件中,命名为k8s-traefik.yaml,然后使用命令创建:

kubectl apply -f k8s-traefik.yaml
clusterrole.rbac.authorization.k8s.io/traefik-role created
serviceaccount/traefik-account created
clusterrolebinding.rbac.authorization.k8s.io/traefik-role-binding created
deployment.apps/traefik-deployment created
service/traefik-dashboard-service created
service/traefik-web-service created

这时候,访问控制台http://localhost:8080/dashboard/#/,可以看到已经成功了。

b7ed541b91f6d1bb91e2f29119fa2e85.png
现在服务部署成功,还需要部署一些后台服务来测试一下,使用官方提供的示例应用程序 traefik/whoami

同样,新建一个文件命名为k8s-whoami.yaml,使用命令创建服务,这样服务就部署成功了。

kubectl apply -f k8s-whoami.yaml
deployment.apps/whoami created
service/whoami created
ingress.networking.k8s.io/whoami-ingress created

从后台可以看到服务启动成功:

65518c0f003bfa2c7162dd901bb50b13.png

同时,可以访问http://localhost访问到服务:

15dfcced278b0cdc9656b023ad059afa.png

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

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

相关文章

【随时更新】面试所需算法数据结构计算机知识点回顾

操作系统LRU算法 MySQL B树 哈夫曼编码和解码 C 哈夫曼编码 【介绍编码过程】 哈夫曼树编码及其图形化的实现 【使用可视化方式展现最终编码效果】 Python中使用哈夫曼算法实现文件的压缩与解压缩 【Python实现】 哈夫曼树 C语言实现 【图解如何生成】 编码过程 1. 使用二进…

基于SpringBoot+Vue的素材管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着数字化时代的到来…

MySQL — 日志、错误日志、二进制日志、查询日志、慢查询日志

文章目录 日志一、错误日志二、二进制日志2.1 介绍2.2 格式2.3 查看二进制日志2.3.1 基于行的二进制日志格式2.3.2 基于语句的二进制日志格式 2.4 日志删除 三、 查询日志四、慢查询日志 日志 一、错误日志 ​ 错误日志是MySQL中最重要的日志之一。 ​ 记录了当MySQLd启动和…

为什么Facebook的转化率要远远低于论坛?

在数字化时代&#xff0c;社交媒体平台如Facebook和论坛都是企业推广和营销的重要渠道。然而&#xff0c;相对于论坛而言&#xff0c;Facebook的转化率明显较低。以下是一些解释&#xff1a; 1.用户意图和参与度的差异 论坛用户更具明确的意图和高度参与度。他们加入论坛是为了…

智能家居家电上应用的触摸芯片有哪些?

电容式触摸芯片&#xff0c;具有灵敏度高、抗干扰能力强&#xff0c;防水防尘、高可靠性等优点已逐步替代传统机械式按钮&#xff0c;广泛应用于家电、智能家居、消费电子、工控等领域。 触摸感应可以穿透绝缘材质检测人体手指带来的电荷移动&#xff0c;从而判断人体手指触摸…

从申请到调用:空号检测 API 使用教程

引言 在当今数字化的时代&#xff0c;手机号码成为了我们日常生活和商业活动中重要的联系方式之一。然而&#xff0c;随着电话号码的泛滥和变动性&#xff0c;验证手机号码的有效性变得越来越重要。 本文将深入探讨空号检测API 的背景和应用场景&#xff0c;介绍如何使用该 A…

STM32 Linux开发板丨STM32MP157开发板资料手册+实战教程+视频教程

iTOP-STM32MP157开发板是基于意法半导体STARM双Cortex-A7核加单Cortex-M4核的一款多核异构处理器。Cortex-A7内核提供对开源操作系统Linux的支持&#xff0c;借助Linux系统庞大而丰富的软件组件处理复杂应用。M4内核上运行对于实时性要求严格的应用。 开发板既有A7核&#xff…

ROS:VScode开发话题(msg)、服务(srv)、动作(action),解决 无法打开源文件

一.解决 无法打开源文件 出错原因&#xff1a;系统没有找到.h文件对应的路径。 在编写完msg、srv、action文件后&#xff0c;要进行编译&#xff08;catkin_make&#xff09; . 编译之后&#xff0c;msg、srv、action会生成相应的.h文件。 其对应的.h文件目录在devel/includ…

一款可发布236T全球影像,构建“离线版地球”的GIS产品

概述 《水经注地图服务&#xff08;WeServer&#xff09;》是一款可快速发布全国乃至全球海量卫星影像的地图发布服务产品&#xff0c;该产品完全遵循OGC相关协议标准&#xff0c;是一个基于若干项目成功经验总结的产品。它可以轻松发布100TB级海量卫星影像&#xff0c;从而使…

Poco 观察者模式(Observer Pattern) 订阅和发布某个感兴趣的通知, Observer和Notification

Poco 观察者模式&#xff08;Observer Pattern&#xff09; 订阅和发布某个感兴趣的通知&#xff0c; Observer和Notification flyfish 先写一个实例代码 #include "Poco/NotificationCenter.h" #include "Poco/Notification.h" #include "Poco/Ob…

Jetpack Hilt 框架的基本使用

什么是 Hilt&#xff1f; Hilt 是一个功能强大、用法简单的依赖注入框架&#xff0c;于 2020 年加入到 Jetpack 家族中。它是 Android 团队联系了 Dagger2 团队&#xff0c;一起开发出来的一个专门面向 Android 的依赖注入框架。相比于 Dagger2&#xff0c;Hilt 最明显的特征就…

Flutter 笔记 | Flutter 核心原理(四)绘制流程

Vsync 机制 在分析首帧渲染的过程中&#xff0c;可以发现Render Tree的渲染逻辑&#xff08;handleDrawFrame方法&#xff09;是直接执行的&#xff0c;但是后续每一帧的渲染都是Framework的主动调用导致的吗&#xff1f;实际上并非如此&#xff0c;也不能如此。试想一下&…

【017】C++ 指针变量详解,理解指针变量

C 指针变量详解 引言一、内存概述二、指针变量2.1、地址和指针变量的关系2.2、定义指针变量2.3、指针变量的初始化2.4、指针类型2.5、案例2.6、注意事项 三、数组元素的指针3.1、概述3.2、在使用中 [ ] 就是 *()的缩写3.3、指向同一数组的元素的两个指针变量间的关系 四、字符串…

6月销量狂欢季:测评自养号助力,引爆跨境电商销量!

随着夏季的到来&#xff0c;跨境电商卖家们迎来了一个极佳的销售机会。6月作为夏季的重要节点&#xff0c;各种活动和节日都为卖家们提供了引流和销售的良机。然而&#xff0c;要真正实现销量的爆发&#xff0c;单纯依靠传统的营销手段可能难以达到预期的效果。在这篇文章中&am…

AI+边缘,是如何加速制造转型的?

在现代工业中&#xff0c;提起智慧工厂、智能制造有一个经久不衰的话题&#xff0c;那便是IT和OT的融合。 IT&#xff08;Information Technology&#xff09;部门专注于处理数据&#xff0c;整个业务系统需要它来维持运营。而OT&#xff08;Operation Technology&#xff09;…

2023智源大会议程公开 |智能的物质基础专题论坛

6月9日&#xff0c;2023北京智源大会&#xff0c;将邀请这一领域的探索者、实践者、以及关心智能科学的每个人&#xff0c;共同拉开未来舞台的帷幕&#xff0c;你准备好了吗&#xff1f;与会知名嘉宾包括&#xff0c;图灵奖得主Yann LeCun、图灵奖得主Geoffrey Hinton、OpenAI创…

基于OA的采购系统和专业的招标采购管理系统区别

当前采购信息化百家争鸣&#xff0c;既有初级版的审批和记录电子化&#xff0c;也有中级版的业务全流程电子化&#xff0c;还有升级版的数智化创新形式&#xff08;如电商平台、智能评标、供应商风险评估、专家行为画像、大数据统计分析等&#xff09;。 近年来&#xff0c;招标…

Zotero文献在word中的引用

前提 确保你的word中有Zotero插件。如下图示&#xff1a; 具体操作 Step01 Zeroto中下载样式 在Zotero中添加相应的文献样式&#xff0c;具体如下&#xff1a; 打开Zotero“编辑”中的首选项&#xff0c;打开“引用”&#xff0c;从“获取更多样式”中搜寻你想要的文献样…

JAVA开发(手工处理数据库表数据的一些示例算法)

背景&#xff1a; 在项目开发中&#xff0c;有时候需要手动处理一下数据库表的数据。涉及到数据得到备份、恢复&#xff0c;清洗&#xff0c;计算&#xff0c;合并等操作。 举例记录一下最近对数据的一些处理过程。 1、对数据表进行数据量统计 select count(*) from table…

API接口的重要性和好处|附加淘宝api接口展示案例|商品数据采集演示

随着互联网的发展&#xff0c;API接口已经成为许多企业进行信息交流和数据管理的重要工具。通过API接口&#xff0c;企业之间能够快速、可靠地进行数据传输和信息共享&#xff0c;从而提高了企业的生产效率和服务质量。以下是API接口的重要性和好处的文章&#xff1a; 1.提高生…