基于亿条数据的内存,redis两种聚合GO计算的实战思考

hugoren · · 1229 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

总结:

(1) go 的 map读,写是线程不安全的
(2) sync.map 用空间换时间的思想,适合读多写少的场景,读,写是线程安全,但遍历是线程不安全的,运行几个小时以后,出现性能巨降的情况。刚开始18w条/分,后来1w条/分;
(3) orcaman/concurrent-map的思路是把大内存的map划分为若干小内存map
(4)后面redis替换内存后,13w条/分,开了四个goroutine

image.png

每天亿条的数据量


image.png

背景

数据经过filebeat ---->logstash--->kafka--->按一定维度聚合计算------>写入mysql---->grafana展示

聚合计算的数据结构

k, v的map内存存储
计算的数据:
最小,最大,平均,总数,成功,失败, 耗时........

内存版本

go 的 map 不加锁

type dataStruct struct {
    cost int64
}

var mapData = make(map[string]dataStruct)

func write(){
    fmt.Println("write")
    //if mapData["cost"].cost != 0 {
    //  fmt.Println("exit")
    //}
    mapData["cost"]=dataStruct{10}
}
func read(){
    fmt.Println("read")
    v := mapData["cost"]
    fmt.Println(v)
}

运行结果:死锁,说明map读,写线程是不安全的


image.png

go map 加锁

type simpleLock struct {
    mu sync.Mutex
    mapData map[string]string

}

var l simpleLock

func write(){
    fmt.Println("write")
    l.mapData = make(map[string]string)
    l.mu.Lock()
    l.mapData["cat"] = "hobb"
    l.mu.Unlock()
}
func read(){
    l.mapData = make(map[string]string)
    fmt.Println("read")
    l.mu.Lock()
    v := l.mapData["cost"]
    l.mu.Unlock()
    fmt.Println(v)

或者这样的写法

var counter = struct{
    sync.RWMutex
    m map[string]int
}{m: make(map[string]int)}

counter.RLock()
n := counter.m["some_key"]
counter.RUnlock()
fmt.Println("some_key:", n)

counter.Lock()
counter.m["some_key"]++
counter.Unlock()

运行的结果


image.png

sync.map

ar syncMap sync.Map

func write(){
    fmt.Println("write")
    syncMap.Store("hugo", "boss")
}
func read(){
    v, _ := syncMap.Load("hugo")
    fmt.Println(v)
}

运行结果


image.png

以上总结

上面的写法,适合,量少,读多写少的场景

大量的读写,还得看redis, mq

通过实践,用redis替代内存后,每分钟的数据由原来的2w条/分达到了 12w条/s。
这性能还可以再优化,通过跟踪,时间有三分之二耗在了消费kafka数据,1条/3ms


image.png

image.png

实践的结果

积压的3亿条数据经过一天的消费,只剩下条4000w数据


image.png

参考

深度解密 Go 语言之 sync.map

Golang:一文解决Map并发问题
https://cloud.tencent.com/developer/article/1539049
go 分段锁ConcurrentMap,map+读写锁,sync.map的效率测试
https://blog.csdn.net/yzf279533105/article/details/98636679


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:hugoren

查看原文:基于亿条数据的内存,redis两种聚合GO计算的实战思考

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1229 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传