我该如何实现一个能够承受每秒数万个请求的数据库?

7

我希望能够实现每秒数万次的请求量,希望能达到60,000 -> +90,000次/秒。

我的设置如下:

用户 ---> web应用程序 --> 消息队列 --> 解析器 --> 数据库?

需要说明的是,解析器目前可以使用COPY解析/填充大约18750条记录/秒,因此我们在这方面受到限制,直到我们开始添加更多解析器为止——现在这对我来说不是一个很大的问题。

我有一个需要尽可能快地批量上传尽可能多记录的系统。同样的系统(或者根据您的方法可以是不同的)应该能够响应类似于这样的分析型查询:

wonq = "select sum(amount) from actions where player = '@player' and " +
       "(type = 'award' or type = 'return') and hand = hand_num"
lostq = "select sum(amount) from actions where player = 'player' and " +
        "type != 'award' and type != 'return' and hand = hand_num"

.....由于它们与另一张表相关联,所以每个用户需要进行10-15千次的查询。不用说,我们现在将这些结果分页显示为每页10个。

我看了以下内容:(假设这些都在同一台服务器上)

  • mysql (普通的关系型数据库) -- 能够达到15-20千次/秒的请求量; 在当前条件下,如果我们尝试扩展它,每次需要扩展时我们都需要一个单独的主机/数据库--这是不可行的

  • couchdb (文档导向数据库) -- 没有超过700次/秒; 我真的希望这能拯救我们——没有机会!

  • vertica (列式数据库) -- 达到了60000次/秒,闭源,非常昂贵; 这仍然是一种选择,但我个人并不喜欢它

  • tokyocabinet (基于哈希的数据库) -- 目前的插入速度为45,000次/秒,选择速度为66,000次/秒; 昨天当我写这篇文章时,我使用的是一个基于FFI的适配器,它的性能约为5555次/秒; 这是我见过的最快、最棒的数据库!!

  • terracotta -- (vm集群) 目前正在评估这个和jmaglev(迫不及待地等待maglev本身的推出)--这是最慢的!

也许我只是错误地处理了这个问题,但我一直听说关系型数据库非常慢——那么我听说过的这些超级快速系统在哪里呢?

测试条件::

只是让人们知道我的开发机规格:

双3.2ghz英特尔处理器,1GB内存

Mysql mysql.cnf 编辑如下:

key_buffer = 400M               # 原为16M
innodb_log_file_size = 100M     # 之前不存在
innodb_buffer_pool_size = 200M  # 之前不存在

更新:

事实证明,terracotta在我们的应用结构中可能有一席之地,但它绝对不会很快取代我们的数据库,因为它的速度非常慢,堆利用率也很差。

另一方面,我很高兴看到tokyocabinet的非FFI ruby库(即tyrant/cabinet)非常快,现在这是第一选择。


feydr - 你能详细说明一下你如何测试Terracotta吗?想知道更多关于为什么你认为Terracotta很慢的原因。大多数人发现它非常快,所以可能是一个糟糕的用例 - 或者需要进行一些调整?非常希望了解更多... - Taylor Gautier
taylor:诚然,这可能是一个糟糕的使用案例;我们仍在评估它,而且可能会持续一段时间,但作为在一个服务器-客户端实例上简单共享对象列表的第一次测试,我们只能以每秒约50个的速度塞入我们的对象,而大多数其他选项则为每秒约600个。 - eyberg
泰勒:刚刚注意到你的博客提到了每秒3500个事务——尽管Terracotta会更容易地扩展(这意味着它仍然可能适合我们),但我认为事务速度相对而言太慢,无法取代我们的关系型数据库。 - eyberg
feydr:我同意50太慢了。我相信有些地方不对劲。如果可能的话,我很乐意帮助你。来我们的论坛看看吧——也许你有一个应用程序或配置需要查看?或者运行集群统计记录器以获取一些数据?通常配置文件是寻找低效率问题的第一步。 - Taylor Gautier
8个回答

6

