微服务架构的数据库为什么喜欢分库分表?

网站建设3年前发布
48 0 0

微服务架构想必大家都是有所耳闻。,简单来说,微服务架构就是把传统的一个单体应用以一套"小服务"的方式进行开发,这些"小服务"可以运行在不同机器上,它们在自己的进程中运行,"小服务"之间可以通过像是 HTTP API 这样的轻量级的机制进行通信,这些"小服务"紧紧围绕项目的业务需求开发,同时,它们是以业务边界进行划分成独立的微服务。这些微服务看似独立又像是一个整体,构成了一个业务集群。,微服务架构从业务逻辑实现的角度上看系统的性能得到了优化,可是对数据库的负担就加重了。假设一个分布式电子商务系统,那么这个系统会包含会员信息、订单信息、商品信息、商品库存信息等等内容,数据存放在数据库中,要访问数据,就要与数据库建立连接,而数据库的连接是有限的,况且在这样的业务环境下,会出现较多的高并发场景,如果都同时向这个商城数据库访问数据,数据库显然是受不起这样的折腾。如图:,上文提到,微服务是以业务边界进行划分的,那么这些服务就可以使用不同的编程语言书写,以及不同数据存储技术,前提是保持最低限度的集中式管理。也就是说,各个微服务处理的数据可以达到自治。,因此,为了处理高并发,设计数据库就可以采取分库的方式进行,使得各个微服务拥有自己独立的数据库,就好比订单微服务自治订单信息、支付流水信息、退款信息等等,当订单微服务需要会员微服务的会员数据时,可以通过服务的通讯机制,比如feign,以此达到分担传统模式压力的效果,如图:,同时,对于每一个划分好的库也可以再进行分库部署,划分出的库拥有相同的表,不同的只有存放的数据集。它可以有效的缓解单机单库的性能瓶颈和压力随着需求的细化,项目的业务量是庞大的,这也导致项目的数据量是庞大的,数据库分库部署可以有效减轻磁盘负担。如图:,微服务开发中,我们经常会遇到大表的情况,所谓大表是指存储了百万级乃至千万级条记录的表,这样的表数据过于庞大,导致数据库在查询和插入的时候耗时太长,就算使用索引,在大量的数据面前,查询的效率也会有所降低,更何况是使用不到索引的情况,下边列举一些使用不到索引的情况:,分表是对表进行分区,最主要的目的就是减轻数据库的负担,提高数据库的效率。表分区是根据一定的规则,把数据库的一张表分解为多个更小的表,使用分区的表从逻辑上看还是一个表,但物理存储分为了多份,表分区后的每个部分,都可以独立的进行数据处理,分区具有以下好处:,分区是将数据分段划分在多个位置存放,可以是同一块磁盘也可以在不同的机器。表分区有很多的策略,根据不同的策略可以适应多种业务场景,例如可以通过表内属性值的范围进行分表,如下图,将商城支付流水表以流水时间进行划分:,表在分区后,表面上还是一张表,但数据散列到多个位置了。应用程序读写的时候操作的还是大表的表名,数据库系统自动去组织分区的数据。 使用分区需要注意:,MySQL 8.0版本前支持创建表分区的存储引擎有InnoDB、Memory、MyISAM、MERGE,MySQL 8.0之后就只支持InnoDB存储引擎了,分区表必须一致,即同一张表分区后,各个分区表必须使用一致的存储引擎,表分区可在创建数据库表的时候进行指定,格式如下:,上文提到表分区有不同策略,也可以称为不同类型:,RANGE分区是基于一个给定连续区间范围,区间之间的不能互相重叠,数据会根据范围,分配到不同的分区,RANGE的分区键必须是单列的int类型,每个分区范围必须按顺序(后一个分区范围值比前一个值大)。 假设指定一表为RANGE分区,分4个区,最后一个区为了防止数据定义问题,将其设置为数值最大值“MAXVALUE”:,LIST分区的分区键的类型也只能是int类型,LIST分区是基于枚举值列表进行分区,枚举的范围同样不能有重复的值,如果插入数据不在枚举范围之内,则会报错。,COLUMNS分区区别于RANGE分区和LIST分区的最大特点是支持多列的分区,COLUMNS分区有两种形式,RANGE COLUMNS和LIST COLUMNS分区。两种分区形式都支持整数类型,日期类型,字符类型,区别在于,如果COLUMNS分区的分区键有多个,当数据库要进行数据插入时,会先考虑第一个键是否满足,如果满足条件就会进行数据写入,如果不满足条件就要对第二个键的条件进行判断,以此类推。,HASH分区主要用于将一整个数据,分散为若干个相等数量的分区,HASH分区有两种类型:,(1)常规HASH分区,使用的是取模运算。假设分区数为4,则有0,1,2,3四个值,对应分区为四个。因为使用的取模运算,所以分区键必须是整数类型的列或返回整数类型的表达式:,(2)线性HASH分区,其语法书写不同于常规HASH分区,需要加上LINEAR关键字。在数据分配的时候,使用的是2的幂运算进行分配数据的配分有两步运算:,KEY分区有与HASH分区类似,不同的地方有以下几点:,子分区是对分区表的每个区分,进行二次的分区,使用RANGE和LIST对表进行分区,则可以使用HASH或KEY进行子分区,假设表有2个分区,这2个分区又被进一步的分为2个子分区,总共有4个分区,写法有两种:,使用RANGE策略进行表分区的好处在于分区后数据的扩容性好,不需要进行数据迁移,如果插入的数据超过原先建立分区的范围可以根据实际情况考虑在原有基础上增加表分区或者水平部署一张相同的表进行存放数据,增加表分区可参考以下格式:,需要注意的是表在RANGE分区的时候指定的分区键需要考虑实际情况,如果使用不当会造成个别分区数据过多的情况。,假设一个电子商务系统需要存放订单的相关信息,用户进行商品购买则产生订单,订单往往包含多个不同商品,可以设置订单项表用于存放订单的每个商品id、商品名、价格、数量等数据,如果以商品id作为分区键则会产生"数据热点"问题,有些商品销量好,那么分区的数据就多,一些商品销量不好那么数据就会很少。,使用HASH策略的好处就在于解决数据热点问题,但是,HASH表分区的分区数量是固定的,如果数据过多达到了瓶颈,就要将分区数量进行修改了,因此原先已经存放的数据又要进行取模运算重新存放,需要进行数据迁移,语法如下:,当MySQL表分区遇到NULL值,MySQL不会禁止分区键有NULL值,但不同的分区类型会将NULL值当成不同的数据对待,如:,在RANGE分区中,NULL值被当成最小的数。,在LIST分区中,NULL被当成字符串,如果NULL不在LIST的枚举范围中,还有出现报错,在HASH和KEY中,NULL值被当成0 所以,在使用分区时,要注意处理NULL值输入,以免出现MySQL的误判,将分区键设为NOT NULL或默认值都可以好的对应这种情况。,本文介绍了为什么微服务架构大多采用分库分表的方式进行设计数据库,当然,分布式系统在设计过程中进行分库分表还需要注意一些问题,比如,在我们创建数据库表的时候是否可以先考虑表内数据的特性,事先将一些不经常需要更改的内容抽离出来,形成一张新的表,从某种程度上说,这种方式也是一种"分表"的操作。,同时,在进行分库在涉及事务安全性的时候也需要注意,比如商城中用户提交了订单,那么系统就需要对所购买商品的库存进行锁定,如果出现用户未支付订单超时等问题,就需要将已经锁定的库存进行数据回滚了,可是订单和库存在不同的数据,要如何保证事务的原子性呢?如果都在本地部署,可以使用AOP对事务进行代理,在不同机器部署的情况下也可以通过设置undo_log表并通过阿里的Seata进行代理。但是在高并发情况下,这些方式容易造成"雪崩",这个时候还可以考虑消息队列,通过延迟队列来完成库存的解锁。

© 版权声明

相关文章