MySQL 作为新的 NoSQL 解决方案: 轻松应对亿级数据

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: MySQL现在是一个更好的NoSQL解决方案。我们这样说是因为在存储 键/值(key/value) 之类数据时, MySQL 具有性能、易用性和稳定性方面的优势。MySQL引擎稳定可靠,并且社区和官方支持良好,有非常丰富的在线资料, 涵盖了各种操作、故障排查,复制以及各种使用模式等方面。

MySQL现在是一个更好的NoSQL解决方案。我们这样说是因为在存储 键/值(key/value) 之类数据时, MySQL 具有性能、易用性和稳定性方面的优势。MySQL引擎稳定可靠,并且社区和官方支持良好,有非常丰富的在线资料, 涵盖了各种操作、故障排查,复制以及各种使用模式等方面。基于这个原因, MySQL比起新兴的NoSQL引擎具有很大优势。

近年来,NoSQL引擎已成为主流。许多开发者将NoSQL引擎(包括: MongoDB, Cassandra, Redis, 和 Hadoop等)视为最优解,同时不赞成使用旧的 SQL 引擎。

选择NoSQL数据库通常是因为炒作,或者是认为关系数据库解决不了和NoSQL相关的事。普通工程师在选择数据库时往往会忽视运营成本,稳定性和成熟度等问题。更多关于各种NoSQL(以及SQL)引擎的区别,以及局限性等方面的问题,请参考 Aphyr 上的 Jepsen专栏文章

本文将阐释为什么用MySQL存储 键/值 数据比大多数专用NoSQL引擎更适合的原因,并提供相应的指导步骤。

Wix 网站的解决方案

当用户访问Wix上的某个网站页面时, 浏览器会向Wix网站服务器发送一个HTTP请求。不管是自定义域名(例如, cncounter.com)还是免费的Wix二级域名(如: user.wix.com/site)。服务器需要通过查询键/值对来将URL请求解析为相应的站点。在下面的讨论中我们将URL视为 route(路由)。

routes 表用来将网址解析为 site 对象。因为网站可能有多个路由, 所以是多对一的关系(many to one, N:1)。找到网站以后, 程序就加载它。site 对象机构比较复杂, 包括两个子对象列表 —— 网站使用的不同服务。下面是示例对象模型, 假设使用标准SQL数据库和规范化表结构:

当更新 site时, 如果使用传统的范式模型来更新多个表, 需要用事务(transaction)来保证数据的一致性(data consistency)。(注意,事务使用数据库级别的锁(DB-level lock),这会阻止并发写操作,有时也会影响相关表的并发读操作。) 使用这种模型, 可能需要在每个表中设置一个序列键(serial key),并使用外键,以及为 routes 表的 URL 字段创建索引。

但是,使用范式设计会碰到很多问题:

  • 锁限制了对表的访问, 所以在高吞吐量情景下会严重影响性能。
  • 读取一个对象需要使用多条SQL语句(此处是4条), 或者使用 join (这又会受延迟影响)。
  • 系列键的生成使用了锁, 限制了写吞吐量。

在MySQL或者其他SQL引擎中, 并发情况和吞吐量问题都是大量出现的。因为这些缺点,实际上在存储 键/值对形式的数据时,很多开发者都倾向于使用 NoSQL 解决方案, 为了提供更好的吞吐量和并发性能, 而牺牲一些 稳定性(stability)、一致性(consistency)、和可用性(availability)。

在 Wix, 我们发现 MySQL 作为键/值存储使用时,比起作为关系数据模型时要强悍得多, 也比大多数NoSQL引擎要优秀很多。仅仅是使用MySQL作为NoSQL引擎,我们的现有系统在扩展性/吞吐量/并发/延迟等指标上都可以媲美任何NoSQL引擎。下面是一些数据:

  • 跨三个数据中心的结构 (active-active-active setup, 三活)。
  • 吞吐量在 200,000 RPM 数量级。
  • routes 表的记录在 1亿 数量级, 占用空间为 10 GB级。
  • sites 表的记录在 1亿数量级,存储空间 200 GB以上。
  • 平均读取延迟在 1.0 -1.5毫秒之间(事实上,同一数据中心是 0.2 - 0.3 毫秒)。

请注意,在大多数 键/值 引擎中, 1.0 毫秒左右的延迟都是卓越的,包括开源的和基于云的! 而我们是用MySQL实现的(MySQL被认为是标准的SQL引擎)。

表结构如下:

CREATE TABLE `routes` (
  `route` varchar(255) NOT NULL,
  `site_id` varchar(50) NOT NULL,
  `last_update_date` bigint NOT NULL,
  PRIMARY KEY (`route`),
  KEY (`site_id`)
)

CREATE TABLE `sites` (
  `site_id` varchar(50) NOT NULL,
  `owner_id` varchar(50) NOT NULL,
  `schema_version` varchar(10) NOT NULL DEFAULT '1.0',
  `site_data` text NOT NULL,
  `last_update_date` bigint NOT NULL,
  PRIMARY KEY (`site_id`)
) /*ENGINE=InnoDB DEFAULT CHARSET=utf8 
    ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=16*/;

所有不需要作为查询条件的字段都已经合并到单个 blob 字段中(site_data text 字段)。其中包含了 sub-obj 记录,以及 site 对象自身的其他属性域。也请注意,这里没有使用自增序列键;相反,我们使用 varchar(50) 来存储客户端生成的 GUID 值。

下面是我们使用的查询语句, 具有高吞吐量和低延迟特性:

select * from sites where site_id = (
  select site_id from routes where route = ?
)

首先通过唯一索引查询 routes 表,这只返回一个结果。然后通过主键查找 site, 也只有一条记录。嵌套查询语法确保 2个SQL查询却只需一次数据库交互。

