银翼杀手 2049

我们都期待自己的存在是特殊的,到头来却平凡不已。

使用 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

Bitwarden 白皮书简析

1Password 太贵了,$2.99 和 $4.99 分别对应单人和家庭套餐!!!现在的 1password 收费模式也转向了订阅付费,同时架构也转向了 CS 架构,所以本质上和 Bitwarden 也差不多了。 Bitwarden 是一款自由且开源的密码管理服务,用户可在加密的保管库中存储敏感信息(例如网站登录凭据)。Bitwarden 平台提供有多种客户端应用程序,包括网页用户界面、桌面应用,浏览器扩展、移动应用以及命令行界面。Bitwarden 提供云端托管服务,并支持自行部署解决方案。 – 维基百科 Bitwarden 安全原则 端到端加密:所有的密码和私人数据都通过 AES-256 进行加密。所有的加密密钥均在客户端生成和管理,加密过程均在客户端完成。 零知识加密:Bitwarden 服务端不存储你的主密钥以及加密密钥,你的数据使用你的个人邮箱以及主密钥进行加密。 源代码可用:代码完全开源,并可自行编译使用。 隐私设计:所有登录信息在你的设备中进行加密后在存储到 Bitwarden服务器的保管库中,并将保管库同步到所用你的设备,你的数据采用 AES-CBC 256 位加密、加盐散列和 PBKDF2 SHA-256 进行密封。 安全审计与合规:Open source and third-party audited, Bitwarden complies with AICPA SOC2 Type 2 / Privacy Shield, GDPR, and CCPA regulations. Bitwarden 核心概念 主密钥(Master Key) 最核心的密钥,所有后续的密钥和加密密钥均通过主密钥派生,主密钥也是解密所有登录信息以及私人数据的唯一密钥,丢失会导致无法获取已经保存的数据,泄漏将导致所有的数据公之于众。所以主密钥复杂点毕竟你所有的密钥都不需要记了,主密钥在特别简单岂不是很危险? 伪代码: masterKeyHash = pbkdf2(masterKey, email) 主密钥哈希 用来鉴权登录,身份认证,从 Bitwarden 服务端获取密码保管库。 伪代码: masterKeyHashHash = pbkdf2(masterKeyHash, masterKey) 扩展主密钥(Stretched Master Key) 通过主密钥派生出加密密钥和签名密钥,并将两个密钥拼接成扩展主密钥。...

九月 24, 2021 · 1 分钟 · Mioto Yaku

项目的迭代升级

只是写自己接手的项目迭代过程,单纯的记录。 这个项目的目的是为了控制电话营销的投诉率,前前后后搞了也有小一年了,大的迭代基本上有三次,这篇文章主要就是记录一下迭代的过程以及自己的想法。 项目伊始 需求:获取 SIP 协议中的手机号信息,去特定的网站查询该手机号在不在投诉黑名单中,并将命中的手机号缓存。 开始的需求很简单,但是本身并不是这个行业的,对 SIP 协议也不是很了解,看了看资料用了最简单的方法实现了他的需求。 实现后的流程如下: 遇到的问题: 由于对 SIP 不了解,所以代码只是单纯的对 SIP 协议做转发,导致中间层只能和前端在同一台机子上。 由于他的前端是破解版本,所以导致系统版本特别低(Centos5)都已经被弃用了,所以最开始设想的中间层运行在 docker 中也随之破灭。 以上问题间接的导致了我需要在他出问题的时候排查和我无关的错误,极大的浪费了个人时间。 第二阶段 由于运行期间间接产生的数据,如自己被投诉的号码,以及明确不愿意在接听到类似电话的人,以及低素质的人。 所以他有了自己的私有数据,但是项目的第一阶段并没有这部分的功能,于是有了第二期的需求。 需求如下: 可以上传自己的黑名单。 可以上传自己的白名单。 可以设定拦截时间(请求过的数据在规定的时间不允许第二次请求)。 第二期的需求本质就是添加自己的黑名单数据,对 SIP 这快的逻辑改动并不大,所以第二期从简实现。 实现后流程如下: 可以看出私有数据服务被单独放到了一台机子,以 RESTful API 的形式给原中间层提供数据拦截状态。 所以阶段二对中间层还是有稍微细小的改动的,但是并没有解决阶段一导致的问题。 阶段二中的片段,由于他的需求一直在增加,导致阶段二变的异常复杂,以下是架构图: 由于配置的繁琐,以及加入了一些新的脱敏数据,出现了一些新的需求,如,满足特定规则后才转发。 介于阶段一,二的复杂程度实在不想基于原先的设计思想继续追加了,所以重新设计了现有的架构。 新设计的架构解决了原先的问题。 必须部署在一台机子上。 由于不完善的 SIP 实现导致处理流程异常耗时(前端的 3 秒 Timeout,3次重试机制)。 无限的堆叠原有服务导致项目结构异常复杂,难以维护。 中间层和和前端必须部署在一起,任何问题都需要登录机器查看,排查问题麻烦(前端属于破解版,系统又是 CentOS 5)。 以下是第三阶段的架构图: 以上架构的优势: 完全基于 K8S 部署,横向扩容,高可用。 我负责的模块完全独立于他的前后端,再也不需要因为前后端的机子出现问题,导致的被迫介入。 规则可配,插件可扩展,基本满足后续的需求。 前后端可 一对多,多对多,多对一,SIP 转发层基本实现了 SIP 协议的真正转发。 第四阶段(规划) 基于 TensorFlow 替换规则的手动设置!!!! 以上 以上算是对接手这个项目的总结,在项目期间也确实接触了好多新的知识。 如 GRPC 并不能在 K8S Service 层做到负载均衡,需要 Service Mesh 的介入(Linkerd2 等)。...

