银行的一天不在午夜结束
一句话总结
银行系统中,时钟指针所指的时间和账簿认可的日期是分开的,这两个时间相差,在相差期间,哪个日期记录了收到的交易,这决定了事故的大部分。
为什么需要这个?
在一般系统中,“今天”是date这是命令告诉你的值。午夜过后日期就会变,就这样结束了。
在银行不是这样的。昨天所有的交易都汇总到每个账户上,加上利息,对外机构结算,制作向监督机构提交的资料,**日终(EOD, End of Day)**部署才能结束一天。这个部署通常从晚上10点左右开始,一直持续到凌晨。在此期间,ATM机仍在运行,网上银行也开放。
所以银行系统有两个日期。
시스템 시각(posted_at) 실제로 그 거래가 들어온 순간. 서버 시계가 찍는다.
계정일자(biz_date) 그 거래가 어느 날 장부에 속하는가. 마감 배치가 끝나야 넘어간다.
凌晨1点入账的转账的账号日期可能是昨天,晚上11点入账的转账的账号日期可能是明天。混淆这两个值是第一次进入银行现场的工程师最常犯的错误。
怎么行动
一天的顺序大致是这样的。
09:00 계정일자 = 2026-08-25. 온라인 거래가 biz_date=2026-08-25 로 들어온다.
22:10 마감 컷오프. 이 시각 이후 유입분은 biz_date=2026-08-26 으로 찍혀야 한다.
22:10 마감 배치 시작. biz_date=2026-08-25 인 거래를 집계한다.
22:40 마감 완료. 계정일자를 2026-08-26 으로 전진시킨다.
核心是选择截止对象不是系统视图,而是账户日期。WHERE posted_at BETWEEN ...以为确定截止日期对象的代码总有一天会出错。
这里有两种可能发生冲突。
**第一,截止后流入部分的账户日期。**如果在线渠道没有读取截止状态,一直拍旧账户日期,那么明天的交易就会进入今天的账目。如果要将该交易改到后天的交易日期,必须从已经制作好的截止结果中删除,但结果可能已经对外机构公布。
第二,截止分配死亡时的重新进行。分配到一半左右死亡的话,只剩下反映部分交易的状态。在这种状态下,重新掷掷分配就会变成两种情况之一。如果再加已经反映的东西,就变成双重反映,如果不知道走到了什么程度,什么都不做就变成遗漏。
所以截止分配必须是等效(idempotent)。这意味着对于相同的账号日期,无论转几次结果都应该是相同的。创造等效性的方法主要有两种。
증분 방식 아직 반영 안 된 것만 골라 기존 산출물에 더한다.
빠르지만 '이미 반영된 것이 전부 옳다' 를 전제한다.
잘못 들어간 것을 빼낼 수단이 없다.
전량 재계산 해당 계정일자의 산출물을 통째로 지우고 처음부터 다시 만든다.
느리지만 이전 실행이 어디까지 갔는지에 의존하지 않는다.
像日结一样每天转一次的配置,几乎总是全额重新计算是正确的答案。计算量是一天的,得到的是一种“无论什么时候再转都安全”的性质。
在现场相遇的样子
首先,**“昨天交易了,今天被抓了”的咨询通常是截止日期的问题。**顾客看着手表说,系统会用账号日期来回答。调查时,只把两个值并排拿出来给顾客看就结束了的情况很多。相反,如果不区分两个值,报告“系统异常”,那就会被认为是意外上报正常运行。
第二,**截止时死亡时最危险的状态是只有单方票据反映的状态。**因为是复式计数,如果完全统计一天的量,便会导致大便和小便抵消,余额总和为0。但是,如果在反映单方票据的大便行和小便行之前死亡,这个总和就不为0。这个数字是告诉你“截止时断续结束”的最快信号。
第三,**如果截止配置对象在执行中通过查询捕获,那么截止期间收到的交易也会被包含进去。**22:10开始的配置在22:12查询时,这段时间内收到的交易将包含在查询结果中。对象必须固定在开始时的账户日期。这个错误平时不会造成任何影响,但只有在截止时间很长的一天或重新执行的日子才会出现。
第四,**截止日期确定和生成结果是另外一回事。**如果制作汇总结果后不向前推进账户日期,在线渠道会一直拍旧日期。相反,如果只通过账户日期而没有生成结果,第二天查询就会收到空值。必须在一次交易中完成两者,或者在顺序和失败时行为要以文档的形式确定。
下次实习要做的事情
2026-08-25 日终配置从22:10开始,途中将死状态保持不变,然后从那里恢复。掌握了只有153行中的240行中反映的状态,在终止期间找到18行账户日期写错的行,将其移至实际营业日,在数字上证明为什么在这种情况下无法进行增量重新执行,然后制作全量重新计算脚本,反复运行两次,证明结果相同。