热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

golang分布式事务_也浅谈下分布式存储要点

本篇文章谢绝转载,欢迎转发几年之前,曾不自量力的想要写一个兼容RDBMS和NoSQL的数据库,结果仅实现了一个Raft协议,
cc9a3b1f9b17fa92ef3e7d524520a208.png
本篇文章谢绝转载,欢迎转发
e1a6e22eb7256766c5f009d7d1814ff2.png

几年之前,曾不自量力的想要写一个兼容RDBMS和NoSQL的数据库,结果仅实现了一个Raft协议,写了一棵BTree,就放弃了。使用Golang写这个算是比较简单的了,但过程难以言诉,有点蚂蚁撼大树了。

而个人,由于工作的关系,也已经有四五年没有和SQL打交道了。最近重拾,感慨良多。

MySQL这种RDBMS,天生是存在分布式缺陷的,在海量数据的今天,很容易就达到瓶颈。过去这么多年,一点长进都没有。所以经常的操作就是换存储引擎、分库分表、引入中间件,阉割功能。

分布式存储特征

能让你不忍割舍的,一个就是MySQL协议,你用惯了;一个就是事务,你怕丢数据。

幸运的是,大多数互联网业务不需要强事务,甚至连MySQL协议都不需要。接下来我们看一下要将一个传统的MySQL改造成分布式的存储,是有多么的困难。

CAP理论应该是人尽皆知的事情了,在此不多提。

单机上的任何数据都是不可信的,因为硬盘会坏,会断电,会被挖光缆。所以一般通过冗余多个副本来保证数据的安全。副本的另外一个作用,就是提供额外的计算能力,比如某些请求,会落到副本上。副本越多,可用性越高

d0247e08e40884c025d164df74bd2acc.png

而加入副本以后,就涉及到数据的同步问题。即使是最快的局域网,也会存在延迟,更不用说机器性能差异引起的同步延迟。这就存在一个问题,读副本的请求读到的数据,可能不是最新的,这就是数据的一致性发生了改变。当然有些手段能保证数据的一致性,但副本越多,延迟越大

副本的加入还会引入主从的问题。主节点死掉以后,要有副本节点顶上去,这个过程的协调需要时间,其间部分不可用。

3f05d2c4feab99d3bb982707ea86f955.png

而当一类数据足够大(比如说某张表),在其上的操作已经非常耗时的情况下,就需要对此类数据进行切割,将其分布到多台机器上。这个切割过程就是Sharding,通过一定规则的分片来减少单次查询数据的规模,增加集群容量。

当某些查询涉及到多个分片,这个过程就比较缓慢了。协调节点需要与每个节点进行沟通,然后聚合查询的结果,分片数越多,时间越长

51e695a25cbfbe1200323d2e1b8cebf2.png

一般,在一个维度上的分库都会遇到上述问题,可怕的是你可能会有多个维度的需求。对于一些NoSQL来说,每一个维度,都需要冗余一份数据,这一般是膨胀性的。


集群的规划并不是一成不变的,你的集群可能会加入新的节点;也可能有节点因为事故离线;也可能因为分片维度的问题,数据发生了倾斜。当这种情况发生,集群间的数据会发生迁移,以便达到平衡。这个过程有些是自动的,也有些是手动进行触发。这个过程也是最困难的:既要保证数据的增量迁移,又要保证集群的正确服务。

如果你想要事务(很多情况是你不懂技术的Leader决定),那就集中存储,不要分片。事务是很多性能场景和扩展场景的万恶之源,流量大了你会急着去掉它。

副本

针对一个分片的数据,只能有一个写入的地方,这就是master,其他副本都是从master复制数据。

副本能够增加读操作的并行读,但会读到脏数据。如果你想要读到的数据是一致的,可以采用同步写副本的方式,比如KAFKA的ack=-1,只有全部同步成功了,才认为本次提交成功。

但如果你的副本太多,这个过程会非常的慢。你可能想要通过分配写入和读取的副本个数来协调写入和读取的效率,QuorumR+W>N就是一个权衡策略。

这个过程可以简单的用抽屉原理来解释。

上面的这个过程比较简单,所以需要有点复杂的压下轴。一个名门就是Paxos,复杂的很,以前看了一个星期也没全部搞懂 -.-。

ZAB协议是ZooKeeperPaxos协议的基础上进行扩展而来的,说实话也没看懂,而且ZK的源代码也非常的…

唯一看得懂的就是Raft协议,这个是EtcdConsul的基础,是简化版的Paxos,目前来看是高效且可靠的。

副本是用来做HA的,所以master死了,要有副本顶上来。这个过程就涉及到master的选举。

kafka,借助zookeeper来进行主分区的选举。而ES是使用Bully算法,通过选出ID最大的节点当作master。无论什么方式,都是要从一堆机器中,找到一个唯一的master节点,而且在选举的过程中,都需要注意一个脑裂问题(也就是不小心找到俩了)。master选举通常都是投票机制,所以最小组集群的台数一般都设置成n/2+1

