second time: code refactor for pr 906. new concurrent-map when init; move lock to WritersType
This commit is contained in:
parent
e73da37bc0
commit
8d6101ec5a
|
@ -101,6 +101,18 @@ func MustLoad(fpaths ...string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if C.WriterOpt.QueueMaxSize <= 0 {
|
||||||
|
C.WriterOpt.QueueMaxSize = 10000000
|
||||||
|
}
|
||||||
|
|
||||||
|
if C.WriterOpt.QueuePopSize <= 0 {
|
||||||
|
C.WriterOpt.QueuePopSize = 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
if C.WriterOpt.SleepInterval <= 0 {
|
||||||
|
C.WriterOpt.SleepInterval = 50
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("heartbeat.ip:", C.Heartbeat.IP)
|
fmt.Println("heartbeat.ip:", C.Heartbeat.IP)
|
||||||
fmt.Printf("heartbeat.interval: %dms\n", C.Heartbeat.Interval)
|
fmt.Printf("heartbeat.interval: %dms\n", C.Heartbeat.Interval)
|
||||||
})
|
})
|
||||||
|
|
|
@ -190,12 +190,10 @@ func handleOpenTSDB(c *gin.Context) {
|
||||||
if has {
|
if has {
|
||||||
common.AppendLabels(pt, target)
|
common.AppendLabels(pt, target)
|
||||||
}
|
}
|
||||||
// 更改分发方式,通过ident分发
|
|
||||||
writer.Writers.PushIdentChan(host, pt)
|
writer.Writers.PushSample(host, pt)
|
||||||
} else {
|
} else {
|
||||||
// 如果没有则默认放入指标名前缀的chan中
|
writer.Writers.PushSample("default_hash_string", pt)
|
||||||
ident := arr[i].Metric[0:strings.Index(arr[i].Metric, "_")]
|
|
||||||
writer.Writers.PushIdentChan(ident, pt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
succ++
|
succ++
|
||||||
|
@ -203,7 +201,6 @@ func handleOpenTSDB(c *gin.Context) {
|
||||||
|
|
||||||
if succ > 0 {
|
if succ > 0 {
|
||||||
promstat.CounterSampleTotal.WithLabelValues(config.C.ClusterName, "opentsdb").Add(float64(succ))
|
promstat.CounterSampleTotal.WithLabelValues(config.C.ClusterName, "opentsdb").Add(float64(succ))
|
||||||
|
|
||||||
idents.Idents.MSet(ids)
|
idents.Idents.MSet(ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,6 @@ type WriterType struct {
|
||||||
Client api.Client
|
Client api.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
var lock = sync.RWMutex{}
|
|
||||||
|
|
||||||
func (w WriterType) Write(items []*prompb.TimeSeries, headers ...map[string]string) {
|
func (w WriterType) Write(items []*prompb.TimeSeries, headers ...map[string]string) {
|
||||||
if len(items) == 0 {
|
if len(items) == 0 {
|
||||||
return
|
return
|
||||||
|
@ -110,7 +108,8 @@ type WritersType struct {
|
||||||
globalOpt GlobalOpt
|
globalOpt GlobalOpt
|
||||||
m map[string]WriterType
|
m map[string]WriterType
|
||||||
queue *list.SafeListLimited
|
queue *list.SafeListLimited
|
||||||
IdentChanMap cmap.ConcurrentMap
|
chans cmap.ConcurrentMap
|
||||||
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WritersType) Put(name string, writer WriterType) {
|
func (ws *WritersType) Put(name string, writer WriterType) {
|
||||||
|
@ -121,99 +120,96 @@ func (ws *WritersType) PushQueue(vs []interface{}) bool {
|
||||||
return ws.queue.PushFrontBatch(vs)
|
return ws.queue.PushFrontBatch(vs)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// PushSample Push one sample to chan, hash by ident
|
||||||
// PushIdentChan 放入chan, 以ident分发
|
|
||||||
// @Author: quzhihao
|
// @Author: quzhihao
|
||||||
// @Description:
|
func (ws *WritersType) PushSample(ident string, v interface{}) {
|
||||||
// @receiver ws
|
if !ws.chans.Has(ident) {
|
||||||
// @param ident
|
ws.Lock()
|
||||||
// @param vs
|
// important: check twice
|
||||||
//
|
if !ws.chans.Has(ident) {
|
||||||
func (ws *WritersType) PushIdentChan(ident string, vs interface{}) {
|
|
||||||
if !ws.IdentChanMap.Has(ident) {
|
|
||||||
lock.Lock()
|
|
||||||
if !ws.IdentChanMap.Has(ident) {
|
|
||||||
c := make(chan *prompb.TimeSeries, Writers.globalOpt.QueueMaxSize)
|
c := make(chan *prompb.TimeSeries, Writers.globalOpt.QueueMaxSize)
|
||||||
ws.IdentChanMap.Set(ident, c)
|
ws.chans.Set(ident, c)
|
||||||
go func() {
|
go ws.StartConsumer(ident, c)
|
||||||
ws.InitIdentChanWorker(ident, c)
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
lock.Unlock()
|
ws.Unlock()
|
||||||
}
|
}
|
||||||
// 往chan扔会导致内存不断增大,如果写入阻塞了,需要提示
|
|
||||||
c, ok := ws.IdentChanMap.Get(ident)
|
c, ok := ws.chans.Get(ident)
|
||||||
ch := c.(chan *prompb.TimeSeries)
|
|
||||||
if ok {
|
if ok {
|
||||||
|
ch := c.(chan *prompb.TimeSeries)
|
||||||
select {
|
select {
|
||||||
case ch <- vs.(*prompb.TimeSeries):
|
case ch <- v.(*prompb.TimeSeries):
|
||||||
case <-time.After(time.Duration(200) * time.Millisecond):
|
default:
|
||||||
logger.Warningf("[%s] Write IdentChanMap Full, DropSize: %d", ident, len(ch))
|
logger.Warningf("Write channel(%s) full, current channel size: %d", ident, len(ch))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// StartConsumer every ident channel has a consumer, start it
|
||||||
// InitIdentChanWorker 初始化ident消费者
|
|
||||||
// @Author: quzhihao
|
// @Author: quzhihao
|
||||||
// @Description:
|
func (ws *WritersType) StartConsumer(ident string, ch chan *prompb.TimeSeries) {
|
||||||
// @receiver ws
|
var (
|
||||||
// @param ident
|
batch = ws.globalOpt.QueuePopSize
|
||||||
// @param data
|
max = ws.globalOpt.QueueMaxSize
|
||||||
//
|
batchCounter int
|
||||||
func (ws *WritersType) InitIdentChanWorker(ident string, data chan *prompb.TimeSeries) {
|
closeCounter int
|
||||||
popCounter := 0
|
series = make([]*prompb.TimeSeries, 0, batch)
|
||||||
batch := ws.globalOpt.QueuePopSize
|
)
|
||||||
if batch <= 0 {
|
|
||||||
batch = 1000
|
logger.Infof("Starting channel(%s) consumer, max size:%d, batch:%d", ident, max, batch)
|
||||||
}
|
|
||||||
logger.Infof("[%s] Start Ident Chan Worker, MaxSize:%d, batchSize:%d", ident, ws.globalOpt.QueueMaxSize, batch)
|
|
||||||
series := make([]*prompb.TimeSeries, 0, batch)
|
|
||||||
closePrepareCounter := 0
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case item := <-data:
|
case item := <-ch:
|
||||||
closePrepareCounter = 0
|
// has data, no need to close
|
||||||
|
closeCounter = 0
|
||||||
series = append(series, item)
|
series = append(series, item)
|
||||||
popCounter++
|
|
||||||
if popCounter >= ws.globalOpt.QueuePopSize {
|
batchCounter++
|
||||||
popCounter = 0
|
if batchCounter >= ws.globalOpt.QueuePopSize {
|
||||||
// 发送到prometheus
|
ws.post(ident, series)
|
||||||
ws.postPrometheus(ident, series)
|
|
||||||
|
// reset
|
||||||
|
batchCounter = 0
|
||||||
series = make([]*prompb.TimeSeries, 0, batch)
|
series = make([]*prompb.TimeSeries, 0, batch)
|
||||||
}
|
}
|
||||||
case <-time.After(10 * time.Second):
|
case <-time.After(time.Second):
|
||||||
// 10秒清空一下,如果有数据的话
|
|
||||||
if len(series) > 0 {
|
if len(series) > 0 {
|
||||||
ws.postPrometheus(ident, series)
|
// has data, no need to close
|
||||||
|
closeCounter = 0
|
||||||
|
|
||||||
|
ws.post(ident, series)
|
||||||
|
|
||||||
|
// reset
|
||||||
|
batchCounter = 0
|
||||||
series = make([]*prompb.TimeSeries, 0, batch)
|
series = make([]*prompb.TimeSeries, 0, batch)
|
||||||
closePrepareCounter = 0
|
|
||||||
} else {
|
} else {
|
||||||
closePrepareCounter++
|
closeCounter++
|
||||||
}
|
}
|
||||||
// 一小时没数据,就关闭chan
|
|
||||||
if closePrepareCounter > 6*60 {
|
if closeCounter > 3600 {
|
||||||
logger.Infof("[%s] Ident Chan Closing. Reason: No Data For An Hour.", ident)
|
logger.Infof("Closing channel(%s) reason: no data for an hour", ident)
|
||||||
lock.Lock()
|
|
||||||
close(data)
|
ws.Lock()
|
||||||
// 移除
|
close(ch)
|
||||||
ws.IdentChanMap.Remove(ident)
|
ws.chans.Remove(ident)
|
||||||
lock.Unlock()
|
ws.Unlock()
|
||||||
logger.Infof("[%s] Ident Chan Closed Success.", ident)
|
|
||||||
|
logger.Infof("Closed channel(%s) reason: no data for an hour", ident)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// post post series to TSDB
|
||||||
// postPrometheus 发送数据至prometheus
|
|
||||||
// @Author: quzhihao
|
// @Author: quzhihao
|
||||||
//
|
func (ws *WritersType) post(ident string, series []*prompb.TimeSeries) {
|
||||||
func (ws *WritersType) postPrometheus(ident string, series []*prompb.TimeSeries) {
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(ws.m))
|
wg.Add(len(ws.m))
|
||||||
|
|
||||||
|
// maybe as backend hashstring
|
||||||
headers := map[string]string{"ident": ident}
|
headers := map[string]string{"ident": ident}
|
||||||
for key := range ws.m {
|
for key := range ws.m {
|
||||||
go func(key string) {
|
go func(key string) {
|
||||||
|
@ -272,6 +268,7 @@ var Writers = NewWriters()
|
||||||
func Init(opts []Options, globalOpt GlobalOpt) error {
|
func Init(opts []Options, globalOpt GlobalOpt) error {
|
||||||
Writers.globalOpt = globalOpt
|
Writers.globalOpt = globalOpt
|
||||||
Writers.queue = list.NewSafeListLimited(globalOpt.QueueMaxSize)
|
Writers.queue = list.NewSafeListLimited(globalOpt.QueueMaxSize)
|
||||||
|
Writers.chans = cmap.New()
|
||||||
|
|
||||||
for i := 0; i < len(opts); i++ {
|
for i := 0; i < len(opts); i++ {
|
||||||
cli, err := api.NewClient(api.Config{
|
cli, err := api.NewClient(api.Config{
|
||||||
|
|
Loading…
Reference in New Issue