Cassandra 线上优化实战

遇到什么问题?

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

官网介绍

https://cassandra.apache.org/_/cassandra-basics.html

配置优化

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

连接客户端配置优化

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;
            }
        };
    }
}

分区优化

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

压测方法:https://zqhxuyuan.github.io/2015/10/15/Cassandra-Stress/

压测过程

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

QPS
P99

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

在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述

压测总结
  • 只要单个分区数据大小合理,哪怕 2000w 分区也能快速查询
  • 查询越大的分区,查询延迟越大
  • 一张表中有大分区,但是不查询大分区,查询速度也很快
    综上设计分区时尽量避免后续产生大分区
如何设计分区
优化思路
  • 使分区尽量散列确保数据的均匀分布
常见两种分区方案
  • 唯一键是字符串
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 的分区

  • 唯一键是自增数字类型
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.提高云盘的规格
2.使用阿里云 AutoPL 云盘,可应对流量突增情况

视频讲解

B站视频讲解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值