以Kafka为原型,手写个MQ,加深对Golang语法应用的理解。
本文会持续更新中,小步快跑式的,有完成的版本都是可以运行的,后续有标记todo的版本都是规划中的。
V0.1版本
最简单的生产消费模型,使用chan做队列。
对生产者和消费者没有任何约束。
package main
import (
"fmt"
"math/rand"
"runtime"
"time"
)
func main() {
queue := make(chan int, 3)
go producer(queue)
go consumer(queue)
// 打印监控信息
for {
time.Sleep(3 * time.Second)
fmt.Printf("[Monitor-%v]GoRoutineNum=%d, channelSize=%d \n", time.Now(), runtime.NumGoroutine(), len(queue))
}
}
// 生产者
func producer(queue chan int) {
for {
queue <- rand.Intn(100)
time.Sleep(1 * time.Second) // 每秒生产一个消息
}
}
// 消费者
func consumer(queue chan int) {
for {
val, ok := <-queue
if !ok {
fmt.Println("queue had been closed")
return
}
time.Sleep(3 * time.Second) // 模拟消费耗时
fmt.Println("val=", val, time.Now())
}
}
V0.2版本
功能要求:
- 生产者:定时持续生产,还可以被打断,超时保护;
- 消费者:保证不会堆积;
package main
import (
"fmt"
"math/rand"
"os"
"os/signal"
"runtime"
"sync"
"syscall"
"time"
)
var wg sync.WaitGroup
func main() {
queue := make(chan int, 3)
go producer(queue)
go consumer(queue)
go monitor(queue)
time.Sleep(1 * time.Second)
wg.Wait()
}
// 生产者:定时持续生产,还可以被打断,超时保护;
func producer(queue chan int) {
osSignal := make(chan os.Signal, 1)
signal.Notify(osSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
timeoutTimer := time.NewTimer(3 * time.Second) // 生产超时计时器
for {
select {
case <-timeoutTimer.C: // 超时保护
fmt.Println("timeout, pid=", os.Getpid())
return
case <-osSignal: // 可以手动打断
fmt.Println("exist, pid=", os.Getpid())
return
default:
queue <- rand.Intn(100)
wg.Add(1)
timeoutTimer.Reset(3 * time.Second) // 重置超时计时器
time.Sleep(1 * time.Second) // 每秒生产一个消息
}
}
}
// 消费者
func consumer(queue chan int) {
for {
val, ok := <-queue
//consumerWorker(val, ok) // 单协程消费,会堆积,生产者会超时
go consumerWorker(val, ok) // Dispatch模式:尽力消费,可以保证队列不堆积,生产者不会超时
}
}
func consumerWorker(val int, ok bool) {
time.Sleep(3 * time.Second) // 模拟消费耗时
if !ok {
fmt.Println("queue had been closed")
return
}
wg.Done()
fmt.Println("val=", val, time.Now())
}
// 监控信息输出
func monitor(queue chan int) {
for {
time.Sleep(1 * time.Second)
fmt.Printf("[Monitor-%v]GoRoutineNum=%d, channelSize=%d \n", time.Now(), runtime.NumGoroutine(), len(queue))
}
}
V0.3版本
// todo
持久化:
- log文件append顺序写磁盘;
- 各topic的offset保存;
- 重启加载;
package main
V0.4版本
// todo
拆分Broker、生产者与消费者,独立出生产与消费客户端、Broker Server端。
V0.5版本
// todo
性能基准测试特性
V0.6版本
// todo
零拷贝
V0.7版本
// todo
多分区,提高并发度
V0.8版本
// todo
消费者组特性

1675

被折叠的 条评论
为什么被折叠?



