news 2026/9/20 14:57:34

JMeter压测实战:从脚本设计到性能瓶颈定位

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JMeter压测实战:从脚本设计到性能瓶颈定位

1. 压测前必须想清楚的几件事

做JMeter压测,最大的坑不是工具不会用,而是不知道为什么压、压什么、压多久。我见过太多团队拿到JMeter就咔咔加线程数,结果压出来的报告除了给自己壮胆,没有任何参考价值。如果手里正好有一个“迁移到云上ECS后需要验证承载能力”的项目,那思路更得捋清楚。

压测这件事,本质上是回答三个问题:系统在什么负载下开始变慢?系统在什么负载下彻底不可用?系统的瓶颈到底在哪个环节?所以开跑之前,先别急着打开JMeter,先想清楚以下四件事。

第一,业务模型。你压的不是“登录接口”或“查询接口”,你压的是用户真实操作路径。比如一个电商系统,浏览商品、加购物车、下单、支付这几个动作的比例大约是6:3:1,那脚本里的请求占比就应该按这个来,而不是平均分配。没有业务模型的压测脚本,压出来的数字没有任何意义。

第二,性能指标。你能接受的响应时间是多少?错误率阈值是多少?CPU、内存、磁盘IO、网络带宽,哪个指标优先看?这些都必须在压测开始前和业务方、开发方对齐,否则压测过程中大家会因为“到底算不算达标”吵起来。

第三,施压策略。是瞬时压满峰值,还是逐步加压寻找拐点?是用恒定QPS,还是有节奏地波峰波谷?不同的施压方式对应的场景完全不同。瞬时压满适合验证容灾能力,而逐步加压适合定位性能拐点,也就是所谓的“容量探测”。

第四,数据准备。压测数据不能全用同一份。账号要大量、并发、独立;商品库存要够;数据库里的数据量要接近生产环境。很多压测得出错误结论,就是因为用了几条测试数据去模拟几十万用户。

这些问题想明白了,再打开JMeter,你会发现每一步操作都有明确的目的,而不是为了跑一个“看起来很大”的并发数。

2. 环境准备与脚本基础

2.1 安装与版本避坑

JMeter安装本身很简单,但版本坑不少。首先,JMeter是一个纯Java应用,所以第一件事是确认JDK版本。JMeter 5.4以前可以用JDK 8,JMeter 5.5开始最低要求JDK 8,JMeter 5.6建议JDK 11或17。如果你用的是最新版JMeter(比如5.6.3)再配一个JDK 7,那是肯定起不来的。

官网下载是首选路径,记住不要从乱七八糟的下载站拿安装包。下载到的压缩包解压后,进入bin目录,Windows用户双击jmeter.bat,Mac或Linux用户执行jmeter.sh。注意,执行命令时如果提示“Permission denied”,记得先chmod +x。

这里有第一个实操经验:生产或测试机上启动JMeter,一定要用命令行模式(jmeter -n -t xxx.jmx -l result.jtl),不要开GUI。GUI模式下JMeter本身就要吃掉不少内存,压在JMeter自己的头上,测出来的数据根本不准。而且GUI模式跑得越久,内存碎片越多,数据偏差越大。

bin目录下有两个文件建议提前改:jmeter.bat(或jmeter.sh)里的HEAP参数,还有jmeter.properties里的配置项。默认堆内存是-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m,如果压测脚本比较大或者聚合报告开得比较多,建议改成-Xms2g -Xmx4g。别觉得内存给多了浪费,JMeter是Java进程,内存不够时频繁GC直接导致线程停顿,压测结果会失真。

2.2 线程组设计是压测的灵魂

进入JMeter后第一个要认识的就是线程组(Thread Group)。简单理解,线程组就是“模拟用户池”,里面每一个线程代表一个模拟用户。但线程数不等于并发用户数,这是一个需要专门说清楚的概念。

线程数只是你开了多少个线程,真正意义上的并发是“同一时刻发出去的请求数量”。如果脚本里带了思考时间(Think Time),比如用户看完页面再点查询,那么100个线程实际同时打在服务器上的请求可能只有30个。所以做容量评估时,要区分开了多少线程和实际RPS(每秒请求数)是多少。

