我知道 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
zgsi 23 小时 51 分钟前
应急电源啊
|
![]() |
2
nekoneko 23 小时 50 分钟前
UPS 保平安
|
![]() |
3
x86 23 小时 50 分钟前
金融系统连 UPS 都没一个吗?
|
4
ghostwind 23 小时 48 分钟前
看你是上游还是下游,如果是下游,可以起一个重发的信号
|
5
ghostwind 23 小时 45 分钟前
如果是交易所,比如是上交所 ,你可以去搜索上交所 ups 电源 结果就是:UPS+柴发
证券技术大厦共 10 层,其中地上 8 层,可提供超过 6000 平米的托管机房,采用双路独立的市政电源作为常用电源,配备了 2N 的 UPS 及 N+1 冗余柴发作为备用电源。 |
![]() |
6
opengps 23 小时 40 分钟前
银行都是异地多活,多可用区(独立供网供电,独立 ups 电源)。内存都已经可以当硬盘用
|
![]() |
7
jvee 23 小时 37 分钟前
双路电源+ups+同城、异地灾备
|
8
scegg 23 小时 37 分钟前
因为突然断电可能不只是导致数据丢失,不少问题很难快速恢复。
所以不如防止突然断电。 |
9
scegg 23 小时 35 分钟前
为了实现一个目标,不可能不需要付出其他代价。不然这个目标早就成为标准了。
当需要付出代价的时候,就要看是否值得。 在这个例子上,保证不突然断电就是代价最低的办法。 |
11
latifrons OP UPS 肯定能解决一部分问题,剩下的例如操作系统内核崩溃这种 UPS 无法解决的问题,似乎还有风险。
核心 concern 是 fsync()没执行 |
12
scegg 23 小时 31 分钟前 ![]() @julyclyde 问题不存在的原因是这个问题不需要被解决。
任何保障“安全性”的设计都会带来“性能”损失。如果为了一个能用更小的代价(解决供电稳定性)来解决“安全性”问题,就不需要因此牺牲“性能”。 如何解决吃垃圾会中毒的问题?那就别吃垃圾。 |
![]() |
13
ivvei 23 小时 31 分钟前 via Android ![]() 高频?多高? 都还在用数据库,那估计也高不到哪里去,那么完全可以先写入再确认嘛。没写入的就当没发过。这是上游的做法。如果是下游的话,找上游要一份最新的快照就行,反正以人家的为准
|
![]() |
16
comlewin 23 小时 28 分钟前
金融核心系统不会存在断电的情况,双路电,UPS 电池,柴发,同城这些都是硬性要求
|
![]() |
17
seers 23 小时 27 分钟前 via Android ![]() db2 可以使用 dio 直接写盘跳过系统的缓存层
|
19
latifrons OP @ivvei 数据总要有地方落盘,落盘就有你落了我没落的情况发生。
假设一个 TCC 事务,被调用方反馈说我做完了,调用方因此完成了这次 TCC ,但此时被调用方突然崩了,数据没落盘,TCC 事务看似做完了实则没做完。 但你要被调用方落盘吧,性能又差了…… |
20
scegg 23 小时 24 分钟前 ![]() @seers 对的。但无法跳过硬盘的缓存。因为不需要。db2 的 dio 就是因为操作系统的内存中的缓存可能不受保护。但原因可能不是因为电力,而是包括电力在内的更多原因(例如系统崩溃、大型机的背板故障之类)。
服务器用的 RAID 系统,缓存自己就带电池,或者是 FBWC 这种掉电不会丢数据的设计。 |
![]() |
21
joyhub2140 23 小时 23 分钟前
一切软件或者 OS 层面的措施都不如物理防御。
直接上 UPS+柴油发电机。简单暴力可靠。 |
24
scegg 23 小时 17 分钟前
@latifrons 如果是担心数据一致性的问题,考虑分布式事务或其等价的逻辑实现方案。如果不能接受其性能开销,考虑硬件冗余机制(包括电力、硬件 FT 或虚拟化 FT )。
|
![]() |
25
crc8 23 小时 12 分钟前
世界的核心不是石油,就是电磁波。
|
![]() |
26
woodfizky 23 小时 6 分钟前
有些技术的牛角尖可以不用钻那么深,有些事情可以不用技术的思路而是用工程的思路去解决。
怕断电,那就保证不要断电就行了。怕机房爆炸,那增设若干套冗余异地系统和线路就好了。 真的遇上事,服务断了就断了吧,比如机房都被炸了,就没必要想过多技术问题了。 |
![]() |
27
picone 22 小时 44 分钟前
分布式系统的 CAP 定理,只能折中。
|
![]() |
28
viking602 22 小时 43 分钟前
同城容灾 异地多活 多可用区 多云 自建机房那就是 UPS 柴发拉满 多演练 保证不断电到电才是硬道理
|
29
Richared 22 小时 38 分钟前
第一家工作电商公司,在一个园区里,一共 7 层,2-3-4 楼是机房,还有两个异地机房。然后 ups+发电机。有一次园区停电,十分钟发电机就顶上了。三台车,在楼下发了两天。别的单位都在摸鱼,只有我们在上班,领导开玩笑,我就说要把机房搬走,如果要从系统层面想招,那么离世界末日不远了。
|
![]() |
30
kkk1234567 22 小时 36 分钟前
机器上配置电容卡,供电电路加 UPS ,机房再弄个柴发
|
31
dem0ns 22 小时 16 分钟前
别人问的是断电数据丢失,都说用 UPS...... 这玩意儿都是标配好吧,几地几中心也是等保强制要求。
|
![]() |
32
dlmy 22 小时 15 分钟前 ![]() 我再补充一下,可以使用 RAID 多磁盘冗余阵列技术,RAID 卡自带了 SDRAM 缓存,还可以配置独立的锂电池或电容,就算服务器掉电了,也可以把服务器缓存中的数据写入到磁盘。
|
![]() |
34
shiny 22 小时 13 分钟前
哪怕没有发电机,UPS 断电时候可以设置向系统发送关机信号。可以避免一些突然断电的故障。
|
35
bli22ard 22 小时 10 分钟前
代码层面,没办法保证断电不丢数据,只能保证断电数据一致性
|
![]() |
36
zong400 22 小时 9 分钟前
用 Oracle 就不用系统管理磁盘,lvm 管理磁盘,redolog 放在高速 ssd 上基本能最大限度规避断电问题
|
37
fuzzsh 22 小时 2 分钟前
了解下 Oracle RAC ,集群多写多读,这也是 Oracle 能主宰数十年的原因,只要应用层面写好 try catch ,数据 99.99%可写入,除非数据阵列挂了
|
38
Jinnrry 21 小时 52 分钟前 via iPhone ![]() 你是研发还是 dba ?如果你是研发,直接找你们 dba ,他们有现成方案。如果你是 dba ,你连这都不知道,趁早收拾东西走人
|
![]() |
39
bearbest 21 小时 37 分钟前
这已经不是技术问题了,这是系统问题。
断电造成的后果,不是一个数据库技术上处理就能解决的问题。 感觉有点程序员思维了。 |
40
yc8332 21 小时 19 分钟前
这是工程问题。。正常都是有 ups 的不断电系统的。。
|
41
littlepigpeppa 20 小时 57 分钟前
这么思考的话无解,不如退而求其次的去保证不断电吧
|
42
lscho 20 小时 49 分钟前
很久之前就考虑过类似的问题,得出的结论和楼上诸位大佬的观点差不多。
非要从技术方面解决断电问题,性能下降极其严重,成本无法接受。 不如从工程方面解决断电问题,保证正常情况下不断电。然后不可抗力情况(地震等)下可以通过人力恢复即可。 |
![]() |
43
030 20 小时 44 分钟前
金融的研发都是这种水平吗
|
![]() |
44
gaxila 20 小时 41 分钟前 ![]() 我理解楼主的担忧, 这个是无法做到完美的, 就算落盘了, 磁盘也可能有坏道等情况发生. 这里其实是一种取舍, 为了小于 1%的场景去牺牲 100%场景的性能不值得, 所以不如接受这种小概率事件, 再引入对账来检测出小概率事件
|
![]() |
45
min 20 小时 35 分钟前
电的问题#5 已经说了
软件的问题应该去看看常见的分布式存储和分布式数据库的解决方案 |
![]() |
46
itskingname 20 小时 28 分钟前
CAP 理论指出,一个分布式系统不可能同时满足一致性( Consistency )、可用性( Availability )和分区容错性( Partition Tolerance )这三个特性,最多只能同时满足其中的两个。
|
![]() |
47
pkoukk 20 小时 14 分钟前
性能劣势怎么了?都玩高频金融了,上高配物理机啊,我们这虽然不是搞金融的,但是强一致性要求的就是拿物理机硬顶的。世界上没有完美的东西,你只能 trade off ,在金融领域,花钱恐怕是最容易解决的问题吧
|
![]() |
48
elltor 20 小时 9 分钟前
UPS ,柴油发电机,多 AZ ,多副本备份....
|
49
XingWu 16 小时 44 分钟前
碰巧我就在金融行业,大家说的是对的,确实就是
技术层面:同城容灾 异地多活 非技术层面:24 小时不间断有人值守+UPS+柴油发电 UPS 可以给机房供电 2 小时,大楼里就有柴油和发电机,再保障 5-6 个小时的核心生产用电不是问题,所以停电导致的问题不大 至于 fsync()的问题,不是后端,就不乱说以免哄堂大笑了 |
![]() |
50
dynastysea 15 小时 41 分钟前
谁告诉你 mysql 会都数据的?第一句话就是错的
|
51
xxx88xxx 15 小时 2 分钟前 via Android
金融系统没接触过,但地铁里面管钱的系统( AFC)我知道,在设计时,安装了超级电容,在检查到断电的一瞬间,保证最后一笔交易上传。
|
![]() |
52
mmdsun 15 小时 1 分钟前 ![]() 如果你的提问是这个标题,那考虑底层的是思路完全不对的... 系统设计中的本质问题,不同层级对“数据完整性”的保障边界不同,如果忽视这个事实,就会走偏方向,甚至产生错误的“安全感”。
即使操作系统可以保证,他也是保证自己的文件系统的完整性,而不是保证你 mysql 甚至应用层丢不丢数据的问题。即使是 tcp 协议可以保证绝对丢消息,你的应用层还好做消息确认这种机制的。 数据一致性的保障是“自上而下”理解,而非只盯着底层。操作系统、文件系统、数据库等底层组件的“保证”,无法等价为业务层金融场景“不会丢数据”。 所以根本上,你需要在应用层当事务出现异常时做处理。 |
53
neoblackcap 14 小时 58 分钟前 ![]() @latifrons 退一步,fsync()成功也不代表落盘成功。fsync 成功了,顶天是 OS 把自己系统缓存刷写到了磁盘设备那边去。数据很有可能还存在磁盘控制器的缓存中而没有被完全落盘。但是磁盘控制器已经响应 OS 了 fsync()成功了
|
54
wxf666 14 小时 37 分钟前
@scegg 数据库能否根据 SSD 『不同块大小顺序写入 - 延迟』关系,等待一段时间,积累更多写入事务,再一次性刷到 SSD 上,实现数据严格一致性的同时,性能影响降到最小呢?
比如,如果发现 SSD 顺序写入 1MB 时,延迟 100 μs ,那每次攒够 256 个事务(假设每事务写入 4KB 页),再一次性落盘,这样总体延迟不高(平均每事务延迟 50 μs ),数据一致性也能得到保证? |
55
noogler67 14 小时 36 分钟前
只要购买尊重 fsync 的硬件就行。至于性能,可以用批量操作。用户发送 1000 条 sql ,只要互相不干扰,db 都批量接收以后发送 fsync 给硬件。硬件批量处理完以后返回 ok 。这样就是延迟大一点,可以是几十几百 ms 。
关键点只要硬件保证收到 fsync ,数据落盘,返回 ok 的时序。就行。 |
56
messaround 14 小时 32 分钟前 via Android
总结下来就是 这个逻辑没有考虑
|
![]() |
57
abcbuzhiming 14 小时 8 分钟前
搞高频金融系统的人,可以为了几毫秒的差距把一座山打穿拉光纤,分布式系统这种延时很大的东西,直接在高频金融系统里用,我个人是怀疑的,用于数据冷备差不多。
我觉得楼主考虑的方向不对,高频金融系统人机就不会考虑意外断电问题,除非发生能让交易中心断电的大事件 |
58
aieruishi 13 小时 39 分钟前
我尝试回答下该问题,下面仅是个人意见。
1. 调整 fsync 频率与事务持久化的权衡,如缩短 fsync 的间隔(如从默认的 1 秒改为 100ms ),可以减少数据丢失的窗口期,但会牺牲一定的吞吐量。 2. 将 WAL 文件放在持久内存( PMEM 设备)上,每次写入都 fsync ,延迟是非常低的,但 PM 厂商不继续生产了。 3. XFS 文件系统可以开启 data=journal 模式能保护数据,但性能代价极高,通常仅用于特殊场景。 4. 减少脏页在内存中的停留时间或者降低脏页触发刷盘的阈值。 5. [楼上提到] 机房/服务器在硬件上双路电源 + UPS ;服务上支持同城多活等 如果还有其他,也欢迎各位进行补充。 另外回到提到的就是,性能和数据不丢失权衡,没有完美的解决方案。在数据中心中,数据存储就算数据落盘我们也没办法保证数据永远不丢,经常会遇到磁盘掉盘,颗粒(或扇区)损坏导致数据静默错误,还是需要在硬件上层处理尽量保证数据不丢。举个例子,AWS S3 设计为默认提供 99.999999999%( 11 个 9 )的数据持久性,也不会保证 100%。 |
![]() |
59
Gilfoyle26 13 小时 30 分钟前
数据不是一份,是 3 份,甚至是 5 份。
|
60
wxf666 13 小时 3 分钟前
@aieruishi
关于第一点,如果数据库能做到 54 楼说的那样,是否能消除『数据丢失的窗口期』呢?毕竟是批量落盘后再返回事务结果的?(这应该是数据库要实现的?) 第二点,还是 54 楼说的,应该没必要每次事务都单独刷盘吧。。等一小会儿,积攒多些事务数据后,再批量落盘,总体更划算?代价就是每个事务延迟大一点点。。但高频系统,要短时间内攒够足够多的事务,轻而易举吧。。 这和你说的第四点是类似的,但应该是脏页在内存中停留时间增大一些?攒够一堆脏页再批量写盘? 当然,上面这些都是软件层面的,硬件不可靠,软件再完善也没法力挽狂澜。。 |
61
hefish 5 小时 45 分钟前
1 、两路供电;
2 、搞个大点的 UPS 3 、定期有计划地维护 UPS 电池 |
63
aieruishi 4 小时 28 分钟前
@wxf666 窗口期可以缩短,但是无法避免。 攒批是常用的技术手段之一,代价多少取决于如何实现。软件上目前很难保证这一点。
redpanda 就吐槽 Kafka 不开 fsync https://www.redpanda.com/blog/why-fsync-is-needed-for-data-safety-in-kafka-or-non-byzantine-protocols 大致意思是:在 Kafka 或其他非拜占庭( Non-Byzantine )分布式协议中,fsync 是保证数据安全性的关键机制,即使系统设计上采用了多副本、持久化存储或高可用策略,仍然需要依赖 fsync 来确保数据真正落盘,避免因操作系统缓存、硬件故障或断电导致数据丢失。 |
64
acorngyl 4 小时 8 分钟前
不考虑机房基建的情况。
感觉 OP 的问题两方面看,一个是单个数据库系统,一个是业务层面。 单数据库,只要业务 commit 了,commit 会写入日志,日志会秒级回写,只要 commit 的日志回写了,数据的事物就算提交了。即便这时电脑崩了,做实例恢复,日志里的事物都能做回来。如果日志都没回写,那肯定业务就丢了。这个没办法避免,除非事物提交强制回写,而且等待。这样系统的响应时间就得是秒级了。 业务层面。首先,越重要的系统,业务流程要越短、越简单。如果业务复杂,最后一定要有个落单系统,业务完成以落单为准。每个稽核账期结束前,所有系统要和落单系统对账,落单系统失败或者没有的业务,其他系统要做回滚操作。这就是充值缴费或者订票,偶尔会有退费的情况(现在很少了)。银行的交易系统和其他业务都是隔离的,交易系统甚至只做 insert ,账单是最后算出来的。 |
![]() |
65
xuanbg 3 小时 52 分钟前
一个 UPS 搞定,想太多没用
|
66
dode 3 小时 48 分钟前
数据顺序写入日志很快,写入完成后作为成功标志返回响应,再写入实际系统内
clickhouse 好像是直接全部都写入一些小文件,再合并,最终稳定存储 |
67
wxf666 3 小时 47 分钟前 via Android
@aieruishi 你们说的『数据丢失』,包括『事务结束后,数据无法持久』吗?
感觉从题主描述来看,是包括的? 但个人认为,数据一致性要求极高的地方,就该攒批落盘数据后,这堆事务再批量返回结果。。 调用方线程被阻塞太多的话,应改用协程等方式实现。。 |
68
dode 3 小时 43 分钟前
操作系统内核接口很多都是原子调用,例如 fsync ,调用后肯定是成功了,调用失败就不会返回
|
69
wxf666 3 小时 43 分钟前 via Android
@acorngyl 为啥不能做到,落盘日志,commit 才结束?
难道 SSD 落盘 1MB 数据,延迟要几秒钟吗? 否则为啥不能积攒几十上百个事务的脏页数据/日志,批量顺序落盘,再 commit 结束,批量返回事务结果呢? |
![]() |
70
wtks1 3 小时 38 分钟前
与其搞系统层的东西,不如改造供电,把 UPS 和应急发电机都准备起来
|
71
tinydancer 3 小时 10 分钟前
@me1onsoda 是的,毫秒级的切换时间,能够保证服务器不掉电
|
![]() |
72
min 3 小时 1 分钟前
不需要无缝,有电容、电池、ups 可以保证备用线路有足够时间跟上来
|
![]() |
73
kiracyan 2 小时 55 分钟前
正规机房都有应急电源
|
74
robinchina 2 小时 49 分钟前
@Richared 对不起,看到园区脑子里的画面就变成了四面环山,丛林茂密,保安都拿着 AK47·······
|
![]() |
75
zfzrx 2 小时 11 分钟前 via Android
金融数据 基本都是双路市电 双 ups 双柴油机
|
76
weirdte 2 小时 3 分钟前 via iPhone
选择一家商用的 oltp 数据库都能够保证数据不丢失(这里说的不丢失,不包含某些超大规模的自然灾害,比如地球爆炸)。 可以了解下数据库的 RPO 指标,商用数据库该指标一般都要求是 0 ,即使单个机房地震摧毁了一样能保证你数据不丢失。 性能在可靠性面前是一定要做出牺牲的。 你如果要自己维护一套高性能的数据库系统,那至少也得有上百人的团队,金融系统的数据库飞掉是不可接受的,凭几个开发根本兜不住底,建议还是采购成熟的商用 db 。
|
77
julyclyde 1 小时 43 分钟前
异地不是用来应付断电的
而是应付地震损毁之类的事故的 |
78
weirdte 1 小时 43 分钟前 via iPhone
什么时候返回成功和 fsync 前后没有必然关系, 返回成功一定是在数据落盘之后再返回成功(不调用 fsync 数据也会落盘)。一般数据库做法是记录当前数据落盘点(通常叫 log sequence number LSN ,或者 WAL id 这种),请求跟踪这个 LSN ,flushed LSN 已经大于我当前请求产生的写操作的 LSN 时就说明数据已经持久化了,可以告诉客户端完成了。 分布式中,这个日志是要同步给其他节点的, 那 global Flushed LSN 应该取节点多数派都已大于的某个 flush lsn
|
79
weirdte 1 小时 41 分钟前 via iPhone
@weirdte “ 返回成功一定是在数据落盘之后再返回成功” => 返回成功一定是数据达成多数派一致的时候再返回成功。
返回失败不一定是真的失败(可能网络原因导致没有收到成功的结果),但返回成功是一定要成功的。 |
80
scegg 1 小时 25 分钟前
@wxf666 在企业应用里,一般都是有存储卡或者 HBA ,并没有这个需求。在家用环境搞这个可能没有人要买单。
企业方案里,首先 SSD 本身就可以做分层设计,部分 SSD 就是拿来做写入缓存的,并不需要等待。在写入写入缓存 SSD 之前的那些数据,放在内存中的部分,内存本身有防掉电保护。 在家用环境(比如 NAS )倒是有类似的功能,使用 SSD 做写入缓存,给 HDD 的 RAID 攒事务。 另外,您自己也提到了,SSD 的顺序写入才会有累积效果,但更新一般不会变成顺序写入,而是一大堆随机事务。所以攒事务之后,也只是一个 cache 的效果。 |
![]() |
81
liqingyou2093 1 小时 20 分钟前
异地冗余呗,这边服务器被炸了换另一个
缺点就是成本翻倍了 |
82
acorngyl 13 分钟前
@wxf666 #68 就说数据库设计原理,不具体说什么数据库,因为每种数据库的具体实现方式不一样。
数据块的修改和回写和日志是平行的两条线。所有的 DML 操作都会记日志,为了避免频繁 IO ,日志先在日志缓存区里,等日志缓存区片满了,会统一写一次硬盘。日志里有所有的操作、操作流水号、还有 commit 。 数据块也会在内存里做同样的操作,并且有和日志一样的流水块。内存里也有内存缓存区,缓存区满了,会写回磁盘。数据块写回磁盘的时候是不管脏不脏的。判断事物结束唯一标识是 commit 。 这样看日志和数据块操作重复了。日志的作用(一般)就是用于做实例恢复,万一突然断电,下次启动做实例恢复,先加载数据文件,从数据文件最后一个流水号开始,去日志文件找相应流水号,把该流水号之后的操作都 redo 一遍(所以日志一般叫 redo 日志)。这样做原因,日志是顺序写,不考虑业务逻辑和数据分布,所以 io 可以非常快,基本可以同步磁盘顺序写的速度。之后,数据块的回写就可以变得非常灵活,因为数据块不仅仅是存储数据,还有查询和计算作用。 即便日志写频繁,SSD 速度快,一般也不能每次 commit 都回写,这样就是散列 IO 了,不管 SSD 和磁盘,4K 速度和连续写都差几十倍了。还有,一个事物可能不足一个块,要不就补空块回写,一堆碎片块,占 IO 和损硬盘;或者每次都写一个空块,再把它读回来,接着写,IO 更慢了。 |