本文翻译自High Scalability的What the heck are you actually using NoSQL for?
引言
我们常说应该为工作选择合适的工具。这一点无人能反驳。但问题是,这种建议在没有回答更具体的问题时并不实用,比如:这些工具擅长处理哪些任务?它们能解决像我这样的问题吗?当我的团队已经熟悉其他工具,并且我们面临紧迫的截止日期时,尝试新工具是否值得冒险?如何让所有这些工具协同工作?
在NoSQL领域,这种实际应用的数据仍然有些模糊。当被问及时,供应商往往给出非常笼统的答案,比如NoSQL适合处理大数据或键值访问。但对于那些身处一线、需要解决具体问题的开发者来说,面对众多令人困惑的选择,这些答案并没有太大帮助。很多时候,很难想象他们的具体问题如何以一种值得冒险和投入的方式得到解决。
让我们改变这一点。你正在用NoSQL解决哪些问题?你使用的是哪种产品?它是如何帮助你的?是的,这是我为12月14日的网络研讨会所做的研究的一部分,但我坚信人们通过实例学习效果最佳。因此,如果我们能提供具体的例子,我相信这将帮助人们更好地理解如何在自己的系统中充分利用这些新产品选择。
以下是我在浏览网络后整理出的一些使用案例。由于来源非常多样,我无法逐一注明,我会在帖子末尾列出参考文献。请随时添加你自己的案例。我将一些特定产品的使用案例单独列出,仅仅是因为我收集到了许多关于它们的案例,将它们单独列出会更加清晰。这并不意味着对任何产品的推荐。以下是一个NoSQL产品的总列表。如果你愿意为某个产品提供一组具体的使用案例,我将非常乐意将其添加进来。
通用案例
以下是一些人们通常提到的使用NoSQL的原因。这些原因可能并不令人惊讶,但它们确实反映了NoSQL的核心优势。
- 大规模数据处理 NoSQL被视为支持新数据堆栈的关键部分,适用于:大数据、大量用户、大量计算机、大型供应链、大型科学项目等。当某些事物变得如此庞大以至于必须进行大规模分布式处理时,NoSQL就派上了用场。不过,并非所有NoSQL系统都针对大规模数据处理。这里的“大规模”可以体现在多个维度,而不仅仅是占用大量磁盘空间。
- 高写入性能 这可能是基于Google影响力的典型用例。例如,Facebook需要每月存储1350亿条消息,而Twitter每天需要存储7TB的数据,并且这一需求每年可能会翻倍多次。这是“数据太大,无法存储在单个节点上”的问题。以80MB/s的速度存储7TB数据需要一天时间,因此写入操作需要在集群中分布,这意味着需要键值访问、MapReduce、复制、容错、一致性等问题。为了更快的写入速度,可以使用内存系统。
- 快速的键值访问 这可能是NoSQL在普遍认知中的第二大优势。当延迟很重要时,很难击败基于键的哈希并从内存中直接读取值或通过尽可能少的磁盘寻址读取数据。并非所有NoSQL产品都专注于快速访问,有些更注重可靠性。但长期以来,人们一直想要一个更好的memcached,而许多NoSQL系统提供了这一点。
- 灵活的schema和数据类型 NoSQL产品支持各种新的数据类型,这是NoSQL创新的一个重要领域。包括:列式存储、图数据库、高级数据结构、文档存储和键值存储。复杂对象可以轻松存储,而无需大量映射。开发人员喜欢避免复杂的schema和ORM框架。缺乏结构允许更大的灵活性。此外,NoSQL还支持对程序员友好的数据类型,如JSON。
- schema迁移 无schema设计使得处理schema迁移更加容易,无需过多担心。schema在某种意义上是动态的,因为它们由应用程序在运行时定义,因此应用程序的不同部分可以有不同的schema视图。
- 写入可用性 无论发生什么,写入操作是否都必须成功?如果是这样,我们可以深入探讨分区、CAP定理、最终一致性等问题。
- 更易维护、管理和操作 这一点非常依赖于具体产品,但许多NoSQL供应商正试图通过简化开发人员的采用来获得市场份额。他们在易用性、最小化管理和自动化操作方面投入了大量精力。这可以降低运营成本,因为无需编写特殊代码来扩展一个原本并非为此设计的系统。
- 无单点故障
并非所有产品都实现了这一点,但我们看到一种明显的趋势,即相对容易配置和管理的高可用性,具有自动负载平衡和集群大小调整功能。这是云的完美搭档。 - 普遍可用的并行计算
我们看到MapReduce被内置到产品中,这使得并行计算成为未来开发的常规部分。 - 开发人员易用性
访问数据应该很容易。虽然关系模型对最终用户(如会计师)来说很直观,但对开发人员来说并不直观。程序员理解键、值、JSON、JavaScript存储过程、HTTP等。NoSQL是为程序员设计的。这是由开发人员主导的变革。解决数据库问题的答案不能总是雇佣一个非常专业的DBA、优化schema、稍微反规范化等,程序员更倾向于一个他们可以自己掌控的系统。让产品表现良好不应该如此困难。成本也是一个问题。如果扩展产品的成本很高,你难道不会选择更便宜、更易控制、更易使用且更易扩展的产品吗? - 为正确的问题选择正确的数据模型
不同的数据模型用于解决不同的问题。例如,人们曾花费大量精力试图将图操作塞入关系模型,但这并不奏效。在图数据库中解决图问题不是更好吗?我们现在看到一种通用策略,即尝试在问题和解决方案之间找到最佳匹配。 - 避免碰壁 许多项目在开发过程中会遇到某种瓶颈。他们已经用尽了所有方法来使系统扩展或正常运行,并想知道接下来该怎么办?选择一种可以通过逐步增加资源线性扩展的产品和方法是一种令人安心的选择。曾经这是不可能的,需要定制一切,但现在情况已经改变。我们看到现成的产品,项目可以轻松采用。
- 分布式系统支持 并非每个人都担心超越非NoSQL系统所能实现的规模或性能。他们需要的是一种可以跨数据中心运行并在故障情况下无缝处理的分布式系统。NoSQL系统由于专注于扩展,往往利用分区,往往不使用严格的一致性协议,因此在分布式场景中表现良好。
- 可调的CAP权衡 NoSQL系统通常是唯一提供“滑块”的产品,允许用户选择在CAP频谱上的位置。关系数据库选择强一致性,这意味着它们无法容忍分区故障。最终,这是一个业务决策,应根据具体情况决定。你的应用程序是否关心一致性?偶尔丢失一些数据是否可以?你的应用程序需要强一致性还是弱一致性?可用性更重要还是一致性更重要?宕机的成本是否比出错更高?拥有可以让你选择的产品是件好事。
更具体的使用案例
以下是一些更具体的NoSQL使用场景,展示了其在解决特定问题时的独特优势。
- 管理大规模非事务性数据流
- 例如:Apache日志、应用程序日志、MySQL日志、点击流等。
- 在线和离线数据同步
- CouchDB在这一领域有特定的应用场景。
- 在所有负载下实现快速响应
- 适用于需要高性能和低延迟的系统。
- 避免复杂连接操作
- 当复杂查询的连接负载对关系数据库(RDBMS)来说过大时,NoSQL可以避免繁重的连接操作。
- 软实时系统
- 低延迟至关重要,例如游戏。
- 支持多种读写、查询和一致性模式
- 有些系统针对50%读50%写、95%写或95%读进行了优化。
- 只读应用需要极速和弹性,简单查询,并能容忍稍微过时的数据。
- 需要中等性能、读写访问、简单查询和完全权威数据的应用。
- 只读应用但需要复杂查询的场景。
- 负载均衡
- 适应数据和使用的集中,并帮助保持微处理器的忙碌。
- 实时插入、更新和查询
- 适用于需要实时处理数据的场景。
- 例如:线程化讨论和零件分解。
- 动态表创建
- 支持动态创建表结构,适应灵活的数据需求。
- 两层应用架构
- 通过快速NoSQL接口提供低延迟数据,而数据本身可以通过高延迟的Hadoop应用或其他低优先级应用计算和更新。
- 顺序数据读取
- 选择适合顺序读取的底层数据存储模型,例如B树可能不是最佳选择。
- 剥离需要更高性能/可扩展性的服务
- 例如:用户登录需要高性能,可以使用专用服务来满足这一需求。
- 缓存
- 为网站和其他应用提供高性能缓存层。例如:大型强子对撞机(LHC)使用的数据聚合系统缓存。
- 投票系统
- 支持高并发的投票操作。
- 实时页面浏览量计数器
- 实时更新和显示页面浏览量。
- 用户注册、配置文件和会话数据
- 高效存储和管理用户相关数据。
- 文档、目录和内容管理系统
- 通过存储复杂文档而非关系表来简化管理。类似逻辑适用于库存、购物车和其他结构化数据类型。
- 归档
- 存储大量持续的数据流,同时保持在线可访问性。文档型数据库的灵活 schema 可以处理随时间变化的 schema 变更。
- 分析
- 使用MapReduce、Hive或Pig执行分析查询,并支持高写入负载的扩展系统。
- 处理异构数据类型
- 例如:在通用级别处理不同的媒体类型。
- 嵌入式系统
- 不需要SQL和服务器的开销,使用更简单的存储方案。
- 市场游戏
- 例如:在游戏中快速显示某人的建筑列表。通过在建筑表的所有者列上进行分区,使查询单分区化。但当某人购买他人的建筑时,更新所有者列和价格。
- JPL使用SimpleDB存储火星车计划属性
- 引用存储在S3中的完整计划blob。
- 联邦执法机构实时跟踪美国人
- 使用信用卡、会员卡和旅行预订数据进行实时跟踪。
- 实时欺诈检测
- 通过将交易与已知模式进行比较来实时检测欺诈。
- 帮助诊断肿瘤类型
- 通过整合每位患者的历史数据来辅助诊断。
- 高更新频率的内存数据库
- 例如:显示每个人的“最后活跃时间”的网站(可能用于聊天)。如果用户每30秒执行一次活动,则大约5000个同时在线用户将达到系统极限。
- 处理低频多分区查询
- 使用物化视图处理低频查询,同时继续处理高频流数据。
- 优先级队列
- 支持优先级队列的实现。
- 对缓存数据运行计算
- 使用对程序员友好的接口,无需通过ORM。
- 去重大型数据集
- 使用简单的键值列进行去重。
- 汇总值以保持查询速度
- 将值汇总到不同的时间切片中。
- 计算两个大型集合的交集
- 当连接操作太慢时,使用NoSQL优化计算。
- 时间线(如Twitter)
- 高效存储和查询时间线数据。
Redis 使用案例
Redis 作为一种数据结构服务器,拥有许多令人兴奋的独特使用场景,以下是开发者和企业正在使用 Redis 解决的一些具体问题:
- 计算在线好友
使用集合(Sets)计算某个用户的好友中有哪些在线。 - 增强版 Memcached
Redis 可以作为 Memcached 的增强替代品,提供更丰富的功能和更高的性能。 - 分布式锁管理器
用于进程协调,确保分布式系统中的资源互斥访问。 - 全文倒排索引查找
支持高效的全文搜索和索引查找。 - 标签云(Tag Clouds)
使用集合或有序集合(Sorted Sets)生成和管理标签云。 - 排行榜
使用有序集合维护高分表或排行榜。 - 环形日志缓冲区
使用列表(Lists)实现环形日志缓冲区,记录系统活动。 - 大学课程可用性数据库
使用集合存储课程 ID,如果集合中包含某个课程 ID,则表示该课程有空位。数据被持续抓取和处理,涉及约 7200 门课程。 - 服务器会话存储
将会话数据存储在 Redis 中,适合存储随机生成的 Cookie 值及其关联的序列化数据。这些数据通常为每个访问者创建,即使他们只是偶然访问并离开。Redis 可以高效管理这些短期数据,避免占用关系数据库的宝贵空间。 - 实时统计计数器
使用原子递增的计数器提供实时统计数据。 - 轮询数据库
在键值存储中轮询数据的成本很低。如果数据分片,可以使用 Redis 集群作为中央查找服务,快速确定某个用户数据所在的分片。GitHub 使用 Redis 管理其多个仓库的分片。 - 临时数据存储
任何应用程序使用的临时数据都适合存储在 Redis 中,例如 CSRF 令牌或安全协议的握手数据。 - 快速且易于设置
Redis 设置简单,性能极高(在默认配置下,一台笔记本电脑上每秒可处理 30,000 次读写操作)。 - 进程间共享状态
在一个 Python 解释器中运行长时间批处理任务(例如将数百万行 CSV 数据加载到 Redis 键值查找表中),同时在另一个解释器中处理已收集的数据,即使第一个进程仍在流式传输数据。可以随时重启解释器而不会丢失数据。 - 生成热力图
例如,为《卫报》生成 BNP 成员列表的热力图。 - 与 Python 原生数据类型紧密映射
Redis 的语义与 Python 原生数据类型非常接近,开发者可以轻松表示数据。 - 实现简单有界日志
使用列表实现有界日志(类似于 MongoDB 的有界集合),将新项添加到日志尾部,并使用LTRIM只保留最后 X 项。适用于跟踪系统当前活动,而无需担心日志信息无限增长。 - 基于 Redis 构建的应用程序示例
例如,Hurl 是一个用于调试 HTTP 请求的工具,由 Leah Culver 和 Chris Wanstrath 在 48 小时内基于 Redis 构建。 - 替代 MySQL 存储键值对
当 MySQL 无法处理高负载时,Redis 可以作为写入缓存,替代 MySQL 存储状态、会话数据、计数器和小型列表等。 - 跟踪系统中所有已使用的 ID
使用集合跟踪系统中所有已使用的记录 ID。 - 从集合中随机选取一项
快速从集合中随机选择一个项目。 - API 限流
Redis 非常适合用于 API 限流,因为每次 API 调用都需要进行限流检查,涉及读写短期数据。 - A/B 测试
Redis 是 A/B 测试的完美选择,因为它需要实时跟踪用户行为,为每个用户导航操作写入数据,并存储短期持久状态。 - 实现收件箱方法
使用 Redis 实现收件箱方法:每个用户都有一个队列(如果担心内存不足,可以使用有界队列)作为收件箱,并使用集合跟踪关注他们的其他用户。例如,Ashton Kutcher 在 Twitter 上有超过 500 万粉丝,以每秒 10 万次写入的速度,不到一分钟即可将消息分发到所有收件箱。 - 发布/订阅模式
使用 Redis 的发布/订阅功能向数十万同时连接的用户广播更新(例如选举结果)。阻塞队列原语意味着无需轮询即可实现消息队列。 - 报告工作负载
让工作进程定期将其负载平均值报告到有序集合中。 - 重新分配负载
当需要分配任务时,从有序集合中获取负载最低的三个工作进程,并随机选择其中一个(以避免“惊群效应”)。 - 多地理信息系统(GIS)索引
支持多个地理信息系统索引。 - 基于关系的推荐引擎
使用 Redis 构建基于用户关系的推荐引擎。 - 物联网数据流
管理物联网设备的数据流。 - 社交图表示
使用 Redis 表示社交图,高效存储和查询用户关系。 - 动态 schema
无需预先设计 schema,通过在代码中动态添加属性和关系来构建数据模型,显著简化代码。 - 减少阻抗不匹配
Redis 的数据模型可以更紧密地匹配应用程序中的数据模型,减少数据库与应用程序之间的阻抗不匹配。
VoltDB使用案例
虽然 VoltDB 作为关系数据库并不传统地被归类为 NoSQL,但其激进的设计理念使其与 Oracle 等传统系统大相径庭,更接近 NoSQL 的传统。以下是一些 VoltDB 的具体使用场景:
- 金融交易监控
- 数据源:实时市场数据
- 分区键:市场符号(股票代码、CUSIP、SEDOL 等)
- 高频操作:写入和索引所有交易,存储报价数据(买价/卖价)
- 低频操作:基于 20 多个条件查找交易订单详情,显示某交易员在所有市场符号中的持仓
- Web 机器人漏洞扫描(SaaS 应用)
- 数据源:传入的 HTTP 请求
- 分区键:客户 URL
- 高频操作:命中日志记录、分析和警报
- 低频操作:漏洞检测、客户报告
- 在线游戏排行榜
- 数据源:在线游戏
- 分区键:游戏 ID
- 高频操作:基于定义的时间间隔和玩家个人最佳成绩排名
- 低频操作:排行榜查询
- 包裹追踪(物流)
- 数据源:传感器扫描
- 分区键:包裹 ID
- 高频操作:包裹位置更新
- 低频操作:包裹状态报告(包括历史记录)、丢失包裹追踪、包裹重新路由
- 广告内容投放
- 数据源:网站或设备,用户或规则触发
- 分区键:供应商/广告 ID 组合
- 高频操作:检查供应商余额、投放广告(目标设备格式)、更新供应商余额
- 低频操作:按设备报告实时广告展示和点击统计数据(供应商发起)
- 电话交换通话详单(CDR)管理
- 数据源:通话发起请求
- 分区键:主叫号码
- 高频操作:实时授权(基于套餐和余额)
- 低频操作:欺诈分析/检测
- 航空公司预订/票务
- 数据源:客户(网站)和航空公司(网站及内部系统)
- 分区键:客户(航班信息被复制)
- 高频操作:座位选择(租赁系统)、添加/删除座位、行李托运
- 低频操作:座位可用性/航班查询、航班时刻变更、航班取消后的乘客重新预订
数据分析使用案例
Twitter 的 Kevin Weil 在提供 Hadoop 使用案例方面非常出色。在 Twitter,这些案例包括使用标准计数、最小值、最大值和标准差对大数据进行计数;使用概率、协方差和影响力对大数据进行相关性分析;以及对大数据进行研究。Hadoop 虽然位于 NoSQL 的边缘,但了解它正在解决哪些问题非常有帮助。
- 我们每天处理多少请求?
- 平均延迟是多少?95% 的延迟是多少?
- 按响应代码分组:每小时的分布情况如何?
- 每天在 Twitter 上发生多少次搜索?
- 这些搜索来自哪里?
- 有多少独特的查询?
- 有多少独特的用户?
- 地理分布如何?
- 移动用户的用法有何不同?
- 第三方桌面客户端用户的用法有何不同?
- 队列分析:所有在同一天注册的用户——然后观察他们随时间的变化。
- 网站问题:哪些问题在同一时间发生?
- 哪些功能让用户上瘾?
- 成功用户经常使用哪些功能?
- 搜索纠正和建议(目前 Twitter 尚未实现,但未来可能会加入)。
- 我们可以从用户的推文中了解到什么?
- 我们可以从你关注的人的推文中了解到什么?
- 我们可以从你的关注者的推文中了解到什么?
- 我们可以从你的关注者/关注人数的比例中了解到什么?
- 哪些图结构会形成成功的网络?(Twitter 的图结构很有趣,因为它不是双向的)
- 哪些功能会让一条推文被转发?
- 当一条推文被转发时,相应的转发链有多深?
- 长期重复检测(短期用于滥用检测和阻止垃圾邮件发送者)。
- 机器学习。关于一开始并不完全知道该问什么问题。我们如何对用户进行聚类?
- 语言检测(联系移动运营商为用户获取 SMS 优惠——首先关注最受欢迎的国家)。
- 我们如何检测机器人和其他非人类推文发布者?
不适用的场景
尽管 NoSQL 在许多领域表现出色,但在某些特定场景下,传统的关系数据库(如 SQL)仍然是更好的选择。以下是一些 NoSQL 不太适用的场景:
- OLTP(在线事务处理)
除了 VoltDB 之外,大多数 NoSQL 系统不支持复杂的多对象事务。开发者通常需要反规范化、使用文档或其他复杂策略(如补偿事务)来实现类似功能。 - 数据完整性
大多数 NoSQL 系统依赖应用程序来确保数据完整性,而 SQL使用声明式方法。在数据完整性方面,关系数据库仍然是赢家。 - 数据独立性
数据的生命周期通常比应用程序更长。在NoSQL 中,应用程序驱动数据的一切。而关系模型的一个优势是它可以作为企业事实的存储库,远远超过任何单个应用程序的预期寿命。 - SQL支持
如果你需要SQL,那么很少有NoSQL系统会提供SQL接口,尽管越来越多的系统开始提供类SQL的接口。 - 临时查询
如果你需要实时回答关于数据的无法预先预测的问题,关系数据库通常仍然是更好的选择。 - 复杂关系
一些NoSQL系统支持关系,但在处理复杂关系方面,关系数据库仍然是赢家。 - 成熟度和稳定性
关系数据库在这方面仍然具有优势。人们熟悉它们的工作原理、功能,并对它们的可靠性有信心。此外,关系数据库有更多的开发人员和工具集支持。因此,在不确定的情况下,人们通常会选择关系数据库。