线程组的三个核心参数分别是线程数、Ramp-Up Period和循环次数。Ramp-Up Period的意思是“在多少秒内启动所有线程”。假设线程数是100,Ramp-Up是10秒,那么每秒启动10个线程,首次并发峰出现在第10秒。很多新手喜欢把Ramp-Up设为0,这意味着所有线程瞬间全部启动,服务器会收到一个非常陡峭的流量冲击。这在某些故障注入场景下是有意的,但常规压测不建议这么干,真实用户不可能在同一毫秒内全部涌进来。

循环次数控制的是每个线程跑多少轮脚本。做容量测试时建议勾选“永远”,然后用调度器(Scheduler)来控制压测时长,例如持续运行15分钟、30分钟。这比设置一个巨大的循环次数更科学,因为你可以精确控制“持续施压的时间窗口”。

2.3 HTTP请求配置的三个关键细节

线程组下面就是Sampler采样器,最常用的就是HTTP Request采样器。这里有几个必须养成的习惯。

第一个是协议、域名、端口分开填,不要直接拼成一个URL。这样做的好处是便于用变量替换。比如说要切换压测环境,从测试环境切到预发环境,只改一个变量就行,而不是在几十个请求里挨个找。我见过有人把整个URL都写在“路径”里,切换环境时改到怀疑人生。第二个是路径不要写死,有查询参数的优先写在“Parameters”里,不要拼在路径后头。因为JMeter里用CSV参数化时,写在Parameters里的东西可以配合变量直接替换,而拼在URL里的字符串处理起来各种别扭。第三个是随请求发送的Headers一定要加齐。比如Content-Type、Accept、Authorization这些,少了任何一个,接口都可能返回错误,而新手往往以为是JMeter配置错了,其实是被接口的鉴权或内容协商拦住了。

3. 参数化与断言:脚本能跑和脚本会说话是两回事

3.1 数据库参数化取值

很多接口的入参不是固定的,尤其是业务主键。JMeter里有好几种参数化方式,比如CSV文件、函数助手、数据库查询。这里我只重点讲数据库参数化,因为它在真实项目里最实用,也最容易出错。

场景是这样的:接口要求传入一个数据库中真实存在的数据ID,而这个ID需要从数据库查出来、去重、再放到请求里。这时候就用到JDBC Request采样器和JDBC Connection Configuration组件。

先在测试计划里配置JDBC Connection Configuration,DataSource(数据库类型)选mysql,JDBC Driver Class选com.mysql.jdbc.Driver(MySQL 8用com.mysql.cj.jdbc.Driver),然后在“Database URL”里填jdbc:mysql://IP:3306/dbname?useUnicode=true&characterEncoding=utf8&useSSL=false,用户名密码按实际填。

这里有个关键点:JDBC Connection Configuration里需要设置“Pool Max”公共的超时参数。多数人忽略这个,导致数据库连接池满了之后,JMeter等不到连接,直接报“Cannot create PoolableConnectionFactory”。建议把Max Number of Connections设为和线程数一致或略高,超时时间设180秒,避免并发一上来就连接池崩溃。

JDBC Request里写查询SQL,比如SELECT id FROM orders WHERE status=1 ORDER BY RAND() LIMIT 1。然后在下一处需要ID的HTTP请求中通过${orderId}引用查询结果。这里要注意的是,JDBC Request的结果变量名(Variable Names)要填一个名字,例如orderId,然后在HTTP请求参数里写${orderId}即可。

还有一个容易被忽略的点:JDBC Request执行结果返回的是ResultSet对象,如果你只取一行一列,没问题。但如果要取多行数据作为后续请求的参数,就要配合计数器(Counter)或ForEach控制器来循环取值。实际项目中,我通常的做法是查出一批ID,比如50个,用计数器变量索引遍历,这样能模拟出真实用户“每个人操作不同的订单”的效果。

3.2 BeanShell断言:不只校验HTTP状态码

JMeter自带的响应断言(Response Assertion)只能做简单文本匹配,比如判断响应里是否包含某个字符串。但真实的接口校验逻辑要复杂得多:状态码200不代表业务成功,可能是“返回码200、业务码500”的假成功;响应JSON里的某个字段可能是动态的,不能全文匹配;有时需要校验多个字段组合逻辑。

这时候就要用到BeanShell断言。在HTTP请求上右键添加“断言 -> BeanShell断言”,在Script区域写脚本逻辑。以下是我常用的一套模板:

