TT Lab
开始
学习 学习路径 课程

构建 EAI 中间层

别让一个慢目标拖垮枢纽

在 TT Lab 中继续学习

目标

用断路器和按目标划分的舱壁,使一个缓慢或已死的目标无法拖垮整个枢纽。

为什么重要

超时只决定一笔要等多久。如果持续调用已死的目标,等待的线程就会堆积,枢纽先窒息,连无关的交易也一起停住。必须为每个目标各自设置快速拒绝的装置,故障才不会蔓延。

步骤

  1. 在 /root/eaimw/breaker/breaker.py 中制作 CircuitBreaker(failure_threshold, reset_timeout, clock=time.monotonic)。state(CLOSED·OPEN·HALF_OPEN)、allow()、record_success()、record_failure()。连续失败达到阈值就变为 OPEN,OPEN 时 allow() 为 False。时刻必须通过 clock() 读取(评分器会传入假时钟)。
  2. 在 OPEN 状态下,经过 reset_timeout 之后,allow() 只返回一次 True,并变为 HALF_OPEN。试探调用成功则 CLOSED,失败则再次 OPEN(时间从头开始)。即使多个线程同时询问,也只允许一笔(锁)。
  3. 以 cp /opt/lab/fixtures/eaimw/breaker/relay_base.py /root/eaimw/breaker/relay.py 开始,加入 --fail-threshold(默认 5)和 --reset-timeout(默认 10)参数,并用断路器包裹对目标的调用。打开时不调用,立即返回 E904。这一步中,把不是 0000 的结果算作失败。
  4. 设置 --max-inflight(默认 10)并发处理上限。上限已满时不等待,立即返回 E905。
  5. 把断路器和并发处理上限按目标(CORE、CLAIM)分别设置。账户系统的故障或饱和不能蔓延到理赔交易。
  6. 在 --breaker-log(默认 /root/eaimw/breaker/breaker.log)中,每当状态变化,就留下一行 <시각>|<대상>|<FROM>-><TO>(占位符依次为时刻、目标)。
  7. 把算作失败的范围缩小到系统错误(E500·E901·E902)。业务拒绝(B2xx)是目标健康地作答,所以算作成功。

参考

连续失败累积就打开回路

让 /root/eaimw/breaker/breaker.py 的 CircuitBreaker 在连续失败达到阈值时变为 OPEN,并且在 OPEN 时 allow() 为 False。

成功时把失败数归零,这样统计的才是“连续”。打开的时刻要用 self.clock() 而不是 time.time() 来记录——评分器会掌握时钟。

用一笔试探,然后关闭

在 reset_timeout 之后的 HALF_OPEN 中只允许一次试探调用,成功则 CLOSED,失败则再次 OPEN。

在 allow() 中,如果处于 OPEN 且时间已到,就变为 HALF_OPEN,并设置一个标记来表示试探调用是否已经发出。请在锁内判断,使两个线程同时询问时,只有一方得到 True。

打开时不调用

复制 relay_base.py,用断路器包裹对目标的调用,打开时立即以 E904 答复(--fail-threshold、--reset-timeout)。

handle_tx 就是要包裹的位置。如果 allow() 为 False,就不调用 call_target 而直接返回,调用之后则根据结果调用 record_success/record_failure。

超出上限就不等待

设置 --max-inflight 并发处理上限,上限已满时立即以 E905 答复。

如果 BoundedSemaphore 的 acquire(blocking=False) 为 False,就说明上限已满。调用之后,即使出现异常也要用 try/finally 确保 release。

按目标划分舱壁

把断路器和并发处理上限按 CORE、CLAIM 目标分别设置,使账户系统的故障、饱和不会蔓延到理赔。

把原来各设一个的做法,改成以目标名称为键的字典。如果只有一道舱壁,一个舱里的水就会灌满整艘船。

记录状态转换

每当状态变化,就在 --breaker-log 中留下一行“时刻|目标|FROM->TO”。

比较 allow() 前后、record 前后的 state,如果不同就写一行。多个线程会写,所以要加锁再写。

业务拒绝不是失败

把算作失败的范围缩小到 E500、E901、E902,B2xx 则算作成功。

余额不足是账户系统健康地作出的答复。如果把它算作失败,仅仅因为月底的业务拒绝,就会切断通往正常账户系统的路。