分布式微服务系统架构第126集:集群,数据库扩展,多节点分布,分库,分表,分片,分表,运维

加群联系作者vx:xiaoda0423

仓库地址:https://webvueblog.github.io/JavaPlusDoc/

https://1024bat.cn/

cassandra 主备集群
elasticsearch
nginx
redis

grafana+prometheus
skywalking

一、开头部分:nohup ... &

nohup ... >/dev/null 2>&1 &

部分

说明

nohup

防止程序因退出终端而终止,保证服务后台运行

> /dev/null 2>&1

把标准输出(stdout)和错误输出(stderr)都重定向到“黑洞”(不显示任何日志)

&

表示 后台运行,不会卡住当前终端

📌 生产环境中常用,可以不挂断地运行服务。

参数

说明

-javaagent=...

启动时加载 SkyWalking 的探针(agent),用于采集调用链

agent.service_name=xx-service

当前服务在链路追踪系统中的名称

collector.backend_service=xxx:xxx

SkyWalking 后端 OAP 服务地址(收集数据)

参数

说明

nacos.discovery.server-addr

配置 Nacos 注册中心地址(服务注册发现)

spring.profiles.active=prod

使用 application-prod.yml 作为配置文件(生产环境)

server.port=xxx

启动服务监听的端口号为 10003

  • ✅ 如果你想看日志

    > /var/log/xxx-service.log 2>&1 &
  • ✅ 如果服务挂了,可以用:

    ps -ef | grep xxx-service
    kill -9 <PID>

给脚本加执行权限

chmod +x start.sh stop.sh restart.sh

生产环境建议

建议项

内容

配置外置

用 application-prod.yml 放到 /config 或指定 -Dspring.config.location

日志系统

使用 logback-spring.xml 输出日志到文件

守护进程

生产中可以考虑用 systemd 或 supervisor 守护 Java 服务防止崩溃

日常部署注意事项

内容

建议

JAR 包版本管理

放在 releases/ 子目录,方便版本管理和回退

使用软链接启动

current -> 真实 jar

,解耦脚本与版本

保持日志不被覆盖

日志写入 logs/ 目录,防止丢失

自动化

可升级为 Jenkins、GitLab CI、Ansible 等自动部署

✅ 工具横向对比推荐

系统

推荐压测工具

并发控制

备注

Cassandra

cassandra-stress

内置工具,广泛使用

Scylla

scylla-bench

官方支持,兼容 Cassandra

Elasticsearch

esrally

官方工具,支持自定义场景

Kafka

kafka-producer-perf-test

吞吐、延迟指标清晰

MySQL

sysbench

支持读写混合、高并发模拟

Redis

redis-benchmark

极高性能测试,支持多命令

(Redis压测参考)

Record Count

Operation

Avg TPS / QPS

Avg Latency

CPU (%)

Mem (MB)

Disk Write

Disk Used

1M

Write

150,000

0.6 ms

80%

500 MB

100 MB/s

0.4 GB

汇总:

Record Count

Operation

QPS (r/s)

Avg Latency (估算)

CPU

MEM

Disk

Space

1,000,000

SET

154930.12

≈ 6.45ms/1M = 0.006

1,000,000

GET

159235.67

≈ 6.28ms/1M = 0.006

日志文件内容(每秒一行):

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 1120000  12300 205500    0    0     5     6  110  210  5  3 90  2  0
 1  0      0 1108000  12000 208000    0    0     4     8  108  190  7  4 87  2  0
 ...

可从中提取:

  • us+sy:CPU使用率(user/system)

  • free:空闲内存

  • wa:I/O等待率

  • bi/bo:磁盘读写速率(block in/out)

✅ 注意事项

项目

建议

✅ 自动调用

主脚本中已经用:./tools/monitor.sh start ... & 和 stop ...

❗防止误删

如果中间卡死或中断,请手动 kill $(cat /tmp/monitor_pid)

✅ 多系统兼容

文件名中加上 ${SYSTEM}_${COUNT} 区分不同压测记录