String response = prev.getResponseDataAsString(); // 解析JSON String code = vars.get("code"); // 如果用JSON提取器先提取了 if (response.contains("\"success\":true") && response.contains("\"code\":200")) { Failure = false; } else { Failure = true; FailureMessage = "业务校验失败,响应内容: " + response; }

但BeanShell有个性能隐患:它走的是解释执行,压测线程多的时候会拖累JMeter自身效率。所以我更推荐用JSR223断言 + Groovy脚本,执行效率远高于BeanShell。JSR223是编译执行的,BeanShell是解释执行的,同样一个断言脚本,Groovy比BeanShell快好几倍。高并发压测时,这会直接影响施压端的最大发压能力。

JSR223断言脚本里,最常用的就是解析JSON响应。配合groovy.jar内置的JsonSlurper可以非常优雅地处理:

import groovy.json.JsonSlurper def response = prev.getResponseDataAsString() def json = new JsonSlurper().parseText(response) if (json.code != 200 || json.data.count < 1) { assert false : "业务异常: ${response}" }

这里分享一个经验:断言不是越多越好。每个断言都消耗JMeter的资源,而且断言逻辑写得复杂了,排错也更困难。我的原则是“核心字段必有断言,次要字段不做校验”。拿支付接口为例,只需要校验返回码和支付状态字段,其它时间戳、签名这种动态字段不应该出现在断言里。

3.3 动态调整QPS的两种方案

有些压测场景要求QPS不是固定不变的,而是按预设曲线变化。比如先跑100QPS,过10分钟升到200QPS,再观察系统表现。JMeter中实现动态QPS调整有两种典型方案。

第一种是使用Constant Throughput Timer(常量吞吐量定时器)。这个定时器可以设定每分钟最大请求数(按分钟设置,所以计算时要把想要的QPS乘以60)。它的工作方式是控制线程组整体发请求的节奏,不追求精确到毫秒。缺点是精度有限,而且如果线程数设少了,吞吐量会达不到设定值;线程数设多了,吞吐量又会超出预期。

第二种是用线程组配合Throughput Shaping Timer插件。这个插件允许你定义“阶段”,比如第一个阶段0-10分钟、QPS 100;第二个阶段10-20分钟、QPS 200。设置好之后,JMeter会自动调配线程去跟上这个节奏。这个方案比较精确,适合做阶梯加压测试。安装方式是在JMeter里通过Plugins Manager(插件管理器)安装Custom Thread Groups组件包。

有一点要提前说明:想用好Throughput Shaping Timer,JMeter本身要安装插件管理器。插件管理器放在lib/ext目录下,重启JMeter就能在“选项”菜单里看到。安装插件时选择Custom Thread Groups即可,不需要额外配置。

3.4 Cookie处理与文件上传

HTTP是“无状态”协议,但很多业务系统需要登录态才能继续操作。JMeter里处理Cookie有两个思路:一是用HTTP Cookie管理器来自动管理Cookie,它会把登录接口返回的Set-Cookie自动捕获并带上;二是手动用正则提取或JSON提取器抓取登录返回的token,然后通过HTTP Header Manager放到后续请求的Header里。

Cookie管理器适合基于Session的认证系统,Token方式适合基于JWT的微服务体系。如果是微服务架构,建议直接用JSON提取器抓token。写法如下:

$.data.token

在登录请求下添加JSON提取器,Variable填写tokenVariable,JSON Path表达式填上面的内容,Match No填1。然后在后续请求的Header Manager里添加Authorization字段,值写作Bearer ${tokenVariable}。

文件上传也是高频场景,尤其是涉及附件、头像、图片的业务。JMeter中在HTTP请求里把请求方式改成POST,然后勾选“Use multipart/form-data”,在“Files Upload”区域填写文件路径和参数名。这里的坑在于:文件路径尽量用绝对路径,相对路径在命令行模式运行时容易找不到文件;另外,参数名必须和接口文档一致,否则服务端永远收不到文件。还有一种更常见的坑是,文件上传时还要带业务参数(比如备注、类型),不能只传文件。

4. 脚本录制与复杂协议扩展

4.1 HTTPS脚本录制的正确姿势

刚开始做JMeter压测的新手,最容易卡住的是不会写脚本。一个一个接口手写虽然可行,但业务复杂时效率太低。这时可以利用JMeter的HTTP(S) Test Script Recorder录制脚本。

