0x0 前言

项目的消息包发的proto的二进制流,遇到的问题是有个别消息包特别大。这里分享一个分析工具

 

0x1 golang代码

package util

import (
    "fmt"
    "reflect"

    "github.com/golang/protobuf/proto"
)

//------------------------------------------------------
// 分析proto结构,计算每个字段序列化后大小
//------------------------------------------------------

// fieldInfo 字段信息
type fieldInfo struct {
    Name  string // 字段名字
    Type  string // 字段类型
    Count int    // 个数(map和slice可能是多个)
    Size  int    // pb序列化成后的大小
}

// ProtoStructInfo // pb结构体信息
type ProtoStructInfo struct {
    Tag        string // 自定义标记
    Total      int    // 序列化后总大小
    Accumulate int    // 每个字段序列化后累加大小
    Fields     fields // 每个字段信息
}

type fields []fieldInfo

// sortFunc quick sort
func sortFunc(f fields, i, j int) {
    if i >= j {
        return
    }
    b, e := i, j
    key := f[i]
    for i < j {
        for i < j && key.Size >= f[j].Size {
            j--
        }
        if i < j {
            f[i] = f[j]
        }
        for i < j && key.Size <= f[i].Size {
            i++
        }
        if i < j {
            f[j] = f[i]
        }
    }
    f[i] = key
    sortFunc(f, b, i-1)
    sortFunc(f, i+1, e)
}

func (f fields) sort() {
    if 0 == len(f) {
        return
    }

    sortFunc(f, 0, len(f)-1)
}

// String 打印字符串
func (f ProtoStructInfo) String() string {
    str := ""
    if f.Tag != "" {
        str = fmt.Sprintf("%s\n", f.Tag)
    }
    str = str + fmt.Sprintf("total\t%8d\nsum\t\t%8d\n", f.Total, f.Accumulate)

    n := 0
    for k, v := range f.Fields {
        //str += fmt.Sprintf("%-16s\t%-16s\tcount:%10d\tsize:%10d\n", v.Name, v.Type, v.Count, v.Size)
        n += v.Size
        str += fmt.Sprintf("%2d %-16s\t %-28s\tcount\t%4d\tsize\t%6d\tflat%%\t%.2f%%\tsum\t%6d\tsum%%\t%.2f%%\n", k, v.Name, v.Type, v.Count, v.Size, 100*float32(v.Size)/float32(f.Accumulate), n, 100*float32(n)/float32(f.Accumulate))
    }
    return str
}

// AnalyseProto 分析proto结构
func AnalyseProto(ptr proto.Message) ProtoStructInfo {
    ret := ProtoStructInfo{
        Fields: make([]fieldInfo, 0),
    }

    // 计算总大小
    if b, err := proto.Marshal(ptr); nil != err {
        panic(err)
    } else {
        ret.Total = len(b)
    }

    v := reflect.Indirect(reflect.ValueOf(ptr))
    t := v.Type()

    for i := 0; i < v.NumField(); i++ {
        f := v.Field(i)
        tt := t.Field(i)
        // 只累计这几个类型,其他类型没法单独计算大小
        if f.Kind() != reflect.Ptr && f.Kind() != reflect.Map && f.Kind() != reflect.Slice {
            continue
        }
        if f.IsNil() {
            continue
        }

        n := 0     // 字段大小
        count := 0 // 字段个数
        if f.Kind() == reflect.Ptr {
            if m, ok := f.Interface().(proto.Message); !ok {
                continue
            } else {
                b, err := proto.Marshal(m)
                if nil != err {
                    panic(err)
                }
                n = len(b)
                count++
            }
        } else if f.Kind() == reflect.Map {
            for it := f.MapRange(); it.Next(); {
                count++
                if m, ok := it.Value().Interface().(proto.Message); !ok {
                    continue
                } else {
                    b, err := proto.Marshal(m)
                    if nil != err {
                        panic(err)
                    }
                    n += len(b)

                }
            }
        } else if f.Kind() == reflect.Slice {
            for i := 0; i < f.Len(); i++ {
                ff := f.Index(i)
                count++
                if m, ok := ff.Interface().(proto.Message); !ok {
                    break
                } else {
                    b, err := proto.Marshal(m)
                    if nil != err {
                        panic(err)
                    }
                    n += len(b)

                }
            }
        }

        if 0 == n && 0 == count {
            continue
        }
        fi := fieldInfo{
            Name:  tt.Name,
            Type:  f.Type().String(),
            Count: count,
            Size:  n,
        }
        ret.Fields = append(ret.Fields, fi)
        ret.Accumulate += n
    }
    ret.Fields.sort()
    return ret
}

 

