前言篇(3)项目目录和阅读代码切入点

190 阅读3分钟

一、项目目录

jocko源码中直接使用了开源serf和raft库,整个项目的代码非常简洁,其项目目录如下:

├── _examples
│   ├── cluster
│   └── sarama
├── cmd
│   └── jocko
├── commitlog
├── jocko
│   ├── config
│   ├── fsm
│   ├── metadata
│   ├── state
│   ├── structs
│   └── util
├── log
├── mock
├── protocol
└── testutil

二、阅读代码切入点

这里,选择example作为阅读的切入点,通过查看如何使用来了解整个核心流程。

1、单节点的场景-example/sarama

该例子展示了如何使用Sarama与Jocko协同生产和消费者消息。

其中Sarama 是一个用 Go 语言编写的 Apache Kafka 客户端库,它允许开发者在 Go 应用程序中轻松地与 Kafka 集群进行交互,包括发布消息到 Kafka 主题(生产者角色)、订阅并消费主题中的消息(消费者角色)以及管理 Kafka 集群的元数据。

下面是项目中给出的例子,这里将一些校验和输出的代码删除,仅留下主要逻辑:

1)首先是创建kafka server,即在集群中创建一个broker

func setup() (*jocko.Server, func()) {
    // 创建broker
    c, cancel := jocko.NewTestServer(&testing.T{}, func(cfg *config.Config) {
       cfg.Bootstrap = true
       cfg.BootstrapExpect = 1
       cfg.StartAsLeader = true
    }, nil)
    // 开启server服务
    if err := c.Start(context.Background()); err != nil {
       fmt.Fprintf(os.Stderr, "failed to start cluster: %v\n", err)
       os.Exit(1)
    }
    
    //创建borker的连接
    conn, err := jocko.Dial("tcp", c.Addr().String())
    if err != nil {
       fmt.Fprintf(os.Stderr, "error connecting to broker: %v\n", err)
       os.Exit(1)
    }
    
    //通过该连接创建topic、topic中的分区数量以及对应的副本个数
    resp, err := conn.CreateTopics(&protocol.CreateTopicRequests{
       Requests: []*protocol.CreateTopicRequest{{
          Topic:             topic,
          NumPartitions:     numPartitions,
          ReplicationFactor: 1,
       }},
    }) 
    if err != nil {
       fmt.Fprintf(os.Stderr, "failed with request to broker: %v\n", err)
       os.Exit(1)
    }
    ...
    return c, func() {
       cancel()
       c.Shutdown()
       os.RemoveAll(logDir)
    }
}

2)连接kafka集群,由sarama根据提供的broker ip信息与Kafka集群建立网络连接

brokers := []string{s.Addr().String()}
producer, err := sarama.NewSyncProducer(brokers, config)
if err != nil {
    panic(err)
}

3)往创建的topic中生产数据

for i := 0; i < messageCount; i++ {
    message := fmt.Sprintf("Hello from Jocko #%d!", i)
    partition, offset, err := producer.SendMessage(&sarama.ProducerMessage{
       Topic: topic,
       Value: sarama.StringEncoder(message),
    }) // 指定发送的数据所在topic
    if err != nil {
       panic(err)
    }
    pmap[partition] = append(pmap[partition], check{
       partition: partition,
       offset:    offset,
       message:   message,
    })
}
if err = producer.Close(); err != nil {
    panic(err)
}

4)从创建的topic中消费数据

for partitionID := range pmap {
    consumer, err := sarama.NewConsumer(brokers, config)
    if err != nil {
       panic(err)
    }
    partition, err := consumer.ConsumePartition(topic, partitionID, 0)
    if err != nil {
       panic(err)
    }
    for msg := range partition.Messages() {
      ... ...// 对读取到的信息进行校验
    }
}

2、集群场景-examples/cluster

使用命令行启动集群

2.1 命令介绍

代码位置:jocko/main.go:

  • 主命令broker,它定义了启动 Jocko broker的行为,下面是它的标志(Flags):

    • --raft-addr:Raft 协议绑定和对外宣告的地址,默认为 "127.0.0.1:9093"。
    • --data-dir:存储日志文件的目录,默认为 "/tmp/jocko",可以是逗号分隔的多个目录。
    • --broker-addr:broker 绑定的地址,默认为 "0.0.0.0:9092"。
    • --serf-addr:Serf 服务发现组件绑定的地址,通过一个 newMemberlistConfigValue 函数封装参数,初始默认值为 "0.0.0.0:9094"。
    • --bootstrap:标识是否进行初始集群引导(危险操作)。
    • --bootstrap-expect:预期集群中的节点数。
    • --join 和 --join-wan:启动时加入的其他 broker 节点的 Serf LAN 和 WAN 地址,可以多次指定。
    • --id:broker 的 ID。
  • 主命令topic,作为管理主题的的命令,存在一个子命令create,该子命令存在以下标志位:

    • --broker-addr:与 broker 交互时需要绑定的地址,默认为 "0.0.0.0:9092"。
    • --topic:待创建主题的名字,这是必填项,通过 MarkFlagRequired("topic") 标记为必需。
    • --partitions:主题的分区数量,默认为 1。
    • --replication-factor:主题的复制因子,默认为 1

2.2 命令启动集群例子

代码 example/cluster/README.md

$ ./jocko broker \
          --data-dir="/tmp/jocko0" \
          --broker-addr=127.0.0.1:9001 \
          --raft-addr=127.0.0.1:9002 \
          --serf-addr=127.0.0.1:9003 \
          --bootstrap \
          --bootstrap-expect=3 \
          --id=1

$ ./jocko broker \
          --data-dir="/tmp/jocko1" \
          --broker-addr=127.0.0.1:9101 \
          --raft-addr=127.0.0.1:9102 \
          --serf-addr=127.0.0.1:9103 \
          --join=127.0.0.1:9003 \
          --bootstrap-expect=3 \
          --id=2

$ ./jocko broker \
          --data-dir="/tmp/jocko2" \
          --broker-addr=127.0.0.1:9201 \
          --raft-addr=127.0.0.1:9202 \
          --serf-addr=127.0.0.1:9203 \
          --join=127.0.0.1:9003 \
          --bootstrap-expect=3 \
          --id=3

其中启动的第一个节点是初始集群的引导节点,下面两个节点是加入该集群中的,他们都指向第一个节点即引导节点来加入,同时每个节点都存在一个编号。