原理很简单:JMeter启动一个本地代理服务器,把你的浏览器或系统HTTP请求转发到目标服务器,同时这个代理服务器会把请求“记录”下来,生成对应的Sampler。你只需要在真实浏览器里操作一遍业务流程,脚本就自动生成了。

实际上手时会遇到HTTPS证书问题。因为JMeter代理本质上拦截了加密流量,浏览器会提示证书不受信任。解决办法是先把JMeter的CA证书装到浏览器里。在JMeter的bin目录下有个ApacheJMeterTemporaryRootCA.crt,安装到系统“受信任的根证书颁发机构”即可。

录制前还需要设置浏览器代理。把HTTP代理和HTTPS代理都指向127.0.0.1,端口填在JMeter Recording Controller里配置的端口(默认8080)。然后开始录制,操作完业务后点停止。

特别提醒:录制的脚本里带了大量静态资源请求(图片、CSS、JS),这些请求在压测时通常要排除掉。真实的用户访问会产生这些请求,但压力测试的重点是业务接口,静态资源应该由CDN或前端缓存来承担。我通常会在录制时启用“记录HTTP请求”下面的排除模式,把这些静态资源URL过滤掉。

4.2 MQTT插件安装与物联网场景压测

现在很多系统不是纯互联网项目,而是物联网后台,消息通信走的是MQTT协议。JMeter原生不支持MQTT,需要安装第三方插件。

安装方法依然是通过Plugins Manager,搜索“MQTT”安装mqtt-jmeter插件。安装后,在“添加 -> 取样器”里会多出MQTT Connect、MQTT Pub Sampler、MQTT Sub Sampler三个组件。

MQTT压测和HTTP压测最大的不同在于通信模式:HTTP是一问一答,MQTT是发布/订阅。脚本设计时要考虑“订阅端”的比例,比如1个订阅者配多少个发布者,消息主题怎么分配,QoS等级用多少,这些都是影响服务端压力的关键因素。

我碰到过一个物联网项目的压测需求,要模拟十万设备并发上报数据。直接开10万线程是不现实的,JMeter单机撑不住。正确做法是分布式压测,多台施压机配合。但MQTT插件的分布式支持不够好,更多时候是把设备数据建模后,每条消息封装成一个发布请求,用几百线程持续高吞吐地发布消息来模拟,而不是真的开10万线程。

4.3 RESTful接口参数写法

RESTful接口的参数有几种情况:路径参数、查询参数、请求体。JMeter里写路径参数,就是在HTTP请求的“路径”里直接把变量拼进去。比如接口是GET /user/{id},那么路径填 /user/${userId},在路径上右键添加“用户参数”或使用CSV文件配置好userId即可。

查询参数写在Parameters表里,和路径用问号分隔后的内容对应。请求体如果是JSON格式,就在Body Data里写JSON字符串,同样可以用变量替换值。唯一要注意的是Content-Type要设置为application/json,否则服务端可能解析不了。

5. 报告输出与数据解读

5.1 HTML报告汉化模板

JMeter压测结束后,官方推荐用命令行生成HTML报告:

jmeter -n -t test_plan.jmx -l result.jtl -e -o report_dir

这个命令会生成一个统计聚合视图的HTML文件,包含响应时间分布、吞吐量、错误率、活跃线程数等图表。但默认模板是英文的,很多测试同学看着费劲,尤其是要拿去跟领导汇报的时候。

汉化模板的做法是准备一套中文的reportgenerator.properties和CSS资源。这里我不建议大家下载来路不明的汉化包,更靠谱的做法是自己翻译模板里的configuration/目录下的properties文件。里面包含面板标题、图表名称、时间单位等文本,翻译后放到模板目录覆盖原文件即可。

我有一个习惯是拿到HTML报告后第一时间看两部分:响应时间百分位(尤其是TP90、TP99)和吞吐量趋势图。TP90和TP99能反映整体用户感受的“长尾”,而不是平均值掩盖掉的那部分慢请求。如果TP99高于业务要求的300ms,即便平均响应时间才80ms,这个系统也是不达标的。

5.2 自己整理一份带趋势的图表

JMeter原生报告够用,但如果你想把压测现场的变化过程记录得更细致,建议自己额外记录一个“压测过程指标表”:每分钟记录一次TPS、平均RT、错误率、CPU使用率、内存使用率、磁盘IO。这样跑完一轮压测,除了JMeter报告之外,你手上还有一份“时间和系统资源”的对照表,定位瓶颈时特别好用。

