NoSQL:在高并发场景下,数据库和NoSQL如何做到互补?

开发 前端
在性能方面,NoSQL数据库利用一些算法将磁盘上的随机写操作转换为顺序写,从而提升了写入性能。在某些场景下,如全文搜索功能,传统的关系型数据库无法有效支持,而需要借助NoSQL数据库的特性。

针对存储服务的优化,我们通常会着手两个方面:

1. 提升读写性能,特别是优化读取效率。因为我们的产品多数是读取频率高于写入频率的。例如,微信朋友圈、微博和淘宝等服务,它们的查询 QPS明显高于写入 QPS。

2. 加强存储系统的扩展性,以满足不断增长的数据存储需求。

NoSQL,No SQL?

NoSQL是一种非关系型数据库,与传统的关系型数据库有所不同。NoSQL数据库不使用SQL作为查询语言,而是提供了其他方式来操作数据。它们通常具有出色的横向扩展能力和高性能的读写操作,非常适合处理互联网项目中的大数据量和高并发访问的需求。因此,许多大型公司,如小米、微博和陌陌,都倾向于选择NoSQL数据库作为其处理高并发大容量数据的存储服务。

Redis、LevelDB等键值存储数据库,以其极高的读写性能而著称,通常在对性能有较高要求的场景下得到广泛应用。Hbase、Cassandra等列式存储数据库则以其以列为存储单位而闻名,特别适用于离线数据统计等场景。至于MongoDB、CouchDB等文档型数据库,其主要特点在于Schema Free,即数据表的字段可以灵活扩展,这使得它们在处理具有多变字段结构的数据,比如电商系统中的商品信息,更加简单和灵活

使用 NoSQL 提升写入性能

数据库系统通常使用传统的机械硬盘进行存储,而机械硬盘的访问方式主要有两种:随机IO和顺序IO。随机IO需要花费大量时间进行磁盘寻道,因此其读写效率通常比顺序IO低两到三个数量级。为了提升写入性能,需要尽量减少随机IO的发生。

以MySQL的InnoDB存储引擎为例,更新binlog、redo log、undo log等操作通常采用顺序IO,而更新datafile和索引文件则需要进行随机IO。尽管关系数据库进行了许多优化,比如先将写入数据存入内存,然后批量刷新到磁盘上,但随机IO仍然难以避免。

在InnoDB引擎中,索引通常采用B+树结构组织。由于MySQL的主键是聚簇索引,即数据和索引数据存储在一起,因此在数据插入或更新时需要找到合适的位置并写入特定位置,这就会引发随机IO。此外,一旦发生页分裂,就不可避免地会涉及数据的移动,进一步降低写入性能。

NoSQL 数据库是怎么解决这个问题的呢?

许多NoSQL数据库都采用基于LSM树的存储引擎,这种算法在性能上取得了很大突破,因此在这里我想深入探讨一下LSM树的工作原理。LSM树(Log-Structured Merge Tree)通过牺牲一定的读性能来实现高效的写入操作,因此像Hbase、Cassandra和LevelDB等数据库都采用了这种存储引擎。

LSM树的核心思想很简单:数据首先写入到一个称为MemTable的内存结构中,并按照写入的键(Key)进行排序。为了避免因机器掉电或重启而丢失MemTable中的数据,通常会通过Write Ahead Log的方式将数据备份到磁盘上。当MemTable累积到一定规模时,会将其刷新为一个新文件,我们称之为SSTable(Sorted String Table)。当SSTable数量达到一定阈值时,会将它们进行合并,以减少文件数量,因为SSTable都是有序的,所以合并速度非常快。

在进行LSM树的数据读取时,首先从MemTable中查找数据,如果未找到,则从SSTable中查找。由于数据是有序存储的,因此查询效率非常高。然而,由于数据被拆分成多个SSTable,读取效率可能低于B+树索引。

图片图片

提升扩展性

