常见问题解答
为什么我不能将 listen_address
设置为监听 0.0.0.0(我的所有地址)?
Cassandra 是一个基于八卦的分布式系统,listen_address
是节点告诉其他节点如何到达它的地址。告诉其他节点“在任何地址上联系我”是一个坏主意;如果集群中的不同节点为你选择不同的地址,就会发生不好的事情。
如果你不想为集群中的每个节点手动指定 listen_address
的 IP(可以理解!),请将其留空,Cassandra 将使用 InetAddress.getLocalHost()
来选择一个地址。然后由你或你的运维团队来确保正确解析(/etc/hosts/
、dns 等)。
此过程的一个例外是 JMX,它默认绑定到 0.0.0.0(Java 错误 6425769)。
请参阅 256
和 43
以获取更多详细信息。
Cassandra 使用哪些端口?
默认情况下,Cassandra 使用 7000 用于集群通信(如果启用 SSL,则为 7001),9042 用于本机协议客户端,以及 7199 用于 JMX。节点间通信和本机协议端口可以在 cassandra-yaml
中配置。JMX 端口可以在 cassandra-env.sh
中配置(通过 JVM 选项)。所有端口都是 TCP。
我从 Cassandra 中删除数据,但磁盘使用量保持不变。这是怎么回事?
写入 Cassandra 的数据会持久化到 SSTable。由于 SSTable 是不可变的,因此在执行删除操作时无法实际删除数据,而是会写入一个标记(也称为“墓碑”)来指示该值的最新状态。不过不用担心,在数据和墓碑之间发生的第一次压缩时,数据将被完全清除,相应的磁盘空间也将被回收。请参阅 compaction
以获取更多详细信息。
为什么 nodetool ring 仅显示一个条目,即使我的节点记录了它们看到彼此加入环?
当每个节点都被分配了相同的令牌时,就会发生这种情况。不要这样做。
这种情况最常发生在人们在 VM 上部署 Cassandra 时(尤其是在使用 Debian 包时,该包在安装后会自动启动 Cassandra,从而生成并保存令牌),然后克隆该 VM 到其他节点。
最简单的解决方法是擦除数据和 commitlog 目录,从而确保每个节点在下一次重启时都会生成一个随机令牌。
我可以在活动集群上更改复制因子(键空间)吗?
可以,但需要运行完整修复(或清理)才能更改现有数据的副本数量。
-
Alter <alter-keyspace-statement>
更改所需键空间的复制因子(例如,使用 cqlsh)。 -
如果你要降低复制因子,请在集群上运行
nodetool cleanup
以删除多余的复制数据。清理在每个节点的基础上运行。 -
如果你要提高复制因子,请运行
nodetool repair -full
以确保数据根据新配置进行复制。修复在每个副本集的基础上运行。这是一个密集型过程,可能会导致集群性能下降。强烈建议进行滚动修复,因为尝试一次修复整个集群很可能会淹没它。请注意,你需要运行完整修复(-full
)以确保已修复的 sstable 不会被跳过。你应该使用ConsistencyLevel.QUORUM
或ALL
(取决于你现有的复制因子)以确保咨询到实际拥有数据的副本。否则,一些客户端可能会被告知没有数据存在,直到修复完成。
我可以在 Cassandra 中存储(大型)BLOB 吗?
Cassandra 并非针对大型文件或 BLOB 存储进行了优化,单个 blob
值始终会被完全读取并发送到客户端。因此,存储小型 blob(小于个位数 MB)应该不成问题,但建议手动将大型 blob 拆分为更小的块。
请特别注意,默认情况下,任何大于 16MiB 的值都会被 Cassandra 拒绝,因为 cassandra-yaml
文件的 max_mutation_size
配置(默认值为 commitlog_segment_size
的一半,而 commitlog_segment_size
默认值为 32MiB)。
Nodetool 显示“连接到主机 127.0.1.1 拒绝”的错误,适用于任何远程主机。这是怎么回事?
Nodetool 依赖于 JMX,而 JMX 又依赖于 RMI,RMI 又会在交换的每一端根据需要设置自己的监听器和连接器。通常,所有这些都在后台透明地进行,但主机连接或被连接主机的名称解析不正确会导致线路交叉和令人困惑的异常。
如果你没有使用 DNS,请确保你的 /etc/hosts
文件在两端都是准确的。如果这不起作用,请尝试在 cassandra-env.sh
底部附近设置 -Djava.rmi.server.hostname=<public name>
JVM 选项,该选项指向你可以从远程机器访问的接口。
对我的操作进行批处理会加快我的批量加载速度吗?
不会。使用批处理加载数据通常只会增加延迟“峰值”。请改用异步 INSERT,或使用真正的 bulk-loading
。
一个例外是对单个分区进行批处理更新,这可能是一件好事(只要单个批处理的大小保持合理)。但永远不要盲目地对所有内容进行批处理!
在 RHEL 节点上,无法加入环
检查 SELinux 是否已启用;如果已启用,请将其关闭。
如何取消订阅邮件列表?
发送电子邮件至 [email protected]
。
为什么 top 报告 Cassandra 使用的内存比 Java 堆最大值多得多?
Cassandra 在内部使用 内存映射文件 (mmap)。也就是说,我们使用操作系统的虚拟内存系统将多个磁盘文件映射到 Cassandra 进程的地址空间。这将“使用”虚拟内存;即地址空间,并且将由 top 等工具相应地报告,但在 64 位系统上,虚拟地址空间实际上是无限的,因此你不应该担心这个问题。
从“内存使用”的角度来看,重要的是在 brk() 或 mmap’d /dev/zero 上分配的数据量,它们代表实际使用的内存。关键问题是,对于 mmap’d 文件,永远不需要保留驻留在物理内存中的数据。因此,你保留在物理内存中的任何内容本质上只是一个缓存,与正常的 I/O 会导致内核页面缓存保留你读取/写入的数据的方式相同。
正常 I/O 和 mmap() 之间的区别在于,在 mmap() 的情况下,内存实际上被映射到进程,因此会影响 top 报告的虚拟大小。使用 mmap() 而不是标准 I/O 的主要论据是,读取只需要接触内存——如果内存驻留,你只需读取它——你甚至不会发生页面错误(因此不会进入内核并进行半上下文切换的开销)。这在 此处 有更详细的介绍。
什么是种子?
种子在启动期间用于发现集群。
如果您将节点配置为引用某个节点作为种子,则环中的节点往往会更频繁地向种子发送 Gossip 消息(另请参阅gossip <gossip>
部分),而不是向非种子节点发送。换句话说,种子充当 Gossip 网络的中心。有了种子,每个节点都可以快速检测到其他节点的状态变化。
新节点在引导时也会引用种子,以了解环中的其他节点。当您将新节点添加到环中时,您需要指定至少一个要联系的活动种子。一旦节点加入环,它就会了解其他节点,因此在后续引导时不需要种子。
您可以在任何时候将节点设为种子。种子节点没有特殊之处。如果您在种子列表中列出该节点,它就是一个种子。
种子不会自动引导(即,如果节点在种子列表中包含自身,它不会自动将数据传输到自身)。如果您希望节点执行此操作,请先引导它,然后将其添加到种子中。如果您没有数据(新安装),则无需担心引导。
种子推荐用法
-
每个数据中心选择两个(或更多)节点作为种子节点。
-
将种子列表同步到所有节点。
为什么我无法在 jconsole 上调用 jmx 方法 X?
一些 JMX 操作使用数组参数,由于 jconsole 不支持数组参数,因此无法使用 jconsole 调用这些操作(它们的按钮处于非活动状态)。您需要编写一个 JMX 客户端来调用此类操作,或者需要支持数组的 JMX 监控工具。
为什么我在日志中看到“……消息被丢弃……”?
这是负载削减的症状——Cassandra 在防御它无法处理的更多请求。
节点间消息在被节点接收后,如果在适当的超时时间内(参见cassandra-yaml
中的read_request_timeout
、write_request_timeout
等)没有被处理,就会被丢弃而不是被处理(因为协调节点将不再等待响应)。
对于写入,这意味着突变没有应用到发送到的所有副本。不一致性将通过读取修复、提示或手动修复来修复。写入操作也可能因此超时。
对于读取,这意味着读取请求可能没有完成。
负载削减是 Cassandra 架构的一部分,如果这是一个持久性问题,通常表明节点或集群过载。
Cassandra 崩溃并显示java.lang.OutOfMemoryError: Map failed
如果 Cassandra 专门因“Map failed”消息而崩溃,则意味着操作系统拒绝 Java 锁定更多内存。在 Linux 中,这通常意味着 memlock 受限。检查/proc/<cassandra 的进程 ID>/limits
以验证这一点并提高它(例如,通过 bash 中的 ulimit)。您可能还需要增加vm.max_map_count.
请注意,Debian 包会自动为您处理此问题。
如果两个更新使用相同的 timestamps 进行,会发生什么?
更新必须是可交换的,因为它们可能在不同副本上以不同的顺序到达。只要 Cassandra 有一种确定性的方法来选择获胜者(在 timestamps 相同的情况下),所选的获胜者与任何其他获胜者一样有效,具体细节应视为实现细节。也就是说,在 timestamps 相同的情况下,Cassandra 遵循两条规则:首先,删除优先于插入/更新。其次,如果有两个更新,则选择词典顺序较大的更新。
为什么引导新节点失败并显示“Stream failed”错误?
两种主要可能性
-
GC 可能会创建长时间暂停,从而中断流式处理过程
-
后台发生的压缩会使流式处理持续时间过长,以至于 TCP 连接失败
在第一种情况下,适用常规的 GC 调整建议。在第二种情况下,您需要将 TCP 保持活动设置为较低的值(Linux 上的默认值非常高)。尝试只运行以下命令
$ sudo /sbin/sysctl -w net.ipv4.tcp_keepalive_time=60 net.ipv4.tcp_keepalive_intvl=60 net.ipv4.tcp_keepalive_probes=5
要使这些设置永久生效,请将它们添加到/etc/sysctl.conf
文件中。
注意:GCE的防火墙将始终中断处于非活动状态超过 10 分钟的 TCP 连接。在该环境中强烈建议运行上述命令。