Skip to content

Commit bc0f39d

Browse files
authored
feat: producer support multiple logstore pack id generate (#307)
* feat: producer support multiple logstroe pack id generate * chore: refine add benchmark
1 parent d719e9d commit bc0f39d

File tree

5 files changed

+109
-17
lines changed

5 files changed

+109
-17
lines changed

producer/log_accumulator.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type LogAccumulator struct {
2121
logger log.Logger
2222
threadPool *IoThreadPool
2323
producer *Producer
24+
packIdGenrator *PackIdGenerator
2425
}
2526

2627
func initLogAccumulator(config *ProducerConfig, ioWorker *IoWorker, logger log.Logger, threadPool *IoThreadPool, producer *Producer) *LogAccumulator {
@@ -32,6 +33,7 @@ func initLogAccumulator(config *ProducerConfig, ioWorker *IoWorker, logger log.L
3233
logger: logger,
3334
threadPool: threadPool,
3435
producer: producer,
36+
packIdGenrator: newPackIdGenerator(),
3537
}
3638
}
3739

@@ -96,10 +98,11 @@ func (logAccumulator *LogAccumulator) createNewProducerBatch(logType interface{}
9698
level.Debug(logAccumulator.logger).Log("msg", "Create a new ProducerBatch")
9799

98100
if mlog, ok := logType.(*sls.Log); ok {
99-
newProducerBatch := initProducerBatch(mlog, callback, project, logstore, logTopic, logSource, shardHash, logAccumulator.producerConfig)
101+
102+
newProducerBatch := initProducerBatch(logAccumulator.packIdGenrator, mlog, callback, project, logstore, logTopic, logSource, shardHash, logAccumulator.producerConfig)
100103
logAccumulator.logGroupData[key] = newProducerBatch
101104
} else if logList, ok := logType.([]*sls.Log); ok {
102-
newProducerBatch := initProducerBatch(logList, callback, project, logstore, logTopic, logSource, shardHash, logAccumulator.producerConfig)
105+
newProducerBatch := initProducerBatch(logAccumulator.packIdGenrator, logList, callback, project, logstore, logTopic, logSource, shardHash, logAccumulator.producerConfig)
103106
logAccumulator.logGroupData[key] = newProducerBatch
104107
}
105108
}

producer/pack_id.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package producer
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"sync"
7+
"sync/atomic"
8+
"time"
9+
)
10+
11+
type PackIdGenerator struct {
12+
mutex sync.RWMutex
13+
logstorePackIdGenerator map[string]*LogStorePackIdGenerator
14+
count atomic.Int32
15+
}
16+
17+
func newPackIdGenerator() *PackIdGenerator {
18+
return &PackIdGenerator{
19+
logstorePackIdGenerator: make(map[string]*LogStorePackIdGenerator),
20+
}
21+
}
22+
23+
func (g *PackIdGenerator) GeneratePackId(project, logstore string) string {
24+
key := project + "|" + logstore
25+
26+
// fast path, logstore already has a generator
27+
g.mutex.RLock()
28+
if l, ok := g.logstorePackIdGenerator[key]; ok {
29+
packNumber := l.packNumber.Add(1)
30+
g.mutex.RUnlock()
31+
return fmt.Sprintf("%s%X", l.prefix, packNumber-1)
32+
}
33+
g.mutex.RUnlock()
34+
35+
// slow path
36+
g.mutex.Lock()
37+
if _, ok := g.logstorePackIdGenerator[key]; !ok {
38+
g.logstorePackIdGenerator[key] = newLogStorePackIdGenerator(g.count.Add(1))
39+
}
40+
l := g.logstorePackIdGenerator[key]
41+
packNumber := l.packNumber.Add(1)
42+
g.mutex.Unlock()
43+
return fmt.Sprintf("%s%X", l.prefix, packNumber-1)
44+
}
45+
46+
type LogStorePackIdGenerator struct {
47+
packNumber atomic.Int64
48+
prefix string // with "-"
49+
}
50+
51+
func newLogStorePackIdGenerator(id int32) *LogStorePackIdGenerator {
52+
hash := fmt.Sprintf("%d-%d", time.Now().UnixNano(), id)
53+
return &LogStorePackIdGenerator{
54+
packNumber: atomic.Int64{},
55+
prefix: strings.ToUpper(generatePackId(hash)) + "-",
56+
}
57+
}