熟练之后,你甚至可以把这些都写入InfluxDB,用Grafana做实时看板。这也是JTL(JMeter结果日志)配合实时监控的常见方案,但那是进阶玩法了,基础阶段先把Excel记录和JMeter报告用明白就够了。

6. 常见问题与排查技巧实录

6.1 “error writing to server”到底什么情况

很多人在压测时会遇到一个报错:java.io.IOException: Error writing to server。这个错误表面上看是网络异常,实际原因不外乎以下几种。

第一种是服务器主动断开了连接。当服务器处理不过来时,它会重置TCP连接,客户端再往这个连接上写数据就会抛IOException。这种原因下,压测结果里往往会伴随大量非200响应和超时。第二种是负载均衡或防火墙的空闲超时设置太短,比如HTTP客户端的KeepAlive时长超过了LB的空闲超时,连接被中间设备关闭,再用就报错。第三种是客户端本地端口不够了。高并发下JMeter频繁建立连接,系统可用临时端口会被耗尽,新连接建立不成功。识别方式是在压测机上用netstat看TIME_WAIT状态的数量是否巨大。

排查顺序建议是:先看服务端监控(CPU是否满负荷、连接数有没有到达上限),再看网络设备(LB是否抛异常日志),最后看施压机资源。我之前遇到过类似问题,折腾了半天发现是压测机上文件描述符上限设得太低,高并发下socket打不开,和服务器一点关系都没有。

6.2 文件“已经存在”导致的采样暂停

JMeter压测过程中,如果结果文件(.jtl)被重新使用,比如第二次运行时用了同一个文件名,而当前目录下已经有这个文件,JMeter会提示“result file already exists”,然后中止执行。默认情况下它不会帮你覆盖。

解决方法有两种:一是每次启动前手动删掉旧的.jtl文件;二是在命令行加参数 -f 强制覆盖。我平时更建议用带时间戳的文件名输出,比如:

jmeter -n -t test_plan.jmx -l result_$(date +%Y%m%d_%H%M%S).jtl -e -o report_$(date +%Y%m%d_%H%M%S)

这样既能避免文件冲突,也方便后续整理两轮压测的对比数据。要知道做性能优化的时候,最宝贵的就是多轮压测结果的对比,它能直观告诉你“上一轮的优化到底有没有效”。

6.3 安全证书问题

压测HTTPS接口时,如果JVM不信任服务端的证书,会报SSLHandshakeException。解决方式有三种:一是把域名证书导成JKS文件,导入JMeter的JVM密钥库;二是在HTTP请求里勾选“Use KeepAlive”下方的SSL配置,关闭证书校验;三是用系统属性方式在启动时加载信任库。

最简单的方式是关闭证书校验,但要注意这种方法只适用于测试环境的压测。生产环境的HTTPS压测还是建议正规导入证书,否则你测的东西根本不是生产环境真实链路,数据没有参考意义。

7. 实战案例:云上环境承载能力验证

结合开头提到的场景,我分享一次完整的云上压测流程,这里不涉及具体的项目名称和敏感信息,只讲方法和思路。

项目背景是:业务系统从一个单节点的自建环境迁移到阿里云ECS上,需要验证新环境的承载能力。压测工具就是JMeter,压测脚本是和业务方确认过的核心链路脚本,脚本里包含了登录、查询列表、创建订单、上传附件等场景,业务比例按生产流量分配。

流程大致是:先在测试环境用小并发(比如50线程)验证脚本正确性,确保参数化和断言都没问题。确认脚本跑通后,用阶梯加压模式逐级增加QPS:100、200、400、800、1600,每级跑10分钟,观察响应时间、错误率和系统资源的变化。

实测过程中,QPS 800之前系统表现很稳,TP99基本在300ms以内,错误率接近0。QPS升到1600时,应用服务器的CPU使用率快速攀升到85%,响应时间开始出现明显上升,但还没有大规模报错。等到QPS跑到2000,错误率直接飙升到15%,TP99涨到5秒以上,数据库连接池出现获取超时,这时可以认定系统的性能拐点在1600左右。