✅ Cassandra 中的 Keyspace 是什么?

Keyspace 类似于 MySQL 的数据库(CREATE DATABASE),是 Cassandra 的最顶层数据结构,里面包含多个表(Table)。每个 Keyspace 有自己的 复制策略(replication strategy) 和 副本数(replication factor) 。

  • 'class': 'SimpleStrategy':复制策略选择的是 SimpleStrategy,适合单数据中心

  • 'replication_factor': 2每条数据保存 2 份,分布在不同节点,提高容灾能力。

✅ 副本数(replication_factor)设置建议

  • 2 表示:写入数据会保存两份,放在两个节点上。

    • 适合生产环境的主数据,防止单节点宕机导致数据丢失。

  • 1 表示:只保存一份,适合日志这类容错要求不高、容量大的场景。

多数据中心的集群

WITH replication = {
  'class': 'NetworkTopologyStrategy',
  'datacenter1': 3,
  'datacenter2': 2
};

你想要 将 Cassandra 数据部署为副本 2(replication_factor=2)的高可用架构,需要满足以下两个条件:


✅ 1. 集群中至少部署两个节点

这是基本前提:因为副本数是 2,Cassandra 需要能在两个不同节点存放相同的数据。

✅ 最小部署拓扑示意:

Node1 (192.168.1.101)   ⇄   Node2 (192.168.1.102)
         __________________/
             数据副本互为备份

✅ 2. 创建 Keyspace 使用 SimpleStrategy(单数据中心)或 NetworkTopologyStrategy(多数据中心)

推荐方式(生产环境):

使用 NetworkTopologyStrategy,即使你只有一个数据中心,也建议使用它。

🛠 部署步骤简化(以两节点集群为例)

假设两台服务器:

  • Node1: 192.168.1.101

  • Node2: 192.168.1.102

修改两台机器的配置

修改 /etc/cassandra/cassandra.yaml 中关键字段:

每台机器都要配置:

cluster_name: 'MyCluster'         # 保持一致
num_tokens: 256                   # 默认值即可
listen_address: 本机IP            # 如 192.168.1.101 / 192.168.1.102
rpc_address: 0.0.0.0              # 或写死本机IP
seed_provider:
  - class_name: org.apache.cassandra.locator.SimpleSeedProvider
    parameters:
      - seeds: "192.168.1.101,192.168.1.102"
endpoint_snitch: GossipingPropertyFileSnitch
修改 /etc/cassandra/cassandra-rackdc.properties

确保都属于同一个数据中心:

dc=datacenter1
rack=rack1

启动 Cassandra 服务并加入集群

分别在两台机器上执行:

sudo systemctl start cassandra

或者:

cassandra -f

确认集群状态(任意节点上)

nodetool status

你会看到类似输出:

Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address         Load       Tokens       Owns (effective)  Host ID                               Rack
UN  192.168.1.101   150.99 KB  256          ?                 abcdefg-...                           rack1
UN  192.168.1.102   160.23 KB  256          ?                 hijklmn-...                           rack1

Cassandra 集群并写数据

连接 Cassandra + 写入 + 查询

import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.cql.*;

import java.net.InetSocketAddress;

public class CassandraExample {
    public static void main(String[] args) {
        // 连接 Cassandra 集群,传入主机 IP 和端口
        try (CqlSession session = CqlSession.builder()
                .addContactPoint(new InetSocketAddress("192.168.1.101", 9042))
                .addContactPoint(new InetSocketAddress("192.168.1.102", 9042))
                .withLocalDatacenter("datacenter1")  // 与 cassandra-rackdc.properties 的 dc 匹配
                .build()) {

            // 使用或创建 Keyspace
            session.execute("CREATE KEYSPACE IF NOT EXISTS demo_db " +
                    "WITH replication = {'class':'NetworkTopologyStrategy', 'datacenter1':2}");

            // 使用该 keyspace
            session.execute("USE demo_db");

            // 创建一个表
            session.execute("CREATE TABLE IF NOT EXISTS users (" +
                    "id UUID PRIMARY KEY," +
                    "name text," +
                    "email text)");

            // 插入数据
            session.execute("INSERT INTO users (id, name, email) VALUES (uuid(), 'Tom', 'tom@example.com')");

            // 查询数据
            ResultSet resultSet = session.execute("SELECT * FROM users");

            for (Row row : resultSet) {
                System.out.println("User: " + row.getString("name") + " - " + row.getString("email"));
            }
        }
    }
}

