Cassandra 线上优化实战

遇到什么问题?

1.查询 Cassandra 总是报查询超时异常、等待获取连接超时 2.虽然查询超时,但是 Cassandra 服务器所在机器 Cpu 使用率缺非常低

官网介绍

cassandra.apache.org/_/cassandra...

配置优化

cassandra 启动配置重点优化以下 4 个参数

  • native_transport_max_threads:

    • 作用:这个配置项表示 Cassandra 数据库的本地传输(Native Transport)线程池的最大线程数。
    • 值: "4096" 表示最大线程数为 4096。这个值决定了 Cassandra 数据库能够处理同时进行的客户端连接请求的数量。增加这个值可以提高 Cassandra 的并发连接处理能力,但也需要更多的系统资源。
  • concurrent_reads:

    • 作用:这个配置项表示 Cassandra 数据库允许同时执行的读取操作(reads)的数量。
    • 值: "64" 表示同时允许执行的读取操作数量为 64。通过调整这个值,可以控制 Cassandra 在同一时间处理读取请求的数量。这可以影响读取操作的吞吐量和响应时间。
  • concurrent_compactors:

    • 作用:这个配置项表示 Cassandra 数据库用于压缩 SSTable 文件的并发压缩线程数。
    • 值: "8" 表示有 8 个并发的 SSTable 压缩线程。SSTable 是 Cassandra 中的一种数据文件格式,通过压缩可以释放磁盘空间并提高性能。通过调整这个值,可以控制压缩操作的并发程度。
  • 垃圾回收器可以尝试改为 G1

连接客户端配置优化

java 复制代码
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.AbstractCassandraConfiguration;
import org.springframework.data.cassandra.config.CqlSessionFactoryBean;
import org.springframework.data.cassandra.config.SessionBuilderConfigurer;

import java.time.Duration;

@Slf4j
@Configuration
public class CassandraConfig extends AbstractCassandraConfiguration {

    //空间名称
    @Value("${spring.data.cassandra.keyspace-name}")
    String keyspaceName;

    //节点IP(连接的集群节点IP)
    @Value("${spring.data.cassandra.contact-points}")
    String contactPoints;

    @Value("${spring.data.cassandra.username}")
    String username;

    @Value("${spring.data.cassandra.password}")
    String password;

    @Value("${spring.data.cassandra.session-name}")
    String sessionName;

    @Value("${spring.data.cassandra.pool-size}")
    Integer poolSize;

    @Override
    public String getKeyspaceName() {
        return keyspaceName;
    }

    @Override
    public String getContactPoints() {
        return contactPoints;
    }

    @Override
    public String getSessionName() {
        return sessionName;
    }

    @Override
    public String getLocalDataCenter() {
        return "datacenter1";
    }

    @Bean
    @Override
    public CqlSessionFactoryBean cassandraSession() {
        CqlSessionFactoryBean cqlSessionFactoryBean = super.cassandraSession();
        cqlSessionFactoryBean.setPassword(password);
        cqlSessionFactoryBean.setUsername(username);
        return cqlSessionFactoryBean;
    }

    /**
     * PT2S 异常优化 & 配置文件修改 request.timeout 不生效
     * DefaultDriverOption 有哪些配置主要看这个类
     *
     * @return
     */
    @Override
    protected SessionBuilderConfigurer getSessionBuilderConfigurer() {
        log.info("getSessionBuilderConfigurer-start poolSize : {}", poolSize);
        return new SessionBuilderConfigurer() {
            @Override
            public CqlSessionBuilder configure(CqlSessionBuilder cqlSessionBuilder) {
                CqlSessionBuilder cqlSessionBuilder1 = cqlSessionBuilder
                        .withConfigLoader(DriverConfigLoader.programmaticBuilder()
                                .withDuration(DefaultDriverOption.REQUEST_TIMEOUT, Duration.ofMillis(6000))
                                .withDuration(DefaultDriverOption.HEARTBEAT_TIMEOUT, Duration.ofMillis(3000))
                                .withInt(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE, poolSize)
                                .withInt(DefaultDriverOption.CONNECTION_POOL_REMOTE_SIZE, poolSize)
                                .build());
                return cqlSessionBuilder1;
            }
        };
    }
}

分区优化

注意:分区优化需要结合压测 & 监控

压测方法:zqhxuyuan.github.io/2015/10/15/...

压测过程

