关于大型网站技术演进的思考(四)--存储的瓶颈(4)

news/2024/5/8 23:07:18/文章来源:https://blog.csdn.net/yazhouren/article/details/43525293

如果数据库需要进行水平拆分,这其实是一件很开心的事情,因为它代表公司的业务正在迅猛的增长,对于开发人员而言那就是有不尽的项目可以做,虽然会感觉很忙,但是人过的充实,心里也踏实。

  数据库水平拆分简单说来就是先将原数据库里的一张表在做垂直拆分出来放置在单独的数据库和单独的表里后更进一步的把本来是一个整体的表进一步拆分成多张表,每一张表都用独立的数据库进行存储。当表被水平拆分后,原数据表成为了一个逻辑的概念,而这个逻辑表的业务含义需要多张物理表协同完成,因此数据库的表被水平拆分后,那么我们对这张表的操作已经超出了数据库本身提供给我们现有的手段,换句话说我们对表的操作会超出数据库本身所拥有的处理能力,这个时候我就需要设计相关的方案来弥补数据库缺失的能力,这就是数据库水平拆分最大的技术难点所在。

  数据库的水平拆分是数据库垂直拆分的升级版,它和垂直拆分更像继承机制里的父子关系,因此水平拆分后,垂直拆分所遇到的join查询的问题以及分布式事务的问题任然存在,由于表被物理拆解增加了逻辑表的维度,这也给垂直拆分里碰到的两个难题增加了更多的维度,因此水平拆分里join查询的问题和分布式事务会变得更加复杂。水平拆分除了垂直拆分两个难题外,它还会产生新的技术难题,这些难题具体如下:

  难题一:数据库的表被水平拆分后,该表的主键设计会变得十分困难;

  难题二:原来单表的查询逻辑会面临挑战。

  在准备本篇文章时候,我看到一些资料里还提到了一些难题,这些难题是:

  难题三:水平拆分表后,外键的设计也会变得十分困难;

  难题四:这个难题是针对数据的新增操作的,大致的意思是,我们到底按什么规则把需要存储的数据存储在拆分出的那个具体的物理数据表里。

  难题三的问题,我在上篇已经给出了解答,这里我进行一定的补充,其实外键问题在垂直拆分就已经存在,不过在讲垂直拆分时候我们没有讲到这个问题,这主要是我设定了一个前提,就是数据表在最原始的数据建模阶段就要抛弃所有外键的设计,并将外键的逻辑抛给服务层去完成,我们要尽全力减轻数据库承担的运算压力,其实除了减轻数据库运算压力外,我们还要将作为存储原子的表保持相对的独立性,互不关联,那么要做到这点最直接的办法就是去掉表与表之间关联的象征:外键,这样我们就可以从根基上为将来数据库做垂直拆分和水平拆分打下坚实的基础。

  至于难题四,其实问题的本质是分库分表后具体的数据在哪里落地的问题,而数据存储在表里的关键障碍其实就是主键,试想一下,我们设计张表,所有字段我们都准许可以为空,但是表里有个字段是绝对不能为空的,那就是主键,主键是数据在数据库里身份的象征,因此我们在主键设计上是可以体现出该数据的落地规则,那么难题四也会随之解决。因此下文我会重点讲解前两个水平拆分的难题。

  首先是水平拆分里的主键设计问题,抛开所有主键所能代表的业务含义,数据库里标的主键本质是表达表里的某一条记录的唯一性,在设计数据库的时候我们可以由一个绝对不可重复的字段表示主键,也可以使用多个字段组合起来表达这种唯一性,使用一个字段表示主键,这已经是很原子级的操作,没法做进一步的修改,但是如果使用多个字段表示一个主键对于水平拆分而言就会碰到问题了,这个问题主要是体现在数据到底落地于哪个数据库,关于主键对数据落地的影响我会在把相关知识讲解完毕后再着重阐述,这里要提的是当碰到联合主键时候我们可以设定一个没有任何业务含义的字段来替代,不过这个要看场景了,我倾向于将联合主键各个字段里的值合并为一个字段来表示主键,如果有的朋友认为这样会导致数据冗余,那么可以干脆去掉原来做联合主键的相关字段就是用一个字段表示,只不过归并字段时候使用一个分隔符,这样方便服务层进行业务上的拆分。

  由上所述,这里我给出水平拆分主键设计的第一个原则:被水平拆分的表的主键设计最好使用一个字段表示

  如果我们的主键只是表达记录唯一性的话,那么水平拆分时候相对要简单的多,例如在Oracle数据库里有一个sequence机制,这其实就是一个自增数的算法,自增机制几乎所有关系数据库都有,也是我们平时最喜欢使用的主键字段设计方案,如果我们要拆分的表,使用了自增字段,同时这个自增字段只是用来表达记录唯一性,那么水平拆分时候处理起来就简单多了,我这里给出两个经典方案,方案如下:

  方案一:自增列都有设定步长的特性,假如我们打算把一张表只拆分为两个物理表,那么我们可以在其中一张表里把主键的自增列的步长设计为2,起始值为1,那么它的自增规律就是1,3,5,7依次类推,另外一张物理表的步长我们也可以设置为2,如果起始值为2,那么自增规律就是2,4,6,8以此类推,这样两张表的主键就绝对不会重复了,而且我们也不用另外做两张物理表相应的逻辑关联了。这种方案还有个潜在的好处,那就是步长的大小和水平数据拆分的粒度关联,也是我们为水平拆分的扩容留有余量,例如我们把步长设计为9,那么理论上水平拆分的物理表可以扩容到9个。

  方案二:拆分出的物理表我们允许它最多存储多少数据,我们其实事先通过一定业务技术规则大致估算出来,假如我们估算一张表我们最多让它存储2亿条,那么我们可以这么设定自增列的规律,第一张物理表自增列从1开始,步长就设为1,第二种物理表的自增列则从2亿开始,步长也设为1,自增列都做最大值的限制,其他的依次类推。

  那么如果表的主键不是使用自增列,而是业务设计的唯一字段,那么我们又如何处理主键分布问题了?这种场景很典型,例如交易网站里一定会有订单表,流水表这样的设计,订单表里有订单号,流水表里有流水号,这些编号都是按一定业务规则定义并且保证它的唯一性,那么前面的自增列的解决方案就没法完成它们做水平拆分的主键问题,那么碰到这个情况我们又该如何解决了?我们仔细回味下数据库的水平拆分,它其实和分布式缓存何其的类似,数据库的主键就相当于分布式缓存里的键值,那么我们可以按照分布式缓存的方案来设计主键的模型,方案如下:

  方案一:使用整数哈希求余的算法,字符串如果进行哈希运算会得出一个值,这个值是该字符串的唯一标志,如果我们稍微改变下字符串的内容,计算的哈希值肯定是不同,两个不同的哈希值对应两个不同字符串,一个哈希值有且只对应唯一一个字符串,加密算法里的MD5,SHA都是使用哈希算法的原理计算出一个唯一标示的哈希值,通过哈希值的匹配可以判断数据是否被篡改过。不过大多数哈希算法最后得出的值都是一个字符加数字的组合,这里我使用整数哈希算法,这样计算出的哈希值就是一个整数。接下来我们就要统计下我们用于做水平拆分的服务器的数量,假如服务器的数量是3个,那么接着我们将计算的整数哈希值除以服务器的数量即取模计算,通过得到的余数来选择服务器,该算法的原理图如下所示:

 

  方案二:就是方案一的升级版一致性哈希,一致性哈希最大的作用是保证当我们要扩展物理数据表的数量时候以及物理表集群中某台服务器失效时候才会体现,这个问题我后续文章会详细讨论物理数据库扩容的问题,因此这里先不展开讨论了。

  由上所述,我们发现在数据库进行水平拆分时候,我们设定的算法都是通过主键唯一性进行的,根据主键唯一性设计的特点,最终数据落地于哪个物理数据库也是由主键的设计原则所决定的,回到上文里我提到的如果原库的数据表使用联合字段设计主键,那么我们就必须首先合并联合主键字段,然后通过上面的算法来确定数据的落地规则,虽然不合并一个字段看起来也不是太麻烦,但是在我多年开发里,把唯一性的字段分割成多个字段,就等于给主键增加了维度,字段越多,维度也就越大,到了具体的业务计算了我们不得不时刻留心这些维度,结果就很容易出错,我个人认为如果数据库已经到了水平拆分阶段了,那么就说明数据库的存储的重要性大大增强,为了让数据库的存储特性变得纯粹干净,我们就得尽力避免增加数据库设计的复杂性,例如去掉外键,还有这里的合并联合字段为一个字段,其实为了降低难度,哪怕做点必要的冗余也是值得。

  解决数据库表的水平拆分后的主键唯一性问题有一个更加直接的方案,这也是很多人碰到此类问题很自然想到的方法,那就是把主键生成规则做成一个主键生成系统,放置在单独一台服务器上统一生成,每次新增数据主键都从这个服务器里获取,主键生成的算法其实很简单,很多语言都有计算UUID的功能,UUID是根据所在服务器的相关的硬件信息计算出的全球唯一的标示,但是这里我并没有首先拿出这个方案,因为它相比如我前面的方案缺点太多了,下面我要细数下它的缺点,具体如下:

  缺点一:把主键生成放到外部服务器进行,这样我们就不得不通过网络通信完成主键值的传递,而网络是计算机体系里效率最低效的方式,因此它会影响数据新增的效率,特别是数据量很大时候,新增操作很频繁时候,该缺点会被放大很多;

  缺点二:如果我们使用UUID算法做主键生成的算法,因为UUID是依赖单台服务器进行,那么整个水平拆分的物理数据库集群,主键生成器就变成整个体系的短板,而且是关键短板,主键生成服务器如果失效,整个系统都会无法使用,而一张表需要被水平拆分,而且拆分的表是业务表的时候,那么这张表在整个系统里的重要度自然很高,它如果做了水平拆分后出现单点故障,这对于整个系统都是致命的。当然有人肯定说,既然有单点故障,那么我们就做个集群系统,问题不是解决了吗?这个想法的确可以解决我上面阐述的问题,但是我前文讲到过,现实的软件系统开发里我们要坚守一个原则那就是有简单方案尽量选择简单的方案解决问题,引入集群就是引入了分布式系统,这样就为系统开发增加了开发难度和运维风险,如果我们上文的方案就能解决我们的问题,我们何必自讨苦吃做这么复杂的方案呢?

  缺点三:使用外部系统生成主键使得我们的水平拆分数据库的方案增加了状态性,而我上面提到的方案都是无状态的,有状态的系统会相互影响,例如使用外部系统生成主键,那么当数据操作增大时候,必然会造成在主键系统上资源竞争的事情发生,如果我们对主键系统上的竞争状态处理不好,很有可能造成主键系统被死锁,这也就会产生我前文里说到的503错误,而无状态的系统是不存在资源竞争和死锁的问题,这洋就提升了系统的健壮性,无状态系统另一个优势就是水平扩展很方便。

  这里我列出单独主键生成系统的缺点不是想说明我觉得这种解决方案完全不可取,这个要看具体的业务场景,根据作者我的经验还没有找到一个很合适使用单独主键生成器的场景。

  上文里我提出的方案还有个特点就是能保证数据在不同的物理表里均匀的分布,均匀分布能保证不同物理表的负载均衡,这样就不会产生系统热点,也不会让某台服务器比其他服务器做的事情少而闲置资源,均匀分配资源可以有效的利用资源,降低生产的成本提高生产的效率,但是均匀分布式数据往往会给我们业务运算带来很多麻烦。

  水平拆分数据库后我们还要考虑水平扩展问题,例如如果我们事先使用了3台服务器完成了水平拆分,如果系统运行到一定阶段,该表又遇到存储瓶颈了,我们就得水平扩容数据库,那么如果我们的水平拆分方案开始设计的不好,那么扩容时候就会碰到很多的麻烦。

  以上问题将是我下篇文章里进行讨论的,今天就写到这里,祝大家生活愉快。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_793661.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于大型网站技术演进的思考(五)--存储的瓶颈(5)

