这周五凌晨进行线上数据库的切换,之前已经改成了读新库,这次是把写也切换到新库,是持续一个月工作的最后一次重要变更。
切换的操作步骤已经 review 通过并写在文档中,但实际情况远没有预料的顺利。
这周五凌晨进行线上数据库的切换,之前已经改成了读新库,这次是把写也切换到新库,是持续一个月工作的最后一次重要变更。
切换的操作步骤已经 review 通过并写在文档中,但实际情况远没有预料的顺利。
我们在调用 http server 或执行 SQL/redis 命令时会打印出这些外部系统调用的耗时,以快速定位问题。随着对 grpc 使用的增多,为 grpc client 增加此功能也是很有必要的,本文章就简单介绍下处理方法。
grpc-go 时生成的 pb.go 文件中结构的字段都有 json:",omitempy"
的 tag,例如:
1 | type HelloReply struct { |
在某些情况可能需要将此结构转成 json 输出,并且需要当是零值时不要在 json 串中忽略此字段。
以上面结构为例,默认编码成的 json 串是 {}
,但需要的是 {"message":""}
。
开始想到的方法是用 shell 脚本删除 omitempty
,但此方法有可能多删除东西,并且不易管理。最后使用的方法是复制了 encoding/json
库的源码到新的库 my_json
,修改这一行中的 omitEmpty
为 false
。当需要忽略 omitempty
时,使用 my_json
库即可。
1 | fields = append(fields, fillField(field{ |
前两天在帮女朋友写代码进行一些数学计算,开始量很小,但后来需要对所有的 32 位数字进行计算。之前的代码无法完成这么大的运算量,所以进行了优化,这篇博客记录代码的优化点。
先通过例子解释一个名词:移位等价
下面按照我优化的顺序记录,其中的截图是使用 pprof 生成的,用来找出占用 cpu 时间较多的操作。
每种语言都有“坑”,有些是语言设计问题,有些是使用者的问题。不管如何,了解这些东西后能让我们的代码更健壮,BUG更少。
func Tick(d Duration) <-chan Time
可用来做定时器,官网上的示例如下:
1 | c := time.Tick(1 * time.Minute) |
但使用此函数的话,没有办法释放底层的资源,看下此函数的说明:
这篇博客对比一些操作的性能情况。
以 RoundRobin 的实例进行说明。在 RoundRobin 中有两种方法返回可用的服务地址
1 | type roundrobin struct { |
今天在写用于限流的漏桶算法,使用了 channel 来模拟“桶”。大致方法是这样:
众所周知,channel 是阻塞的,但有办法模拟出第 3 点的要求,代码如下:
1 | var bucket = make(chan struct{}) |
运行结果如下(或点击这里修改运行程序)
1 | bucket is full |
关键在于 select 中的 default,当其他分支阻塞时会执行 default 分支,这样就实现了“非阻塞 channel”的需求。
网络 API(Networked APIs)
Google API
googleapis.com
域名上。不包括客户端库和 SDK 等其他类型的 API。API 接口(API Interface)
gRPC API 应该(should) 使用 proto3 在 .proto
文件中定义。
文件中 必须(must) 将高层级和更重要的定义放在其他项目之前。原型文件 应该(should) 参照下面的顺序:
syntax
, package
, option
和 import
的顺序写的原型service
定义message
定义,父资源 必须(must) 在子资源之前定义message
定义,与对应方法的顺序相同。每个请求信息 必须(must) 在对应响应信息之前(如果有的话)通常使用 .proto
文件定义 API,使用 .yaml
文件做为配置。
每个 API 服务 必须(must) 有一个 API 目录来存放定义文件和构建脚本。
API 目录 应该(should) 遵循如下的标准结构:
{service}.yaml
:主服务的配置文件,google.api.Service
的 YAML 格式prod.yaml
:产品环境配置文件staging.yaml
:Staging 环境配置文件test.yaml
:测试环境配置文件local.yaml
:本地环境配置文件v[0-9]*/*
:每一个子目录包含 API 的一个主版本,主要存放原型文件和构建脚本{subapi}/v[0-9]*/*
:每一个 {subapi}
目录包含子 API 的接口定义。每个子 API 可以有它独立的主版本号type/*
: 包含类型定义的原型文件,包括这些:在不同 API 间共享的类型、不同 API 版本间共享的类型或 API 与服务实现间共享的类型。一旦发布,type/*
中定义的类型 不应该(should not) 有破坏兼容性的修改。