使用 Spring Data for Apache Cassandra(推荐企业项目)

💡 依赖(Spring Boot 项目使用):

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>

✅ application.yml 示例配置

spring:
  data:
    cassandra:
      contact-points: 192.168.1.101,192.168.1.102
      port: 9042
      keyspace-name: demo_db
      local-datacenter: datacenter1
      schema-action: create_if_not_exists

✅ Entity + Repository 示例

@Table("users")
public class User {
    @PrimaryKey
    private UUID id;

    private String name;
    private String email;

    // getters/setters ...
}
public interface UserRepository extends CassandraRepository<User, UUID> {
}

✅ 使用 Service 或 Controller 中调用

@Autowired
private UserRepository userRepository;

public void demo() {
    User user = new User();
    user.setId(UUID.randomUUID());
    user.setName("Alice");
    user.setEmail("alice@example.com");

    userRepository.save(user);

    userRepository.findAll().forEach(u -> System.out.println(u.getName()));
}

方案

适合场景

优点

原生 DataStax Java Driver

轻量项目 / 快速集成

灵活、性能好、控制粒度大

Spring Data Cassandra

Spring Boot 项目

快速开发、抽象更高、更易维护

项目结构预览

spring-cassandra-demo/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/com/example/demo/
│   │   │   ├── DemoApplication.java
│   │   │   ├── entity/User.java
│   │   │   ├── repository/UserRepository.java
│   │   │   └── controller/UserController.java
│   │   └── resources/
│   │       ├── application.yml
│   │       └── logback-spring.xml

✅ 1. pom.xml 添加依赖

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>spring-cassandra-demo</artifactId>
  <version>1.0.0</version>
  <dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Cassandra Starter -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-cassandra</artifactId>
    </dependency>

    <!-- UUID 工具包(可选) -->
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.6</version>
    </dependency>
  </dependencies>

  <properties>
    <java.version>17</java.version>
    <spring.boot.version>3.1.0</spring.boot.version>
  </properties>

  <build>
    <plugins>
      <!-- Spring Boot Plugin -->
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

✅ 2. application.yml 配置 Cassandra 连接

spring:
  data:
    cassandra:
      contact-points: 192.168.1.101,192.168.1.102
      port: 9042
      keyspace-name: demo_db
      local-datacenter: datacenter1
      schema-action: create_if_not_exists

✅ 3. DemoApplication.java 启动类

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

✅ 4. User.java 实体类

import org.springframework.data.cassandra.core.mapping.PrimaryKey;
import org.springframework.data.cassandra.core.mapping.Table;

import java.util.UUID;

@Table("users")
public class User {

    @PrimaryKey
    private UUID id;
    private String name;
    private String email;

    // Getters & Setters
    public UUID getId() { return id; }
    public void setId(UUID id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}

✅ 5. UserRepository.java 仓储接口

import com.example.demo.entity.User;
import org.springframework.data.cassandra.repository.CassandraRepository;
import java.util.UUID;

public interface UserRepository extends CassandraRepository<User, UUID> {
}

✅ 6. UserController.java 示例接口

import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @PostMapping
    public User create(@RequestBody User user) {
        user.setId(UUID.randomUUID());
        return userRepository.save(user);
    }

    @GetMapping
    public List<User> list() {
        return userRepository.findAll();
    }
}

🚀 启动 & 测试

1. 启动项目:

mvn spring-boot:run

2. 测试接口:

POST http://localhost:8080/users
Body:
{
  "name": "Alice",
  "email": "alice@example.com"
}

GET http://localhost:8080/users
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值