结果前面提到了, 在高流量和高更新率的情况下, 保持在平均 ~1毫秒左右 的性能。虽然没有使用事务,但 update 是半事务性质的(semi-transactional)。这是因为, 先输入一个 site, 但在输入 route 记录之前,都不会查询到相关的记录。所以如果我们先输入 site, 再输入 route, 依然能确保数据一致性状态, 即使在 sites 表中有很多孤儿数据的情况下。

MySQL当做 NoSQL引擎使用指南

通过上面的例子(以及Wix的其他类似情景), 我们精心制作了一份用MySQL作为NoSQL引擎的经验指南。

最主要的是要记住, 使用MySQL作为NoSQL引擎时要避免数据库锁(DB locks)以及复杂的查询

  • 不使用事务,因为会导致锁(locks)。相反, 应该使用应用层事务(applicative transactions)。
  • 不使用序列键(serial key)。序列键会导致锁以及引起复杂的 active-active 配置。
  • 使用客户端生成的唯一键(client-generated unique keys)。我们使用的是 GUID。

设计数据库时,进行查询优化时还有如下要点:

  • 不要使用范式(Do not normalize)。
  • 只存储有索引的字段。如果某个字段不需要索引, 那么将其存储在 blob/text 字段中(如JSON或XML)。
  • 不要使用外键(foreign key)。
  • 必须允许读取单行数据。
  • 不准执行 alter 命令。表的 alter 命令会导致锁以及宕机。如果不得不这样做, 应该使用动态迁移(live migrations)。

在查询数据时:

  • 使用主键(primary key)和索引(index)作为条件来查询.
  • 不要使用 join.
  • 不要使用聚合函数(aggregation).
  • 只在副本(replica)中执行繁重的查询(housekeeping queries), 比如商业智能(BI), 数据研究(data exploration)等操作, 尽量不要在主库(master database)上执行.

我们准备在另一篇博客中深入介绍实时迁移(live migrations)和应用层事务(applicative transactions)。

总结

本文最主要的目的是让你认识 MySQL 的新特性。将 MySQL 作为NoSQL引擎是很棒的, 虽然MySQL不是专为NoSQL设计的。文中展示了如何使用 MySQL 代替专用 NoSQL引擎来存储 键/值(key/value) 信息。

在 Wix , 保存键/值信息(等情况下)会选择MySQL引擎, 原因是其易于使用和操作, 并且MySQL强大的生态系统。另外,比起多数NoSQL引擎来说,在延迟(latency)、吞吐量(throughput)和并发性(concurrency)等指标(metrics)上MySQL并不逊色。

原文链接: http://engineering.wix.com/2015/12/10/scaling-to-100m-mysql-is-a-better-nosql/

原文日前: 2015年12月10日

翻译日期: 2015年12月27日

作者: 铁锚 http://blog.csdn.net/renfufei



相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
9天前
|
缓存 NoSQL 关系型数据库
13- Redis和Mysql如何保证数据⼀致?
该内容讨论了保证Redis和MySQL数据一致性的几种策略。首先提到的两种方法存在不一致风险:先更新MySQL再更新Redis,或先删Redis再更新MySQL。第三种方案是通过MQ异步同步以达到最终一致性,适用于一致性要求较高的场景。项目中根据不同业务需求选择不同方案,如对一致性要求不高的情况不做处理,时效性数据设置过期时间,高一致性需求则使用MQ确保同步,最严格的情况可能涉及分布式事务(如Seata的TCC模式)。
35 6
|
16天前
|
SQL 关系型数据库 MySQL
轻松入门MySQL:保障数据完整性,MySQL事务在进销存管理系统中的应用(12)
轻松入门MySQL:保障数据完整性,MySQL事务在进销存管理系统中的应用(12)
|
21天前
|
缓存 NoSQL 关系型数据库
在Python Web开发过程中:数据库与缓存,MySQL和NoSQL数据库的主要差异是什么?
MySQL是关系型DB,依赖预定义的表格结构,适合结构化数据和复杂查询,但扩展性有限。NoSQL提供灵活的非结构化数据存储(如JSON),无统一查询语言,但能横向扩展,适用于大规模、高并发场景。选择取决于应用需求和扩展策略。
112 1
|
23天前
|
关系型数据库 MySQL
elasticsearch对比mysql以及使用工具同步mysql数据全量增量
elasticsearch对比mysql以及使用工具同步mysql数据全量增量
20 0
|
25天前
Mybatis+mysql动态分页查询数据案例——测试类HouseDaoMybatisImplTest)
Mybatis+mysql动态分页查询数据案例——测试类HouseDaoMybatisImplTest)
20 1
|
25天前
Mybatis+mysql动态分页查询数据案例——房屋信息的实现类(HouseDaoMybatisImpl)
Mybatis+mysql动态分页查询数据案例——房屋信息的实现类(HouseDaoMybatisImpl)
21 2
|
25天前
Mybatis+mysql动态分页查询数据案例——工具类(MybatisUtil.java)
Mybatis+mysql动态分页查询数据案例——工具类(MybatisUtil.java)
15 1
|
22天前
|
关系型数据库 MySQL
MySQL查询当天昨天明天本月上月今年等数据
MySQL查询当天昨天明天本月上月今年等数据
19 2
|
25天前
|
Java 数据库连接 mybatis
Mybatis+mysql动态分页查询数据案例——Mybatis的配置文件(mybatis-config.xml)
Mybatis+mysql动态分页查询数据案例——Mybatis的配置文件(mybatis-config.xml)
14 1
|
25天前
Mybatis+mysql动态分页查询数据案例——配置映射文件(HouseDaoMapper.xml)
Mybatis+mysql动态分页查询数据案例——配置映射文件(HouseDaoMapper.xml)
14 1

推荐镜像

更多