关于大型网站技术演进的思考(五)--存储的瓶颈(5) 上文里我遗留了两个问题,一个问题是数据库做了水平拆分以后,如果我们对主键的设计采取一种均匀分布的策略,那么它对于被水平拆分出的表后续的查…

关于大型网站技术演进的思考(六)--存储的瓶颈(6)

关于大型网站技术演进的思考(六)--存储的瓶颈(6) 在讲数据库水平拆分时候,我列出了水平拆分数据库需要解决的两个难题,它们分别是主键的设计问题和单表查询的问题,主键问题前文已经做了比较详细…

使用HTML5、CSS3和jQuery增强网站用户体验[留存]

记得几年前如果你需要添加一些互动元素到你的网站中用来改善用户体验?是不是立刻就想到了flash实现?这彷佛年代久远的事了。使用现在最流行的Web技术HTML5,CSS3和jQuery,同样也可以实现类似的用户体验。而且使用这些特性将会比使用…

途牛网站无线架构变迁实践

origin: http://geek.csdn.net/news/detail/55369途牛从一开始的单机系统,发展到现在已拥有数百个分布式部署的系统。本文主要将途牛网站无线系统在从小到大的过程中,遇到的问题以及解决方法与大家分享,希望为大家带来一定借鉴。文章将从服务…

