ScyllaDB 运维 FAQ 深度解析:性能调优、磁盘空间、Snitch 策略与 RAID0 最佳实践
本文以 ScyllaDB 官方 FAQ 为核心,系统梳理生产环境中最常见的 20 余类问题:内存/CPU 限制、HDD 的 io.conf 调优、swap 配置、快照与 tombstone 导致的磁盘空间疑问、实验特性开关、Debian/Ubuntu 补丁版本 pinning、DC-aware Snitch 与复制策略搭配、多可用区扩容、RAID0 选型以及 nodetool repair 语义。读完后你可以直接照文档完成 ScyllaDB 节点的容量与拓扑配置,并理解其背后的源码实现依据(如 db/config.cc、conf/scylla.yaml、conf/cassandra-rackdc.properties)。
性能(Performance)
为什么 ScyllaDB 会占满全部可用内存?
ScyllaDB 会主动使用可用内存来缓存数据,并且动态管理这部分内存以追求最优性能:
- 当大量客户端连接涌入时,它会从缓存中驱逐部分数据,腾出内存容纳这些连接;
- 当连接数回落后,这些内存又会归还给缓存。
因此"内存被吃满"是设计行为而非故障,节点不会因此 OOM——ScyllaDB 知道自己用了多少内存,何时该让渡。
如何限制 ScyllaDB 使用的 CPU 与内存
--smp(如--smp 2):将 ScyllaDB 限制到更少的 CPU 核数。它仍会以 100% 的占用率跑满这些核,但至少不会把整机拖垮。仓库中 Docker 部署工具也印证了该参数的存在,见 dist/docker/commandlineparser.py 中定义的--smp选项,以及测试代码中常见的--smp 2启动方式。-m:内存的对应选项,用于限制 ScyllaDB 可使用的内存上限。
这对把 ScyllaDB 部署在共享主机(如开发机、与其他服务混布)的场景尤为重要。
ScyllaDB 实现高性能的核心技术
ScyllaDB 的性能模型可以概括为:永远并行、永不阻塞。它尝试榨干处理器核、内存、存储与网络的所有资源。典型流程是:
- 需要读取一个磁盘块时,ScyllaDB 发起读请求后立即切去执行其他任务;
- 读完成后,再从暂停点恢复原任务继续执行。
这种非阻塞协作调度使得所有资源都能被推到极限利用率,形成天然的软件级高并发,而不需要靠线程切换来掩盖 I/O 延迟。
为什么 Seastar 一核上不止一个线程?
有读者注意到:既然 Seastar 是"每核一线程"模型,为什么每个核上看到多于一个线程?
原因是 Seastar 会为每个核额外创建一个线程专门执行阻塞型系统调用(如 open() / fsync() / close()),保证在阻塞操作进行时,Seastar reactor 线程能继续执行其他工作。这些辅助线程通常处于空闲状态,不会带来显著的上下文切换开销。
单个节点上看到大量 Compaction 并行,正常吗?
正常,而且有多重原因:
- 每个 shard(核)独立运行自己的 compaction,经常同时发生;
- 每张表独立运行自己的 compaction,也经常同时发生;
- compaction 策略本身允许并行。例如 Size-Tiered Compaction Strategy(STCS)中,大 sstable 的 compaction 耗时较长,期间允许把更多小 sstable 合并进来。
因此"几十个 compaction 同时在跑"在分片架构下是预期行为,不必惊慌。
HDD 存储:为 io.conf 设置 max-io-request
在 ScyllaDB 的初始化过程中,iotune 会对存储做一次简短基准测试,并生成 /etc/scylla.d/io.conf 配置文件。已知 iotune 在 HDD 上的基准测试存在偏差,因此针对 HDD 场景有专门建议:
- 将所有可用磁盘组建 RAID0;
- 手动修改
io.conf中的max-io-request参数——它控制同时发往存储的并发请求数; - 经验值:
max-io-request = 3 × 磁盘数。例如 3 块盘就设置max-io-request=9。
这样可以让 HDD 阵列的吞吐在并发 I/O 下接近饱和,避免请求队列空转。
每个客户端应用应该开多少条连接?
经验法则:每个 ScyllaDB 客户端至少需要每核 1–3 条连接。
举例:一个 3 节点集群、每节点 16 核,那么每个客户端应用对每个 ScyllaDB 节点应打开约 2 × 16 = 32 条连接。连接数过少会导致单条连接的队列成为瓶颈,无法打满服务端多核的并行处理能力。
需要为 ScyllaDB 节点配置 swap 吗?
建议配置。大小取以下两者的较小值:
total_mem / 3(total_mem 为节点总内存);- 16 GB。
示例:
| 节点总内存 total_mem | 建议 swap 大小 |
|---|---|
| 18 GB | 6 GB |
| 240 GB | 16 GB |
具体搭建步骤可参考仓库文档 kb/set-up-swap.rst(How to Set up a Swap Space)。
查询没有返回数据(或部分数据)怎么办?
如果查询条件中包含时间范围,最常见的原因是时区处理问题:存储与比较时间戳时若时区不一致,会导致时间范围"落空"。官方将此类问题归入排障文档 troubleshooting/time-zone.rst(Time Range Queries Do Not Return Some or All of the Data)。
我只建了二级索引(SI),为什么 DESC SCHEMA 显示大量物化视图(MV)?
这是正常的:二级索引本身就是构建在物化视图(Materialized View)之上的,所以 schema 中会看到对应的 MV 定义,系统没有任何问题。更深入的原理可参考 features/secondary-indexes.rst(Global Secondary Indexes)。
Java 驱动的 SimpleStatement 为什么慢?
Java 驱动的 SimpleStatement 默认是 token unaware(不感知 token)的:请求发出后先到达 Controller 节点,此时还不知道该访问哪个 shard,需要额外解析路由。官方建议改用 PreparedStatement——准备阶段即可确定 token 路由,避免每次请求都走 Controller 中转,延迟显著更低。
磁盘空间(Disk Space)
删表(DROP TABLE)后磁盘空间不下降,怎么清理?
根源在于 conf/scylla.yaml 中的 auto_snapshot 参数(默认为 true,源码定义见 db/config.cc):
# 仓库 conf/scylla.yaml 中的实际默认配置
auto_snapshot: true
auto_snapshot_ttl: 864000
当 auto_snapshot 为 true 时,ScyllaDB 在删除一张表之前会先对其创建快照作为安全措施。快照位于该表 SSTable 目录下的 snapshots 子目录中,例如已删除的 mykeyspace.users 表:
/var/lib/scylla/data/mykeyspace/users-bdba4e60f6d511e7a2ab000000000000/snapshots/1515678531438-users
由于快照占用与已删除表相同的空间,磁盘用量不会下降。清理方式:
- 使用
nodetool clearsnapshot,命令语义见 operating-scylla/nodetool-commands/clearsnapshot.rst; - 快照与 clearsnapshot 的完整说明见 operating-scylla/procedures/backup-restore/delete-snapshot.rst。
删除(DELETE)数据后磁盘占用不变,为什么?
这是 SSTable 不可变(immutable)模型的直接结果:
- 写入 ScyllaDB 的数据落在 SSTable 中;
- 由于 SSTable 不可变,执行 DELETE 时无法真正删除旧数据,而是写入一个标记(tombstone/墓碑)来表示该值的新状态;
- 在数据与 tombstone 首次共同参与的一次 compaction 中,被删数据会被彻底清除,对应磁盘空间随之回收。
因此 DELETE 后磁盘占用不降是符合预期的,等待或触发 compaction 即可回收。
功能特性(Features)
如何启用实验特性(experimental features)
特性可以逐个通过配置文件或命令行开关启用。
方式一:修改 scylla.yaml
-
打开配置文件:
- Linux 系统:
$ vi /etc/scylla/scylla.yaml - Docker:
$ docker exec -it your_node vi /etc/scylla/scylla.yaml
- Linux 系统:
-
追加要启用的特性。仓库内配置模板 conf/scylla.yaml 中即保留了对应注释位置:
# 示例:启用 UDF 与强一致表特性 experimental_features: - udf - strongly-consistent-tables -
保存退出。
-
重启节点:
- RHEL / CentOS / Ubuntu:
$ sudo systemctl restart scylla-server - Docker:
$ docker stop <your_node> && docker start <your_node>
- RHEL / CentOS / Ubuntu:
方式二:命令行参数 --experimental-features
该参数可重复出现多次:
$ docker run --name <your_node> -d scylladb/scylla \
--experimental-features=udf \
--experimental-features=strongly-consistent-tables
如何查看当前 ScyllaDB 版本
- 普通系统或虚拟机(Ubuntu、CentOS、RedHat Enterprise):
$ scylla --version - Docker 节点:
$ docker exec -it Node_Z scylla --version
版本与操作系统支持范围的组合需要参照官方 OS 支持矩阵,仓库内版本信息由 SCYLLA-VERSION-GEN 与 version.hh 生成。
Docker
应用连接 Docker 中的 ScyllaDB 集群报连接错误?
最常见的原因:你正试图用 ScyllaDB 节点的 Docker 内部 IP 从容器外部去连接。
如果节点需要被 Docker 内部网络之外访问,必须把相应端口发布(expose)到 Docker 宿主上,否则外部应用无法路由到容器内部地址。
安装(Installation)
能否在已装 Apache Cassandra 的服务器上安装 ScyllaDB?
ScyllaDB 自带一套 Apache Cassandra 客户端工具,打包在 scylla-tools 中。若目标机器已装 Cassandra,可能出现包冲突:
Unpacking scylla-tools (1.0.1-20160411.b9fe89b-ubuntu1) ...
dpkg: error processing archive /var/cache/apt/archives/scylla-tools_1.0.1-20160411.b9fe89b-ubuntu1_all.deb (--unpack):
trying to overwrite '/usr/bin/nodetool', which is also in package cassandra 2.1.4
官方建议:安装 scylla-tools 前先卸载 Apache Cassandra,避免 nodetool 等二进制文件冲突。
Debian/Ubuntu 上能否安装/升级到非最新的补丁版本?
APT 安装(Ubuntu、Debian 及镜像安装)默认安装某主版本(x.y)下最新的补丁版本(x.y.z)。要停留在非最新的补丁版本,可用 pinning(版本固定) 变通:
$ cat <<EOF | sudo tee /etc/apt/preferences.d/99scylla-enterprise
Package: scylla-enterprise*
Pin: version 2021.1.0-0.20210511.9e8e7d58b-1
Pin-Priority: 1001
EOF
Pinning 在降级或升级到非最新可用版本时尤其有用。
或者显式安装目标版本的全部相关包:
sudo apt-get install scylla-enterprise{,-server,-tools,-tools-core,-kernel-conf,-node-exporter,-conf,-python3}=2021.1.0-0.20210511.9e8e7d58b-1
sudo apt-get install scylla-enterprise-machine-image=2021.1.0-0.20210511.9e8e7d58b-1 # 仅在 AMI 实例上执行
拓扑:Snitch 与复制策略
该选哪种 Snitch 和复制策略?
核心规则一句话:只要生产集群、只要跨多个数据中心,就必须使用 DC-aware(数据中心感知)的 Snitch + DC-aware 的复制策略。
- DC-aware Snitch 示例:
GossipingPropertyFileSnitch、Ec2MultiRegionSnitch; - DC-aware 复制策略示例:
NetworkTopologyStrategy。
官方的一般推荐:始终使用 NetworkTopologyStrategy;基于 AWS 的集群用 Ec2XXX 系列 snitch,其余场景用 GossipingPropertyFileSnitch。
完整的 snitch 选项说明见仓库文档 operating-scylla/system-configuration/snitch.rst。从源码结构看,各 snitch 均有独立实现:locator/gossiping_property_file_snitch.hh、locator/ec2_multi_region_snitch.hh 等。
强烈不建议的混搭:
SimpleSnitch+ DC-aware 复制策略;- DC-aware snitch +
SimpleStrategy。
这类错配会造成集群不按预期工作。典型报错:
Unavailable: code=1000 [Unavailable exception] message="Cannot achieve consistency level for cl LOCAL_ONE. Requires 1, alive 0" info={'required_replicas': 1, 'alive_replicas': 0, 'consistency': 'LOCAL_ONE'}
看到这个错误,应首先检查是否在用 SimpleSnitch 搭配了失败表所在 keyspace 的 DC-aware 复制策略。
cassandra-rackdc.properties 如何写
使用 GossipingPropertyFileSnitch 或 Ec2MultiRegionSnitch 时需要编辑 cassandra-rackdc.properties(仓库自带模板见 conf/cassandra-rackdc.properties,其中注释列出了 dc、rack、prefer_local、dc_suffix 四项)。
GossipingPropertyFileSnitch 节点:
dc=asia_datacenter
rack=rack1
prefer_local= true
含义:该节点位于 Asia 数据中心 rack1;prefer_local=true 用于尽量减少跨数据中心带宽消耗。
Ec2MultiRegionSnitch 节点:
dc_suffix=my_dc
该后缀会拼接到节点位置之后,例如生成 us-east1_my_dc 作为数据中心名。
配置正确性的核查步骤
- 确保 keyspace 的 snitch 与复制策略都是 DC-aware;
- 确认复制策略中使用的数据中心名称与集群实际名称一致——用
nodetool status核对数据中心名。
能否在运行中的集群上修改复制因子(RF)?
可以,但已有数据的副本数变化需要一次全量 repair(增大 RF)或 cleanup(减小 RF):
- 用 cqlsh 等工具执行
ALTER KEYSPACE修改目标 keyspace 的复制因子; - 降低 RF:对修改过的 keyspace 运行
nodetool cleanup <updated Keyspace>,清除多余的副本数据;cleanup 以节点为单位执行; - 提高 RF:按安全流程操作,见仓库文档 kb/rf-increase.rst(How to Safely Increase the RF);
- 注意:必须显式给出 keyspace 名,否则 cleanup/repair 会对该节点的所有 keyspace 生效。
为什么 listen_address 不能设为 0.0.0.0?
ScyllaDB 是基于 gossip 的分布式系统,listen_address 是节点告诉其他节点"通过这个地址联系我"的地址。广播"随便选我的一个地址来找我"是很危险的:如果集群中不同节点为你选定了不同地址,就会引发混乱。
如果不想逐节点手工指定 IP:把该项留空,ScyllaDB 会用 InetAddress.getLocalHost() 自动选地址,剩下的工作是保证你的 /etc/hosts、DNS 等能正确解析主机名。
多可用区(Multi-AZ)扩容的最佳实践
以三节点、RF=3、每节点位于不同 AZ 的集群为例(nodetool status 输出):
Datacenter: DC1
Status=Up/Down
State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 192.168.1.201 118.82 KB 256 33.6% 8d5ed9f4-7764-4dbd-bad8-43fddce94b7c A1
UN 192.168.1.202 111.82 KB 256 33.1% 8d5ed9f4-7764-4dbd-bad8-43fddce94b7c B1
UN 192.168.1.203 114.82 KB 256 33.3% 8d5ed9f4-7764-4dbd-bad8-43fddce94b7c C1
此时每个节点持有 100% 的数据。如果只新增一个节点(scale out),集群会失衡——因为新节点只会与同 AZ 的现有节点切分 token:
AZ A1 node A: 100% of the data
AZ B1 node B: 100% of the data
AZ C1 node C: 50% of the data
AZ C1 node D: 50% of the data
正确做法是每个 AZ 各加一个节点,重新达到均衡(每节点约 16.1%–16.6%):
Datacenter: DC1
Status=Up/Down
State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 192.168.1.201 118.82 KB 256 16.6% 8d5ed9f4-7764-4dbd-bad8-43fddce94b7c A1
UN 192.168.1.202 111.82 KB 256 16.1% 8d5ed9f4-7764-4dbd-bad8-43fddce94b7c B1
UN 192.168.1.203 114.82 KB 256 16.3% 8d5ed9f4-7764-4dbd-bad8-43fddce94b7c C1
UN 192.168.1.204 118.82 KB 256 16.6% 8d5ed9f4-7764-4dbd-bad8-43fddce94b7c A1
UN 192.168.1.205 111.82 KB 256 16.1% 8d5ed9f4-7764-4dbd-bad8-43fddce94b7c B1
UN 192.168.1.206 114.82 KB 256 16.3% 8d5ed9f4-7764-4dbd-bad8-43fddce94b7c C1
注:以上为示例,节点更多或 RF 不同时所需节点数可能不同。
这一行为与 dht/ 下的 token 分区器(如 dht/murmur3_partitioner.hh)及 locator/token_metadata.hh 的 vnode 所有权分配逻辑一致:新节点加入时按同 rack/同 AZ 边界切分 token 范围。
存储选型:RAID0、RAID 与 JBOD
ScyllaDB 必须用 RAID0 吗?
不强制,但多盘场景下强烈推荐。 原因:
- ScyllaDB 需要一块盘放数据文件、一块盘放 commit log(可以是同一块盘);
- 想利用多块盘时,最简单的方式就是把它们全部组成 RAID0(条带化);
scylla_setup可以代你完成 RAID0 与 XFS 文件系统(推荐)的搭建;- EC2 上的 ScyllaDB AMI 会自动将所有可用 SSD 挂成 RAID0。
应该用 RAID1/RAID4 等带冗余的 RAID 吗?
可以,但不推荐。 从源码结构看,ScyllaDB 的集群架构(replication、repair 等,见 docs/architecture/ringarchitecture)已经在节点间和数据中心间提供了数据复制。在每个节点内再加一层磁盘级冗余是重复建设:
- 拖慢 I/O;
- 减少可用存储空间。
想要更高冗余级别?提高相关 Keyspace 的**复制因子(RF)**才是正解。
能不能用 JBOD 而不用 RAID0?
JBOD(Just a Bunch Of Disks)不被 ScyllaDB 支持。
JBOD 对 Cassandra 或许是合理的(节点重建非常慢,隔离单盘故障有价值),但对 ScyllaDB 不是问题:
- JBOD 下每块盘是独立文件系统,I/O 不做条带化,性能低于 RAID;且自由空间不共享,单盘写满而其他盘仍有空间;
- JBOD 的唯一优势是把故障隔离在单盘而非整个节点——但 ScyllaDB 重建节点的速度足够快,整节点重建不构成痛点。
所以对 ScyllaDB 而言,RAID 的方案明显更优。
集群维护
nodetool repair 是本地操作还是全集群操作?
在某个节点上运行 nodetool repair 时,它会对该节点拥有的每个 token 范围执行 repair,同时也会顺带 repair 共享这些范围的其他节点——但不会覆盖整个集群。
若要 repair 整个集群,推荐在集群的每个节点上依次(sequentially)执行 nodetool repair -pr,或使用 ScyllaDB Manager 编排。
如何修改 IN 子句的最大限制数量
两个配置项限制 IN 元组的规模,源码定义见 db/config.cc,默认值均为 100,且均支持热更新(liveness::LiveUpdate):
--max-partition-key-restrictions-per-query:单条查询中分区键限制的条数上限。该限制约束 IN 元组的大小,尤其当多个分区键列同时带 IN 限制时。默认100。--max-clustering-key-restrictions-per-query:单条查询中聚簇键限制的条数上限。语义同上。默认100。
超限时会收到类似 cql3/restrictions/statement_restrictions.cc 中定义的报错,明确提示用对应配置项调整默认值。
警告:官方建议谨慎使用。把上限调到 100 以上可能导致服务端不稳定。
配置方式有三种:命令行参数、/etc/default/scylla-server(Debian 系)或 /etc/sysconfig/scylla-server(RHEL 系)中的 SCYLLA_ARGS、或直接写入 scylla.yaml(配置总览见 operating-scylla/admin.rst)。
能否修改 coredump 的挂载点?
可以,通过编辑 sysctl.d 实现:
-
创建
/etc/sysctl.d/99-scylla-coredump.conf(ScyllaDB AMI 中默认已有该文件); -
打开该文件;
-
加入一行:
kernel.core_pattern=|/home/centos/core/ %p %u %g %s %t %e -
执行
sysctl -p /etc/sysctl.d/99-scylla-coredump.conf使其生效。
更多资源
FAQ 未覆盖的问题,官方指明的社区渠道:
- ScyllaDB Community Forum:讨论 ScyllaDB 的使用与客户端应用开发;
- scylladb-dev 邮件列表:讨论 ScyllaDB 本身的开发。
另外,FAQ 中引用的完整文档体系(snitch 配置、nodetool 命令、快照管理、RF 提升、时区排障等)均可在当前仓库 docs/ 目录对应路径下继续深入阅读。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



