本文解释了为什么使用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.),不要在主数据库上运行这些查询。
原文参考:
| Wix Eng