producer/pack_id_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package producer
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestPackIdGenerator(t *testing.T) {
12+
g := newPackIdGenerator()
13+
wg := &sync.WaitGroup{}
14+
m := 1000
15+
n := 10
16+
for i := 0; i < n; i++ {
17+
wg.Add(1)
18+
go func(i int) {
19+
project := fmt.Sprintf("test%d", i)
20+
logstore := fmt.Sprintf("test%d", i)
21+
results := make([]string, 0, m)
22+
for j := 0; j < m; j++ {
23+
result := g.GeneratePackId(project, logstore)
24+
results = append(results, result)
25+
}
26+
prefix := results[0][:16]
27+
for j := 0; j < m; j++ {
28+
assert.Equal(t, prefix, results[j][:16])
29+
suffix := results[j][17:]
30+
assert.Equal(t, fmt.Sprintf("%X", j), suffix)
31+
}
32+
33+
wg.Done()
34+
}(i)
35+
}
36+
wg.Wait()
37+
}
38+
39+
// BenchmarkPackIdGenerator-12 8366719 120.7 ns/op 64 B/op 4 allocs/op
40+
func BenchmarkPackIdGenerator(b *testing.B) {
41+
g := newPackIdGenerator()
42+
for i := 0; i < b.N; i++ {
43+
g.GeneratePackId("test", "test")
44+
}
45+
}

producer/producer_batch.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package producer
22

33
import (
4-
"fmt"
5-
"strings"
64
"sync"
75
"time"
86

@@ -36,7 +34,7 @@ func generatePackId(source string) string {
3634
return ToMd5(srcData)[0:16]
3735
}
3836

39-
func initProducerBatch(logData interface{}, callBackFunc CallBack, project, logstore, logTopic, logSource, shardHash string, config *ProducerConfig) *ProducerBatch {
37+
func initProducerBatch(packIdGenerator *PackIdGenerator, logData interface{}, callBackFunc CallBack, project, logstore, logTopic, logSource, shardHash string, config *ProducerConfig) *ProducerBatch {
4038
logs := []*sls.Log{}
4139

4240
if log, ok := logData.(*sls.Log); ok {
@@ -52,17 +50,11 @@ func initProducerBatch(logData interface{}, callBackFunc CallBack, project, logs
5250
Source: proto.String(logSource),
5351
}
5452
if config.GeneratePackId {
55-
config.packLock.Lock()
56-
if config.packPrefix == "" {
57-
config.packPrefix = strings.ToUpper(generatePackId(logSource)) + "-"
58-
}
59-
packStr := config.packPrefix + fmt.Sprintf("%X", config.packNumber)
53+
packStr := packIdGenerator.GeneratePackId(project, logstore)
6054
logGroup.LogTags = append(logGroup.LogTags, &sls.LogTag{
6155
Key: proto.String("__pack_id__"),
6256
Value: proto.String(packStr),
6357
})
64-
config.packNumber++
65-
config.packLock.Unlock()
6658
}
6759
currentTimeMs := GetTimeMs(time.Now().UnixNano())
6860
producerBatch := &ProducerBatch{

producer/producer_config.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package producer
22

33
import (
44
"net/http"
5-
"sync"
65
"time"
76

87
sls "github.com/aliyun/aliyun-log-go-sdk"
@@ -40,10 +39,6 @@ type ProducerConfig struct {
4039
CredentialsProvider sls.CredentialsProvider
4140
UseMetricStoreURL bool
4241

43-
packLock sync.Mutex
44-
packPrefix string
45-
packNumber int64
46-
4742
// Deprecated: use CredentialsProvider and UpdateFuncProviderAdapter instead.
4843
//
4944
// Example:

0 commit comments

Comments
 (0)