六安沧州西安三亚宝鸡菏泽
投稿投诉
菏泽德阳
山西湖州
宝鸡上海
茂名内江
三亚信阳
长春北海
西安安徽
黄石烟台
沧州湛江
肇庆鹤壁
六安韶关
成都钦州

一种以特征为依据的数据分片策略

  假如您有一个应用程序,随着业务越来越有起色,系统所牵涉到的数据量也就越来越大,此时您要涉及到对系统进行伸缩(Scale)的问题了。一种典型的扩展方法叫做向上伸缩(ScaleUp),它的意思是通过使用更好的硬件来提高系统的性能参数。而另一种方法则叫做向外伸缩(ScaleOut),它是指通过增加额外的硬件(如服务器)来达到相同的效果。从硬件成本还是系统极限的角度来说,向外伸缩一般都会优于向上伸缩,因此大部分上规模的系统都会在一定程度上考虑向外的方式。由于许多系统的瓶颈都处在数据存储上,因此一种叫做数据分片(DatabaseSharding)的数据架构方式应运而生,本文便会讨论这种数据架构方式的一种比较典型的实现方式。
  简介
  数据分片,自然便是将整体数据分摊在多个存储设备(下文统称为数据分区或分区)上,这样每个存储设备的数据量相对就会小很多,以此满足系统的性能需求。值得注意的是,系统分片的策略有很多,例如常见的有以下几种:
  根据ID特征:例如对记录的ID取模,得到的结果是几,那么这条记录就放在编号为几的数据分区上。
  根据时间范围:例如前100万个用户数据在第1个分区中,第二个100万用户数据放在第2个分区中。
  基于检索表:根据ID先去一个表内找到它所在的分区,然后再去目标分区进行查找。
  在这些数据分片策略之中没有哪个有绝对的优势,选择哪种策略完全是根据系统的业务或是数据特征来确定的。值得强调的是:数据分片不是银弹,它对系统的性能和伸缩性(Scalability)带来一定好处的同时,也会对系统开发带来许多复杂度。例如,有两条记录分别处在不同的服务器上,那么如果有一个业务是为它们建立一个关联,那么很可能表示关联的记录就必须在两个分区内各放一条。另外,如果您重视数据的完整性,那么跨数据分区的事务又立即变成了性能杀手。最后,如果有一些需要进行全局查找的业务,光有数据分片策略也很难对系统性能带来什么优势。
  数据分片虽然重要,但在使用之前一定要三思而后行。一旦踏上这艘贼船,往往不成功便成仁,很难回头。在我的经验里,一个滥用数据分片策略而事倍功半的项目给我留下了非常深刻的印象(当然也有成功的啦),因此目前我对待数据分片策略变得愈发谨慎。
  那么现在,我们便来讨论一种比较常见的数据分片策略。
  策略描述
  这里我先描述一个极其简单的业务:
  系统中有用户,用户可以发表文章,文章会有评论
  可以根据用户查找文章
  可以根据文章查找评论
  那么,如果我要对这样一个系统进行数据分片又该怎么做呢?这里我们可以使用上面提到的第一种方式,即对记录的ID取模,并根据结果选择数据所在的分区。根据后两条业务中描述的查询要求,我们会为分区策略补充这样的规则:
  某个用户的所有文章,与这个用户处在同一数据分区内。
  某篇文章的所有评论,与这篇文章处在用一数据分区内。
  您可能会说,似乎只要保证相同用户文章在同一个数据分区内就行了,不是吗?没错,不过我这里让文章和用户在同一个分区内,也是为了方便许多额外的操作(例如在关系数据库中进行连接)。那么假设我们有4个数据分区,那么它们内部的条目可能便是:
  分区0分区1
  User4
  Article8
  Article12
  Comment4
  Comment16
  User12
  Article4
  User1
  Article5
  Article9
  Comment13
  Comment17
  User5
  Article13
  分区2分区3
  User2
  Article10
  Article14
  Comment6
  Comment10
  User10
  Article4
  User7
  Article7
  Article11
  Comment3
  Comment15
  User11
  Article4
  在ID为0的分区中,所有对象的ID模4均为0,其他分区里的对象也有这样的规律。那么好,在实际应用中,如果我们需要查找ID为2的用户,便去第2分区搜索便是;如果要查找ID为8的文章的所有评论那么也只要去第0分区进行一次查询即可。既然查询不成问题,那么我们该如何添加新记录呢?其实这也不难,只要:
  添加新用户时,随机选择一个数据分区
  添加新文章时,选择文章作者所在分区(可根据Article的UserID求模得到)
  添加新评论时,选择文章所在分区(可根据Comment的ArticleID求模得到)
  但是,我们又如何保证新纪录的ID正好满足我们的分区规律?例如我们向第3分区添加的新数据,则它的ID必须是3、7、11等等。以前,我们可能会使用数据库的自增列作为ID的值,但这似乎不能满足我们取模的要求。以前我们可能还会使用GUID,但是我们如何生成一个被4模于3的GUID呢?其实我们还是可以使用自增ID来解决这个问题,只不过需要进行一些简单的设置。例如在SQLServer中,默认的自增ID属性为IDENTITY(1,1),表示ID从1开始,以1为间距自动增长。于是我们在创建数据分区的时候,每个自增列的属性则可以设置为:
  分区0:IDENTITY(4,4)
  分区1:IDENTITY(1,4)
  分区2:IDENTITY(2,4)
  分区3:IDENTITY(3,4)
  这样,ID方面的问题便交由数据库来关心吧,我们的使用方式和以前并没有什么区别。
  缺陷
  那么这个数据分片策略有什么缺陷呢?当然缺陷还是有很多啦,只是大多数问题可能还是要和业务放在一起考虑时才会凸显出来。不过有一个问题倒和业务关系不大:如果数据继续增长,单个数据分区的数据量也超标了,怎么办?
  自然,继续拆分咯。那么我们使用什么分区规则呢?和原先一致吗?我们举个例子便知。假设我们原有4个分区,有一个ID为1的用户落在第1分区里,他的文章也都在这个分区里,ID分别是1、5、9、13、17等等。于是在某一天,我们需要将分区数量提高到5个(财力有限,一台一台来吧),在重新计算每篇文章所在的分区之后,我们忽然发现:
  ID为1的文章,模5余1,处在分区1。
  ID为5的文章,模5余0,处在分区0。
  ID为9的文章,模5余4,处在分区4。
  ID为13的文章,模5余3,处在分区3。
  ID为17的文章,模5余2,处在分区2。
  呼,5个分区都齐了!这说明,如果我们保持记录原来的ID不变,是没有办法直接使用之前的分区规则无论您扩展成几个分区,(即便是从4个到8个)也只能缓解也不能解决这个情况。那么这时候该如何是好呢?例如,我们可以重新分配记录,改变原有ID,只是这么做会产生一个问题,便是外部URL可能也会随着ID一起改变,这样对SEO的折损很大。为此,我们可以制作一个查询表:例如在查询小于1234567的ID时(这是老系统的最大ID),假设是100,则根据查询表得知这条记录的新ID为7654321,再以此去数据源进行查找。解决这类问题的方法还有几种,但无论怎么做都会对新系统带来额外的复杂度。而且,一次扩展也罢,如果以后还要有所扩展呢?
  有朋友可能会说,取模自然会带来这样的问题,那么为什么不用一致性哈希(ConsistentHash)呢?现在一致性哈希是个很流行的东西,和Memcached一样,如果不用上就会被一些高级架构师所鄙视。不过在这里一致性哈希也不能解决问题。一致性哈希的目的,是希望在增加服务器的时候降低数据移动规模,让尽可能多的数据保留在原有的服务器上。而我们现在的问题却是在增加服务器的时候,让特征相同的数据同样放在一起。两个目标不同,这并不是一致性哈希的应用场景。
  我在以前的一个项目中曾经用过这样的方法:根据对访问量与数据量的预估,我们认为使用最多24个分区便一定可以满足性能要求(为什么是24个?因为它能被许多数字整除)。于是,从项目第一次在生产环境中部署时便创建了24个数据分区,只不过一开始只用了2台服务器,每台服务器放置12个数据分区。待以后需要扩展时,则将数据分区均匀地迁移到新的服务器上即可。我们团队当时便是用这种方法避免尴尬的数据分配问题。
  没错,数据分区的数目是个限制,但您真认为,24个数据分区还是无法满足您的项目需求吗?要知道,需要用上24个数据分区的项目,一般来说本身已经有充分的时间和经济实力进行架构上的重大调整(也该调整了,几乎没有什么架构可以满足各种数据规模的需求)。此外,无论是系统优化还是数据分片都可以同时运用其他手段。
  不过,我们目前还是想办法解决这个问题吧。
  策略改进
  我们之所以会遇到上面这个问题,在于我们没有选择好合适的策略,这个策略把一些重要的要求给具体化了,导致具体化后的结果在外部条件改变的时候,却无法重新满足原有的要求。还是以前面的案例来说明问题,其实我们要求其实是:
  某个用户的所有文章,与这个用户处在同一数据分区内。
  某篇文章的所有评论,与这篇文章处在用一数据分区内。
  而我们具体化以后的结果却是:
  某个用户的所有文章ID,与这个用户的ID模4后的余数相同。
  某篇文章的所有评论ID,与这篇文章的ID模4后的余数相同。
  之所以能如此具体化,这是因为有4个分区这样的前提条件在,一旦这个前提条件发生了改变,则杯具无法避免。因此,我们在制定规则的时候,其实不应该把前提条件给过分的具体化具体化可以,但不能过度,得留有一定空间(这个稍后再谈)。打个比方,还是前面的条件(XX和XX处在同一数据分区内),但我们换一种具体化的方式:
  某个用户的所有文章ID的前缀,便是这个用户的ID。例如,ID为1的用户的所有文章,其ID便可能是1A1、1A2、1A3
  某篇文章的所有评论ID,与这个文章的ID使用相同前缀。例如,ID为3A1的文章的所有评论,其ID便可能是3C1、3C2、3C3
  使用这个策略,我们便可以保证与某个用户相关的所有数据都共享相同的特征(ID的前缀都相同),然后我们便可以根据这个特征来选择分区例如,还是以取模的方式。此时,我们已经确保了相同分区内的所有数据都具备相同的特征,即便分区数量有所调整,我们也只需要根据特征重新计算分区即可,影响不大。而以前为什么不行?因为模4的余数只是结果而不是特征,这里的特征应该是追本溯源后的用户ID相同,而这一点已经体现在新的策略中了。
  还是通过图示来说明问题吧。假设原有4个分区,使用取模的策略:
  分区0分区1
  User4
  Article4A1
  Article4A2
  Comment4C1
  Comment4C2
  User12
  Article12A3
  User1
  Article1A4
  Article1A5
  Comment1C3
  Comment1C4
  User5
  Article5A6
  分区2分区3
  User2
  Article2A7
  Article2A8
  Comment2C5
  Comment2C6
  User10
  Article10A9
  User7
  Article7A10
  Article7A11
  Comment7C7
  Comment7C8
  User11
  Article11A12
  当分区数量调整为5个之后(为了避免分区3空缺,我又补充了一些对象):
  分区0分区1
  User10
  Article10A9
  User5
  Article5A6
  User1
  Article1A4
  Article1A5
  Comment1C3
  Comment1C4
  User11
  Article11A12
  分区2分区3
  User2
  Article2A7
  Article2A8
  Comment2C5
  Comment2C6
  User12
  Article12A3
  User7
  Article7A10
  Article7A11
  Comment7C7
  Comment7C8
  User8
  Article8A12
  Article8A13
  Comment8C9
  Comment7C10
  分区4
  User4
  Article4A1
  Article4A2
  Comment4C1
  Comment4C2
  是不是很合理?
  值得一提的是,只要满足了特征这个要求,其实选择分区的方式并没有什么限制。例如,我们可以不用取模的方式,而是使用一致性哈希没错,这里就是一致性哈希的使用场景了。在利用一致性哈希来选择分区之后,在添加服务器的情况下便可以相对减少数据的迁移数量了。
  当然,在实现时还可以运用一些技巧。例如,我们的特征并非一定要把用户ID作为前缀毕竟用户ID可能比较长,作为ID前缀还真有些难看(请想象把GUID作为ID前缀,再加上另一个GUID作为ID主体的情景)。此时,我们可以把前提条件先进行一定程度的具体化(但就像之前提到的,不能过度),例如我们可以把用户ID先进行取模,可能是1000万,便可以得到一个落在较大区间范围内的数字。然后,再把这个数字作BASE64编码,一下子前缀就缩小为4个字符以内了。而且,1000万这个区间范围,无论是使用取模还是一致性哈希的方式来选择分区都非常可行,一般不会造成什么问题。
  总结

