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

相关推荐
加勒比之杰克1 分钟前
【数据库初阶】MySQL数据类型
linux·数据库·mysql·数据类型·varchar
Libby博仙4 分钟前
asp.net core webapi中的数据注解与数据验证
数据库·asp.net·.netcore
网络安全成叔16 分钟前
【整理集合大全】MySQL(4) 数据库增删改查SQL语句
网络·数据库·sql·mysql·web安全·网络安全
雪芽蓝域zzs41 分钟前
MySQL(六)MySQL 案例
数据库·mysql·oracle
yuanbenshidiaos44 分钟前
QT-------------多线程
数据结构·数据库·qt
亦世凡华、1 小时前
从CRUD到高级功能:EF Core在.NET Core中全面应用(一)
数据库·经验分享·.netcore·ef core
XiangHua.Ma2 小时前
Redis 入门与实战指南
数据库·redis·缓存
皮克斯的进化之路2 小时前
Redis知识总结
数据库·redis·缓存
老大白菜2 小时前
MongoDB基本操作
数据库·mongodb
小小小妮子~3 小时前
深入解读MVCC中的三大日志:Undo Log、Redo Log和B-Log
服务器·数据库·oracle·日志