此外,在可扩展性方面,许多NoSQL数据库具有天然的优势。以您的垂直电商系统为例,您已经添加了评论系统,最初对系统的评估比较乐观,认为评论量级不会迅速增长,因此将数据库分成了8个库,每个库又分成了16张表。但是评论系统上线后,存储量迅速增长,您不得不将数据库进一步分割成更多的库和表,而数据也必须重新迁移到新的库表中,这个过程非常痛苦且容易出错。在这种情况下,您是否考虑过使用NoSQL数据库来彻底解决可扩展性问题呢?经过调查,您会发现NoSQL数据库在设计之初就考虑到了分布式和大数据存储的场景,比如像MongoDB就具备三个关键的扩展性特性。

另一个关键特性是Replica,也称为副本集。您可以将其视为主从复制,即通过将数据复制多份来确保在主节点故障时数据不会丢失。同时,副本还可以分担读请求。在副本中,主节点负责处理写请求,并将数据变更记录到oplog中(类似于binlog);从节点接收oplog后,会修改自身的数据以保持与主节点的一致性。一旦主节点故障,MongoDB将从从节点中选取一个节点作为主节点,继续提供写入数据的服务。

第二个特性是Shard,也称为分片,您可以将其视为分库分表,即根据某种规则将数据拆分成多份,存储在不同的机器上。MongoDB的Sharding特性通常需要三个角色来支持:Shard Server,实际存储数据的节点,是一个独立的Mongod进程;Config Server,也是一组Mongod进程,主要存储一些元信息,例如哪些分片存储了哪些数据等;最后是Route Server,它不实际存储数据,仅用作路由,从Config Server获取元信息后,将请求路由到正确的Shard Server。

图片图片

另外一个关键特性是负载均衡,即当MongoDB发现Shard之间数据分布不均匀时,会启动Balancer进程对数据进行重新分配,以确保不同Shard Server的数据尽可能均衡。当Shard Server的存储空间不足需要扩容时,数据会自动迁移到新的Shard Server上,从而减少了数据迁移和验证的成本。

在性能方面,NoSQL数据库利用一些算法将磁盘上的随机写操作转换为顺序写,从而提升了写入性能。在某些场景下,如全文搜索功能,传统的关系型数据库无法有效支持,而需要借助NoSQL数据库的特性。

就扩展性而言,NoSQL数据库天生支持分布式架构,具备数据冗余和数据分片的特性。这些特点使得NoSQL成为传统关系型数据库的有效补充。在选择NoSQL数据库时,需要深入了解各种组件的实现原理,并具备一定的运维经验。否则,盲目地引入新的NoSQL数据库可能导致故障无法解决,成为整个系统的负担。

我曾在以前的项目中使用Elasticsearch作为持久存储,支持社区的动态流功能。初期开发进展顺利,Elasticsearch提供了灵活高效的查询功能,业务功能得以快速迭代,代码也简洁易懂。然而,随着流量的增加,由于缺乏成熟的Elasticsearch运维能力,频繁出现故障。尤其是在高峰期,节点不稳定的问题更加突出。由于业务压力巨大,无法投入足够的人力和时间深入学习和理解Elasticsearch,最终不得不做出重大改动,回归熟悉的MySQL。因此,对于开源组件的使用,不应止步于简单的入门阶段,而应具备足够的运维能力。

责任编辑:武晓燕 来源: 二进制跳动
相关推荐

2024-02-02 10:51:53

2024-03-28 09:00:00

NoSQL数据库

2015-10-22 15:09:12

NoSQL数据库应用场景

2013-02-27 10:23:55

NoSQL数据库

2019-07-23 11:41:45

数据库SQLDocker

2011-10-09 09:38:03

OracleNoSQL

2011-08-02 16:27:50

SQLNoSQL

2022-02-14 09:00:00

SQLNoSQL数据库

2020-09-21 06:53:41

NoSQL高并发面试

2021-09-28 09:25:05

NoSQL数据库列式数据库

2019-03-20 15:59:11

NoSQLRedis数据库

2019-07-08 10:36:34

数据库WebNoSQL

2010-04-01 09:45:38

NoSQL

2011-07-19 09:08:50

JavaNoSQL

2024-02-01 09:51:17

数据库缓存

2024-10-10 08:46:28

2017-05-18 08:14:48

NoSQL数据库场景

2010-10-12 10:58:13

NoSQL

2021-01-28 09:00:00

SQL数据库NoSQL

2011-05-16 10:29:44

HandlerSockNoSQL
点赞
收藏

51CTO技术栈公众号