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

加群联系作者vx:xiaoda0423

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

https://1024bat.cn/

go 复制代码
cassandra 主备集群
elasticsearch
nginx
redis

grafana+prometheus
skywalking

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

go 复制代码
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
  • ✅ 如果你想看日志

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

    go 复制代码
    ps -ef | grep xxx-service
    kill -9 <PID>

给脚本加执行权限

go 复制代码
chmod +x start.sh stop.sh restart.sh

生产环境建议

建议项 内容
配置外置 application-prod.yml 放到 /config 或指定 -Dspring.config.location
日志系统 使用 logback-spring.xml 输出日志到文件
守护进程 生产中可以考虑用 systemdsupervisor 守护 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

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

go 复制代码
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 表示:只保存一份,适合日志这类容错要求不高、容量大的场景。

多数据中心的集群

go 复制代码
WITH replication = {
  'class': 'NetworkTopologyStrategy',
  'datacenter1': 3,
  'datacenter2': 2
};

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


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

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

✅ 最小部署拓扑示意:

go 复制代码
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 中关键字段:

每台机器都要配置:

go 复制代码
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

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

go 复制代码
dc=datacenter1
rack=rack1

启动 Cassandra 服务并加入集群

分别在两台机器上执行:

go 复制代码
sudo systemctl start cassandra

或者:

go 复制代码
cassandra -f

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

go 复制代码
nodetool status

你会看到类似输出:

go 复制代码
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 + 写入 + 查询

go 复制代码
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 项目使用):

go 复制代码
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>

✅ application.yml 示例配置

go 复制代码
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 示例

go 复制代码
@Table("users")
public class User {
    @PrimaryKey
    private UUID id;

    private String name;
    private String email;

    // getters/setters ...
}
go 复制代码
public interface UserRepository extends CassandraRepository<User, UUID> {
}

✅ 使用 Service 或 Controller 中调用

go 复制代码
@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 项目 快速开发、抽象更高、更易维护

项目结构预览

go 复制代码
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 添加依赖

go 复制代码
<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 连接

go 复制代码
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 启动类

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

✅ 4. User.java 实体类

go 复制代码
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 仓储接口

go 复制代码
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 示例接口

go 复制代码
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. 启动项目:

go 复制代码
mvn spring-boot:run

2. 测试接口:

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

GET http://localhost:8080/users
相关推荐
DLYSB_6 小时前
存储运维实战:基于 Ceph Event 监听与 Python 适配器的分布式存储健康度物理声光响应架构
运维·ceph·python·报警灯
阿里云云原生7 小时前
可用性从 99.9% 跃升至 99.995%:畅捷通如何用 AI 重塑运维底座?
运维·网络·人工智能
阿童木写作8 小时前
Python实现Temu图片批量翻译自动化教程
运维·人工智能·python·自动化
iori97king9 小时前
库存不足自动通知:第一次使用自动化
运维·自动化
@insist1239 小时前
信息系统管理工程师-信息系统运维资源、技术与智能运维核心考点解析
运维·软考·信管·软件水平考试·信息系统管理工程师
木子欢儿9 小时前
Intel 架构的 MacBook Pro 运行 Linux 发热量高解决
linux·运维·服务器
凌虚9 小时前
面向 MySQL 用户的 PostgreSQL 快速上手指南
数据库·后端·架构
五阿哥永琪9 小时前
MySQL中操作json的函数!
数据库·mysql·json
来者皆善9 小时前
了解Mysql优化吗?如何优化索引?
数据库·mysql
纯真时光10 小时前
微服务保护
微服务