Apache Storm 核心 API 详解

Apache Storm 核心 API 详解

Storm 的核心 API 提供了构建实时流处理应用的基础框架,以下是对其关键组件及使用方式的深度解析:


一、TopologyBuilder(拓扑构建器)

核心功能

构建数据处理拓扑结构,定义 Spout 和 Bolt 之间的数据流向

TopologyBuilder builder = new TopologyBuilder();

// 设置Spout (数据源)
builder.setSpout("kafka-spout", new KafkaSpout(), 3); // 并行度=3

// 设置Bolt (处理单元)
builder.setBolt("parser-bolt", new LogParserBolt(), 4)
       .shuffleGrouping("kafka-spout"); // 随机分组

builder.setBolt("counter-bolt", new CountBolt(), 4)
       .fieldsGrouping("parser-bolt", new Fields("ip")); // 按IP分组

// 定义输出Bolt
builder.setBolt("hdfs-bolt", new HdfsBolt(), 2)
       .globalGrouping("counter-bolt"); // 全局分组

关键方法

方法参数功能
setSpout(id, spout, parallelism)定义数据源
setBolt(id, bolt, parallelism)定义处理单元
shuffleGrouping(componentId)随机分组策略
fieldsGrouping(componentId, fields)按字段分组
allGrouping(componentId)广播分组
customGrouping(componentId, grouping)自定义分组

二、Spout API(数据源)

1. 基础接口:IRichSpout

public class KafkaSpout extends BaseRichSpout {
    private SpoutOutputCollector collector;
    private KafkaConsumer<String, String> consumer;

    // 初始化方法
    @Override
    public void open(Map conf, TopologyContext context, 
                    SpoutOutputCollector collector) {
        this.collector = collector;
        Properties props = new Properties();
        props.put("bootstrap.servers", "kafka:9092");
        consumer = new KafkaConsumer<>(props);
        consumer.subscribe(Arrays.asList("logs"));
    }

    // 核心数据拉取方法
    @Override
    public void nextTuple() {
        ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
        for (ConsumerRecord<String, String> record : records) {
            // 发射数据并携带MessageID (用于ACK)
            collector.emit(new Values(record.value()), record.offset());
        }
    }

    // ACK回调
    @Override
    public void ack(Object msgId) {
        consumer.commitSync(Collections.singletonMap(
            new TopicPartition("logs", 0), 
            new OffsetAndMetadata((Long)msgId + 1)
        ));
    }

    // Fail回调
    @Override
    public void fail(Object msgId) {
        LOG.error("Message failed: " + msgId);
    }
}

2. 核心方法说明

方法调用时机典型用途
open()Spout初始化时建立外部连接
nextTuple()循环调用获取并发射数据
ack(Object msgId)Tuple处理成功提交偏移量/清理状态
fail(Object msgId)Tuple处理失败重发/记录错误
declareOutputFields()拓扑声明时定义输出字段

三、Bolt API(处理单元)

1. 基础接口:IRichBolt

public class CountBolt extends BaseRichBolt {
    private OutputCollector collector;
    private Map<String, Integer> counters;

    @Override
    public void prepare(Map conf, TopologyContext context, 
                       OutputCollector collector) {
        this.collector = collector;
        this.counters = new HashMap<>();
    }

    @Override
    public void execute(Tuple input) {
        String ip = input.getStringByField("ip");
        
        // 更新计数
        int count = counters.getOrDefault(ip, 0) + 1;
        counters.put(ip, count);
        
        // 发射新数据
        collector.emit(new Values(ip, count));
        
        // 显式ACK
        collector.ack(input);
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        declarer.declare(new Fields("ip", "count"));
    }
    
    @Override
    public void cleanup() {
        // 拓扑关闭时执行
        counters.forEach((ip, count) -> 
            System.out.println(ip + " : " + count));
    }
}

2. 核心方法说明

方法调用时机典型用途
prepare()Bolt初始化时初始化资源
execute(Tuple input)收到Tuple时业务逻辑处理
declareOutputFields()拓扑声明时定义输出字段
cleanup()Bolt关闭时资源清理

四、Tuple(数据单元)

核心操作

// 获取字段值
String ip = tuple.getString(0);       // 按位置索引
String url = tuple.getStringByField("url"); // 按字段名

// 获取元数据
ComponentId sourceComponent = tuple.getSourceComponent();
int sourceTask = tuple.getSourceTask();
StreamId streamId = tuple.getSourceStreamId();

// 创建新Tuple
List<Object> values = Arrays.asList("192.168.1.1", "/index.html", 200);
Tuple newTuple = new TupleImpl(context, values, tuple.getMessageId(), streamId);

五、分组策略(Stream Grouping)

1. 内置分组实现

// 随机分组(轮询分发)
ShuffleGrouping shuffle = new ShuffleGrouping();

// 字段分组(相同字段值到同一Task)
FieldsGrouping fields = new FieldsGrouping("ip", "user_id");

// 全局分组(所有数据发往同一Task)
GlobalGrouping global = new GlobalGrouping();

// 广播分组(所有Task都收到)
AllGrouping all = new AllGrouping();

2. 自定义分组策略

public class IPRangeGrouping implements CustomStreamGrouping {
    @Override
    public void prepare(WorkerTopologyContext context, 
                       GlobalStreamId stream, 
                       List<Integer> targetTasks) {
        // 初始化操作
    }
    
