0

我正在尝试将大量数据加载到 10 节点 Cassandra 环中。

执行插入的脚本获得约 4000 次插入 / 秒,大概在网络 I/O 上被阻塞。我在一台机器上启动了其中的 8 个,吞吐量几乎呈线性增长。(单个吞吐量略有下降,但通过额外的流程得到了更多的补偿。)

这工作得很好,但是,我仍然没有获得足够的吞吐量,所以我在另外 3 个虚拟机上启动了相同的设置。(因此,8 个进程 * 4 个 VM)在第一个附加 VM 之后,随着进一步 VM 的添加频率和严重性的增加,会发生以下情况:

  • 客户端开始接收超时错误。他们可以重新尝试他们的写入,但因为他们是分批这样做的,他们的前进进度几乎完全被消除了。
  • 环变得不稳定,节点开始将自己标记为“关闭”。此外,不同的节点往往对谁宕机有不同的想法。脚本中止时环不会恢复。(我什至无法通过重启单个节点来解决这个问题:我不得不重启整个环。)

“下”不一。在我最后一次运行中:

  • 4 个节点完全死亡。(Cassandra 根本没有运行。)检查日志,似乎没有任何关于它为什么死亡的记录。
  • 第五天,卡桑德拉正在奔跑。nodetool status在那个节点上挂起。两个线程似乎处于某种无限循环中。(他们一直在使用 100% 的 CPU。)java.lang.OutOfMemoryError: Java heap space日志中有一个。

代码本质上是:

def prepped_batch_insert(session, items, insert_query, silent=False):

    # A mapping of number of inserts -> a prepared query for that number of
    # inserts.
    prepped_statements = {}

    def get_prepped_statement(inserts):
        if inserts in prepped:
            # We already created a prepared query for this many inserts, use
            # it:
            return prepped_statements[inserts]
        else:
            # We haven't yet created a prepared query for this many inserts, so
            # do so now:
            query = ['BEGIN UNLOGGED BATCH']
            for idx in xrange(inserts):
                query.append(insert_query.query)
            query.append('APPLY BATCH;')
            query = '\n'.join(query)
            ps = session.prepare(query)
            prepped_statements[inserts] = ps
            return ps

    def do_prepped_batch_insert(batch)
        ps = get_prepped_statement(len(batch))

        # Generate the list of params to the prepared query:
        params = []
        for idx, item in enumerate(batch):
            for k in insert_query.keyorder:
                params.append(item[k])
        # Do it.
        session.execute(ps, params)

    return inserter.insert_and_time(
        items,  # data generator
        do_prepped_batch_insert,  # The above function
        _WHAT_APPEARS_TO_BE_THE_OPTIMAL_CASSANDRA_BATCH_SIZE,  # = 200
        silent=silent,
    )

该函数insert_and_time分成items大小为 200 的批次,调用上述函数,并对整个套件和 kaboodle 进行计时。(此代码对戒指有毒。)

我们尝试了更多的读取,因为(有人告诉我)每秒 20k 的插入速度很慢(以这种速度插入我想插入的数据需要一段时间……),而且 Cassandra 具有高容量。

我的问题:

  1. 我在做什么有什么不寻常的地方吗?哪里不对了?
  2. 我只是对我的戒指进行 DDoS 攻击吗?
  3. 我该如何去调试有什么问题?
  4. 一个错误的客户端,恕我直言,永远不能杀死服务器。(以上内容并没有非常错误。)我能做些什么来防止这种情况发生?

¹客户端似乎也慢慢泄漏文件描述符。我不认为这是相关的。(我.shutdown同时调用集群和连接。)查看驱动程序源,似乎有很多异常会导致泄漏的路径。

4

2 回答 2

0

看起来很像您正在对您的设置进行 DDoS 攻击。

执行插入的脚本获得约 4000 次插入 / 秒,大概在网络 I/O 上被阻塞。我在一台机器上启动了其中的 8 个,吞吐量几乎呈线性增长