这也是为什么很多集群推荐奇数台的原因!

cassandra采用了另外一种协议来维护集群的状态,那就是gossip,是最终一致性的典范。

副本机制在传统的DB上也工作的很好。比如MySQL通过binlog完成副本的同步;Postgresql采用WAL日志完成同步。但涉及到主从的切换,尤其是有多个从库的情况下,一般都不能够自动化执行。

分片

分片就是对资料的切割,也就是一套主从已经装不下了。分片的逻辑可以放在客户端,比如驱动层的数据库中间件,Memcache等;也可以放在服务端,比如ES、Mongo等。

分片的信息组成了一组元数据,存放了切割的规则。这些信息可以借助外部的存储比如KAFKA;也有的直接同步在集群每个节点的内存中,比如ES。比较流行的NoSQL主从信息最小维度一般都是分片,一个节点上同时会有master分片和其他分片的副本。


分片的规则一般有下面几种:

Round-Robin 资料轮流落进不同的机器,数据比较平均,适合弱相关性的数据存储。坏处是聚合查询可能会非常慢,扩容、缩容难。

Hash 使用某些信息的Hash进行寻路,客户端依照同样的规则可以方便的找到服务端数据。问题与轮询类似,数据过于分散且扩容、缩容难。Hash同样适合弱相关的数据,并可通过一致性哈希来解决数据的迁移问题。

Range 根据范围来分片数据,比如日期范围。可以将一类数据归档到特定的节点,以增加查询速度。此类分片会遇到热点问题,会冷落很多机器。

自定义 自定义一些分片规则。比如通过用户的年龄,区域等进行切分。你需要维护大量的路由表,然后自己控制数据和访问的倾斜问题。

嵌套 属于自定义的一种,路由规则可以嵌套。比如首先使用Range进行虚拟分片,然后再使用Hash进行实际分片。在实际操作中,这很有用,需要客户端和服务端的结合才能完成。

路由的元数据不能太多,否则它本身就是一个访问瓶颈;也不能够太复杂,否则数据的去向将成为谜底。分布式系统的数据验证和测试是困难的,原因就在于此。


可惜的是,使用用户的年龄,和使用用户的地域进行分片,数据的分布完全不同。增加了一个维度的查询速度,会减慢另一个维度的性能,这是不可避免的。切分字段的选择非常重要,如果几个维度都很必要,解决的方式就是冗余—-按照每个切分维度,都写一份数据。

大部分互联网业务一般通过用户ID即可找到用户的所有相关信息,规划一个分层的路由结构即能满足需求。但数据统计类的需求就困难的多,你看到的很多年度报告,可能是算了个把月才出来的。

3189b4060472ef90ed61c628bb141c7e.png

一般组成结构

数据写入简单,因为是按条写的。但数据的读取就复杂多了,因为可能涉及到大量分片,尤其是AGG查询业务。一般会引入中间节点负责数据的聚合,因为大量的计算会影响master的稳定,这是不能忍受的。

通过区分节点的职责,可以保证集群的稳定。根据不同的需要,会有更多的协调节点被加入。

在做分布式之前,先要确保在单机场景能够最优。除了一些缓冲区优化,还有索引。但分布式是一直缺少一个索引的,曾经想设计一种基于内存的分布式索引,但还是赚钱养家要紧。

存储要有一个强大的查询语法引擎,目前来看非SQL引擎莫属。抽象成一棵巨大但语法树,然后在其上编程。像Redis这样简单的文本协议,是一个特定领域的特例。

分布式事务

ACID是强事务的单机RDBMS的特性。涉及到跨库,会有二阶段提交、三阶段提交之类的分布式事务处理。

数据库的分布式事务实现叫做XA,也是一种2PC,MySQL5.5版本开始已经支持这种协议。

2PC会严重影响性能,并不是和高并发的场景,而且其实现复杂,牺牲了一部分可用性。


另一种常用的方式就是TCC(补偿事务)。TCC的本质是:对于每一个操作,都需要一个与之对应的确认和撤销操作。但可惜的是,在确认和撤销阶段,也有一定概率发生问题,需要TCC的TCC;很多业务根本没有相应的逆操作,比如删除某些数据,TCC就没法玩了。

TCC需要大量编码,适合在框架层统一处理。


还有一种思路是将分布式事务合并成本地事务来处理。也就是一个事务包含一条消息+一堆数据库操作,成功执行完毕后再设置消息的状态,失败后会重试。 此种方式将消息强制耦合到业务中,且消息系统本身的事务问题也是一个需要考虑的因素。


分布式事务除了要写多个分片的协调问题,还有并发读写某一个值的问题。

比如有很多请求同时在修改一个余额。常用的方法就是加锁,但是效率太低。我们回忆一下java如何保证这种冲突。