大型网站架构系列:电商网站架构案例(1)

origin: http://www.cnblogs.com/itfly8/p/5006197.html大型网站架构是一个系列文档,欢迎大家关注。本次分享主题:电商网站架构案例。从电商网站的需求,到单机架构,逐步演变为常用的,可供参考的分布式架构的原型。除具…

大型网站架构系列:电商网站架构案例(2)

origin: http://www.cnblogs.com/itfly8/p/5006200.html电网网站架构案例系列的第二篇文章。主要讲解网站架构分析,网站架构优化,业务拆分,应用集群架构,多级缓存,分布式Session。 五、网站架构分析 根据以上预估&…

大型网站架构系列:电商网站架构案例(3)

origin: http://www.cnblogs.com/itfly8/p/5009005.html本文章是电商网站架构案例的第三篇,主要介绍数据库集群,读写分离,分库分表,服务化,消息队列的使用,以及本电商案例的架构总结。 6.5数据库集群&#…

大型分布式网站架构技术总结

origin: http://www.cnblogs.com/itfly8/p/4967966.html本文是学习大型分布式网站架构的技术总结。对架构一个高性能,高可用,可伸缩,可扩展的分布式网站进行了概要性描述,并给出一个架构参考。一部分为读书笔记,一部分…

安装php cms 系统教程,如何安装PHPCMS网站管理系统

