使用 Go 语言每秒百万量级的模拟数据生成优化总结

本文旨在深入研究如何使用Go语言优化模拟数据生成性能。我们将介绍三个不同版本的代码实现,并详细分析它们的性能和优点。 版本一:基础实现 首先,让我们来看看第一个版本的代码,这是一个基础实现,没有引入并发。以下是版本一的核心代码: func randomVersion1(labels []int) *strings.Builder { str := &strings.Builder{} for i := 0; i < len(labels); i++ { switch labels[i] { case 0: str.WriteString(strconv.Itoa(rand.Intn(2) - 1)) case 1: str.WriteString(fmt.Sprintf("%.8f", 0.1+rand.Float64()*(1-0.1))) } if i < len(labels)-1 { str.WriteString(",") } } return str } func TestVersion1(t *testing.T) { f, _ := os.OpenFile(filename, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644) buf := bufio.NewWriter(f) s := time.Now() buf.WriteString(fmt.Sprintf("%s\n", header)) for i := 0; i < 1000000; i++ { buf....

九月 25, 2021 · 3 分钟 · Mioto Yaku

Plan9 汇编入门讲解

为什么要看 Plan9 汇编?如果你是 Go 开发者,去学习和理解一下 Plan9 是很有必要的,因为它可以解决你对一段代码的理解(为什么这样不行?那样却可以?)。 Plan9 不同于 AT&T 和 Intel 汇编器,但是懂这两个汇编语法的话对理解 Plan9 还是有很大帮助的。 疑惑 // 为什么这个函数的返回值会是 -1 func demo1() int { ret := -1 defer func() { ret = 1 }() return ret } // output: -1 // 为什么这个函数的返回值会是 1 func demo2() (ret int) { defer func() { ret = 1 }() return ret } // output: 1 相信大部分人都看过类似的解答,demo1 中是临时变量导致的,而 demo2 中没有临时变量,这是最终结果。 在汇编层面到底做了什么?本文将会探讨这个问题。(本文所使用的平台是 MacOS AMD64)不同的平台指令集和寄存器都不一样。 基础 通用寄存器 下面是通用通用寄存器的名字在 IA64 和 plan9 中的对应关系:...

一月 19, 2021 · 5 分钟 · Mioto Yaku

Go HTTP Response 写超时导致的 EOF 错误

前天在联调过程中出现了一个神奇的错误, 错误在 client 端的表现为 http 请求错误 Get "http://127.0.0.1:8800": EOF, 但是服务端却没有任何 异常 所有的日志都是正常执行 由于只有 client 端的错误, 所以 Google 搜索的处理结果全都不是实际场景导致的(并没有怀疑到服务端出了问题), 无奈只能抓包, 最终问题得以解决 原因 server 端处理请求耗时 30s, 但是 http.Server 的 write timeout 设置的时间是 10s, 所以在 handler 处理请求完毕的时候, server 端和 client 端的连接已经被关闭了 但是由于 server 端写入的 data 远远小于 http/net 包中设定的 write buffer 缓冲大小(4096 byte), 所以 bufio 的 Write 方法并没有返回 error 抓包 源码: https://github.com/yakumioto/demo-response-write-timeout 由于测试环境太过复杂, 所以写了个 demo 复现了整个流程, 以下是 wireshark 导出的 svc 由此可以看出: 客户端通过三次握手和服务端建立了 TCP 连接 客户端正常的发送了 HTTP Request 请求 正常的保持了一段时间的 Keep-Alive 服务端通过四次挥手和客户端断开了连接 "No....

十月 1, 2020 · 4 分钟 · Mioto Yaku

Hyperledger Fabric 加入通道时遇到 channel doesn't exist 问题

据同事说 node sdk@v2.x.x 版本中没有对网络操作相关的 API 实现, 所以只能自己照着 v1.4.x 版本的 手撸底层代码, 但是在实现 JoinChain 这个功能时出现了 channel doesn't exist 错误 原因 // SignedProposal 部分结构 { "proposal_bytes": { "header": { "channel_header": { "channel_id": "" }, "signature_header": { "creator": { "mspid": "", "id_bytes": "" } } }, "payload": "" }, "signature": "" } 当 peer 收到 client 发来的 SignedProposal 时, 会进行签名校验 根据 proposal_bytes.header.channel_header.channel_id 获取对应的 mspMgmtMgr, 如果此时通道不存在, 则会创建一个未经初始化的 mspMgmtMgr 根据 proposal_bytes.header.signature_header.creator.mspid 获取对应的 mspManagerImpl, 但是由于 mspMgmtMgr 未初始化, 所以直接返回了 channel doesn't exist 源码追踪 重要的事情说三遍...

六月 27, 2020 · 3 分钟 · Mioto Yaku

Hyperledger Fabric peer block 的交付流程详解

本文基于 hyperldeger fabric 1.4.7 进行代码追踪讲解 假设场景描述: peer 重启场景 peer 有 user channel peer 使用的是 goleveldb peer 的 core.peer.gossip.orgLeader 为 true 流程简介 初始化账本根据账本中保存的 channel id 创建通道实例, 并初始化与之对等的 gossip 服务, 用 来接收对应通道的最新的 配置或交易 block, 接收到 block 后, 经过 Verify, Validate, Validate RW sets 三个验证步骤, 提交给 Ledger Commiter 进行写入文件, 并将当前通道的 blkMgrInfo 更新到最新状态 源码追踪 伊始: main -> node.Cmd -> startCmd -> nodeStartCmd -> serve peer.Initialize 文件: core/peer/peer.go:241 初始化 ledgermgmt, 里面做的事情太多了, 要讲清楚有点困难建议大家自己去看看, 里面主要做的就是 各种初始化工作 // /var/hyperledger/production/ledgersData 下有这些东西, 这里面的工作跟此目录有关 // chains/index goleveldb: 保存了所有通道的最新状态信息 // fileLock goleveldb: 用于锁程序的,文章最末尾有介绍 // historyLeveldb goleveldb: 保存历史交易的 // ledgerProvider goleveldb: 保存的是 chain ids, 也就是通道id // pvtdataStore goleveldb: 存储私有数据库 // stateLeveldb goleveldb: 世界状态数据库, 可以替换为 couchdb // 这两个我不确定没有细追 // configHistory 看名字应该是保存了 config block 相关的东西....

六月 15, 2020 · 4 分钟 · Mioto Yaku

Go 删除 Slice 中的某一个值

方法一 优点: 速度最快 缺点: 会导致切片数据顺序改变 a := []string{"A", "B", "C", "D", "E"} i := 2 a[i] = a[len(a)-1] // 将数组的最后一位赋值给需要删除的 index 上 a = a[:len(a)-1] // 移除掉最后一个没用的数据 // Output: // [A B E D] 方法二 优点: 速度会随着切片长度改变 缺点: 保持原有切片顺序 a := []string{"A", "B", "C", "D", "E"} i := 2 a = append(a[:i], a[i+1:]...) // Output: // [A B D E] Benchmark goos: linux goarch: amd64 pkg: github.com/yakumioto/go-example/benchmark/delete-element-slice Benchmark1 Benchmark1-4 1000000000 0....

六月 3, 2020 · 1 分钟 · Mioto Yaku

Fabric 中 etcdraft 共识讲解

为什么要通过 etcdraft 来进行共识? 我觉得有以下原因 solo 并不适合大多数场景, 例如: 组织A, 组织B, 都想在自己放置共识节点 kafka 虽然能满足以上需求, 但是 kafka 加上 zookeeper 需要额外部署并且实在是太重了, 不方便部署 所以基于 etcdraft 的共识来了, 解决了以上的痛点 重要的话说三遍! 千万不要错过文章中的源码部分, 里面有很多很多的注释!!! 千万不要错过文章中的源码部分, 里面有很多很多的注释!!! 千万不要错过文章中的源码部分, 里面有很多很多的注释!!! 核心接口 以下是我认为实现 etcdraft 共识核心的接口 // ClusterServer 集群Server接口 type ClusterServer interface { Step(Cluster_StepServer) error } // ClusterClient 集群Client接口 type ClusterClient interface { Step(ctx context.Context, opts ...grpc.CallOption) (orderer.Cluster_StepClient, error) } // Handler 用于共识的两个接口 type Handler interface { OnConsensus(channel string, sender uint64, req *orderer.ConsensusRequest) error OnSubmit(channel string, sender uint64, req *orderer....

一月 15, 2020 · 8 分钟 · Mioto Yaku

Go 100 行实现 HTTP(S) 正向代理

目标是现实一个 HTTP HTTPS 的代理服务器, 目前代理的实现方法有两种 普通代理: 这种代理扮演的是中间人角色, 对于客户端来说, 它就服务器, 对于服务端来说, 它是客户端, 它负责在中间来回传递 HTTP 报文 隧道代理: 它是通过 HTTP 正文部分(body) 完成代理, 以 HTTP 的方式实现基于 TCP 的应用层协议代理, 这种代理使用 HTTP 的 CONNECT 方法建立连接 这是一次 HTTP 的请求, 用 \r\n 进行换行, 碰到连续两个 \r\n 后内容为请求数据, 分为以下几个部分 请求行 (request line) 请求头 (header) 空行 请求数据 (body) curl -Lv http://baidu.com > GET / HTTP/1.1 > Host: baidu.com > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1....

八月 21, 2019 · 2 分钟 · Mioto Yaku

Go HTTP POST 附件

前段时间为了使用 adb 进行钉钉打卡, 写了个 Go 的程序, 想着万一没打上怎么办, 不如截个图发给自己(现在以 root, 辣鸡钉钉), 文章只为了记录一下实现. // curl -X POST https://example.com/sendPhoto -F photo=@./screen.png // 以下代码是根据以上 curl 命令的实现 buf := &bytes.Buffer{} mu := multipart.NewWriter(buf) part, err := mu.CreatePart(textproto.MIMEHeader{ "Content-Disposition": []string{`form-data; name="photo"; filename="screen.png"`}, "Content-Type":[]string{"application/octet-stream"}, }) checkError(err) fp, _ := os.Open("/home/mioto/screen.png") io.Copy(part, fp) mu.Close() req, err := http.NewRequest(http.MethodPost, "https://example.com/sendPhoto", bf) checkError(err) req.Header.Set("Content-Type", mu.FormDataContentType()) res, err := http.DefaultClient.Do(req) checkError(err)

五月 16, 2019 · 1 分钟 · Mioto Yaku

Go 解析 ECPrivate Key 遇到的问题

最近在做 fabric 证书私钥管理系统, 遇到的一个问题, 在使用 x509.ParseECPrivateKey() 方法的时候会直接报错, 而 fabric 确实用的是 椭圆曲线算法 错误输出: x509: failed to parse EC private key: asn1: structure error: tags don't match (4 vs {class:0 tag:16 length:19 isCompound:true}) {optional:false explicit:false application:false private:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} @5 原因是 fabric 将私钥转成 pem 格式的时候使用的方法是 x509.MarshalPKCS8PrivateKey() 解决办法 block, _ := pem.Decode(pemBytes) key, err := x509.ParsePKCS8PrivateKey(block.Bytes) checkErr(err) switch priv := key.(type) { case *ecdsa.PrivateKey: // do something }

五月 7, 2019 · 1 分钟 · Mioto Yaku