    @Override
    public List<Integer> chooseTasks(int taskId, List<Object> values) {
        String ip = (String) values.get(0);
        // 自定义路由逻辑:按IP段分配
        if (ip.startsWith("192.168")) {
            return Arrays.asList(0); // 分配到Task0
        } else {
            return Arrays.asList(1); // 分配到Task1
        }
    }
}

// 使用自定义分组
builder.setBolt("geo-bolt", new GeoBolt(), 2)
       .customGrouping("spout", new IPRangeGrouping());

六、可靠性机制(ACK框架)

1. 锚定机制(Anchoring)

// 在Bolt中发射新Tuple时建立锚定
collector.emit(input, new Values(derivedData)); 

// 多锚定场景(一个输出Tuple对应多个输入)
collector.emit(input1, Arrays.asList(input2), new Values(result));

2. 手动ACK/FAIL

public void execute(Tuple input) {
    try {
        process(input);
        collector.ack(input); // 处理成功
    } catch (Exception e) {
        collector.fail(input); // 处理失败
    }
}

3. 超时配置

Config conf = new Config();
conf.setMessageTimeoutSecs(30); // Tuple处理超时时间

七、配置系统(Config)

常用配置项

Config conf = new Config();

// 资源设置
conf.setNumWorkers(4); // Worker进程数
conf.setMaxSpoutPending(1000); // Spout最大未ACK数
conf.setMaxTaskParallelism(16); // 最大并行度

// 可靠性配置
conf.setNumAckers(2); // ACK线程数
conf.setMessageTimeoutSecs(30); // 超时时间

// 序列化配置
conf.registerSerialization(LogEntry.class, LogEntrySerializer.class);

// JVM参数
conf.put(Config.TOPOLOGY_WORKER_CHILDOPTS, "-Xmx2g -XX:+UseG1GC");

// 提交拓扑
StormSubmitter.submitTopology("network-monitor", conf, 
                            builder.createTopology());

配置优先级

  1. topology.* (拓扑代码设置)
  2. storm.yaml (集群配置文件)
  3. defaults.yaml (Storm默认配置)

八、Trident API(高级抽象)

核心操作示例

TridentTopology topology = new TridentTopology();

// 定义数据流
Stream stream = topology.newStream("spout", new KafkaSpout());

// 数据转换
stream.each(new Fields("log"), new ParserFunction(), new Fields("ip", "path"))
      .groupBy(new Fields("ip"))
      .persistentAggregate(
          new RedisStateFactory(), 
          new Count(), 
          new Fields("count")
      )
      .newValuesStream()
      .each(new Fields("ip", "count"), new ThresholdFilter(1000))
      .peek(new AlertFunction());

Trident 操作类型

操作API示例功能
Filter.each(filterFn)数据过滤
Function.each(functionFn)字段转换
Aggregation.aggregate(aggFn)聚合计算
State Query.stateQuery(state, queryFn)状态查询
Partitioning.partitionBy(fields)数据分区

九、序列化扩展

自定义序列化器

public class LogEntrySerializer implements Serializer<LogEntry> {
    @Override
    public void write(Kryo kryo, Output output, LogEntry entry) {
        output.writeString(entry.getIp());
        output.writeLong(entry.getTimestamp());
        output.writeString(entry.getPath());
    }
    
    @Override
    public LogEntry read(Kryo kryo, Input input, Class<LogEntry> type) {
        return new LogEntry(
            input.readString(),
            input.readLong(),
            input.readString()
        );
    }
}

// 注册序列化器
conf.registerSerialization(LogEntry.class, LogEntrySerializer.class);

十、高级特性API

1. 分布式RPC

// 定义DRPC流
DRPCSpout drpcSpout = new DRPCSpout("url-count");
builder.setSpout("drpc", drpcSpout);

builder.setBolt("counter", new UrlCounterBolt())
       .shuffleGrouping("drpc");

// 客户端调用
DRPCClient client = new DRPCClient("drpc-server", 3772);
String result = client.execute("url-count", "https://example.com");

2. 指标上报

public class MetricBolt extends BaseRichBolt {
    private transient Counter processedCounter;
    
    @Override
    public void prepare(Map conf, TopologyContext context, 
                       OutputCollector collector) {
        processedCounter = context.registerCounter("processed_records");
    }
    
    @Override
    public void execute(Tuple input) {
        // 业务处理...
        processedCounter.inc(); // 指标递增
    }
}

总结:Storm API 核心价值

1. 简洁的流处理抽象

  • Spout/Bolt 模型直观表达数据流
  • Tuple 作为统一数据载体
  • 分组策略灵活控制数据分发

2. 可靠的容错机制

  • ACK/Fail 精确控制消息生命周期
  • 锚定机制保障衍生数据可靠性
  • 超时配置防止系统阻塞

3. 灵活的扩展能力

  • 自定义分组策略
  • 自定义序列化器
  • 指标上报与监控集成

4. 丰富的生态集成

  • Kafka/JDBC/HDFS 等连接器
  • Redis/HBase 状态后端支持
  • 分布式RPC服务能力

通过合理组合这些API组件,开发者可以构建从简单ETL管道到复杂事件处理系统的各类实时应用,满足毫秒级延迟的业务场景需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值