帝国CMS技术互助群:540946827 一帮大神带你装逼带你飞!还有漂亮的妹纸陪你玩哦!(一)安装前的预备Phpcms 具备跨平台特性,可以运行于 Linux/FreeBSD/Unix 及微软 Windows 2000/2003 等各种操作系统环境下。我们已在软件中 针对上述…

大型网站架构演变和知识体系

2019独角兽企业重金招聘Python工程师标准>>> 之前也有一些介绍大型网站架构演变的文章,例如LiveJournal的、ebay的,都是非常值得参考的,不过感觉他们讲的更多的是每次演变的结果,而没有很详细的讲为什么需要做这样的演…

linux日志服务源码,Linux系统下nginx+php实现清理服务器网站日志

本篇文章主要讲述的是在Linux系统下用nginx和php实现清理服务器网站日志,具有一定参考价值,感兴趣的朋友可以了解一下,希望对你能有所帮助。1.清空nginx站点日志的内容(如果删除日志文件,只有重启服务器才能重新生成日志文件进行记…

玛曲seo关键词互点软件_请看!张家港seo关键词优化价格,启销软件

广东无忧云网络科技有限公司为您详细解读XzMLCf张家港seo关键词优化价格的相关知识与详情,跟着时间的推移,页面排名由用户行为、用户交互、用户保举等因素决议,而新页面排名则由相关关键字密度、文章本创性等因素决议。那种影响会渐渐削弱&am…

layui的tab加入其他页面_网站建设费用_网站制作如何让页面更具特色

对于一个页面,毫无特色,是没有办法吸引用户的目光,只有有特色的页面才能吸引更多的用户,才能留住用户,所以页面设计的好坏会直接影响网站用户的体验,在这个网络十分发达的年代,用户没有太多的时…

python爬取电商数据_吴裕雄--天生自然PYTHON爬虫:使用Selenium爬取大型电商网站数据...

用python爬取动态网页时,普通的requests,urllib2无法实现。例如有些网站点击下一页时,会加载新的内容,但是网页的URL却没有改变(没有传入页码相关的参数),requests、urllib2无法抓取这些动态加载的内容,此时…

多平台的网站实现单点登录系统(SSO)的开发思路 让你的会员中心更加统一(参考资料)...

单点登录并不是一个新鲜的玩意儿,比较官方的解释是企业业务整合的解决方案之一,通俗来讲SSO就是一个通用的用户中心,国内比较流行的UCenter就是一套单点登录解决方案。而近期以CSDN明文存储用户密码并泄露用户信息开始的各大网站争先恐后的泄…

报名系统网页导出html,教资报名系统提示网站兼容性怎么办 ie浏览器兼容性操作流程...

教师资格证报名2021年入口已经于1月14日开通,3月13日举行笔试,相信不少考生在报名过程中,遇到兼容性站点添加的问题,报名的浏览器不是IE系列,兼容性站点如何添加呢?为帮助各位考生报考,小编来帮助大家解决…

国外服务器 百度云,百度云加速如何配置网站海外加速

一、纯静态网站加速所谓纯静态网站就是网页全部由HTML纯静态页生成的网页,没有会员注册登陆、在线支付等需要调用数据库的功能。这类网页想要加速很简单,只需要把网页全部缓存至百度云加速节点即可。操作方法如下:1.进入报表下拉的-特定页面规…

java和seo哪个好_seo和java哪个更好

一个seo行业站点,科学的内容制作应该与seo相关,且内容本身是有人搜索的。seo和java哪个更好是有人搜索的语句,且与seo是强相关的,对于站增网来讲,这样的内容再适合不过了。任何一门技术,如果精通&#xff0…

nginx 判断手机端跳转_前后端分离情况下如何做SEO优化?

大家好,我是吉礻羊!前后端分离情况下如何做SEO优化?优化针对这个问题分2个点:1,前后端分离的架构,无法提供搜索引擎可收录的页面,需要搜索引擎蜘蛛拥有执行javascript能力才行,可现实…

网页设计 html鼠标悬停,20个酷炫的鼠标悬停效果的网站设计

原标题:20个酷炫的鼠标悬停效果的网站设计出处:设计之家链接:http://www.sj33.cn/digital/wysj/201706/47570.htmlPixels by Tomer Lernerhttp://tomerlerner.com/Haushttps://www.madeinhaus.com/Canvahttps://www.canva.com/Mainworkshttp:…