作者 kevin

use kq from go-queue

... ... @@ -3,11 +3,13 @@ module github.com/tal-tech/go-stash
go 1.14
require (
github.com/DataDog/zstd v1.4.0 // indirect
github.com/fortytw2/leaktest v1.3.0 // indirect
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
github.com/json-iterator/go v1.1.10
github.com/mailru/easyjson v0.7.3 // indirect
github.com/olivere/elastic v6.2.34+incompatible
github.com/segmentio/kafka-go v0.3.5
github.com/tal-tech/go-zero v1.0.3
github.com/segmentio/kafka-go v0.4.2
github.com/tal-tech/go-queue v0.0.0-20200901073541-0da84ebed328
github.com/tal-tech/go-zero v1.0.8
)
... ...
... ... @@ -11,6 +11,7 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
github.com/beanstalkd/go-beanstalk v0.1.0/go.mod h1:/G8YTyChOtpOArwLTQPY1CHB+i212+av35bkPXXj56Y=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
... ... @@ -36,6 +37,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/siphash v1.2.1/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819/go.mod h1:MvzMVHq8BH2Ji/o8TGDocVA70byvLrAgFTxkEnmjO4Y=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
... ... @@ -61,6 +63,8 @@ github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dT
github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-xorm/builder v0.3.4/go.mod h1:KxkQkNN1DpPKTedxXyTQcmH+rXfvk4LZ9SOOBoZBAxw=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
... ... @@ -105,6 +109,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
... ... @@ -122,6 +127,8 @@ github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999/go.mod h1:hY+WOq6m2F
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.9.8 h1:VMAMUUOh+gaxKTMk+zqbjsSjsIcUcL/LF4o63i82QyA=
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
... ... @@ -193,6 +200,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/segmentio/kafka-go v0.3.5 h1:2JVT1inno7LxEASWj+HflHh5sWGfM0gkRiLAxkXhGG4=
github.com/segmentio/kafka-go v0.3.5/go.mod h1:OT5KXBPbaJJTcvokhWR2KFmm0niEx3mnccTwjmLvSi4=
github.com/segmentio/kafka-go v0.4.2 h1:QXZ6q9Bu1JkAJQ/CQBb2Av8pFRG8LQ0kWCrLXgQyL8c=
github.com/segmentio/kafka-go v0.4.2/go.mod h1:Inh7PqOsxmfgasV8InZYKVXWsdjcCq2d9tFV75GLbuM=
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
... ... @@ -210,8 +219,12 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/tal-tech/go-queue v0.0.0-20200901073541-0da84ebed328 h1:rWeU2ZWx/Jwmd77IQtd7k3RMZIh8e7i4yzztrt4kPLM=
github.com/tal-tech/go-queue v0.0.0-20200901073541-0da84ebed328/go.mod h1:vffND44z/ta5szc5rD0cEAK7qphrgT2rrTxghQ1JWDE=
github.com/tal-tech/go-zero v1.0.3 h1:B7yo8yMh27ZfEpjM7s6tPKGaLtSBufIPxTPMwjsiDxI=
github.com/tal-tech/go-zero v1.0.3/go.mod h1:MZHttkq0yf8kUd3TGaGvwUpiRIw9eD2iNFFfkx4YgG4=
github.com/tal-tech/go-zero v1.0.8 h1:Wca6UVi5+Pr1GOFCpvcB178EzlecLlKEgGb3v8Ln1dQ=
github.com/tal-tech/go-zero v1.0.8/go.mod h1:/e0i8rMFzFO6Lha+UG9/nkzLSvv5dyYCCN+TFP1JcB0=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
... ... @@ -222,6 +235,7 @@ github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
... ...
package kq
import "github.com/tal-tech/go-zero/core/service"
const (
firstOffset = "first"
lastOffset = "last"
)
type KqConf struct {
service.ServiceConf
Brokers []string
Group string
Topic string
Offset string `json:",options=first|last,default=last"`
NumConns int `json:",default=1"`
NumProducers int `json:",default=8"`
NumConsumers int `json:",default=8"`
MinBytes int `json:",default=10240"` // 10K
MaxBytes int `json:",default=10485760"` // 10M
}
package kq
import (
"context"
"strconv"
"time"
"github.com/segmentio/kafka-go"
"github.com/segmentio/kafka-go/snappy"
"github.com/tal-tech/go-zero/core/executors"
"github.com/tal-tech/go-zero/core/logx"
)
type (
PushOption func(options *chunkOptions)
Pusher struct {
produer *kafka.Writer
topic string
executor *executors.ChunkExecutor
}
chunkOptions struct {
chunkSize int
flushInterval time.Duration
}
)
func NewPusher(addrs []string, topic string, opts ...PushOption) *Pusher {
producer := kafka.NewWriter(kafka.WriterConfig{
Brokers: addrs,
Topic: topic,
Balancer: &kafka.LeastBytes{},
CompressionCodec: snappy.NewCompressionCodec(),
})
pusher := &Pusher{
produer: producer,
topic: topic,
}
pusher.executor = executors.NewChunkExecutor(func(tasks []interface{}) {
chunk := make([]kafka.Message, len(tasks))
for i := range tasks {
chunk[i] = tasks[i].(kafka.Message)
}
if err := pusher.produer.WriteMessages(context.Background(), chunk...); err != nil {
logx.Error(err)
}
}, newOptions(opts)...)
return pusher
}
func (p *Pusher) Close() error {
return p.produer.Close()
}
func (p *Pusher) Name() string {
return p.topic
}
func (p *Pusher) Push(v string) error {
msg := kafka.Message{
Key: []byte(strconv.FormatInt(time.Now().UnixNano(), 10)),
Value: []byte(v),
}
if p.executor != nil {
return p.executor.Add(msg, len(v))
} else {
return p.produer.WriteMessages(context.Background(), msg)
}
}
func WithChunkSize(chunkSize int) PushOption {
return func(options *chunkOptions) {
options.chunkSize = chunkSize
}
}
func WithFlushInterval(interval time.Duration) PushOption {
return func(options *chunkOptions) {
options.flushInterval = interval
}
}
func newOptions(opts []PushOption) []executors.ChunkOption {
var options chunkOptions
for _, opt := range opts {
opt(&options)
}
var chunkOpts []executors.ChunkOption
if options.chunkSize > 0 {
chunkOpts = append(chunkOpts, executors.WithChunkBytes(options.chunkSize))
}
if options.flushInterval > 0 {
chunkOpts = append(chunkOpts, executors.WithFlushInterval(options.flushInterval))
}
return chunkOpts
}
package kq
import (
"context"
"io"
"log"
"time"
"github.com/segmentio/kafka-go"
_ "github.com/segmentio/kafka-go/gzip"
_ "github.com/segmentio/kafka-go/lz4"
_ "github.com/segmentio/kafka-go/snappy"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/queue"
"github.com/tal-tech/go-zero/core/service"
"github.com/tal-tech/go-zero/core/stat"
"github.com/tal-tech/go-zero/core/threading"
"github.com/tal-tech/go-zero/core/timex"
)
const (
defaultCommitInterval = time.Second
defaultMaxWait = time.Second
)
type (
ConsumeHandle func(key, value string) error
ConsumeHandler interface {
Consume(key, value string) error
}
queueOptions struct {
commitInterval time.Duration
maxWait time.Duration
metrics *stat.Metrics
}
QueueOption func(*queueOptions)
kafkaQueue struct {
c KqConf
consumer *kafka.Reader
handler ConsumeHandler
channel chan kafka.Message
producerRoutines *threading.RoutineGroup
consumerRoutines *threading.RoutineGroup
metrics *stat.Metrics
}
kafkaQueues struct {
queues []queue.MessageQueue
group *service.ServiceGroup
}
)
func MustNewQueue(c KqConf, handler ConsumeHandler, opts ...QueueOption) queue.MessageQueue {
q, err := NewQueue(c, handler, opts...)
if err != nil {
log.Fatal(err)
}
return q
}
func NewQueue(c KqConf, handler ConsumeHandler, opts ...QueueOption) (queue.MessageQueue, error) {
if err := c.SetUp(); err != nil {
return nil, err
}
var options queueOptions
for _, opt := range opts {
opt(&options)
}
ensureQueueOptions(c, &options)
if c.NumConns < 1 {
c.NumConns = 1
}
q := kafkaQueues{
group: service.NewServiceGroup(),
}
for i := 0; i < c.NumConns; i++ {
q.queues = append(q.queues, newKafkaQueue(c, handler, options))
}
return q, nil
}
func newKafkaQueue(c KqConf, handler ConsumeHandler, options queueOptions) queue.MessageQueue {
var offset int64
if c.Offset == firstOffset {
offset = kafka.FirstOffset
} else {
offset = kafka.LastOffset
}
consumer := kafka.NewReader(kafka.ReaderConfig{
Brokers: c.Brokers,
GroupID: c.Group,
Topic: c.Topic,
StartOffset: offset,
MinBytes: c.MinBytes, // 10KB
MaxBytes: c.MaxBytes, // 10MB
MaxWait: options.maxWait,
CommitInterval: options.commitInterval,
})
return &kafkaQueue{
c: c,
consumer: consumer,
handler: handler,
channel: make(chan kafka.Message),
producerRoutines: threading.NewRoutineGroup(),
consumerRoutines: threading.NewRoutineGroup(),
metrics: options.metrics,
}
}
func (q *kafkaQueue) Start() {
q.startConsumers()
q.startProducers()
q.producerRoutines.Wait()
close(q.channel)
q.consumerRoutines.Wait()
}
func (q *kafkaQueue) Stop() {
q.consumer.Close()
logx.Close()
}
func (q *kafkaQueue) consumeOne(key, val string) error {
startTime := timex.Now()
err := q.handler.Consume(key, val)
q.metrics.Add(stat.Task{
Duration: timex.Since(startTime),
})
return err
}
func (q *kafkaQueue) startConsumers() {
for i := 0; i < q.c.NumConsumers; i++ {
q.consumerRoutines.Run(func() {
for msg := range q.channel {
if err := q.consumeOne(string(msg.Key), string(msg.Value)); err != nil {
logx.Errorf("Error on consuming: %s, error: %v", string(msg.Value), err)
}
}
})
}
}
func (q *kafkaQueue) startProducers() {
for i := 0; i < q.c.NumProducers; i++ {
q.producerRoutines.Run(func() {
for {
msg, err := q.consumer.ReadMessage(context.Background())
// io.EOF means consumer closed
// io.ErrClosedPipe means committing messages on the consumer,
// kafka will refire the messages on uncommitted messages, ignore
if err == io.EOF || err == io.ErrClosedPipe {
return
}
if err != nil {
logx.Errorf("Error on reading mesage, %q", err.Error())
continue
}
q.channel <- msg
}
})
}
}
func (q kafkaQueues) Start() {
for _, each := range q.queues {
q.group.Add(each)
}
q.group.Start()
}
func (q kafkaQueues) Stop() {
q.group.Stop()
}
func WithCommitInterval(interval time.Duration) QueueOption {
return func(options *queueOptions) {
options.commitInterval = interval
}
}
func WithHandle(handle ConsumeHandle) ConsumeHandler {
return innerConsumeHandler{
handle: handle,
}
}
func WithMaxWait(wait time.Duration) QueueOption {
return func(options *queueOptions) {
options.maxWait = wait
}
}
func WithMetrics(metrics *stat.Metrics) QueueOption {
return func(options *queueOptions) {
options.metrics = metrics
}
}
type innerConsumeHandler struct {
handle ConsumeHandle
}
func (ch innerConsumeHandler) Consume(k, v string) error {
return ch.handle(k, v)
}
func ensureQueueOptions(c KqConf, options *queueOptions) {
if options.commitInterval == 0 {
options.commitInterval = defaultCommitInterval
}
if options.maxWait == 0 {
options.maxWait = defaultMaxWait
}
if options.metrics == nil {
options.metrics = stat.NewMetrics(c.Name)
}
}
... ... @@ -3,7 +3,7 @@ package config
import (
"time"
"github.com/tal-tech/go-stash/kq"
"github.com/tal-tech/go-queue/kq"
)
type (
... ...
{
"Input": {
"Kafka": {
"Name": "gostash",
"Brokers": [
"172.16.186.16:19092",
"172.16.186.17:19092"
],
"Topic": "k8slog",
"Group": "pro",
"NumProducers": 16
}
},
"Filters": [
{
"Action": "drop",
"Conditions": [
{
"Key": "k8s_container_name",
"Value": "-rpc",
"Type": "contains"
},
{
"Key": "level",
"Value": "info",
"Type": "match",
"Op": "and"
}
]
},
{
"Action": "remove_field",
"Fields": [
"message",
"_source",
"_type",
"_score",
"_id",
"@version",
"topic",
"index",
"beat",
"docker_container",
"offset",
"prospector",
"source",
"stream"
]
}
],
"Output": {
"ElasticSearch": {
"Hosts": [
"172.16.141.4:9200",
"172.16.141.5:9200"
],
"DailyIndexPrefix": "k8s_pro-"
}
}
}
\ No newline at end of file
... ... @@ -5,7 +5,7 @@ import (
"time"
"github.com/olivere/elastic"
"github.com/tal-tech/go-stash/kq"
"github.com/tal-tech/go-queue/kq"
"github.com/tal-tech/go-stash/stash/config"
"github.com/tal-tech/go-stash/stash/es"
"github.com/tal-tech/go-stash/stash/filter"
... ...