Replies: 1 comment
-
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
由 yuque 文档 Pixiu路由原理简介.pdf 总结而来,原作者 @yqxu
Pixiu路由字典树(Trie)并发优化方案
1. 背景:当前实现的瓶颈
在当前的Pixiu路由实现中,为了保证数据一致性,对字典树的所有读、写操作都由一把全局锁(LOCK)来控制。无论是读取路由规则进行匹配,还是通过RDS协议动态更新路由规则,操作前都必须先获取这把锁。
这种设计的直接问题是,当读、写操作并发进行时,会产生激烈的锁竞争。特别是在高并发场景下,大量的读请求(URL匹配)会被少数的写请求(规则更新)所阻塞,从而影响网关的整体性能和延迟。该实现之所以要求读操作也加锁,是因为底层大量使用了Go语言的
map结构,该结构在并发读写时会直接导致程序崩溃。当前实现示意图:
graph LR subgraph "读/写线程" A(读请求) B(写请求) end subgraph "全局锁控制" C{LOCK} end D[Trie] A -- "竞争锁" --> C B -- "竞争锁" --> C C -- "获取成功" --> D2. 优化目标
为了解决全局锁带来的性能瓶颈,优化目标是实现对字典树的无锁读取,从而让路由匹配(读操作)的性能不受规则更新(写操作)的影响。
3. 优化方案:读写分离与双树切换
本次优化引入了读写分离的设计思想,核心是维护两棵功能上完全相同的字典树(Trie1和Trie2),一棵用于读取(“读树”),另一棵用于写入(“写树”)。
方案核心组件:
command对象,放入一个先进先出(FIFO)的队列中。整体架构示意图:
graph LR subgraph "用户写操作" A[Operator: url add /a/b/c] --> Q; B[Operator: url remove /a/b] --> Q; end subgraph "Command队列 (FIFO)" Q(Command Queue) end subgraph "后台追Log线程" T[追Log线程] end subgraph "双Trie实例" T1(Trie1 - 读树); T2(Trie2 - 写树); end R[读请求] Q -- "读取Command" --> T; T -- "写入" --> T2; R -- "无锁读取" --> T1; %% 切换逻辑 style T1 fill:#cde,stroke:#333 style T2 fill:#fce,stroke:#3334. 角色切换逻辑
为了让“写树”上更新的配置能够生效,系统会周期性地(例如,每3秒)切换“读树”和“写树”的角色 [cite: 246, 247]。切换过程经过精心设计,以保证服务的平滑过渡:
通过这个机制,可以实现配置的“延迟生效”(例如延迟3秒),同时保证了最终一致性,因为两棵树追赶的是同一份操作日志(Command队列)。
5. 优化带来的收益
Beta Was this translation helpful? Give feedback.
All reactions