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 服务器,而在云盘

相关推荐
日里安22 分钟前
8. 基于 Redis 实现限流
数据库·redis·缓存
EasyCVR1 小时前
ISUP协议视频平台EasyCVR视频设备轨迹回放平台智慧农业视频远程监控管理方案
服务器·网络·数据库·音视频
Elastic 中国社区官方博客1 小时前
使用真实 Elasticsearch 进行更快的集成测试
大数据·运维·服务器·数据库·elasticsearch·搜索引擎·集成测试
明月与玄武2 小时前
关于性能测试:数据库的 SQL 性能优化实战
数据库·sql·性能优化
PGCCC3 小时前
【PGCCC】Postgresql 存储设计
数据库·postgresql
PcVue China5 小时前
PcVue + SQL Grid : 释放数据的无限潜力
大数据·服务器·数据库·sql·科技·安全·oracle
魔道不误砍柴功7 小时前
简单叙述 Spring Boot 启动过程
java·数据库·spring boot
锐策7 小时前
〔 MySQL 〕数据库基础
数据库·mysql
远歌已逝8 小时前
管理Oracle实例(二)
数据库·oracle
日月星宿~8 小时前
【MySQL】summary
数据库·mysql