nginx参数调优能提升多少性能
前言
nginx安装后一般都会进行参数优化,网上找找也有很多相关文章,但是这些参数优化对Nginx性能会有多大影响?为此我做个简单的实验测试下这些参数能提升多少性能。
声明一下,测试流程比较简单,后端服务也很简单,测试时间也很短,所以实验并不严谨,结果仅作参考,需要根据实际情况进行参数调优。
文章或有错误和疏漏之处,欢迎各位大佬指出或补充。
环境
IP | 操作系统 | CPU | 内存 | 部署服务 |
---|---|---|---|---|
192.168.3.60 | Debian 11.8 | 4 | 4 GB | wrk |
192.168.3.61 | Debian 11.8 | 4 | 4 GB | nginx |
192.168.3.62 | Debian 11.8 | 4 | 4 GB | 后端服务 |
- nginx:版本1.24.0,编译参数:
./configure --with-threads --with-file-aio --with-http_ssl_module --with-http_v2_module --with-http_gunzip_module --with-http_gzip_static_module --with-stream --with-compat --with-pcre-jit --prefix=/home/admin/apps/nginx
- 使用wrk进行性能测试,版本为 4.1.0,通过 apt 包管理器安装。
- 因为主要测试nginx反向代理的性能,所以用go写了个响应"hello world"的api,减少后端服务导致的性能影响。
测试方法:调整nginx参数后多次运行wrk,取平均值。(方法并不严谨,应该用更专业的工具测试运行几小时,将测试数据采用更科学的方法汇总,但时间精力有限,所以采用这个非常简单无脑的实验方法)
实验结果
下面的实验过程主要就是调参数,比较繁琐,所以把实验结果先放到前面。综合配置可参考“实验过程 - 13. 综合调优”。
再次声明,由于测试流程和后端逻辑都比较简单,服务器和网络情况也没严格控制变量所以结果仅供参考。
根据实验结果来看,增大工作进程数能直接提升性能,但不是和CPU核心数一致就能最大化,可能少一点才能达到最佳性能。
除了nginx和系统参数调优,网络和后端服务对性能的影响也很大,而且在大部分ToB业务场景下,后端服务和数据库才是性能短板。
序号 | 测试方式 | Nginx参数优化项 | 总请求数 | 平均每秒请求数 | 平均延迟 | 优化效果 |
---|---|---|---|---|---|---|
1 | wrk -> 后端 | 无 | 4139984 | 68884.59 | 1.66ms | +673% |
2 | wrk -> nginx -> 后端 | 无,默认配置 | 534859 | 8911.30 | 12.04ms | - |
3.1 | wrk -> nginx -> 后端 | 设置工作进程数为2 | 1027745 | 17127.49 | 5.95ms | +92.19% |
3.2 | wrk -> nginx -> 后端 | 设置工作进程数为3 | 676651 | 11274.05 | 8.97ms | +26.51% |
3.3 | wrk -> nginx -> 后端 | 设置工作进程数为auto(4) | 547794 | 9125.66 | 11.14ms | +2.41% |
4 | wrk -> nginx -> 后端 | 设置工作进程数和CPU亲和性为auto | 537713 | 8958.10 | 11.67ms | +0.52% |
5 | wrk -> nginx -> 后端 | 在4的基础上设置worker_connections 65535; | 532758 | 8874.85 | 11.80ms | -0.4% |
6 | wrk -> nginx -> 后端 | 在5的基础上设置accept_mutex on; | 425540 | 7088.39 | 15.58ms | -20.45% |
7 | wrk -> nginx -> 后端 | 在6的基础上设置multi_accept on | 591500 | 9854.77 | 10.60ms | +10.58% |
8 | wrk -> nginx -> 后端 | 在7的基础上设置改为upstream | 558679 | 9308.30 | 12.00ms | +4.45% |
9 | wrk -> nginx -> 后端 | 在8的基础上设置keepalive | 632673 | 10541.49 | 10.06ms | +18.29% |
10 | wrk -> nginx -> 后端 | 在9的基础上设置加一个后端 | 1006485 | 16772.08 | 6.53ms | +88.21% |
11 | wrk -> nginx -> 后端 | 在2的基础上设置加一个后端 | 610882 | 10178.26 | 10.21ms | +14.21% |
12 | wrk -> nginx -> 后端 | 在3.1的基础上设置keepalive | 1041024 | 17348.36 | 5.94ms | +94.67% |
13 | wrk -> nginx -> 后端 | 在2的基础上设置deferred | 596197 | 9934.61 | 10.90ms | +11.48% |
14 | wrk -> nginx -> 后端 | 在2的基础上修改内核参数 | 581535 | 9689.91 | 10.95ms | +8.73% |
15 | wrk -> nginx -> 后端 | 综合调优 | 1087151 | 18115.78 | 5.94ms | +103.28% |
单独测试nginx的性能,避免后端服务和网络情况的影响。
序号 | Nginx参数优化项 | 总请求数 | 平均每秒请求数 | 平均延迟 | 优化效果 |
---|---|---|---|---|---|
1 | 无,默认配置 | 2327400 | 38787.61 | 2.71ms | - |
2 | 在1的基础上设置工作进程数为auto | 7418729 | 123633.13 | 791.04us | 218.74% |
3 | 在2的基础上设置CPU亲和性 | 7437087 | 123945.45 | 784.02us | 219.54% |
4 | 在3的基础上设置工作进程连接数和多请求 | 7638947 | 127300.44 | 764.67us | 228.19% |
调整环境,nginx都采用默认配置,只是修改了各组件的位置。因为组件在同一台服务器,资源竞争情况也会影响性能。
环境 | 总请求数 | 平均每秒请求数 | 平均延迟 |
---|---|---|---|
wrk、nginx和后端各在不同的服务器 | 534859 | 8911.30 | 12.04ms |
wrk单独服务器,nginx和后端在同一台服务器 | 386630 | 6441.05 | 16.24ms |
wrk、nginx和后端在同一台服务器 | 402163 | 6700.38 | 15.15ms |
实验过程
1. 直连后端测试
首先用wrk直接测试后端。因为没有中间商赚差价,所以理论上直连性能会比nginx代理的性能高。
# curl 测试后端响应是否正常
curl http://192.168.3.62:8101# wrk 直接测试后端服务。线程数为4,连接数为100,测试时间为60秒。
wrk -t4 -c100 -d60s http://192.168.3.62:8101
wrk测试结果
总请求数 | 平均每秒请求数 | 平均延迟 |
---|---|---|
4139984 | 68884.59 | 1.66ms |
2. 使用nginx默认配置代理
nginx刚安装后有一个默认配置,这里只改了location /
的配置,修改为反向代理到后端服务
location / {#root html;#index index.html index.htm;proxy_pass http://192.168.3.62:8101;
}
wrk测试结果。相较于后端直连,性能缩水很多
总请求数 | 平均每秒请求数 | 平均延迟 |
---|---|---|
534859 | 8911.30 | 12.04ms |
3. 增加工作进程数
nginx默认工作进程数为1,通过修改worker_processes可指定,一般小于或等于CPU核心数
worker_processes | 总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|---|
1(默认) | 534859 | 8911.30 | 12.04ms | - |
2 | 1027745 | 17127.49 | 5.95ms | +92.19% |
3 | 676651 | 11274.05 | 8.97ms | +26.51% |
auto(4) | 547794 | 9125.66 | 11.14ms | +2.41% |
4. 设置CPU亲和性
通过worker_cpu_affinity绑定工作进程和CPU,避免nginx进程在CPU之间切换导致的伪共享带来的性能问题。
nginx配置:
worker_processes auto;
worker_cpu_affinity auto;
wrk测试结果
总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|
537713 | 8958.10 | 11.67ms | +0.52% |
5. 设置worker_connections
worker_connections用于设置每个Nginx进程可处理并发连接的最大数,默认为1024。
worker_processes auto;
worker_cpu_affinity auto;
events {worker_connections 65535;
}
wrk测试结果
总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|
532758 | 8874.85 | 11.80ms | -0.4% |
6. 启用互斥锁
nginx配置
worker_processes auto;
worker_cpu_affinity auto;
events {worker_connections 65535;accept_mutex on;
}
wrk测试结果
总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|
425540 | 7088.39 | 15.58ms | -20.45% |
7. 启用多请求支持
默认情况下,每个工作进程一次只接受一个新连接。开启后,每个工作进程将接受所有的新连接。
nginx配置
worker_processes auto;
worker_cpu_affinity auto;
events {worker_connections 65535;accept_mutex on;multi_accept on;
}
wrk测试结果
总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|
591500 | 9854.77 | 10.60ms | +10.58% |
8. 使用upstream
之前的配置都通过proxy_pass
直接反向代理到后端,修改为upstream。
nginx配置
worker_processes auto;
worker_cpu_affinity auto;
events {worker_connections 65535;accept_mutex on;multi_accept on;
}
http {upstream backend {server 192.168.3.62:8101;}server {location / {proxy_pass http://backend;}}
}
wrk测试结果。性能有所降低,但在多个后端的情况下,还是配置upstream更方便。
总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|
558679 | 9308.30 | 12.00ms | +4.45% |
9. 设置keepalive长连接
长连接的存在可以减少建立和关闭TCP连接带来的消耗和延迟。
nginx配置
worker_processes auto;
worker_cpu_affinity auto;
events {worker_connections 65535;accept_mutex on;multi_accept on;
}
http {upstream backend {server 192.168.3.62:8101;keepalive 32;keepalive_requests 2000;}server {location / {proxy_pass http://backend;}}
}
wrk测试结果
总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|
632673 | 10541.49 | 10.06ms | +18.29% |
10. 增加后端实例数
分别在默认配置和上一步的基础上,将后端实例数加1。
修改后的nginx配置
worker_processes auto;
worker_cpu_affinity auto;
events {worker_connections 65535;accept_mutex on;multi_accept on;
}
http {upstream backend {server 192.168.3.62:8101;server 192.168.3.62:8102;keepalive 32;keepalive_requests 2000;}server {location / {proxy_pass http://backend;}}
}
wrk测试结果
配置 | 总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|---|
默认配置多后端 | 610882 | 10178.26 | 10.21ms | +14.21% |
默认配置,长连接,工作进程数2 | 1041024 | 17348.36 | 5.94ms | +94.67% |
修改配置多后端 | 1006485 | 16772.08 | 6.53ms | +88.21% |
11. 延迟处理新连接
设置deferred参数可延迟处理新连接,加上这个配置后,当用户与nginx
服务器建立连接时,只有用户有请求数据时才会将TCP
连接状态改为ESTABLISHED
,否则就直接丢弃这条连接。通过减少服务器和客户端之间发生的三次握手建立连接的数量来帮助提高性能。
nginx配置
worker_processes 1;
events {worker_connections 1024;
}
http {server {listen 8100 deferred;}
}
wrk测试结果
总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|
596197 | 9934.61 | 10.90ms | +11.48% |
12. 修改内核参数
修改的内核参数如下
# 网卡接受数据包的队列最大长度
net.core.netdev_max_backlog = 24800
# 已经收到syn包,但是还没有来得及确认的连接队列
net.ipv4.tcp_max_syn_backlog = 24800
# 端口监听队列的最大长度, 存放的是已经处于ESTABLISHED而没有被应用程序接管的TCP连接
net.core.somaxconn = 65535
# SYN的超时重传次数
net.ipv4.tcp_syn_retries = 2
# 服务端等待客户端响应ACK的超时重传次数
net.ipv4.tcp_synack_retries = 2
# 作为服务端才拥有TCP Fast Open机制
net.ipv4.tcp_fastopen = 2
nginx的配置为默认配置。
wrk测试结果
总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|
581535 | 9689.91 | 10.95ms | +8.73% |
13. 综合调优
开启多请求支持,增加工作进程连接数,配置长连接,增加后端实例,修改内核参数。
如果不想一遍遍修改工作进程数,直接设置为auto最省事,虽然不一定会是最优配置,但总比默认强。
nginx配置
worker_processes auto;
events {worker_connections 65535;multi_accept on;
}
http {upstream backend {server 192.168.3.62:8101;server 192.168.3.62:8102;keepalive 32;keepalive_requests 2000;}server {lister deferred backlog=24800;location / {proxy_pass http://backend;}}
}
内核参数
net.core.netdev_max_backlog = 24800
net.ipv4.tcp_max_syn_backlog = 24800
net.core.somaxconn = 65535
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_fastopen = 2
wrk测试结果
总请求数 | 平均每秒请求数 | 平均延迟 | 对比默认配置 |
---|---|---|---|
1087151 | 18115.78 | 5.94ms | +103.28% |
14. 单独测试nginx
以上测试场景都有nginx反向代理后端,而网络和后端也会在一定程度上影响nginx性能,所以这里单独测试nginx。
nginx配置
worker_processes auto;
worker_cpu_affinity auto;
events {worker_connections 65535;multi_accept on;
}
http {server {location / {return 200 'hello world';}}
}
wrk测试结果。在没有反向代理的情况下,增加工作进程数就能直接提升nginx性能。
序号 | Nginx参数优化项 | 总请求数 | 平均每秒请求数 | 平均延迟 | 优化效果 |
---|---|---|---|---|---|
1 | 无,默认配置 | 2327400 | 38787.61 | 2.71ms | - |
2 | 在1的基础上设置工作进程数为auto | 7418729 | 123633.13 | 791.04us | 218.74% |
3 | 在2的基础上设置CPU亲和性 | 7437087 | 123945.45 | 784.02us | 219.54% |
4 | 在3的基础上设置工作进程连接数和多请求 | 7638947 | 127300.44 | 764.67us | 228.19% |
【性能测试】终于有一套全面的性能测试教程啦!真实企业性能测试全流程项目实战!
相关文章:
nginx参数调优能提升多少性能
前言 nginx安装后一般都会进行参数优化,网上找找也有很多相关文章,但是这些参数优化对Nginx性能会有多大影响?为此我做个简单的实验测试下这些参数能提升多少性能。 声明一下,测试流程比较简单,后端服务也很简单&…...

用友U8 Cloud 反序列化RCE漏洞复现
0x01 产品简介 用友U8 Cloud是用友推出的新一代云ERP,主要聚焦成长型、创新型企业,提供企业级云ERP整体解决方案。 0x02 漏洞概述 用友U8 Cloud存在多处(FileManageServlet和LoginVideoServlet)反序列化漏洞,系统未将…...
acwing算法基础之数据结构--STL简介
目录 1 基础知识2 模板3 使用示例3.1 vector3.2 pair3.3 string3.4 queue 1 基础知识 无。 2 模板 vector, 变长数组,倍增的思想size() 返回元素个数empty() 返回是否为空clear() 清空front()/back() 使用时,必须判断向量类容器非空push_back()/po…...

【Python深入学习】- 书籍推荐|数据结构和算法介绍|内建集合数据类型
🌈个人主页: Aileen_0v0 🔥系列专栏:PYTHON学习系列专栏 💫"没有罗马,那就自己创造罗马~" 若把编写代码比作行军打仗,那么要想称霸沙场,不能仅靠手中的利刃,还需深谙兵法。Python是一把利刃&…...
物联网对接协议
物联网对接协议有很多种,以下是几种常见的物联网对接协议: Modbus:是一种强大的通信标准,广泛应用于工业自动化和SCADA系统,以便将仪表、传感器和执行器的信号发送回主控制器。 Modbus具有广泛的通信协议,…...

腾讯待办关停,导出的数据怎么恢复到手机上面?
相信有不少腾讯待办的用户都发现了其“业务关停通知”,确实如此,由于业务调整,腾讯待办将于2023年的12月20日全面停止运营并下架,这就表示以后我们无法继续使用它了。在腾讯待办关停之前,绝大多数用户需要做的就是及时…...

视频特效编辑软件 After Effects 2022 mac中文版介绍 (ae 2022)
After Effects 2022 mac是一款视频特效编辑软件,被称为AE,拥有强大的特效工具,旋转,用于2D和3D合成、动画制作和视觉特效等,效果创建电影级影片字幕、片头和过渡,是一款可以帮助您高效且精确地创建无数种引…...

innovus:解决报告复制时一行拆成两行的问题
我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? innovus复制报告时一行的东西出现在两行上,解决只需要一条命令: set_table_style -no_frame_width...

MySQL数据脱敏(Data masking plugin functions)
对于企业而言,数据脱敏可以在数据共享或测试时用于保护敏感数据(如信用卡,社保卡,地址等)。通过对敏感数据进行脱敏处理,组织可以最大限度地降低数据泄露和未经授权访问的风险,同时仍能够使用真…...

Flutter 07 框架和三棵树(Widgets、Elements和RenderObjects)
一、Flutter框架的整体结构: Flutter是Google推出并开源的跨平台开发框架,主打跨平台、高保真、高性能。开发者可以通过Dart语 言开发Flutter应用,一套代码同时运行在ios和Android平台。不仅如此,Flutter还支持Web、桌面、嵌 入应…...

EasyExcel 导出冻结指定行
导出的实体类 package org.jeecg.modules.eis.test;import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.*; import lombok.Getter; import lombok.Setter; import org.apache.poi.ss.usermodel.HorizontalAlignment;import…...

ke9案例三:页面提交文件,我服务器端接收
案例三:页面提交文件,我服务器端接收 ProcessFile.java 1value "/process-file" 2获取邮件消息的所有部分part--Collection<Part> partsrequest.getParts(); 3遍历每一个part 4之后可以打印头文件等String headerpart.getHeader("content-disposition&q…...

springboot调用第三方接口json转换成对象
请求接口是一个比较常见的需求,接口返回一般是一个json类型,需要进行组装成对应的类,例 {"status_code": 200,"message": "success","data": {"cost": 286.6933,"bom_list": […...

uniapp使用vue3和ts开发小程序自定义tab栏,实现自定义凸出tabbar效果
要实现自定义的tabbar效果,可以使用自定义tab覆盖主tab来实现,当程序启动或者从后台显示在前台时隐藏自带的tab来实现。自定义一个tab组件,然后在里面实现自定义的逻辑。 组件中所使用的组件api可以看:Tabbar 底部导航栏 | uView…...

麒麟信安获批牵头成立国家关键领域信创行业产教融合共同体
日前,由麒麟信安、长沙理工大学、长沙职业技术学院联合牵头成立的国家关键领域信创行业产教融合共同体(以下简称:共同体)已获湖南省教育厅批准,并推荐至教育部。 目前共同体已吸引10余家联盟单位及全国20余家企业、高…...

好消息,微信消费者投诉工具升级,可以直接回复用户、处理投诉了。。。
大家好,我是小悟 兄弟们,阅读本文之前,建议先阅读【连夜干出来一个自动处理【微信消费者投诉管理系统】,支持多商户】。 为了使工具更好用,也为帮助商户更好地处理消费者投诉,提升用户满意度,…...
手动修复 rabbitmq 报错 “Crash dump is being written to“
rabbitmq 报错: 2023-11-07 16:38:52.682 [error] emulator Error in process <0.368.0> on node rabbitrabbitmq-0.rabbitmq-discovery.openstack.svc.cluster.local with exit value: {shutdown,[{mnesia_loader,handle_exit,2,[{file,"mnesia_loader.erl"}…...
日志门面技术
1.JCL public abstract class LogFactory {public static Log getLog(Class clazz) throws LogConfigurationException {// 默认实现类为LogFactoryImplreturn getFactory().getInstance(clazz);} }利用LogFactoryImpl实例化具体的日志框架。其中,如果存在log4j依赖…...

机器人制作开源方案 | 管内检测维护机器人
一、作品简介 作者:李泽彬,李晋晟,杜张坤,禹馨雅 单位:运城学院 指导老师:薛晓峰 随着我国的社会主义市场经济的飞速发展和科学技术的革新,各行各业的发展越来越离不开信息化和网络化的…...

k8s存储卷
目录 1、emptyDir存储卷 2、hostPath存储卷 3、nfs共享存储卷 4、PVC 和 PV 4.1 PV和PVC之间的相互作用遵循这个生命周期: 4.2 PV的状态 4.3 一个PV从创建到销毁的具体流程如下: 静态PVC: 动态PVC 1、emptyDir存储卷 当Pod被分配给节…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...

C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...

Java数组Arrays操作全攻略
Arrays类的概述 Java中的Arrays类位于java.util包中,提供了一系列静态方法用于操作数组(如排序、搜索、填充、比较等)。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序(sort) 对数组进行升序…...
ArcPy扩展模块的使用(3)
管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如,可以更新、修复或替换图层数据源,修改图层的符号系统,甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...