分区相关知识

  • Cassandra 官方建议单个分区数据大小不要超过 50 M,实战可以控制在 10M 左右性能更好
  • Cassandra 的每个节点都是协调器,每个节点之间都会互相通信,所以当一个节点接收请求时它可以知道数据在哪个节点,每个节点负责一定范围的令牌, Cassandra 通过查看表中的分区键来执行这些读取和写入操作,并使用令牌(tokens)(一个 -2^{63}−263 到 +2^{63}-1+263−1 范围内的 long 类型值)来进行数据分布和索引,拿到分区键就可以快速通过令牌分区函数定位到分区,又因为这个 tokens 数非常多,所以可以做到哪怕 2000w 分区也可以快速查询

查询有 2000w 数据的表,表中一共 2000w 分区,但是没有大分区的情况

查询有 2400w 数据的表,表中有 2000w 小分区和 2 个 200w 数据的大分区,查询 2 个大分区

查询有 4000w 数据的表,表中有 2000w 小分区和 2 个 1000w 数据的大分区,查询 2 个大分区

查询有 4000w 数据的表,表中有 2000w 小分区和 2 个 1000w 数据的大分区,不查询 2 个大分区,只查询小分区

压测总结

  • 只要单个分区数据大小合理,哪怕 2000w 分区也能快速查询
  • 查询越大的分区,查询延迟越大
  • 一张表中有大分区,但是不查询大分区,查询速度也很快 综上设计分区时尽量避免后续产生大分区

如何设计分区

优化思路
  • 使分区尽量散列确保数据的均匀分布
常见两种分区方案
  • 唯一键是字符串
java 复制代码
import org.apache.commons.codec.digest.MurmurHash3;

public Integer getPartitionId(String uuid) {
    int hash32x86 = MurmurHash3.hash32x86(uuid.getBytes());
    int finalHash = Math.abs(hash32x86 % 1000000);
    return finalHash;
}

注意:1000000 取决于你的数据大小,这个案例实际含义该表最大会有 1000000 个分区,每个分区总数据大小不要超过 50M,如果可能超过 50M 则应在设计表时扩大分区数直到预估不存在超过 50M 的分区

  • 唯一键是自增数字类型
java 复制代码
public Long getPartitionId(Long userId) {
    long partitionId = userId / 1000;
    return partitionId;
}

注意:1000 取决于你的数据大小,这个案例实际含义就是每 1000 个用户的该表数据在一个分区,一个用户可能存在多条数据,每 1000 个用户的分区总数据大小不要超过 50 M

云盘读写达上限,导致读延迟

Cassandra 延迟数据表现

Cassandra Cpu 使用率

云盘吞吐量,突增达到上限

咨询阿里云是否超过上限,得到回答:秒级监控读达到 475M/s ,超过上限 这也解释了一大困惑:为什么 cassandra 延迟很高,但是 cpu 使用率却不高,因为性能瓶颈在云盘,并不在 cassandra 服务器,而在云盘

相关推荐
数据库小学妹8 小时前
金融数据库成本怎么算?五笔钱加一张TCO表
数据库·金融行业·数据库选型·国产化替代·tco·金融数据库
KaiwuDB8 小时前
KaiwuDB 分布式集群扩缩容,从原理到完整操作踩坑总结
运维·数据库·分布式
auspicious航8 小时前
PostgreSQL的备份与恢复
数据库·postgresql
这个DBA有点耶9 小时前
从 MySQL 到时序数据库:我帮朋友做迁移的完整记录
数据库·架构·dba
泡海椒9 小时前
深度解析JQuick-SQL AST到逻辑计划转换机制|分布式SQL原理
数据库·分布式·sql
心静财富之门9 小时前
Python 数据共享四种方案完整实例(同进程 / JSON / Redis / HTTP)
数据库·python·oracle
略略略咯咯9 小时前
啊啊啊啊啊
java·服务器·数据库
奇牙coding9 小时前
GPT-5.5 报 401 invalid_api_key 怎么办?换密钥前按 4 层排查请求头、项目权限和端点
数据库·gpt·ios·ai
IvorySQL9 小时前
PostgreSQL 日报| WAL summarizer 断言失败(10 月 26 日)
数据库·postgresql·区块链
这个DBA有点耶10 小时前
2026年国产数据库“实际用户增长最快”核验指南:口径优先级、可查数据与选型动作清单
数据库·mysql·架构