tailnode 的博客

给岁月以文明,而不是给文明以岁月


  • 首页

  • 关于

  • 归档

  • 标签

  • 搜索

一次事故

发表于 2018-04-21 | 阅读次数

这周五凌晨进行线上数据库的切换,之前已经改成了读新库,这次是把写也切换到新库,是持续一个月工作的最后一次重要变更。

切换的操作步骤已经 review 通过并写在文档中,但实际情况远没有预料的顺利。

阅读全文 »

grpc-go client 打印请求的耗时

发表于 2018-02-28 | 阅读次数

我们在调用 http server 或执行 SQL/redis 命令时会打印出这些外部系统调用的耗时,以快速定位问题。随着对 grpc 使用的增多,为 grpc client 增加此功能也是很有必要的,本文章就简单介绍下处理方法。

阅读全文 »

json.Marshal 忽略 omitempty 的方法

发表于 2018-02-09 | 阅读次数

grpc-go 时生成的 pb.go 文件中结构的字段都有 json:",omitempy" 的 tag,例如:

1
2
3
type HelloReply struct {
Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"`
}

在某些情况可能需要将此结构转成 json 输出,并且需要当是零值时不要在 json 串中忽略此字段。
以上面结构为例,默认编码成的 json 串是 {},但需要的是 {"message":""}。

开始想到的方法是用 shell 脚本删除 omitempty,但此方法有可能多删除东西,并且不易管理。最后使用的方法是复制了 encoding/json 库的源码到新的库 my_json,修改这一行中的 omitEmpty 为 false。当需要忽略 omitempty 时,使用 my_json 库即可。

1
2
3
4
5
6
7
8
fields = append(fields, fillField(field{
name: name,
tag: tagged,
index: index,
typ: ft,
omitEmpty: opts.Contains("omitempty"), // 改为 false
quoted: quoted,
}))

记录一次性能优化

发表于 2017-10-08 | 阅读次数

前两天在帮女朋友写代码进行一些数学计算,开始量很小,但后来需要对所有的 32 位数字进行计算。之前的代码无法完成这么大的运算量,所以进行了优化,这篇博客记录代码的优化点。

先通过例子解释一个名词:移位等价

  • 二进制数 0001 的移位等价的数有且只有 0010/0100/1000
  • 0000/0001/0011/0101/0111/1111 这些数移位不等价

下面按照我优化的顺序记录,其中的截图是使用 pprof 生成的,用来找出占用 cpu 时间较多的操作。

阅读全文 »

Go 中的一些坑

发表于 2017-07-21 | 阅读次数

每种语言都有“坑”,有些是语言设计问题,有些是使用者的问题。不管如何,了解这些东西后能让我们的代码更健壮,BUG更少。

资源泄漏

time.Tick()

func Tick(d Duration) <-chan Time可用来做定时器,官网上的示例如下:

1
2
3
4
c := time.Tick(1 * time.Minute)
for now := range c {
fmt.Printf("%v %s\n", now, statusUpdate())
}

但使用此函数的话,没有办法释放底层的资源,看下此函数的说明:

阅读全文 »

Go 中一些操作的性能对比

发表于 2017-05-28 | 阅读次数

这篇博客对比一些操作的性能情况。

  • 循环遍历 slice 各元素
  • 字符串拼接

循环遍历 slice 各元素

以 RoundRobin 的实例进行说明。在 RoundRobin 中有两种方法返回可用的服务地址

1
2
3
4
type roundrobin struct {
i int // 服务地址索引
servers []string // 可用的服务地址
}
阅读全文 »

在 go 中实现非阻塞的 channel

发表于 2017-05-20 | 阅读次数

今天在写用于限流的漏桶算法,使用了 channel 来模拟“桶”。大致方法是这样:

  1. 定时从 channel 中读出数据(模拟桶漏水)
  2. 收到请求时如果 channel 没有满,就写入
  3. 收到请求时如果 channel 满了,就抛弃请求并返回“超出 QPS 限制”(不要阻塞)

众所周知,channel 是阻塞的,但有办法模拟出第 3 点的要求,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var bucket = make(chan struct{})

func main() {
go leak()
for i := 0; i < 10; i++ {
time.Sleep(500 * time.Millisecond)
select {
case bucket <- struct{}{}:
fmt.Println("add data to bucket")
default: // 注意这里
fmt.Println("bucket is full")
}
}
}

func leak() {
tick := time.Tick(time.Second)
for range tick {
<-bucket
}
}

运行结果如下(或点击这里修改运行程序)

1
2
3
4
5
6
7
8
9
10
bucket is full
bucket is full
add data to bucket
bucket is full
add data to bucket
bucket is full
add data to bucket
bucket is full
add data to bucket
bucket is full

关键在于 select 中的 default,当其他分支阻塞时会执行 default 分支,这样就实现了“非阻塞 channel”的需求。

Google API 设计指南-词汇表

发表于 2017-04-22 | 阅读次数

翻译自 API Design Guide - Glossary

网络 API(Networked APIs)

  • 通过计算机网络中运行的应用程序接口。它们使用包括 HTTP 在内的网络协议进行通信,并且生产和消费 API 的往往是不同的组织。

Google API

  • Google 服务的网络 API。大部分在 googleapis.com 域名上。不包括客户端库和 SDK 等其他类型的 API。

API 接口(API Interface)

  • 一个 Protocol Buffer 服务的定义。在大多数编程语言中它被映射到一个接口。一个 API 接口可以被多个 API 服务实现。
阅读全文 »

Google API 设计指南-文件结构

发表于 2017-04-21 | 阅读次数

翻译自 API Design Guide - File Structure

gRPC API 应该(should) 使用 proto3 在 .proto 文件中定义。

文件中 必须(must) 将高层级和更重要的定义放在其他项目之前。原型文件 应该(should) 参照下面的顺序:

  • 版权和许可协议(如果需要)
  • 按照 syntax, package, option 和 import 的顺序写的原型
  • API 概述文档
  • 以引入顺序降序排列的 service 定义
  • 资源 message 定义,父资源 必须(must) 在子资源之前定义
  • RPC 请求和响应的 message 定义,与对应方法的顺序相同。每个请求信息 必须(must) 在对应响应信息之前(如果有的话)
阅读全文 »

Google API 设计指南-目录结构

发表于 2017-04-21 | 阅读次数

翻译自 API Design Guide - Directory Structure

通常使用 .proto 文件定义 API,使用 .yaml 文件做为配置。

每个 API 服务 必须(must) 有一个 API 目录来存放定义文件和构建脚本。

API 目录 应该(should) 遵循如下的标准结构:

  • API 目录
  • 配置文件
    • {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) 有破坏兼容性的修改。

查看其他章节

12…4
tailnode

tailnode

39 日志
10 标签
GitHub Email
© 2019 tailnode
由 Hexo 强力驱动
主题 - NexT.Pisces