功能点 11-12:客户端、RPC 通信、监控与安全

功能点 11-12:客户端、RPC 通信、监控与安全 ------ 源码阅读笔记

对应源码阅读计划功能点 11-12:FlussClient、Netty RPC、LogScanner、MetricRegistry、PrometheusReporter、FlussAuthorizer。


笔记 11.1:FlussClient ------ 客户端入口

文件:FlussClient.javaFlussConnection.java

路径fluss-client/src/main/java/org/apache/fluss/client/

核心结构

java 复制代码
public class FlussClient implements AutoCloseable {
    private final FlussConnection connection;
    private final Map<TabletKey, LogScanner> scanners;
    private final Map<TabletKey, LogWriter> writers;
    
    // ===== 流式读取 =====
    public LogScanner newLogScanner(
            TablePath tablePath, 
            int bucketId, 
            long startOffset,
            int[] projectedColumns) {
        
        // 1. 查找 Bucket 的 Leader TabletServer
        TabletServerInfo leader = findLeader(tablePath, bucketId);
        
        // 2. 连接到 Leader TabletServer
        return new LogScanner(
            connection.connect(leader),
            tablePath, bucketId, startOffset,
            projectedColumns  // ★ 传递给服务端用于列裁剪
        );
    }
    
    // ===== PK 查询 =====
    public byte[] pointLookup(TablePath tablePath, byte[] key) {
        // 1. 计算分桶
        int bucketId = bucketingFunction.getBucket(key, numBuckets);
        
        // 2. 查找 Leader
        TabletServerInfo leader = findLeader(tablePath, bucketId);
        
        // 3. 发送 PK Lookup RPC
        KvLookupRequest request = KvLookupRequest.builder()
            .tablePath(tablePath)
            .bucketId(bucketId)
            .key(key)
            .build();
        
        KvLookupResponse response = connection.send(leader, request);
        return response.getValue();  // 亚毫秒级
    }
    
    // ===== 流式写入 =====
    public LogWriter newLogWriter(
            TablePath tablePath, 
            int bucketId, 
            WriteMode mode) {
        
        // 1. 查找 Leader
        TabletServerInfo leader = findLeader(tablePath, bucketId);
        
        // 2. 创建 Writer
        return new LogWriter(
            connection.connect(leader),
            tablePath, bucketId,
            mode,  // APPEND / UPSERT / DELETE
            producerId, producerEpoch  // ★ 幂等写入参数
        );
    }
    
    // ===== 管理操作 =====
    public void createTable(TablePath tablePath, TableDescriptor descriptor) {
        // 发送到 CoordinatorServer
        CoordinatorServerInfo coordinator = findCoordinatorLeader();
        CreateTableRequest request = CreateTableRequest.builder()
            .tablePath(tablePath)
            .descriptor(descriptor)
            .build();
        connection.send(coordinator, request);
    }
}

笔记 11.2:LogScanner ------ 日志扫描器

文件:LogScanner.java

java 复制代码
public class LogScanner {
    
    private long currentOffset;
    private final int[] projectedColumns;
    
    /**
     * 拉取下一批数据
     */
    public ArrowRecordBatch nextBatch() {
        // 1. 构造 Fetch RPC 请求
        FetchRequest request = FetchRequest.builder()
            .tabletId(tabletId)
            .startOffset(currentOffset)
            .maxBytes(MAX_FETCH_SIZE)      // 默认 1MB
            .isolation(FetchIsolation.READ_COMMITTED)  // 只读已提交数据
            .projectedColumns(projectedColumns)  // ★ 列裁剪
            .build();
        
        // 2. 发送到 TabletServer
        FetchResponse response = rpcClient.fetch(tabletServer, request);
        
        // 3. 解析 Arrow IPC 格式的响应
        if (response.getRecordBatch() != null) {
            ArrowRecordBatch batch = ArrowRecordBatch.fromIpc(
                response.getRecordBatch()
            );
            currentOffset = response.getNextOffset();
            return batch;
        }
        
        return null;  // 没有新数据
    }
}

