程序如何突然终止造成数据丢失

每一次操作之前都会记录日志,防止中断造成数据丢失。

操作如下:
A 记录日志
B redis 计数+1
C 清除日志

1、如果执行完A中断,启动之后检查日志,可以再次执行操作B,数据不丢失。
2、如果执行完b就中断,那么日志恢复之后就会多执行一次b,数据虽然不丢失,但是造成重复数据。

题目原本是断电,后来可能都围绕断电回答了,其实断电概率还是挺小的,主要是应用执行的时候突然被用户终止运行,或者程序崩溃等等造成的数据丢失。


看评论还有人抬扛的。
实际上,很多数据库都有类似的机制防止突然中止造成数据丢失。。

1、比如 leveldb :log文件在LevelDb中的主要作用是系统故障恢复时,能够保证不会丢失数据。因为在将记录写入内存的Memtable之前,会先写入Log文件,这样即使系统发生故障,Memtable中的数据没有来得及Dump到磁盘的SSTable文件,LevelDB也可以根据log文件恢复内存的Memtable数据结构内容,不会造成系统丢失数据,在这点上LevelDb和Bigtable是一致的。

相关文章:https://www.cnblogs.com/haipp...

2、还有elasticsearch:

如果没有用 fsync 把数据从文件系统缓存刷(flush)到硬盘,我们不能保证数据在断电甚至是程序正常退出之后依然存在。为了保证 Elasticsearch 的可靠性,需要确保数据变化被持久化到磁盘。

相关文章:https://www.elastic.co/guide/...

3、还有rabbitmq的防止丢消息和重复消费:

相关文章:https://www.jianshu.com/p/5ad...

阅读 4k
5 个回答

一般情况确实不需要考虑断点和宕机造成数据丢失的问题。但如果对一致性要求非常严格的时候还是应该考虑,比如银行转账、淘宝微信等的收付款、软件升级(只升级一半是有可能导致程序无法启动的)等。

遇到这种情况记日志是肯定需要的,而如何防止你说的第二个重复执行的问题,我觉得重点不是防止重复执行,而是重复执行不会带来副作用。比如替换文件就是一个没有副作用的操作,你用A替换原来的B,无论你拷贝粘贴多少次,结果都是一样的,最终的文件都是A。而直接给账户加钱和扣钱就是有副作用的,你的例子里给计数加1也是有副作用的。这种时候必须对操作进行修改,通常是拆分成更多的步骤,每个步骤必须没有副作用,然后给每个步骤加日志。

比如你的例子,我可以这样拆分:

  1. 加锁,开始执行操作并记录日志
  2. 读入redis当前计数并记录日志
  3. 计数+1
  4. 写回计数并记录日志
  5. 操作完成,释放锁

由于锁的存在,整个操作是原子性的。假如中间有任何一步出现问题,下次恢复执行的时候就可以检查出来。如果是第二步出问题,那么只需要简单地重新来一遍即可。如果是第三步出问题,第四步还没来得及执行,那么将只会在第二步有日志,重新执行之后,读入当前的redis计数,如果与日志记录的相同,则重新从第三步开始执行,如果比日志记录的大1,则说明第三步已经执行过了,从第四步开始执行即可。

思考了一夜,我发现这个问题无解。
想想为什么要考虑程序频繁挂掉的场景呢?偶尔的断电,小概率数据丢失应该都是可以忍受的。

最重要的是,防止这种事情发生。

这不是单单软件该考虑的范畴,你要综合硬件去考虑,如果硬件没有提供支持,软件怎么处理都会有疏漏的,因为这是个意外情况。

通常机房都会提供断电后的临时供电来保证你有处理数据的时间,单个主机也可以通过加TPS来保证。

皮一下 中间加一个可存电的稳压器

网上有很多方案有解决断电后恢复数据的办法,但是就目前的情况而言,大部分的数据服务器要么托管在各个云服务商那边,或者自己公司有钱,买的服务器,托管在当地专门管理服务器的地方,或者由自己公司运维人员去维护服务器(后面这两种情况,一般运维都会考虑这些情况进去),所以这类问题,作为软件开发的我们,更需要关注的是,电力恢复以后,如何处理在断电过程中,存在的数据不一致等其他问题。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