如果需要实现大规模可扩展性,您需要关注以下两个方面:

  • 分片:将数据集拆分成不重叠的组。有一种简单快速的方式可以从请求映射到服务器。(例如,以字母a-f开头的玩家使用服务器1;g-q的玩家使用服务器2...等等)
  • 缓存:使用Memcache来记住一些常见查询的输出结果,这样您就不必经常访问磁盘。

1

在编程领域中,大佬级别的公司是Oracle,但那需要花费巨额资金。

如果你想省钱,那么你就必须用不同的方式付出代价:

  • 通过将数据库分区到多个实例并分配负载来实现。
  • 可能会缓存结果以减少实际的数据库访问。

0

在写入频繁的应用程序中快速存储数据的典型方式是使用追加日志。如果正确部署,使日志文件位于自己的旋转磁盘上,则磁盘寻道时间会在每个写入/追加操作中最小化。

可以在每次写入后更新元数据以了解某些主键的偏移量。

如果您想使用mysql,则有一个mysql存储引擎可以执行此操作。另一个选择是使用新的nosql数据库之一,例如fleetdb。

您也尝试过使用固态硬盘吗?

有很多选项可用于解决这个问题,但它们很可能需要一些手动劳动。


0

你尝试过redis吗?他们承诺每秒110000个SET操作和81000个GET操作的速度。这是一个支持列表和集合的高级键值数据库。


实际上我已经评估了Redis并且非常喜欢它——然而对于这个问题,我有几个问题——主要的问题是你需要足够的内存来匹配你想要存储的内容……如果不进行分布式处理,那将是一个很大的难题。 - eyberg
是的,出于同样的原因,Redis看起来并不适合我们的项目。在这种情况下,LightCloud项目似乎很有趣,因为它在Tokyo Tyrant或Redis之上构建了分布式键值数据库。 - AlexD

0

我怀疑任何系统都无法提供您所需的开箱即用性能。您可能会开始在您所在的机器上遇到严格的限制(使用几乎任何写入密集型数据库,您将很快达到I/O限制)。可能需要进行一些分析,但磁盘几乎总是瓶颈。增加更多的RAM将有所帮助,使用固态硬盘也会有所帮助。

然而,无论您使用哪种实际的数据库,您可能都需要某种形式的集群。您可以对数据本身进行分片,或者使用MySQL,设置读取从节点将分散负载并应该为您提供所需的吞吐量。

另外:MongoDB非常棒。值得一看。


我已经看过了MongoDB,相比Couch(两者都是文档导向型数据库),我更喜欢它,因为它更快。在我的笔记本上,我每秒可以处理8,000-10,000个请求。你说得对,关于集群的问题...目前我们正在考虑使用Hadoop堆栈中的HDFS/HBase。虽然不太快,但应该能满足我们的需求。 - eyberg

0

用户 ---> Web 应用程序 --> 消息队列 --> 解析器 --> 数据库?

你为什么需要消息队列呢? 通常它们会带来很大的性能问题。


好问题,然而消息队列几乎没有任何明显的性能影响...它存在的原因是我们最终希望有多个解析器从中获取数据,并且我希望来自Web服务器的工作能够立即被投入队列,以便Web服务器可以尽其所能。 - eyberg

0

正如ojrac所说,分片和缓存。

另一个选择是退一步,想出用更少的查询完成工作的方法!从你提供的少量信息中,我不禁想到“一定有更好的方法”。从你提供的例子中,一些汇总表(可选缓存)可能是一个简单的胜利。

Hypertable等在某些数据访问模式下提供更好的性能,但你的听起来非常适合典型的数据库。

是的,CouchDB的速度令人失望。


我完全不知道CouchDB这么弱!我想它至少有10k的能力。 - Robert Gould
我们过去做过一些总结表,或多或少都能用,但是现在我回到了基本的“我们能有多快地把东西扔进去并取出来”的状态。 - eyberg

0

你尝试过使用PostgreSQL吗?它应该比MySQL更快。但无论如何,你需要在多个服务器上平衡负载(分割数据库)。你可以拥有多个数据库(例如为每个客户端一个),然后有一个集中的数据库与这些小数据库同步...


我还没有尝试过PostgreSQL,尽管我在过去的项目中使用过它,并且它具有行业质量的强大功能--但从过去的经验来看,它并不具备我所需的速度。 - eyberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接