笔记 11.3:Netty RPC 通信层

文件:NettyClient.javaNettyServer.javaRpcGateway.java

路径fluss-rpc/src/main/java/org/apache/fluss/rpc/netty/

RPC 协议栈

复制代码
应用层:
  FlussClient / FlussServer
      ↓
RPC 层:
  RpcGateway (接口定义)
      ↓
  RpcRequest / RpcResponse (封装)
      ↓
序列化:
  ProtobufSerializer (Protobuf 3.25.5)
      ↓
传输层:
  Netty 4.x (NIO, EventLoop)
      ↓
网络:
  TCP (直接连接)

Netty Server 实现

java 复制代码
public class NettyServer {
    private final EventLoopGroup bossGroup;    // 接受连接
    private final EventLoopGroup workerGroup;  // 处理 I/O
    
    public void start() {
        ServerBootstrap bootstrap = new ServerBootstrap()
            .group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .childHandler(new ChannelInitializer<>() {
                @Override
                protected void initChannel(SocketChannel ch) {
                    ch.pipeline()
                        .addLast("frameDecoder", 
                            new LengthFieldBasedFrameDecoder(
                                MAX_FRAME_SIZE, 0, 4, 0, 4
                            ))  // ★ 处理 TCP 粘包/拆包
                        .addLast("protobufDecoder",
                            new ProtobufDecoder(RpcRequest.getDefaultInstance()))
                        .addLast("protobufEncoder",
                            new ProtobufEncoder())
                        .addLast("rpcHandler",
                            new RpcServerHandler(rpcService));
                }
            })
            .option(ChannelOption.SO_BACKLOG, 128)
            .childOption(ChannelOption.TCP_NODELAY, true)  // ★ 关闭 Nagle,降低延迟
            .childOption(ChannelOption.SO_KEEPALIVE, true);
        
        ChannelFuture future = bootstrap.bind(port).sync();
    }
}

关键优化

  • TCP_NODELAY:关闭 Nagle 算法,避免小数据包延迟(延迟敏感场景)
  • LengthFieldBasedFrameDecoder:处理 TCP 流式传输的边界问题
  • ProtobufEncoder/Decoder:高效二进制序列化

笔记 12.1:MetricRegistry ------ 监控指标系统

文件:MetricRegistry.javaPrometheusReporter.java

指标注册与上报

java 复制代码
public class MetricRegistry {
    
    // 指标类型
    private final Map<String, Counter> counters;      // 计数器(累积)
    private final Map<String, Gauge> gauges;          // 瞬时值
    private final Map<String, Histogram> histograms;  // 分布
    
    /**
     * TabletServer 关键指标注册
     */
    public void registerTabletMetrics() {
        // 日志读写速率
        registerCounter("fluss.tablet.log.write.rate", 
            () -> logWriteCount.getAndReset());  // 每秒写入条数
        
        registerCounter("fluss.tablet.log.read.rate",
            () -> logReadCount.getAndReset());   // 每秒读取条数
        
        // KV 读写延迟
        registerHistogram("fluss.tablet.kv.get.latency",
            new long[]{1, 5, 10, 50, 100, 500});  // P50/P90/P99
        
        registerHistogram("fluss.tablet.kv.put.latency", ...);
        
        // 磁盘使用
        registerGauge("fluss.tablet.disk.usage.bytes",
            () -> getDiskUsage());
        
        // Tiering 延迟
        registerGauge("fluss.tablet.tiering.offset.lag",
            () -> LEO - lastTieredOffset);
    }
}

Prometheus 输出格式

java 复制代码
public class PrometheusReporter implements MetricReporter {
    
    @Override
    public String report() {
        StringBuilder sb = new StringBuilder();
        
        // Prometheus 文本格式
        // fluss_tablet_log_write_rate{job="fluss",instance="ts-1"} 52340
        // fluss_tablet_kv_get_latency_p99{job="fluss",instance="ts-1"} 3.2
        
        for (var entry : counters.entrySet()) {
            sb.append(formatPrometheusMetric(
                entry.getKey(), 
                labels, 
                entry.getValue().get()
            )).append("\n");
        }
        
        return sb.toString();
    }
}