0x2 使用方法

fmt.Println(util.AnalyseProto(&pb.User{Name:1,ID:2}))

 

 

0x3 问题

1. 没有统计基本类型

2. 可以把string的统计也加进去

posted @ 2020-08-25 10:18 MrBlue 阅读(1170) 评论(0) 推荐(0) 编辑
摘要: 转自 https://www.jianshu.com/p/62bed9cc8349 1 - distinct SELECT DISTINCT(user_id) FROM table WHERE user_id_type = 3; { "query": { "term": { "user_id_typ 阅读全文
posted @ 2020-07-24 10:55 MrBlue 阅读(3594) 评论(0) 推荐(0) 编辑
摘要: 本文展示如何用Gitbook快速搭建一套wiki 必备环境 1、gitbook(如何安装gitbook自行百度) 2、nginx(或其他的能当作静态http服务器的) 3、gitlab(或者svn,需要能触发CI/CD的。我这里只展示用gitlab的.gitlab-ci.yml配置CI/CD,svn 阅读全文
posted @ 2020-01-08 15:52 MrBlue 阅读(1865) 评论(0) 推荐(0) 编辑
摘要: 因为内网服务越来越多,各种IP加端口地址根本记不住,于是用Nginx做反响代理,也可以很好管理内网的地址分发。 下面提供几种Nginx配置模板。因为也是自己摸索着配置的,有错误的地方请指正,谢谢先。 # 重载配置 # php配置 # 反向代理1 # 需要传http header参数的 #反向代理2# 阅读全文
posted @ 2020-01-08 15:02 MrBlue 阅读(1592) 评论(0) 推荐(0) 编辑
摘要: 0x0 需求 我们所有的服务启动后都以lease形式注册入ETCD,现要把这些服务监控起来。 0x1 ETCD key监听器实现 可动态增删要监听的键值对 https://github.com/bailu1901/pkg/blob/master/etcd_watcher/watcher.go 0x3 阅读全文
posted @ 2019-10-28 15:20 MrBlue 阅读(1801) 评论(0) 推荐(0) 编辑
摘要: 0x0 前言 最近项目开始使用nats作为消息中间件。 nats的引入确实解决项目很多痛点。 比如: 1)服务动态横向扩展 2)负载均衡(nats的均衡机制只有随机,不过对我们来说也够用了) 3)多服务之间方便快捷的消息通信 0x1 mynats是什么 mynats是对nats.go的一个包装。目的 阅读全文
posted @ 2019-09-27 14:24 MrBlue 阅读(904) 评论(0) 推荐(0) 编辑
摘要: 0x0 Gin简介 1.Gin 是什么? Gin 是一个用 Go (Golang) 编写的 HTTP web 框架。 它是一个类似于 martini 但拥有更好性能的 API 框架, 由于 httprouter,速度提高了近 40 倍。如果你需要极好的性能,使用 Gin 吧。 2.Gin相关地址 d 阅读全文
posted @ 2019-08-30 14:37 MrBlue 阅读(2665) 评论(0) 推荐(0) 编辑
摘要: 关于go modules的使用外面的教程实在太多了,我这里只讲下我自己使用的三种情形。 准备工作: 1、新建个文件加gomod_test。 2、在这个目录输入命令 go mod init gomod_test 情形一:比较常见的情况,引用github的包 比方我有如下代码 main.go 直接命令  阅读全文
posted @ 2019-07-31 16:14 MrBlue 阅读(2377) 评论(0) 推荐(0) 编辑
摘要: 0x0 需求 消费Kafka的日志并写入ElasticSearch供查询 0x1 依赖库 golang版Kafka客户端 https://github.com/Shopify/sarama golang版ElasticSearch客户端 https://github.com/elastic/go-e 阅读全文
posted @ 2019-07-26 17:00 MrBlue 阅读(2232) 评论(0) 推荐(1) 编辑
摘要: 记录一个用http.Post的问题 阅读全文
posted @ 2019-06-12 11:15 MrBlue 阅读(734) 评论(0) 推荐(0) 编辑
摘要: 0x0 前言 最近这几天研究了一下ElasticSearch相关的技术栈。前面一篇转发了别人些的非常详细的ElasticSearch和Kibana搭建的过程。发现Elastic家族还有Metricbeat这个神器,今天我们把前面搭建的和这个工具一起利用起来。 0x1 需求 需求是这样:我有很多个Go 阅读全文
posted @ 2019-05-22 21:03 MrBlue 阅读(1520) 评论(0) 推荐(0) 编辑
摘要: 搭建Elasticsearch和kibana环境 作者:IT云清 原文:https://blog.csdn.net/weixin_39800144/article/details/81162002 1.Elasticsearch和kibana均基于5.5.3版本;官方建议:在二者版本选择时,Elas 阅读全文
posted @ 2019-05-15 09:53 MrBlue 阅读(883) 评论(0) 推荐(0) 编辑
摘要: #0 前言 最近因为项目需要,研究了一下传说中的Codis。下面跟大家分享Codis3的搭建流程 https://github.com/CodisLabs/codis #1 Codis是什么 官方的介绍是:"Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis 阅读全文
posted @ 2019-04-28 15:27 MrBlue 阅读(547) 评论(0) 推荐(0) 编辑
摘要: 一、kafka集群搭建 至于kafka是什么我都不多做介绍了,网上写的已经非常详尽了。 (没安装java环境的需要先安装 yum -y install java-1.8.0-openjdk*) 1. 下载zookeeper https://zookeeper.apache.org/releases. 阅读全文
posted @ 2019-04-25 21:16 MrBlue 阅读(8941) 评论(2) 推荐(0) 编辑
摘要: 我的另外一个开源项目,任何建议、指正错误和优化我都非常欢迎 baibaibai_000@163.com 简介 扩展 可以扩展成战斗逻辑用lua编写的战斗验证服务器。这里展示了golang运行多个lua虚拟机,充分利用多核性能的个实现。 可以扩展用grpc做外部的可负载均衡的接口,我这里只简单的实现了 阅读全文
posted @ 2019-03-09 15:11 MrBlue 阅读(979) 评论(0) 推荐(0) 编辑
摘要: 代码如下,如有问题请联系 baibaibai_000@163.com package work_test import ( "math/rand" "runtime" "sync" "testing" "time" ) // TestWorker // test目的:展示当多个worker同时处理一个通道的任务,被关闭时,通道剩余的任务需要被全部处... 阅读全文
posted @ 2019-01-29 17:29 MrBlue 阅读(359) 评论(0) 推荐(0) 编辑
摘要: 转自:http://www.cnblogs.com/li-peng/p/8522592.html Devle是一个非常棒的golang 调试工具,支持多种调试方式,直接运行调试,或者attach到一个正在运行中的golang程序,进行调试。 线上golang服务出现问题时,Devle是必不少的在线调 阅读全文
posted @ 2019-01-17 18:50 MrBlue 阅读(2840) 评论(1) 推荐(2) 编辑
摘要: 1、安装GitLab-Runner 1)curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh | sudo bash 2)yum install git 阅读全文
posted @ 2018-12-28 20:19 MrBlue 阅读(1289) 评论(0) 推荐(0) 编辑
摘要: * 查看所有分支的所有操作记录(关键时刻能救命) git reflog 阅读全文
posted @ 2018-12-07 20:01 MrBlue 阅读(157) 评论(0) 推荐(0) 编辑
摘要: 最新项目需求是要做一个实时排行榜,有积分Score变动就直接影响排行榜,这里讲一种比较高效的实现,欢迎指正。 基本实现原理: 1、排行榜用的数据结构是跳表 SkipList (跳表是一种有序的链表,随机检索、插入和删除的性能非常高,Redis和LevelDB都有采用跳表这种数据结构,是一种空间换时间 阅读全文
posted @ 2018-11-30 11:25 MrBlue 阅读(5058) 评论(0) 推荐(1) 编辑
摘要: 1、加入代码 //version.go 2、Makefile 3、make 4、查看 ./myapp -v 阅读全文
posted @ 2018-10-30 10:50 MrBlue 阅读(1203) 评论(0) 推荐(0) 编辑
摘要: 具体看README吧 https://github.com/bailu1901/lockstepserver 阅读全文
posted @ 2018-10-29 18:32 MrBlue 阅读(2968) 评论(2) 推荐(0) 编辑
摘要: //sevice.go //watch.go 阅读全文
posted @ 2018-09-29 11:15 MrBlue 阅读(5001) 评论(0) 推荐(0) 编辑
摘要: go的pprof包 go中有pprof包来做代码的性能监控,在两个地方有包: net/http/pprof runtime/pprof 其实net/http/pprof中只是使用runtime/pprof包来进行封装了一下,并在http端口上暴露出来. 本篇只讲如何在web上查看性能。 一、代码部分 阅读全文
posted @ 2018-08-29 16:20 MrBlue 阅读(6662) 评论(0) 推荐(0) 编辑
摘要: 递归枚举文件并操作 阅读全文
posted @ 2018-08-06 15:33 MrBlue 阅读(585) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示