三月 23, 2021 · 1 分钟 · Mioto Yaku

回顾 2020

2020 年,多灾多难的一年,戴了一年的口罩,过年也没回家,相比上一年并没有获得很大的进步,相反体重继续走高涨幅 3.9% 。 工作 2020年8月加入了联通大数据,继续做着区块链方向,但是不做交付相关了,转向了 BaaS 平台,工资也小有涨幅,这里要感谢我的同事然而他并不活跃在社交网站就不 @他 了。 学习 在前半年继续较为深入的了解了 Hyperledger Fabric 共识相关的底层实现,也写下了几篇自认为有用文章。 开了个 Fabric BaaS 的坑 Alkaid,但是后面慢慢的就没时间更新了(理直气壮)。 开始了新公司的工作,完成平台的区块链 BaaS。 朋友开了新坑还是跟 VOIP 有关,做了个稍微有点大的项目,预计 TPS 在 500/s 左右,数据量大概有个几亿的数据。 建了个 K8S 集群,搞了个高可用的 Mongo Sharded Cluster 集群。 研究了 Makefile 的编写。 看了看 Plan9 的汇编。 文章 今年共水了 9 篇文章。 回顾 2019 Fabric 中 etcdraft 共识讲解 基于 Windows 的开发环境 Go 删除 Slice 中的某一个值 Hyperledger Fabric peer block 的交付流程详解 Hyperledger Fabric 加入通道时遇到 channel doesn’t exist 问题 神经网络的数据基础 Go HTTP Response 写超时导致的 EOF 错误 Plan9 汇编入门讲解 B站 还是晚上看视频,看的最多相关的视频是 彩虹六号 嗯,是个不错的游戏。...

二月 26, 2021 · 1 分钟 · 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

神经网络的数据基础

神经网络的数据表示 张量(tensor) 是一个数据容器, 它包含的数据几乎总是数值数据, 因此它的数字容器, 张量是矩阵向任意维度的推广, 维度(dimension) 通常也叫作 轴(axis). 标量(scalar): 仅包含一个数字的张量叫作 标量(标量张量, 零维张量, 0D 张量), 一个 float32 或 float64 的数字就是一个标量张量. x = numpy.array(12) 向量(vector): 数字组成的数组叫作 向量(一维张量, 1D 张量), 张量有一个轴. x = numpy.array([12, 3, 6, 14, 7]) 矩阵(matrix): 向量组成的数组叫作 矩阵(二维张量, 2D 张量), 矩阵有两个轴(行, 列). x = numpy.array([ [5, 78, 2, 34, 0], [6, 79, 3, 35, 1], [7, 80, 4, 36, 2]]) 3D张量与更高维的张量: 矩阵组成的数据叫作 3D 张量, 3D 张量组成的数组叫作 4D 张量, 以此类推....

九月 6, 2020 · 3 分钟 · 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