笔记 12.2:FlussAuthorizer ------ 安全授权

文件:FlussAuthorizer.java

路径fluss-server/src/main/java/org/apache/fluss/server/authorizer/FlussAuthorizer.java

授权模型

java 复制代码
public interface Authorizer {
    
    /**
     * 检查用户是否有权限执行操作
     * 
     * @param user      请求用户
     * @param operation 操作类型(READ/WRITE/CREATE/ALTER/DROP)
     * @param resource  操作资源(TablePath/DatabaseName)
     */
    boolean authorize(User user, Operation operation, Resource resource);
    
    enum Operation {
        READ,       // SELECT / 流式读取
        WRITE,      // INSERT / UPDATE / DELETE
        CREATE,     // CREATE TABLE / DATABASE
        ALTER,      // ALTER TABLE
        DROP,       // DROP TABLE / DATABASE
        DESCRIBE,   // SHOW / DESCRIBE
    }
    
    /**
     * SASL/PLAIN 认证配置
     * 
     * fluss-conf.yaml:
     *   security.enabled: true
     *   sasl.mechanism: PLAIN
     *   sasl.users: "user1:password1,user2:password2"
     */
    void authenticate(String username, String password);
}

阅读小结(全系列)

功能点 核心文件数 关键收获
1. 启动流程 3 Standby→Leader 两阶段、ZK Fence 防脑裂
2. 元数据 3 ZK 元数据树、createTable 6步链路、Schema Evolution
3. 数据分布 3 MurmurHash3、轮询+容量感知分配、渐进式 Rebalance
4. LogStore 4 Segment 布局、稀疏索引二分查找、LEO/HW、幂等写入
5. KvStore 3 RocksDB 配置、三种 Merge Engine、WAL 恢复
6. Arrow 4 列式写入、零拷贝列裁剪、类型映射、Direct Memory
7. 副本/ISR 4 Leader/Follower 状态机、HW 推进、ZK 选举
8. Tiering 3 Arrow→Parquet、Union Read、3种 Lake Format
9. Flink Connector 4 Catalog/Source/Sink/Lookup、Two-Phase Commit
10. Delta Join 3 无状态算子、JoinStateStore、秒级恢复
11-12. 客户端/监控 4 Netty RPC、Prometheus、SASL 认证

全系列 12 个功能点源码阅读笔记完成。基于 Apache Fluss main 分支 (2026年8月)

相关推荐
数据知道17 分钟前
Java 安全审计实战:SSRF、反序列化、SpEL 注入
java·开发语言·安全·网络安全
楷哥爱开发1 小时前
HTTP代理是什么?性能分析、适用场景与配置教程
网络·网络协议·http
_codeOH1 小时前
LLM 应用安全实战:从 Prompt 注入到数据泄露的防护体系
安全·ai编程
q567315232 小时前
Curl 报 CONNECT tunnel failed, response 6xx:排查思路全解
数据库·网络协议·scrapy·http·中间件·http代理
shiyi.十一2 小时前
第8章:计算机网络中的安全 — 知识要点与架构
计算机网络·安全·架构
treesforest3 小时前
前端表单提效实践:基于IP地理位置实现国家区号智能预填
前端·网络协议·tcp/ip·ip定位·ip属地
瓦学妹3 小时前
HTTP代理性能分析:如何利用 IPFoxy 快速灵活切换协议?
网络·网络协议·http
国科安芯3 小时前
小卫星综合电子系统中RISC-V抗辐射MCU的功能安全与多接口集成架构分析
单片机·嵌入式硬件·安全·fpga开发·架构·risc-v
OpenCloudOS3 小时前
高危|Linux 内核 XFS reflink 本地提权漏洞修复指南
linux·网络·安全