时间:2021-07-01 10:21:17 帮助过:13人阅读
相对于传统行业的相对服务时间9x9x6或者9x12x5。由于互联网电子商务以及互联网游戏的实时性,所以服务要求7*24小时,业务架构无论是应用还是数据库,都须要容灾互备,在mysql的体系中,最好通过在最開始阶段的数据库架构阶段来实现容灾系统。所以这里从业务宏观角度阐述下mysql架构的方方面面。
虚线表示跨机房部署,比方电子商务系统。一个Master既有读也有些写。对读数据一致性须要比較重要的。读要放在Master上面。
M(R)仅仅是一个备库。仅仅有M(WR)挂了之后,才会切换到M(R)上,这个时候M(R)就变成了读写库。
比方游戏系统。有非常多Salve会挂载后面一个M(R)上面。
假设是电子商务类型的。这样的读多写少的。通常是1个master拖上4到6个slave,全部slave挂载在一个master也足够了。
切换的时候。把M1的读写业务切换到M2上面,然后把全部M1上的slave挂到M2上面去。例如以下所看到的:
假设是游戏行业的话,读非常多蛮明显的,会出现一般1个Master都会挂上10个以上的Slave的情况,所以这个时候。能够把一部分Slave挂载新的M(R)上面。
至少会降低一些压力,这样至少server挂掉的时候,不会对全部的slave有影响。另一部分在M(R)上的slave在继续,不会对全部的slave受到影响。见图3,
图3
意味着读并不会影响写的效率。所以读写都能够放在一个M1(WR),而另外一个不提供读也不提供写,仅仅提供standby冗余异地容灾。
这个异地容灾是非常重要的,否则假设是单机的,单边的业务。万一idc机房故障了,一般就会影响在线业务的。这样的 造成业务2小时无法应用,对于在线电子商务交易来说。影响是蛮大的,所以为了最大限度的保证7*24小时,必须要做到异地容灾,MM要跨idc机房。尽管对资源有一些要求,可是对HA来说是必不可少的,一定要有这个MM机制。
做切换的时候,把全部的读写从M1直接切换到M2上就能够了。
读和写差点儿相同。可是读不能影响写的能力,把读写放在M1(WR)上,然后把一部分读也放在M2(R)上面,当然M1和M2也是跨机房部署的。
切换的时候,把一部分读和全部写从M1切换到M2上就能够了。
对读一致性的权衡。假设是对读写实时性要求非常高的话。就将读写都放在M1上面。M2仅仅是作为standby,就是採取和上面的一(4)的读少写多的一样的架构模式。
比方,订单处理流程。那么对读须要强一致性。实时写实时读,相似这样的涉及交易的或者动态实时报表统计的都要採用这样的架构模式
假设是弱一致性的话。能够通过在M2上面分担一些读压力和流量,比方一些报表的读取以及静态配置数据的读取模块都能够放到M2上面。比方月统计报表,比方首页推荐商品业务实时性要求不是非常高。全然能够採用这样的弱一致性的设计架构模式。
假设既不是非常强的一致性又不是非常弱的一致性,那么我们就採取中间的策略。就是在同机房再部署一个S1(R),作为备库,提供读取服务。降低M1(WR)的压力,而另外一个idc机房的M2仅仅做standby容灾方式的用途。
当然这里会用到3台数据库server。或许会添加採购压力。可是我们能够提供更好的对外数据服务的能力和途径。实际中尽可能两者兼顾。
比方PV、UV操作、页数的统计、流量的统计、数据的汇总等等,都能够划归为统计类型的业务。
数据库上做大查询的统计是非常消耗资源的。统计分为实时的统计和非实时的统计。由于mysql主从是逻辑sql的模式,所以不能达到100%的实时。假设是online要严格的非常实时的统计比方像火车票以及金融异地结算等的统计,mysql这块不是它的强项,就仅仅有查询M1主库来实现了。
A,可是对于不是严格的实时性的统计,mysql有个非常好的机制是binlog,我们能够通过binlog进行解析Parser,解析出来写入统计表进行统计或者发消息给应用端程序来进行统计。这样的是准实时的统计操作,有一定的短暂的可接受的统计延迟现象。假设要100%实时性统计仅仅有查询M1主库了。
通过binlog的方式实现统计,在互联网行业,尤其是电商和游戏这块,差点儿相同能够解决90%以上的统计业务。
有时候假设用户或者客户提出要实时read-time了,大家能够沟通一下为什么须要实时,了解详细的业务场景,有些可能真的不须要实时统计,须要有所权衡,须要跟用户和客户多次有效沟通。做出比較适合业务的统计架构模型。
B。另一种offline统计业务。比方月份报表年报表统计等。这样的全然能够把数据放到数据仓库里面或者第三方Nosql里面进行统计。
历史数据迁移。须要尽量不影响如今线上的业务,尽量不影响如今线上的查询写入操作,为什么要做历史数据迁移?由于有些业务的数据是有时效性的。比方电商中的已经完毕的历史订单等,不会再有更新操作了。仅仅有非常easy的查询操作。并且查询也不会非常频繁。甚至可能一天都不会查询一次。
假设这时候历史数据还在online库里面或者online表里面。那么就会影响online的性能,所以对于这样的,能够把数据迁移到新的历史数据库上。这个历史数据库能够是mysql也能够是nosql。也能够是数据仓库甚至hbase大数据等。
实现途径是通过slave库查询出全部的数据。然后依据业务规则比方时间、某一个纬度等过滤筛选出数据,放入历史数据库(History Databases)里面。迁移完了,再回到主库M1上,删除掉这些历史数据。
这样在业务层面,查询就要兼顾如今实时数据和历史数据,能够在filter上面依据迁移规则把online查询和history查询对接起来。比方说一个月之内的在online库查询一个月之前的在history库查询,能够把这个规则放在DB的迁移filter层和应用查询业务模块层。假设能够的话,还能够配置更细化。通过应用查询业务模块层来影响DB的迁移filter层,比方曾经查询分为一个月为基准。如今查询业务变化了,以15天为基准。那么应用查询业务模块层变化会自己主动让DB的filter层也变化。实现半个自己主动化,更加智能一些。
像oracle这样的基于rac基于共享存储的方式。不须要sharding仅仅须要扩从rac存储就能实现了。可是这样的代价相对会比較高一些,共享存储一般都比較贵。随着业务的扩展数据的爆炸式增长,你会不停累计你的成本,甚至达到一个天文数字。
眼下这样的share disk的方式,除了oracle的业务逻辑层做的非常完好之外其它的解决方式都还不是非常完美。
Mysql的sharding也有其局限性。sharding之后的数据查询訪问以及统计都会有非常大的问题,mysql的sharding是解决share nothing的存储的一种分布式的方法,大体上分为垂直拆分和水平拆分。
能够横向拆分。能够纵向拆分。能够横向纵向拆分。还能够依照业务拆分。
6.1.1横向拆分
Mysql库里面的横向拆分是指,每个数据库实例里面都有非常多个db库。每个db库里面都有A表B表。比方db1库有A表B表,db2库里也有A表和B表,那么我们把db1、db2库的A表B表拆分出来,把一个库分成2个,就拆分成db1、db2、db3、db4,其中db1库和db2库放A表数据,db3库和db4库放B表的数据。db1、db2库里面仅仅有A表数据,db3、db4库里面仅仅有B表的数据。
打个比方。作为电商来说。每个库里面都有日志表和订单表,假如A表是日志表log表,B表是订单表Order表,一般说来写日志和写订单没有强关联性,我们能够讲A表日志表和B表订单表拆分出来。那么这个时候就做了一次横向的拆分工作。将A表日志表和B表订单表拆分开来放在不同的库,当然A表和B表所在的数据库名也能够保持一致(PS:在不同的实例里面),例如以下图所看到的:
PS:这样的拆分主要针对于不同的业务对表的影响不大,表之间的业务关联非常弱或者基本上没有业务关联。拆分的优点是不相关的数据表拆分到不同的实例里面,对数据库的容量扩展和性能提高的均衡来说,都是蛮有优点的。
6.1.2纵向拆分
把同一个实例上的不同的db库拆分出来,放入单独的不同实例中。
这样的拆分的适应场景和要求是db1和db2是没有多少业务联系的,相似6.1.2里面的A表和B表那样。假设你用到了跨库业务同一时候使用db1和db2的话,个人建议要又一次考虑下业务,又一次梳理下尽量把一个模块的表放在一个库里面,不要垮库操作。
这样的库纵向拆分里面。单独的库db1,表A和表B是强关联的。例如以下图所看到的:
PS:看到非常多使用mysql的人,总是把非常多没有业务关联性的表放在一个库里面,或者总是把非常多个的db库放在同一个实例里面,就像使用oracle那样就一个instance的概念而已。
Mysql的使用一大原则就是简单,尽量单一。简单的去使用mysql,库要严格的分开;表没有关系的,要严格拆分成库。
这样的话扩展我们的业务就非常方便简单了,仅仅须要把业务模块所在的db拆分出来。放入新的数据库server上就可以。
6.1.3 横向纵向拆分
有些刚起步的,開始为了高速出产品,就把所以的库全部的表都放在一个实例上,等业务发展后,就面临着数据拆分。这里就会把横向纵向拆分结合起来,一起实现,例如以下图所看到的:
跟水平拆分有点相似,可是有不同的地方。
比方一个供应商,可能整个站点上有10个供应商,一个站点上面每个供应商都有一定的量,并且供应商之间的数据量规模都差点儿相同的规模。那么这个时候就能够使用供应商的纬度来做拆分。
比方usern库中,a、b、c表都是强关联的,都有完整的业务逻辑存在。这里仅仅实用户(供应商)纬度是没有关联的。那这个时候就能够把数据以用户的纬度来进行拆分。
就是用户1和用户2各自都有一套完整的业务逻辑,并且彼此之间不关联。所以就能够把用户1和用户2数据拆分到不同的数据库实例上面。眼下非常多互联网公司或者游戏公司有非常多业务都是以用户纬度进行拆分的。比方qunaer、sohu game、sina等。
水平拆分相对要简单一些。可是难度偏大,会导致分布式的情况、跨数据的情况、跨事务的情况能够分为大概三类。1是历史数据和实时数据拆分,2是单库多表拆分,3是多库多表拆分。
6.2.1 实时数据历史数据的拆分和历史数据迁移是一样的逻辑,就是要将online库的数据迁移到listory的数据库里面。对于实时的读写来说,数据是放在online db库里面,对于时间较远的数据来说。是放在历史History DB记录库里面的,这里的历史库能够是mysql也能够是别的nosql库等。
6.2.2 单库多表拆分
主要不是解决容量问题,而是解决性能问题而扩展的,添加当前实例仅仅有一个DB。有一个大表。一个大表就把整个实例占满了,这个时候就不能拆分db了。由于仅仅有一个单表。这个时候我们就仅仅能拆表了,拆表的方式主要是解决性能问题,由于单个表越大,对于mysql来说遍历表的树形结构遍历数据会消耗很多其它的资源。有时候一个简单的查询就可能会引起整个db的非常多叶子节点都要变动。表的insert、update、delete操作都会引起差点儿全部节点的变更。此时操作量会非常大,操作的时候读写性能都会非常低,这个时候我们就能够考虑把大表拆分成多个小表,工作经历中是依照hash取模打散成16个小表。也有依照id主键/50取模打散到50个小表其中,下图实例是打散成2个小表。
6.2.3 多库多表拆分
在单库多表的基础上,假设单库空间资源已经不足以提供业务支撑的话,能够考虑多库多表的方式来做,攻克了空间问题和性能问题。只是会有一个问题就是跨库查询操作,查询就会有另外的策略。比方说加一个logic db层来实现跨库跨实例自己主动查询。简单例如以下图所看到的:
水平拆分原则:
-- a. 尽量均匀的拆分维度。
-- b. 尽量避免跨库事务。
-- c. 尽量避免跨库查询。
设计:
--a依据拆分维度,做mod进行数据表拆分,大部分都是取模的拆分机制,比方hash的16模原则等。
--b依据数据容量。划分数据库拆分
数据操作
--a跨事务操作:分布式事务,通过预写日志的方式来间接地实现。
--b跨库查询:数据汇总or消息服务
u 案例:
– 依照用户维度进行拆分成64个分库。1024个分表