钱包处理多链请求时,并发控制的核心是“分片隔离、两级队列、自适应限流”,只有让慢链不拖垮快链,让突发流量不压垮节点,聚合钱包才能在十几条链之间保持稳定响应。
钱包从单链走向多链,看似只是多接几个RPC节点,实际却是把一套原本简单的请求流程搬进了复杂路网,用户打开资产页,钱包要同时向以太坊、Arbitrum、Polygon、Solana等链发起余额查询;用户点一笔跨链交易,钱包要在目标链上轮询交易状态,这些请求看起来互不相干,却共享同一套网络资源、内存和线程池,如果处理不好,一条链的节点卡顿会拖慢整个钱包的响应,甚至让App直接白屏,下面从场景、策略、节点配合、故障兜底四个层面拆解并发控制的完整方法,最后附一份可直接照做的排查清单。
钱包多链并发请求从哪里来
多链请求并不是均匀分散的,它往往集中在几个高频动作上,搞清流量来源,才能知道该在哪里做隔离、在哪里做削峰。
资产聚合时的请求风暴
打开钱包首页,钱包默认需要对每个网络上的常用Token做余额查询,假设一个钱包聚合了10条链,每条链有5个常用Token,那就是50个RPC请求同时在几秒内发出,如果再赶上行情波动,用户频繁下拉刷新,请求量会成倍增长。
这些请求的响应时间参差不齐,Solana的RPC通常几百毫秒返回,Ethereum主网在拥堵时可能要等3到5秒,而一些新链的公共RPC偶尔会直接超时,如果线程池被这些慢请求占满,所有链的查询都会被阻塞。业内专家指出这本质上是“线程饥饿”问题,不是网络带宽问题,而是调度问题。
交易监听与状态轮询
钱包另一大并发来源是pending交易监听,用户发起一笔交易后,钱包要不断轮询该交易是否上链、是否被替换,每条链的轮询间隔还不一样,有的链推荐5秒轮询一次,有的链2秒一次,多链同时有交易在途时,这部分轮询就会形成持续不断的后台流量。
处理这类高并发场景,很多钱包会引入WebSocket订阅替代HTTP轮询,但这又带来连接数管理问题,每条链维护几十个WebSocket连接,内存开销不容小觑,断线重连时还会有瞬时请求高峰。
多链钱包并发请求如何处理的三个层次
并发控制不是简单加一个线程池就算完事,它需要从入口拦、从队列排、从调度分流,下面这套方案在多数开源钱包项目里能得到验证,也适合自研钱包作为起步框架。
h3标签示例:分片隔离,让一条链的抖动不出圈
既然多链请求共享线程池会被慢链拖垮,那就把线程池拆成多个独立分片,每条链拥有单独的连接池、单独的队列、单独的线程数上限。
Ethereum分片有20个线程配额,Polygon分片有20个线程配额,Solana分片有15个线程配额,各分片的水位线互不相通,哪怕Ethereum主网的RPC全线超时,占满的也只是自己分片的20个线程,Polygon的请求依然能正常返回。
实操中推荐用语言自带的协程或异步任务分组来实现,比如Go的errgroup按链分组,Java的ThreadPoolExecutor按链各建实例,JavaScript则可以为每条链建一个独立的p-limit队列。
这种隔离还有一个额外好处:可以按链的RPC成本精细控制流量,付费的高性能节点分片可以多给并发额度,免费公共节点分片就少给一些。
两级队列,把突发流量从“乱闯”变成“排队”
有一类问题线程池分片解决不了瞬时的集中爆发,比如用户从备份恢复助记词,钱包一次性要扫描20条链的资产,这波突发的请求量可能是平时的10倍,如果直接全部放行,RPC服务商会直接封禁钱包的API Key。
解决办法是双队列缓冲,第一级队列接收钱包所有个性化服务的请求,按用户会话维度做去重和合并,同一用户在短时间内对同一条链、同一个Token地址的重复余额请求,直接合并为一个请求,这在大户钱包里效果明显,因为大户持有的Token种类固定,频繁刷新的场景非常多。
第二级队列是每链的令牌桶队列,令牌以固定速率填充,比如Polygon分片每秒放行30个请求,超出的请求排队等待或者快速失败,这个设计把突发流量变成平滑的涓涓细流,保护了RPC端点,也让请求在钱包自己这一侧承受超时压力,而不是直接抛给节点。
自适应限流,给节点留出喘气空隙
固定限流虽然简单,但不够聪明,晚高峰RPC节点本身延迟已经很高,如果钱包还按照额定QPS打过去,会加剧节点负载,形成恶性循环,自适应限流则实时监控每个分片的请求成功率、P99延迟、节点返回的错误码比例,动态收紧或放宽令牌桶速率。
自适应的触发条件通常有两个,一个是错误率陡增,比如最近10秒有超过20%的请求返回429或者504,就把令牌速率下调到原来的60%,另一个是延迟持续偏高,比如连续两个窗口P99超过2秒,就主动把并发上限压缩一半,等节点恢复稳定后,再逐步放开。
这套策略让钱包在节点故障初期就能感知压力,不必等用户反馈“加载不出来”才临时处理。
多链RPC节点并发限制怎么调
钱包做了内部调度还不够,节点本身的并发限制往往才是真正的“壁垒”,不同节点服务的并发处理能力差异很大,搞清楚边界才能设定合理的上游限速值。
| 节点类型 | 典型并发上限 | 适合场景 | 限制特征 |
|---|---|---|---|
| 公共RPC(免费) | 数十次/秒/Key | 测试、小额场景 | 容易触发429,不稳定 |
| 自建全节点 | 数百次/秒 | 主力生产环境 | 受机器配置和网络带宽影响 |
| 商业RPC聚合器 | 数千次/秒 | 高并发聚合钱包 | 按套餐限速,成本较高 |
对于自建节点,并发瓶颈往往不在节点软件,而在服务器的文件描述符限制和数据库连接数,调整节点前的ulimit和内存缓存往往比优化节点本身更有效,多数情况下,自建节点不会标出明确QPS,但会受限于最大TCP连接数,所以钱包侧需要做好连接复用,避免每次请求都新建连接。
接头节点聚合服务(如Infura、Alchemy、QuickNode)的限速逻辑,它们通常按“每秒请求数+每日请求总数”双重限制,钱包要做的是把限流参数设为套餐上限的70%,留出安全余量,在适配多链RPC节点并发限制时,还需要区分archive节点和full节点的并发能力,archive节点处理历史数据更慢,并发配额要给得更少。
聚合钱包请求超时怎么解决
并发控制做得再好,也不可能完全避免单条链的节点故障或网络分区,此时超时和重试策略是最后一道防线,也是用户最容易感知的部分。
超时分级设置,不同请求不同耐心
不能所有请求都用同一个超时时间,三秒超时对余额查询太长,对交易状态轮询又太短,合理的方式是按请求类型分级设置超时时间。
- 余额查询 / 价格查询:超时设置在5秒到2秒,这类请求对新鲜度要求高,可以快速失败,下次刷新再请求。
- 交易状态获取:超时设置在5秒到8秒,交易状态查询链路长,涉及交易收据、区块确认数,需要多给时间。
- 推送类消息(新交易通知):不设固定超时,但要有连接心跳和断线重连机制。
重试要带退避,不能原地打转
无脑重试是最容易踩的坑,一条链的RPC挂了,钱包每隔500毫秒重试一次,结果每个请求都在等超时,线程池很快就满了,模块化方案是“指数退避+抖动”:第一次重试等待1秒,第二次重试等待2秒,第三次4秒,上限10秒,再加上随机数偏移(±20%),避免所有钱包请求在同一时刻打向已故障节点。
如果重试超过3次仍然失败,应该主动降级,比如把该链标记为“暂时不可用”,用缓存展示最近一次数据,并在界面上提示用户稍后重试,这种降级策略能让钱包保持主要功能可用的状态,而不是一个链卡死全局。
熔断机制,防止连续请求扩大故障
熔断和重试是相互配合的队伍,熔断器在节点连续失败超过阈值时打开,之后一段时间内所有该链的请求不再进入网络层,直接返回错误,这让故障节点能安心恢复,也让应用层有机会切换备用节点。
对于公共RPC,还需要准备备用节点列表,检测到主节点熔断后自动切换,切换过程对用户透明,行业常见做法是维护一个“多链RPC节点池”,每个节点带上健康标记,调度层每次优先选择健康且延迟最低的节点。
多链钱包并发控制排查手记
前面讲了很多原理,这里给出一份可以直接照着做的排查步骤,排查对象是自研聚合钱包,按顺序操作,大部分并发问题能在十到二十分钟内定位到根因。
- 第一步:先关掉WebSocket订阅,全部改用HTTP轮询,看问题是否消失,如果线程池占用率明显下降,说明是连接管理泄漏,而不是HTTP链路问题。
- 第二步:给每条链加上独立的QPS计数日志,拉取最近五分钟的请求分布,观察是否存在某条链的请求量占比超过50%的异常,如果有,检查是否有轮询循环没有加节流。
- 第三步:在节点返回429时记录响应头的
Retry-After字段,看服务商给的重试时间建议,多个节点的建议值放一起,可以作为令牌桶速率的初始参考。 - 第四步:用压测工具直接攻击最慢的那条链的RPC端口,记录崩溃时钱包的内存占用和线程数,通常反应快的钱包会比反应慢的更早发现节点故障。
- 第五步:检查缓存命中率,特别是Token地址变更和下架后的缓存清理逻辑。缓存失效导致的无意义重复请求,在多数钱包中占比相当大,这部分是零成本优化点。
这五步做完,能发现大多数“用户反馈钱包卡顿”背后的真实原因,而不是靠猜。
关于钱包多链并发请求的常见疑问解答
是不是无脑把并发线程数调大就能解决问题?
不是,并发线程数调整到一定程度后,瓶颈会转移到RPC服务商那边,再加大只会让429错误增多,线程池大小应该根据最慢链的P99延迟和节点允许的QPS来推导,计算公式为:并发数 = 每秒新请求数 × P99延迟(秒),假设某链每秒进来50个新请求,P99延迟2秒,那么该链分片的并发数设为100左右是合理的,超出这个值的线程只会积压。
用第一层队列合并重复请求,会不会导致数据不新鲜?
要看合并窗口的时长,如果是针对用户手动刷新,窗口可以设为1秒到2秒,用户无感知;如果是后台资产自动同步,窗口可以放宽到5秒,对于价格敏感型请求,合并窗口要更短,或者干脆不合并只做并发限制,更稳妥的做法是合并时带上“最小刷新间隔”参数,控制层在满足任意一个条件时才触达RPC时间到期,或者请求参数变化。
钱包冷启动时扫链太快被节点封禁怎么办?
冷启动扫描是多链钱包拉新时频发的问题,用户在恢复钱包后,要立即对几十条链做历史交易查询,直接抛全部请求出去一定会被封,建议把扫链任务拆为“高优先级链”和“低优先级链”两张表,以太坊、BNB Chain这类用户主力链优先扫,小众链排队后扫,同时把同一链上的多个地址查询用eth_getBalance批量接口合并,节点封禁往往是按Key维度限次数的,用批量接口能把请求量降到原来的五分之一。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/644832.html





