2.1.2 MongoDB
MongoDB是当前非常流行的文档型NoSQL数据库,因为其天然的Free Schema、高可用、Sharding等能力,被广泛应用在游戏、物流、IoT等领域。文档型数据库天然支持JSON数据类型,并提供如Aggregate等丰富的查询分析语言,可以更快地适应业务的发展与迭代。下面分两节来详细介绍MongoDB。
2.1.2.1 MongoDB介绍
MongoDB是目前业界流行的非关系型数据库之一,其天然具备分布式、高可用等特点,在使用上也易于扩展并具有丰富的功能。MongoDB是文档型数据库,它面向文档而不是面向行的概念,其采用更为灵活的“文档”模式,通过在文档中嵌入文档和数组,仅用一条记录就能够表现复杂的层次关系。MongoDB的设计采用横向扩展方式,面向文档的数据模型使它能很容易地在多台服务器之间进行数据分割。MongoDB能自动处理跨集群的数据和负载,自动重新分配文档,以及将用户请求路由到正确的机器上。同时MongoDB也支持多种索引,例如二级索引、唯一索引、复合索引、地理空间索引、TTL索引以及全文索引等,并能通过Aggregate来进行聚合分类、过滤等复杂操作。这些特性,使得MongoDB非常适合在游戏、社交、IoT等场景中使用。
表2-2中给出了MongoDB与RDBMS中常用概念的对应关系,方便大家能更快地理解MongoDB中文档、集合等概念。
表2-2 MongoDB与RDBMS中常用概念的对应关系
2.1.2.2 MongoDB部署形态
目前MongoDB主要有三种部署形态,即单节点、副本集和分片集群模式,阿里云MongoDB具有云上独有的Serverless部署模式,接下来我们将逐一进行介绍。
1. 单节点模式
单节点模式,顾名思义,只有一个服务节点,即Primary节点。单节点架构只有一个副本,无法提供高可用服务,当发生故障时,在极端情况下会造成服务不可用超过30分钟,因此强烈建议在生产环境中使用副本集架构。
2. 副本集模式
MongoDB副本集由一组Mongod实例(进程)组成,包含一个Primary节点和多个Secondary节点,MongoDB Driver(客户端)的所有数据都写入Primary节点,Secondary节点从Primary节点同步写入的数据,以保持副本集内所有成员存储相同的数据集,提供数据的高可用性,如图2-5所示。
图2-5 MongoDB副本集模式示意图
副本集通过replSetInitiate命令(或mongo shell的rs.initiate())进行初始化,初始化后各个成员之间开始发送心跳消息,并发起Primary选举操作,获得大多数成员投票支持的节点会成为Primary,其余节点成为Secondary。
除了Secondary节点,副本集中还有其他特殊的节点,如下所示。
Arbiter节点:Arbiter节点本身不存储数据,是非常轻量级的服务,只参与投票,不能被选为Primary,并且不从Primary节点同步数据。当副本集成员为偶数时,最好加入一个Arbiter节点,以提升节点集的可用性。很多公司都会选择Primary节点+Secondary节点+Arbiter节点的副本集部署架构,其带来的好处是既可以满足高可用的需要,又能降低节点存储和部署成本。
Priority0节点:Priority0节点的选举优先级(Priority)为0,不会被选为Primary。
Vote0节点:在MongoDB 3.0中,副本集成员最多有50个,参与Primary选举投票的成员最多有7个,其他成员(Vote0节点)的vote属性必须被设置为0,即不参与投票。
Hidden节点:Hidden节点不能被选为Primary(Priority为0),并且对Driver不可见,因为Hidden节点不会接受Driver的请求,使用Hidden节点可以做一些数据备份、离线计算的任务,不会影响副本集的服务。阿里云MongoDB副本集模式以及分片集群中的Shard副本集节点即采用此种部署模式,Hidden节点对用户不可见,通常备份也是在Hidden节点上进行的,备份不影响用户的正常读/写访问。
Delayed节点:Delayed节点必须是Hidden节点,并且其数据落后于Primary节点一段时间,具体的延迟时间可以设置。该部署模式相对较少使用,主要用于当错误或者无效的数据写入Primary节点时,可通过Delayed节点的数据来恢复到之前的时间点的场景中。
ReadOnly节点:只读节点,可被应用在没有写请求,但是有大量读请求的场景中,以释放Primary节点和Secondary节点的访问压力。阿里云MongoDB结合阿里巴巴集团和云上大客户的实际使用诉求,为了扩展Primary节点的读请求能力,MongoDB提供了具备独立连接地址的只读节点,适合独立系统直连访问,以缓解大量读请求给Primary节点造成的压力。在对数据库没有写请求,但是有大量读请求的应用场景中,数据库的主从节点可能难以承受读取压力,甚至对业务造成影响。为了分担主从节点的访问压力,我们可以根据业务情况创建一个或多个只读节点,来满足大量的数据库读取需求,提高应用的吞吐量,如图2-6所示。例如,在某个业务场景中,对数据库有更高的读取性能要求,如阅读类网站、订单查询系统等读多写少的场景或者有临时活动等突发业务需求,可以按需增删Secondary节点来弹性调整实例的读取性能。
图2-6 阿里云MongoDB多副本场景
3. 分片集群模式
MongoDB分片集群由Mongos、Shard和ConfigServer三个组件组成,如图2-7所示。Mongos节点负责将查询和写操作路由到对应的Shard节点中;Shard节点负责存储与计算,可以通过增加Shard节点的方式来横向扩展集群的数据存储和读/写并发能力,单个分片集群最多支持32个Shard节点;ConfigServer主要用于存储集群和Shard节点的元数据,即各Shard节点中包含哪些数据的信息。阿里云MongoDB分片集群中的ConfigServer采用副本集部署架构,由于ConfigServer不直接对外提供服务且不太可能存在性能瓶颈,所以其规格也无法改变(固定为1核2GB)。
图2-7 阿里云MongoDB分片集群模式示意图
通常,在存储容量受单机限制,即磁盘资源遭遇瓶颈,或者读/写能力受单机限制(读能力也可以通过在副本集里加Secondary节点来扩展),可能是CPU、内存或网卡等资源遭遇瓶颈,导致读/写能力无法扩展等场景下,我们会选择使用分片集群模式。
如何选择Shard key至关重要,在MongoDB 4.4版本中的Refinable Shard Keys特性出现之前,Shard key一旦设定后期是无法修改的,如果早期Shard key设置有问题,导致出现了Jumbo Chunk或者热点分片等情况,调整Shard key需要重新创建集合并迁移数据,这将是一个非常复杂的过程。目前MongoDB支持两种分片方式:范围分片和Hash分片。范围分片通常能很好地支持基于Shard key的范围查询,Hash分片通常能将写入均衡地分布到各个Shard上。然而,在一些场景中,这两种分片方式并不能满足业务的诉求。例如,某个Shard key的某个值的文档特别多,将导致单个Chunk特别大(即Jumbo Chunk),影响Chunk迁移及负载均衡,或者根据非Shard key进行的查询、更新操作都会变成scatter-gather查询,影响效率等。那么应该如何选择Shard key呢?建议在选择Shard key时应该考虑满足如下三个特性。
key分布足够离散(Sufficient Cardinality)。
写请求均匀分布(Evenly Distributed Write)。
尽量避免scatter-gather查询(Targeted Read)。
上面提到,如果Shard key选择不当的话,其中一个潜在的危害是出现Jumbo Chunk。那么,什么是Jumbo Chunk呢?MongoDB默认的chunk size值为64MB,如果Chunk的大小超过64MB并且不能分裂(比如所有文档的Shard key都相同),那么它会被标记为Jumbo Chunk,Balancer不会迁移这样的Chunk,从而可能导致负载不均衡,所以应尽量避免出现Jumbo Chunk。
如果出现了Jumbo Chunk该怎么办呢?在通常情况下,如果Jumbo Chunk的出现没有导致严重的分片倾斜或者影响使用的话,则可以考虑忽略;如果一定要处理,则可以参考官方的处理方法,大致思路是:
尝试对Jumbo Chunk进行分裂(Spilt),如果能成功分裂,则Chunk的Jumbo标记会被自动清除。
对于不可再分裂的Chunk,如果该Chunk已不再是Jumbo Chunk,则可以尝试手动清除Chunk的Jumbo标记(注意先备份config数据库,以免误操作导致config数据库损坏)。
调大chunk size的值,当Chunk的大小不再超过chunk size的值时,Jumbo标记最终会被清理。但是这个方法治标不治本,随着数据的写入仍然会出现Jumbo Chunk,根本的解决方法还是合理地规划Shard key。
4. 阿里云MongoDB Serverless架构
Serverless架构是阿里云MongoDB特有的一种部署架构,这种架构主要用于初学者学习或者调研等目的,其优势是开箱即用、按量计费,通过租户ID(TenantID)和命名空间(Namespace)的方式在Mongos层面实现数据的逻辑隔离,如图2-8所示。
图2-8 阿里云MongoDB Serverless架构
在创建实例后,系统会在VPC中为用户申请虚拟IP地址(VIP),并使用该虚拟IP地址随机绑定代理资源池内固定的两个Mongos节点,在提供服务时,仅连接其中一个Mongos节点,当该Mongos节点发生故障无法访问时,系统会自动切换到另一个Mongos节点,同时故障节点会被自动修复挂起备用,以保证服务的高可用。