这个数据拿回去后,和业务方对齐的结论是:ECS配置下系统能支撑每秒1600次请求,如果业务峰值预期是1200QPS,那当前配置是够用的;如果后续业务增长到1500QPS以上,需要提前扩容数据库或做缓存优化。

个人来说,这类验证最需要注意的是“压测完一定要看系统有没有残留问题”。高并发压测结束后,连接池、线程池、日志文件都可能出现异常状态,建议压测完成后观察10分钟,确认系统能自动恢复,才算验证结束。

8. 几个压测老手才会注意的细节

最后分享几个小的经验,都是踩坑踩出来的。

第一,JMeter脚本里不要开“View Results Tree”(察看结果树)监听器跑压测。GUI模式跑有监听器会消耗资源,命令行模式跑也会把结果写进日志,大量情况下影响JMeter自身性能。需要调试脚本的时候可以临时开,正式压测必须关掉。

第二,压测机和服务器之间的网络带宽要提前估算。假设单请求响应包体是20KB,QPS是1000,那么需要160Mbps的带宽。如果压测机是云上ECS,注意一下带宽计费模式,别把带宽跑满了导致结果全部超时。

第三,压测前检查系统文件描述符。Linux默认1024,压测并发一高就不够用。临时调一下:

ulimit -n 65535

如果是systemd管理的服务,还要在service文件里加LimitNOFILE=65535,重启服务才生效。

第四,JMeter分布式压测时,所有机器的时间要同步,否则聚合报表里的时间戳对不上,分析数据时非常痛苦。用NTP做时间同步是最简单可靠的方案。

第五,多轮压测之间要有“冷却时间”。服务器在高压状态下,CPU、内存、连接池、JVM GC都需要时间恢复。连续两轮压测中间至少等5到10分钟,否则第一轮的尾部效应会影响第二轮的基线数据。

做压测这行,越深入越会发现,工具本身只占三分之一,剩下的是你对业务的理解、对数据的敏感度和对系统底层的熟悉程度。JMeter只是一个玩具,重点是你怎么用它把事情测明白。

先把脚本跑通,然后试着去回答那三个问题:系统在什么负载下变慢?在什么负载下挂掉?瓶颈在哪里?答案找到了,压测才算真正做完。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 14:57:04

Wireshark安装核心原理:Npcap驱动与架构匹配详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 14:54:55

电力工程二次设计必备:国际图集D部分的高效利用与资料管理实战

简介&#xff1a;这是一份面向电气设计与施工从业者的电力图集PDF资料&#xff0c;聚焦国际图集电力D部分&#xff0c;涵盖变配电二次接线、防雷接地、电缆敷设、低压配电与电动机控制、舞台灯光、住宅小区电气设计等关键环节&#xff0c;适用于民用建筑与工业环境中的方案参考…

作者头像 李华
网站建设 2026/9/20 14:54:20

零代码本地部署Gemini 3.1 Flash:Ollama+Open WebUI实战指南

1. 为什么要在本地跑一个 Flash 级模型先把结论摆在前面&#xff1a;如果你手头有一台内存 16GB 以上的普通笔记本&#xff0c;或者一台带独显的台式机&#xff0c;那么用 Ollama 加 Open WebUI 把 Gemini 3.1 Flash 这类轻量模型跑起来&#xff0c;是一件当天就能搞定的事。整…

作者头像 李华
网站建设 2026/9/20 14:53:36

LibreChat自托管AI对话平台:多模型统一入口的Docker部署实操指南

我大概花了两个晚上&#xff0c;把本地一直凑合用的几套AI聊天客户端全部换掉&#xff0c;统一指向了LibreChat。如果你最近也在GitHub上刷到过这个项目&#xff0c;或者正被“想用多个模型又不想开一堆网页标签”的问题困扰&#xff0c;那这篇实操笔记应该能帮你省下不少弯路。…

作者头像 李华
网站建设 2026/9/20 14:53:21

USB 3.2 Gen2x2真相:20Gbps为何跑不满?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 14:52:59

TRIZ功能分析实操指南:从组件建模到裁剪创新

简介&#xff1a;四十四页课件聚焦TRIZ理论中的功能分析模块&#xff0c;面向产品设计师、研发工程师及创新方法初学者&#xff0c;帮助读者摆脱直觉试错&#xff0c;用系统化功能视角识别技术系统问题。课件以第三章功能分析为主线&#xff0c;先厘清技术系统、子系统、超系统…

作者头像 李华