袖子长一截时髦翻一倍时尚从来都是不正经的穿衣服,最近刮起了一阵断掌风,袖子越长越时髦,意外的很受时髦精的欢迎,让这个冬天多了一股慵懒的欧美范儿。2019年超长袖注定要大火一把,你确定不来一件?……抖音违规都有哪些抖音常见的几种违规方式最近,为了保障抖音用户的权利,抖音平台公布了最新的《抖音对违规运用商品分享性能账号的检讨通告》。并永远封禁9097个账号,累计封禁521款商品。有些人一不不慎就踩雷,招致……牛仔短裤配什么鞋才时髦款夏日美鞋颜值牛仔短裤配什么鞋子好看?显腿长又舒适的尖头平底鞋还是高街运动鞋?赶紧来看看时髦星人都选择什么鞋子来搭配牛仔短裤吧,六款至热美鞋教你牛仔短裤怎么搭配鞋子才够in。牛仔短裤运……用最少的钱将信用卡养到最大额度并且快每个人手中都有信用卡,每天都会用它进行刷卡消费,但是大家最为关心的问题是什么,无非就是如何将手中的信用卡安全可靠的快速提额罢了。今天,卡友群为大家讲解一些用POS机商户消费快速……十一成王识伪迎周公周成王名叫姬诵,是周武王姬发的儿子,他即位时,年仅十三岁。姬诵继位不久,便发生了一起企图使周朝分裂的事件。姬诵虽然年纪幼小,但天资聪明,善于动脑,他及时调查研究,辨清真伪,排除……乘风破浪电影简介导语:《乘风破浪》是由韩寒导演,邓超、彭于晏、赵丽颖、董子健、金士杰、易小星、张本煜、李荣浩、高华阳、李淳主演的电影。下面励志故事网小编为大家整理了《乘风破浪》电影简介,希望大……四款美食吃出丰满胸部四款DIY美食吃出丰满胸部1:木瓜莲子乳准备木瓜半个、牛奶200ml,莲子肉适量,红枣少许。把新鲜的木瓜去皮去籽,切成小块,莲子和红枣用水泡一下,莲子去芯,红枣去核……没有一个冬天不可逾越即使是年来最冷当新年的熹微曙光笼罩大地之时,我们会知道,没有任何东西比一个信念更为珍贵,也从没有任何一个时代有如此之多的困难,有如此之多的希望。2009年新年致辞:当经济危机带来……厕所哲学为什么男人便后不爱洗手译者zhenzhen2743丨心理学与生活超级细菌广泛传播,洗手行为的研究也越发重要。心理学家们已经开始着手研究这一行为。因此,科学家们躲在洗手间的小隔间里,观察人们在洗……散碎的记忆文:王势午昨天在饭店,饭桌上朋友点了一盘姐留(蝉),由于是反季节的原因,一桌食客边吃边赞。而我看着被油炸的金黄又稍稍有点发黑的姐留,却无论如何也提不起对它的食欲。小……屋漏偏逢连夜雨每一次下雨,我总是把目光集中在我家阳台棚顶,那一道道裂痕,说不定就有雨水滴答滴答地流下来。果然,这一次没有幸免,雨水顺着窗台一直淌下来。难怪,雨已经下了一天一夜了。本来,……焦虑症有什么症状焦虑症应该吃什么药焦虑症又称之为焦虑性神经症,是常见的一种精神性疾病。那患上焦虑症的时候有什么症状呢?焦虑症的时候又应该吃什么药好呢?今天小编就来为大家一一解答一下。想知道的朋友就来看一下吧。……
咖啡和奶茶的区别是什么操作方法01:hr咖啡是需要对咖啡豆烘焙进行制作的,一般来说都是作为热饮,当然也有冰咖啡,咖啡在现如今的社会中是很流行的饮料之一。02:hr喝咖啡能够起到利尿提神的……酥皮火烧的做法脆皮火烧是一道地地道道的北方美食,它外酥里嫩,香酥可口,下面给大家分享一下脆皮火烧的做法。工具材料面粉、植物油、酵母、白芝麻、花椒、葱花、食物盐、白糖、调料操……银行部年季度工作总结银行XX部2020年季度工作总结2020年是一个特殊的开局之年,新型冠状病毒充斥着我们中华大地,原本热闹、祥和的春节,也变得冷冷清清。全行各网点为了给卫材企业提供资金支持……加大金融支持帮助企业升级自疫情爆发以来,菏泽分行营业部按照监管部门和总分行各项要求,扎实推进小微金融服务工作,不断创新合作模式,推出各类金融产品,提高服务效率,有效的助力了小微企业的发展。(一)……认真开展群众路线教育切实加强作风建设去年下半年以来,在全党开展的党的群众路线教育实践活动,以贯彻落实中央八项规定作为切入点,强化党员干部宗旨意识,进一步突出作风建设,着力解决人民群众反映强烈的突出问题。作风……试论加强石油企业廉洁文化建设的意义摘要:企业廉洁文化是社会主义先进文化的重要组成部分,是构建惩治和预防腐败体系的重要内容。我国石油企业作为国有企业,大力推进以廉洁从业价值观为核心的廉洁文化建设,对于提升党员干部……护照过期刑事案件冒名信用卡留学生需警惕这些电话诈您好,我是中国驻X国大使馆,对于海外中国公民来说,在电话中得到这样的问候,本应感到十分温暖和贴心,殊不知,如果不提高警惕,很可能掉入不法分子精心设计的诈骗陷阱。随着出国热……热议中国债市发展主要依靠改革与开放1月17日,中国债券市场国际论坛今日在京召开。央行副行长朱鹤新,央行副行艮、外管局局长潘功胜,财政部国库司司长王小龙,香港交易所行政总裁李小……中国近代史读书笔记《中国近代史》是蒋廷黻先生的经典著作,他以冷静客观的态度,叙述了从鸦片战争到辛亥革命这段时间的中国历史,对中国国家前途、民族命运以学术的形式表达了关切,提出了许多真知灼见。翻开……夺命绝活一hr康熙年间,在老北京菜市口有一个叫黑三子的鞋匠,每逢菜市口处决犯人,他是一定要去的。这天上午,黑三子正在看处决犯人,只听三声催命炮响,十几个人头落地。围观的人群里,胆……关于重拾信心与勇气的电影面对巨人简介电影《面对巨人》是由埃里克斯肯德里克(AlexKendrick)执导,埃里克斯肯德里克、BaileyCave等主演的剧情片。讲述的是一位教练如何重拾信心与勇气,并用信仰击败恐惧……雪儿飘飘第九节白面小生的痴心守望第二天下午,韩雪独自一人来到阶梯教室上自习。她刚坐好位置,一位眉清目秀、书声气很浓的白面小生朝她微笑地点点头坐到了他前面的位置。韩雪回敬他一个浅浅的微笑,便进入了学习状态。……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网