V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
latifrons
V2EX  ›  程序员

高频金融系统如何防止突然断电导致的数据丢失?

  •  1
     
  •   latifrons · 136 天前 · 10980 次点击
    这是一个创建于 136 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我知道 MySQL ,RocksDB 等数据库其实都有 WAL ,但同样地都依赖操作系统定期将内存缓存中的数据通过 fsync()刷回磁盘。如果此时断电(或者操作系统崩溃),1 秒内的数据可能会丢失。

    MySQL:innodb_flush_log_at_trx_commit

    https://dba.stackexchange.com/questions/12611/is-it-safe-to-use-innodb-flush-log-at-trx-commit-2

    The default value of 1 is required for full ACID compliance. You can achieve better performance by setting the value different from 1, but then you can lose up to one second worth of transactions in a crash. With a value of 0, any mysqld process crash can erase the last second of transactions. With a value of 2, only an operating system crash or a power outage can erase the last second of transactions. InnoDB's crash recovery works regardless of the value.

    所以似乎为了数据完备性,innodb_flush_log_at_trx_commit=1 是不可避免的,从而会导致比较严重的性能劣势。

    例如 LevelDB ,开启 WriteOptions(Sync=true)后,tps 从 190000/s 骤降为 1200/s.

    Qwen3 的一个回答: https://chat.qwen.ai/s/0e7d9977-4400-41da-883f-2972893104cf?fev=0.0.85

    想请教一下大家,在对数据完备性要求极高的场景下,大家是怎么优化性能的?

    第 1 条附言  ·  136 天前
    感谢大家的回复,可能是我没有表述清楚。

    我的核心 concern 不是怎么防止掉电,而是在一个分布式系统中,如果各业务系统在 fsync()前就返回业务成功,无法保证系统间数据一致性;如果调用 fsync()后再返回业务成功,无法保证性能。

    操作系统有文件缓存,但 kernel 会崩。
    磁盘有写入缓存,但磁盘也会掉电。

    基于此,我是应该假设 fsync() 一定会发生,还是手动去 fsync()?每次强制 fsync() 性能太差,无法接受。

    感谢 @scegg 提供 DB2 思路,也希望听听业界的具体实践。
    第 2 条附言  ·  135 天前
    听了大家说了这么多,收获颇丰,感谢大家。

    其实这个问题在我这里产生的根源就是在分布式系统中。单体状态自己说了算,灾难恢复回来是什么就是什么。而分布式系统就需要考虑一致性了。

    TCC 分布式事务环境下,正如 @weirdte 所说,“返回失败不一定是真的失败,但返回成功是一定要成功的”。 如果被调用方返回成功,但结果却因未落盘而回滚,调用方根本不会知道有这么个回滚节点。回滚节点也不知道有什么应该做而没做的事。

    事后对账当然是一个办法,但很多时候对账并不能挽回损失。例如扣减余额这种事如果回滚,肯定要有人背锅了。

    似乎解决方法就是双写/强制落盘,不知道例如银行、券商这样的系统,对于涉及钱的跨系统的一致性,除了对账,在技术上是如何实践的呢?又如果性能要求极其苛刻,有什么更好的优化方案?

    又从业务角度而言,问题归结为:防止数据回滚,是不是应该成为每一个程序员在开发分布式系统时必须考虑的标准设计规范,还是,程序员不用管,交给 DBA ?
    133 条回复    2025-05-10 11:39:29 +08:00
    1  2  
    wxf666
        101
    wxf666  
       132 天前 via Android
    @scegg 就算磁盘保证实际写入一定完成,也不能解决楼主《提交事务后,每秒落盘前,数据库/系统崩溃,数据丢失》问题吧。。

    还是得在 commit 里,落盘数据,再结束事务。。

    但每次 commit 都落盘数据,不划算,最好攒个几百事务平摊成本。。( 4K 顺序写,慢于,1M 顺序写)

    数据库有提供此种机制吗?
    julyclyde
        102
    julyclyde  
       132 天前
    @wxf666 数据库的事务日志就是这样的
    kk2syc
        103
    kk2syc  
       132 天前
    @julyclyde 怎么每次你都能把不懂装懂演绎到极致?而且究极嘴硬。
    julyclyde
        104
    julyclyde  
       132 天前
    @kk2syc 不懂的是你吧
    starinmars
        105
    starinmars  
       132 天前
    在线式 ups 加柴油发动机自启
    scegg
        106
    scegg  
       131 天前
    wxf666
        107
    wxf666  
       131 天前
    @julyclyde #102 数据库的事务日志。。是啥样的? commit 后,每秒刷新落盘到磁盘上?

    那还是解决不了楼主说的《 commit 后,落盘前,数据库/系统崩溃,数据丢失》呀。。



    @scegg #106 《要求事务完全持久化》肯定是数据库基础功能。连几百 KB 的 SQLite ,甚至在 20 年前都做到了。。( PRAGMA synchronous = FULL )

    关键是数据库有没有采取措施,既保证《完全持久化》,又降低每个事务的持久化时间。。

    每次 commit 都落盘,会很慢。积攒一堆事务再落盘,可以平摊成本。

    但 sqlserver 文档里没看到类似方法及配置选项?(如:最长等待 0.1 秒就落盘现存事务;最多积攒 1000 个事务 / 1MB 数据页就落盘;……)
    kk2syc
        108
    kk2syc  
       131 天前
    公开信息里面最好的参考就是微众银行,用的自研 TDSQL 。

    在文档的“强同步”部分说明了( https://cloud.tencent.com/document/product/557/10570 ),只有当备机数据完全同步(日志)后,才由主机给予应用事务应答,保障数据正确安全。

    julyclyde
        109
    julyclyde  
       131 天前
    @wxf666 我没说解决啊
    我说“数据库的事物日志是这样的”回复的是“攒个几百事务平摊成本”

    想解决的话,你自己也知道方法啊,就是不攒,每个都写入
    放弃性能什么都好说
    scegg
        110
    scegg  
       131 天前
    @wxf666 数据库没有办法满足既要又要的功能,只能允许使用者自己做出取舍。既要又要这种需求只能存在在无法实现的文件里。
    wxf666
        111
    wxf666  
       131 天前
    @julyclyde #109 你说的是《 commit 后,攒几百再落盘》吧

    我意思是,数据库应该提供《 commit 时,等待积攒一批事务,再落盘,最后才结束事务》特性,既《确保数据完全持久化》,又《平摊落盘成本,尽可能降低每事务延迟》的。。



    @scegg #110 提供上一行的功能,会有啥问题吗?

    sql server 不也允许《不同事务有不同持久性:完全持久( commit 时,积攒一个落盘一次)、延迟持久( commit 后,积攒一堆落盘一次)》吗?

    再多加一个《延迟完全持久( commit 时,积攒一堆落盘一次)》不算过分吧。。

    特别地,《延迟完全持久》配置为《最多积攒一个》或《最多等待 0 秒》,就退化成《完全持久》了。。

    感觉没啥问题呀。。
    OC0311
        112
    OC0311  
       130 天前
    真出现了 就使用上一次快照信息,直接回滚数据再重放消息处理。
    julyclyde
        113
    julyclyde  
       130 天前
    @wxf666 攒几百是你说的。我是回复给你
    你如果选择了攒几百,那必然会丢数据;每个都写盘,那必然性能差
    这都是没什么可讨论的事了
    wxf666
        114
    wxf666  
       130 天前
    @julyclyde #113 请教一下,为啥会丢数据呢?(攒几百事务落盘,再结束这几百个 commit / 事务)

    还是说《用户只要发了交易请求,就算处理过程中数据库 / 系统崩溃,服务器也必须处理成功!不接受 rollback !即使是可串行化级别事务也不行!》?

    用户为啥不能接受《交易失败,您的资金一切正常,请稍后重试》呢。。

    scegg
        115
    scegg  
       130 天前
    @wxf666 积攒提交在数据库服务器上意义不大。
    首先,数据库是随机操作,积攒落盘也只是要批量执行这一些写入操作,并不一定会减少写入次数。
    然后,数据库后端通常都是 HBA 连接的 LUN ,它自己就有自己的写入队列、写入日志、写入缓存、分层存储等多个策略在排队,并不需要数据库替他们操心。
    stone981023655
        116
    stone981023655  
       129 天前
    金融银行都有 UPS+发电机的, 停电了发电机就在工作了, 完全不虚。
    Litccc
        117
    Litccc  
       129 天前
    楼主说的是软件层面的吧,金融行业的数据中心硬件层面有双路市电+UPS+柴发,断电造成数据丢失基本不可能
    julyclyde
        118
    julyclyde  
       129 天前
    @wxf666 想要攒够再存盘,结果还没存上就断电了,于是就丢了呗。攒的越多,风险越大啊
    不只 redo log 可以合并,连 page 的写盘动作也是可以合并的

    发展了这么多年,并没有从理论上突破这个限制,只是在工程实践上有所改善而已
    Kazetachinu
        119
    Kazetachinu  
       128 天前
    @stone981023655 #116 可能他说的不是高压侧,而是末端的设备突然自己断电,跟高压无关。现在的高压基本上都稳定的了,这种用电在高压设计中,至少都是双回路和高可靠专线接入,还有发电机和 ups ,除非上级变电站全部跳闸失压,要么地球爆炸,不然没有高压断电风险的。
    wxf666
        120
    wxf666  
       128 天前
    @scegg #115

    1. 不追求一定要减少随机写入次数呀?关键是想利用顺序写入,快速完全持久化一批事务数据,减少交易事务延迟?(毕竟是落盘才结束事务)

    2. 你是说,fsync 能又快又安全落盘到 LUN 写入队列/日志/缓存/分层/…,所以即使 commit 一次就落盘一次,延迟也能很低,并发量也能很大,系统崩溃断电 数据也能很安全,进而解决楼主的问题了?



    @julyclyde #118

    1. 丢就丢了呗,反正事务没提交成功(因为是攒一批事务,再一起完全落盘提交,事务才结束),又不会对后续其他交易事务有啥影响(比如一钱多用),提示用户《交易失败,服务器忙,资金不变,稍后重试》就行了?

    2. 就算不攒事务,commit 一次落盘一次,高频系统每秒钟照样还有几千上万笔交易事务在处理呀?系统崩溃 / 断电,这些处理中事务照样失败,这批用户交易请求数据照样丢失,照样需要提示用户《交易失败,稍后重试》?
    julyclyde
        121
    julyclyde  
       128 天前
    @wxf666 金融系统有个特点就是客户下单和完成交易是两个阶段
    换句话说就是可以光明正大的执行失败
    scegg
        122
    scegg  
       128 天前
    @wxf666 对于需要落盘的事务,直接使用数据库功能,强制他落盘再返回。对于不需要落盘的事务,使用数据库的默认策略提交事务。
    至于数据库的性能,那是数据库系统构建者(不是数据使用者)需要考虑的事。数据库使用者需要的是不要给数据库系统带来不必要负担,而不是替数据库系统考虑问题。而数据库系统构建者(比如服务器提供方、运维)则需要根据实际使用需求来设计存储。
    wxf666
        123
    wxf666  
       127 天前
    @julyclyde #121 银行转账算金融系统吗?如果提现了却没落盘。。



    @scegg #122 楼主不是说《强制落盘再返回》速度骤降 99.37% 吗?

    我一直认为《强制攒批再落盘最后返回》应该能极大缓解问题,只是看起来没有数据库去实现。。
    scegg
        124
    scegg  
       127 天前
    @wxf666 嗯。速度降低是因为数据库的提供者没有解决问题。批量写入能带来一定的性能提升,但不大(因为实际操作还是零散的随机 IO ,性能只在通道开闭的开销上可以提升)。正常的解决问题方法是让存储系统(比如 LUN )增加各类合适的缓存和队列(他们也是落盘的“盘”)。
    julyclyde
        125
    julyclyde  
       127 天前
    @wxf666 转账和提现两码事啊
    提现也是先写数据库后给钞票的,只可能少给钞票不可能多给
    sampeng
        126
    sampeng  
       127 天前
    所有后面这些都是逻辑问题。你不可能去重新 mysql 等数据库。首先,假定基础设施是安全。你的整体事务是否安全先把这个事保证了。
    其次基础设施如何安全是另一个问题,我以前公司是自己的两路电源管理,两路市电+公司内的柴油发电。机房断电?生意都别做了,还想数据丢没丢??。
    latifrons
        127
    latifrons  
    OP
       127 天前
    2025/5/7
    洛杉矶 West 7 Center 停电

    West 7 Center 楼中的一个托管机房停电,Coresite 托管在当中的机器受到影响。
    据说 AB 两路电全断,已知多个商家受影响:

    DMIT 洛杉矶 (官方已发通知)
    搬瓦工洛杉矶 v66XX 节点/DC1 (官方已发通知)
    ZgoCloud 洛杉矶 (官方已发通知)



    当然我们的机房不是这种小云商,但 AB 两路电断掉的确不是什么不可能事件。
    断电期间有 BCP 计划,断电恢复不了有 DRP 计划,前提是数据整体状态一致,分布式系统中每个成员的世界状态是相同的,那么来电就能起。否则一边扣钱一边没扣钱(但返回成功),一边下单了一边订单找不到,世界状态就乱了。

    分布式系统中,真的需要对每个可能掉了的持久化都进行 peer to peer 对账检查吗?那就太复杂了。
    wxf666
        128
    wxf666  
       126 天前
    @scegg #124 真是《零散随机 IO 导致速度骤降》吗?

    每秒落盘 1 次,随机 IO 次数差不多,为啥提速 99.37% 呢。。



    @julyclyde #125 问题是《写数据库后,没及时落盘,就给钞票》了。。

    如果高频系统允许延迟 1 秒以上响应(等数据库完全落盘事务数据),那就没啥问题了。。
    julyclyde
        129
    julyclyde  
       126 天前
    @wxf666 ATM 的延迟不止 1 秒吧
    scegg
        130
    scegg  
       125 天前
    @wxf666 99.37%是哪位提供的,就请 at 哪位回答呗。
    racgas
        131
    racgas  
       125 天前
    @wxf666 #54 哥们这每个事务延迟是怎么算的
    racgas
        132
    racgas  
       125 天前
    @wxf666 #54 请问这个平均每事务延迟是怎么算的?不应该都是 100 才对?
    kios
        133
    kios  
       125 天前
    UPS 吧
    1  2  
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2686 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 13:45 · PVG 21:45 · LAX 06:45 · JFK 09:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.