如果启动通过同一 NIC 访问 Cassandra 的其他脚本实例会导致吞吐量接近线性增加,则您不会在网络 IO 上被阻止。

一个错误的客户端,恕我直言,永远不能杀死服务器。

在任何服务器上投入足够的负载,它就会开始失败。一些服务器试图最小化这种情况,例如,Web 服务器通常会接受最大数量的并发 HTTP 请求,之后它们会回复它们正忙。然而,即使处理连接并告诉客户端“暂时离开”也需要一些周期。适当的 DoS 保护涉及专用的网络硬件。

(他们一直在使用 100% 的 CPU。)有一个 java.lang.OutOfMemoryError: Java heap space

更多证据表明您只是将戒指装入超出其容量的范围。

要提高吞吐量,请查看硬件和 Cassandra 配置。

  • IO是否过载?这是许多持久性系统的典型瓶颈。我没有使用 Cassandra 的具体经验,但是一旦工作集无法放入内存,Mongo DB IO 性能就非常重要。如果它过载,考虑更快的 IO 子系统(如果这是例如 AWS,有多种方法可以提高 IO 性能)。
  • 你有足够的内存吗?您提到 Java 堆用完了。您是否将堆大小设置为每个节点上的最大值,从而允许操作系统和系统上的其他进程可能需要一些 RAM?
  • CPU是否过载?好像是的。但是,在考虑适当的磁盘和网络 IO 性能并查看 Cassandra 配置之后,我会最后查看 CPU。高 CPU 有时可能是其他问题的征兆。
  • 验证 Cassandra 配置。我不是这方面的专家,但是看看 Netflix 在对 Cassandra 性能进行基准测试时使用的配置http://techblog.netflix.com/2011/11/benchmarking-cassandra-scalability-on.html
于 2014-02-11T23:58:12.983 回答
0

您的情况听起来不寻常,但没有关于您正在运行的硬件的任何详细信息,这是我的一些猜测。问题很可能是堆大小,其次是 IO 瓶颈。除非您在 SSD 上运行,否则 CPU 使用率应该不是问题。

1) 如果您正在寻找一次性数据加载,然后是较小的一致数据流,请考虑使用批量加载工具。

2) 可能从某种意义上说,您尝试以比您使用的硬件可以处理的速度更快的速度加载数据。

3)您应该查看 Cassandra 系统日志中的消息,例如“尝试刷新内存表以恢复空间”,这些消息是堆用完的症状,它们将包含有关内存 GC 和其他正在进行的任务的信息。对于实时监控,您还可以使用 jconsole 或 visualvm 通过 JMX 连接到您的 Cassandra 实例。当查看这些时,如果堆开始填满并且系统开始备份应该很明显。大多数生产 Cassandra 实例的堆大小为 8GB,随着停止世界 GC 事件变得越来越普遍,其数量大于收益递减。

您应该注意的另一件事是待处理的压缩,这是 Cassandra 的关键 IO 瓶颈之一。如果这个数字无限制地增长,则意味着您的系统受到硬盘驱动器速度的限制,您可以通过更多机器或升级到 SSD 来缓解压力。检查这个

 nodetool compactionstats  

Datastax Opscenter是您可以用来监控所有这些的工具。该工具将允许您从一个地方轻松监控整个集群,并且社区版完全免费。

我确实想知道是否还有其他问题,因为我定期对 Amazon m1.large 实例进行基准测试,发现其中大约 10 个可以支持 40~50k 写入/秒的流量,而不会出现任何类型的系统不稳定。

4) 正如 Eric 所指出的,像 Cassandra 这样的面向性能的分布式系统很难在保持可用性和性能的同时保持对客户端行为的防护。权衡是提高速度,以便在写入发生时对系统状态进行最少的检查。这允许极快的写入,但让维护者有责任正确配置和监控他们的系统。

于 2014-02-12T07:10:44.660 回答