什么是微服务
微服务就是一些可独立运行、可协同工作的小的服务。
从概念中我们可以提取三个关键词:可独立运行、可协同工作、小。这三个词高度概括了微服务的核心特性。下面我们就对这三个词作详细解释。
- 可独立运行
- 微服务是一个个可以独立开发、独立部署、独立运行的系统或者进程。
- 可协同工作
- 采用了微服务架构后,整个系统被拆分成多个微服务,这些服务之间往往不是完全独立的,在业务上存在一定的耦合,即一个服务可能需要使用另一个服务所提供的功能。这就是所谓的“可协同工作”。与单服务应用不同的是,多个微服务之间的调用时通过RPC通信来实现,而非单服务的本地调用,所以通信的成本相对要高一些,但带来的好处也是可观的。
- 小而美
- 微服务的思想是,将一个拥有复杂功能的庞大系统,按照业务功能,拆分成多个相互独立的子系统,这些子系统则被称为“微服务”。每个微服务只承担某一项职责,从而相对于单服务应用来说,微服务的体积是“小”的。小也就意味着每个服务承担的职责变少,根据单一职责原则,我们在系统设计时,要尽量使得每一项服务只承担一项职责,从而实现系统的“高内聚”
数据库的服务化切分
1.什么是”分库分表”?
随着微服务架构、分布式存储等概念的出现,数据存储问题也渐渐迎来了转机。而数据分片是目前解决海量数据持久化存储与高效查询的一种重要手段。数据分库分表的过程在系统设计阶段完成,要求系统设计人员根据系统预期的业务量,将未来可能出现瓶颈的数据库、数据表按照一定规则拆分成多个库、多张表。这些数据库和数据表需要部署在不同的服务器上,从而将数据读写压力分摊至集群中的各个节点,提升数据库整体处理能力,避免出现读写瓶颈的现象。
目前数据分片的方式一共有两种:离散分片和连续分片
离散分片是按照数据的某一字段哈希取模后进行分片存储。只要哈希算法选择得当,数据就会均匀地分布在不同的分片中,从而将读写压力平均分配给所有分片,整体上提升数据的读写能力。然而,离散存储要求数据之间有较强的独立性,但实际业务系统并非如此,不同分片之间的数据往往存在一定的关联性,因此在某些场景下需要跨分片连接查询。由于目前所有的关系型数据库出于安全性考虑,均不支持跨库连接。因此,跨库操作需要由数据分库分表中间件来完成,这极大影响数据的查询效率。此外,当数据存储能力出现瓶颈需要扩容时,离散分片规则需要将所有数据重新进行哈希取模运算,这无疑成为限制系统可扩展性的一个重要因素。虽然,一致性哈希能在一定程度上减少系统扩容时的数据迁移,但数据迁移问题仍然不可避免。对于一个已经上线运行的系统而言,系统停止对外服务进行数据迁移的代价太大。
第二种数据分片的方式即为连续分片,它能解决系统扩容时产生的数据迁移问题。这种方式要求数据按照时间或连续自增主键连续存储。从而一段时间内的数据或相邻主键的数据会被存储在同一个分片中。当需要增加分片时,不会影响现有的分片。因此,连续分片能解决扩容所带来的数据迁移问题。但是,数据的存储时间和读写频率往往呈正比,也就是大量的读写往往都集中在最新存储的那一部分数据,这就会导致热点问题,并不能起到分摊读写压力的初衷。
2.数据库的扩展
数据库扩展一共有四种分配方式,分别是:垂直分库、垂直分表、水平分表、水平数据分片。每一种策略都有各自的适用场景。
i.垂直分库
垂直分库即是将一个完整的数据库根据业务功能拆分成多个独立的数据库,这些数据库可以运行在不同的服务器上,从而提升数据库整体的数据读写性能。这种方式在微服务架构中非常常用。微服务架构的核心思想是将一个完整的应用按照业务功能拆分成多个可独立运行的子系统,这些子系统称为“微服务”,各个服务之间通过RPC接口通信,这样的结构使得系统耦合度更低、更易于扩展。垂直分库的理念与微服务的理念不谋而合,可以将原本完整的数据按照微服务拆分系统的方式,拆分成多个独立的数据库,使得每个微服务系统都有各自独立的数据库,从而可以避免单个数据库节点压力过大,影响系统的整体性能,如下图所示。
ii.垂直分表
垂直分表如果一张表的字段非常多,那么很有可能会引起数据的跨页存储,这会造成数据库额外的性能开销,而垂直分表可以解决这个问题。垂直分表就是将一张表中不常用的字段拆分到另一张表中,从而保证第一章表中的字段较少,避免出现数据库跨页存储的问题,从而提升查询效率。而另一张表中的数据通过外键与第一张表进行关联,如下图所示。
iii.水平分表
如果一张表中的记录数过多(超过1000万条记录),那么会对数据库的读写性能产生较大的影响,虽然此时仍然能够正确地读写,但读写的速度已经到了业务无法忍受的地步,此时就需要使用水平分表来解决这个问题。水平分表是将一张含有很多记录数的表水平切分,拆分成几张结构相同的表。举个例子,假设一张订单表目前存储了2000万条订单的数据,导致数据读写效率极低。此时可以采用水平分表的方式,将订单表拆分成100张结构相同的订单表,分别叫做order_1、order_2……、order_100。然后可以根据订单所属用户的id进行哈希取模后均匀地存储在这100张表中,从而每张表中只存储了20万条订单记录,极大提升了订单的读写效率,如下图所示。 当然,如果拆分出来的表都存储在同一个数据库节点上,那么当请求量过大的时候,毕竟单台服务器的处理能力是有限的,数据库仍然会成为系统的瓶颈,所以为了解决这个问题,就出现了水平数据分片的解决方案。
iiii.水平分库分表
水平数据分片与数据分片区别在于:水平数据分片首先将数据表进行水平拆分,然后按照某一分片规则存储在多台数据库服务器上。从而将单库的压力分摊到了多库上,从而避免因为数据库硬件资源有限导致的数据库性能瓶颈,如下图所示。
3.引入分库分表中间件后面临的问题
跨库操作
在关系型数据库中,多张表之间往往存在关联,我们在开发过程中需要使用JOIN操作进行多表连接。但是当我们使用了分库分表模式后,由于数据库厂商处于安全考虑,不允许跨库JOIN操作,从而如果需要连接的两张表被分到不同的库中后,就无法使用SQL提供的JOIN关键字来实现表连接,我们可能需要在业务系统层面,通过多次SQL查询,完成数据的组装和拼接。这一方面会增加业务系统的复杂度,另一方面会增加业务系统的负载。 因此,当我们使用分库分表模式时,需要根据具体的业务场景,合理地设置分片策略、设置分片字段,这将会在本文的后续章节中介绍。
分布式事务
我们知道,数据库提供了事务的功能,以保证数据一致性。然而,这种事务只是针对单数据库而言的,数据库厂商并未提供跨库事务。因此,当我们使用了分库分表之后,就需要我们在业务系统层面实现分布式事务。 常用的分布式事务解决方案