MySQL是更好的NoSQL

本文解释了为什么使用MySQL作为key/value使用要优于相应的NoSQL数据库,并且提供了有关这样使用的相关指南。

以Wix网站为例,当有人点击一个会跳转到Wix网站的链接时,他的浏览器会发送一个Http请求到Wix服务器,如果这个请求是请求服务器上不同的子域名,比如user.wix.com/site,该服务器需要分析这个请求的网址,根据不同的子域名名称定位到相应的虚拟空间,这个过程需要key/value查询。

路由表是用来解决这个定位问题,一旦找到对应的站点,该站点对象就被加载使用,该站点可能有复杂的目录结构,比如包含两个子对象列表,每个列表中有很多服务,下图是这个站点案例示意图:


上图其实是一个数据库表模型图,routes是主表,Sites代表不同的虚拟空间网站内容,sub-obj-1..代表该网站内的不同服务内容。

当我们使用通常的关系数据库模型更新上述几个数据表时,我们需要使用事务机制更新多表,这样才能确保几个表的数据一致性,因此我们可能在每个表中设计序列主键 外键或对URL字段设立索引。但是会带来下面问题:
1. 锁限制了数据表的访问,当需要高吞吐量时,锁会降低我们的性能。
2. 执行一些SQL查询或join之类查询,会有一定的延迟。
3.序列主键(Serial key)实际是使用了锁机制,因此会影响写入的吞吐量。

这些都限制了MySQL的吞吐量和并发性,因此这些缺点,而且这个案例实际是需要一个key/va;ue,因而很多开发人员会使用NoSQL解决方案,NoSQL能提供更好的吞吐量和并发性,即使在稳定性 一致性和可用性上有所牺牲。

在Wix网站实现中创造性地使用MySQL作为一个key/value存储,能够表现出比上述通用数据模型更好的成绩,包括相对于大多数NoSQL数据库,也就是说,将MySQL作为NoSQL引擎使用,这样的系统有杰出的扩展性 高吞吐量和并发性以及低延迟。下面是这些表现数据:
1. 吞吐量是200,000RPM数量级
2.路由表有100,000,000条记录数据量级,10G的存储空间
3.站点site表有100,000,000 记录,200GB存储空间
4.读延迟是平均1.0-1.5毫秒(如果在一个数据中心是0.2-.03毫秒)

注意,相比于大多数key/value数据库,不管开源或者基于云的,1毫秒的延迟是相当令人震撼的,这是使用MySQL实现完成的啊。

下图是这个傲人实战成绩中的schema数据结构:



CREATE TABLE `routes` (
`route` varchar(255) NOT NULL,
`site_id` varchar(50) NOT NULL,
`last_update_date` bigint NOT NULL,
PRIMARY KEY (`key`),
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这个字段,包括sub-obj表,这里并没有使用序列键 serial key,而是使用了一个 varchar(50)作为主键类型,这是存储客户端应用程序中产生的GUID 值作为主键。

下面的查询能够获得高吞吐量和低延迟


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

这是根据主键查询,这种嵌套查询语法能够确保我们只要将查询SQL一次性就发送到数据库,实则是运行两条SQL查询。

这条查询显示平均是1毫秒的稳定性能,而更新是半事务的,无需使用事务机制,这是因为使用insert插入数据到site表,然后才进入route表,直至这两步完成之前,这条记录是不会被查询发现的,这样我们首先插入site表再插入route表,我们就能确保一个一致性的状态,即使在特殊情况下可能在site表中有孤儿数据,也就是site有而route表没有的数据记录。

使用MySQL作为NoSQL经验指南:
1. 不要使用事务机制,这会引入锁机制,使用应用程序内的事务机制。
2. 不要使用序列主键serial key. Serial key会引入锁和复杂的active-active配置.
3.使用应用程序客户端产生唯一键作为主键,可以使用GUID

当设计数据表结构用于优化读操作时,下面一些经验供参考:
1.不要规范化normalize.
2.只有需要索引的字段才设计为一个字段,如果一个字段不需要索引,将其合并到统一的blob/text类型字段中,比如JSON和XML。
3.不要使用外键
4.设计数据表结构能实现一行查询语句。
5.不要执行性能调整命令,这些性能调整命令会引入锁和downtime当机时间,使用活跃迁移(live migration)。

当查询数据时:
1.通过主键或index键查询记录。
2.不要使用join
3.不要使用聚合aggregation.
4.在另外备份上运行自己内部复杂查询(BI, data exploration, etc.),不要在主数据库上运行这些查询。

原文参考:
Scaling to 100M: MySQL is a Better NoSQL | Wix Eng

用法有些极端。。。。

我们是通过拆库和水平分表的方法来存储数据的,数据库仅支持根据主要字段来查询;其他复杂查询,通过将数据在es中建索引来实现
[该贴被tecentID83E67于2015-12-26 15:26修改过]

用法比较奇特。。
不过1ms 的稳定性还不错。
NOsql, 有时候不稳定,会出现100ms超时 。
比较麻烦的就是 过期清除策略不好实现。