对于读远大于小的操作,可以使用CopyOnWrite这种方式优化;对于原子操作,可以使用CompareAndSet的方式先比较再赋值。要想保证余额的安全,使用后者是很有必要的。

MVCC是行级别锁的一种妥协,他用来保证一个值在某个事务中是一致的,避免了脏读和幻读,但并不能保证数据的安全,这点一定要注意。

最终一致性

举个栗子:你的家庭资金共有500w,你私自借给好基友500万。使出了洪荒之力在年底讨回了借款,并追加了利息。在老婆查帐的时候,原封不动的展示给她看。这就是最终一致性。

我习惯性这样描述:在可忍受的时间内,轻过程、重结果,达成一致即可。虽然回味起来心有余悸。

在这种情况下,不需要过多的使用分布式事务来控制。你只管写你的数据,不用管别人是否写成功。我们通过其他的手段来保证数据的一致性。

一种方式是常见的定时任务,不断的扫描最近生成的数据,进行补齐。如果程序实在无法判断,则写入到异常表中人工介入。

另外一种方式就是重放数据,将这个过程重新执行一遍,要求业务逻辑是可重入的(幂等)。如果依然有问题,还是需要人工介入。

比较幸运的是,良好的设计下,这些异常状况产生的几率是比较小的,投入和产出会超出期望。采用了BASE的系统,选择的是弱一致性,高度依赖业务监控组件来及时的发现问题。

这种思想已经被大多数研发所接受,除非你的老板可忍受时间很短!

哦,BASE的全称是:

Basically Available(基本可用),

Soft state(软状态),

Eventually consistent(最终一致性)

总结

作为研发人员,是不能对软件有好恶倾向的,只有合适与不合适的区别。没有精力去改进这些系统,只能通过不断的取舍,组合它们的优点。

Greenplum和ElasticSearch,在分布式DB领域,是两个典型实现,它们都以强大的分布式能力著称。

Greenplum代表了RDBMS是如何向分布式发展的,当然它是建立在强大的Postgresql基础上的。

ES是建立在Lucene上的全文检索搜索引擎,但好像大家也拿它当数据库使用。源码是java的,有很多值得推敲的地方。

缓慢的I/O设备,再也无法压榨单机的性能,注定了要走向分布式。但前路依然漫漫,看看五花八门的分布式数据库就知道了。

没有谁,能一统江湖。



推荐阅读
  • MySQL:互联网公司常用 分库分表
    本文目录一、数据库瓶颈IO瓶颈CPU瓶颈二、分库分表水平分库水平分表垂直分库垂直分表三、分库分表工具四、分库分表步骤五、分库分表问题非partit ... [详细]
  • nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文介绍了关系型数据库和NoSQL数据库的概念和特点,列举了主流的关系型数据库和NoSQL数据库,同时描述了它们在新闻、电商抢购信息和微博热点信息等场景中的应用。此外,还提供了MySQL配置文件的相关内容。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • MySQL笔记_MySQL笔记1|数据库17问17答
    本文由编程笔记#小编为大家整理,主要介绍了MySQL笔记1|数据库17问17答相关的知识,希望对你有一定的参考价值。 ... [详细]
  • Java工程师书单(初级,中级,高级)
    简介怎样学习才能从一名Java初级程序员成长为一名合格的架构师,或者说一名合格的架构师应该有怎样的技术知识体系,这是不仅一个刚刚踏入职场的初级程序员也是工作一两年之后开始迷茫的程序 ... [详细]
  • 前面刚有AWS开战MongoDB,双方“隔空互呛”,这厢又曝出2亿+简历信息泄露——MongoDB的这场开年似乎“充实”得过分了些。长期以来,作为“最受欢迎的NoSQL数据库”,M ... [详细]
  • 数据库基本介绍
    1、数据库基本知识概念:数据库:database(DB),是一种存储数据的仓库数据库是根据数据结构组织、存储和 ... [详细]
  • hackingTeam是如何被黑的
    hackingTeam是如何被黑的 ... [详细]
  • 什么是堡垒机?堡垒机是一个主机系统,其自身通常经过了一定的加固,具有较高的安全性,可抵御一定的攻击,其作用主 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
  • 从Oracle安全移植到国产达梦数据库的DBA实践与攻略
    随着我国对信息安全和自主可控技术的重视,国产数据库在党政机关、军队和大型央企等行业中得到了快速应用。本文介绍了如何降低从Oracle到国产达梦数据库的技术门槛,保障用户现有业务系统投资。具体包括分析待移植系统、确定移植对象、数据迁移、PL/SQL移植、校验移植结果以及应用系统的测试和优化等步骤。同时提供了移植攻略,包括待移植系统分析和准备移植环境的方法。通过本文的实践与攻略,DBA可以更好地完成Oracle安全移植到国产达梦数据库的工作。 ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
author-avatar
风云时尚_榜中榜_434
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有