Go反模式之越俎代庖

反模式(anti-pattern或antipattern)又叫做反面模式,指的是在实践中经常出现但又低效或是有待优化的设计模式,是用来解决问题的带有共同性的不良方法。Andrew Koenig在1995年造了anti-pattern这个词,灵感来自于GoF的《设计模式》一书。

按《AntiPatterns》作者的说法,可以用至少两个关键因素来把反面模式和不良习惯、错误的实践或糟糕的想法区分开来:

  • 行动、过程和结构中的一些重复出现的乍一看是有益的,但最终得不偿失的模式
  • 在实践中证明且可重复的清晰记录的重构方案

维基百科上列出了一些反模式列表: 反面模式, 我开了☝系列,用来记录Go语言开发中的一些反模式。

这是第一篇,介绍 越俎代庖 反模式,或者叫做画蛇添足反模式,或者叫做镀金反模式(Gold plating)。 意思是指项目已经达到了设计的最高价值,结果还添加额外的功能,反而使项目变得很差。

阅读全文

[译]配置 sql.DB 获得更好的性能(2020年更新版)

原文在2020年4月9号做了更新,所以重新翻译了原文。

网上有很多教程介绍sql.DB, 以及如何使用它来执行SQL数据库查询和语句, 但是大部分都没有介绍SetMaxOpenConns()SetMaxIdleConns()SetConnmaxLifetime()方法。事实上你可以使用这些方法来配置sql.DB的行为并改善其性能。

在这篇文章中,我想准确地解释这些设置的作用,并演示它们可能产生的(正面和负面)影响。

阅读全文

基于protobuf快速生成服务治理的RPC代码

rpcx是一个流行的Go语言实现的服务治理的框架,只要你简单会写Go的函数,你就能实现带服务治理的RPC服务,超级简单,比如下面的加法服务:

1
2
3
4
5
type Arith struct {}
func (a *Arith) Add(ctx context.Context, args int, reply *int) error {
*reply = args + 100
}

但是,很多情况下,尤其在大型互联网公司中,常用Protobufproto文件定义数据类型(Message)和(Service),这样做有一个好处,就是方便部门和部门、服务提供者和服务使用者之间沟通,通过 IDL 文件的方式更能精准的描述服务和数据类型。

比如下面的helloworld.proto,定义一个打招呼的服务(Greeter), 这个服务使用HelloRequestHelloResponse做请求参数和返回结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
syntax = "proto3";
option go_package = "helloword";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}

rpcx的用户也不止一次的提出希望rpcx也能支持从proto生成rpcx服务端和客户端的代码,现在可以宣布了,rpcxio组织提供了两个protoc的插件,可以方便的生成Go代码,和grpc插件的使用姿势一样:

  • protoc-gen-rpcx:基于官方的grpc插件,生成标准的protobuf GO类型和rpcx代码
  • protoc-gen-gogorpcx: 基于 gogo/protobuf的插件,可以生成性能更加优异、更多辅助代码的Go代码和rpcx代码

下面就介绍这两种工具的实现。

阅读全文

Redis 6.0 客户端缓存特性及实践

Redis 6.0 发布了。

Redis 6.0的新特性也是在一步步的讨论和优化中确定的。

很多的特性已经在之前的RC等版本中介绍过了。

但是正式GA版中也有一些新的变化:

@antirez 提到只是Redis历史上最大的一次版本更新,所以谨慎建议在应用的产品中还是多多测试评估,并且承诺一旦遇到大的bug就会紧急发布6.0.1版。果不其然,一天后就发布了 6.0.1版,修复了一个allocator的bug,这个bug是为了优化而引入的,现在暂时去掉了。

I just released Redis 6.0.1. Unfortunately there was a bug in Redis 6.0.0 introduced just a few days before the release, that only happens when using the non-default allocator (libc malloc in this case triggers it). Optimization reverted, 6.0.1 released. Sorry for the issue.

本文主要关注Client side caching(客户端缓存)这一特性。

smallnest/RESP3 是Redis RESP3协议的解析库,你可以使用它和Redis底层通讯,或者包装它实现新版的Redis client库或者Redis Server端。

阅读全文

[译]自定义Go Json的序列化方法

编译自 Custom JSON Marshalling in Go

我们知道,通过tag,可以有条件地实现定制Go JSON序列化的方式,比如json:",omitempty", 当字段的值为空的时候,我们可以在序列化后的数据中不包含这个值,而json:"-"可以直接不被JSON序列化,如果想被序列化key-,可以设置tag为json:"-,",加个逗号。

如果你为类型实现了MarshalJSON() ([]byte, error)UnmarshalJSON(b []byte) error方法,那么这个类型在序列化反序列化时将采用你定制的方法。

这些都是我们常用的设置技巧。

如果临时想为一个struct增加一个字段的话,可以采用本译文的技巧,临时创建一个类型,通过嵌入原类型的方式来实现。他和JSON and struct composition in Go一文中介绍的技巧还不一样(译文和jsoniter-go扩展可以阅读陶文的Golang 中使用 JSON 的一些小技巧)。JSON and struct composition in Go一文中是通过嵌入的方式创建一个新的类型,你序列化和反序列化的时候需要使用这个新类型,而本译文中的方法是无痛改变原类型的MarshalJSON方式,采用Alias方式避免递归解析,确实是一种非常巧妙的方法。

以下是译文:

阅读全文

理解Go接口的实际应用

Go是静态类型的编程语言,自2009年发布以来,已经十多岁了。现在,Go广泛应用于云原生系统、微服务、web开发、运维等场景,并且在webassembly、嵌入式等也有进一步的探索。尤其在中国,Go语言越来越多的被众多公司和开发者所采用,相关的研究文章也不断的涌现,从编译器的优化、运行时的内部机制、标准库的设计、语言规范的探索、第三库的研究和应用、产品中的应用、不同语言的比较等等目不暇接。

Go是面向对象的编程语言吗?

阅读全文

Rust半小时教程

原文: A half-hour to learn Rust

为了熟练的掌握一门编程语言,人们不得不阅读它的大量的相关资料。但是如果你不理解这些资料介绍的内容,如何能学习更多的资料呢?
在本文中,我将尽可能多地列举Rust代码片段,并解释它们包含的关键字和符号的含义,而不是只关注Rust的一两个概念。

准备好了吗,让我们出发吧!

阅读全文

分布式ID生成方案

不管我们是不是有身份的人,我们一定是有身份证的人,身份证上面的号码就是我们的ID,理论上这个ID是全国唯一的,而且通过这个号码,我们还可以得到一些个人信息,比如前两位可以确定我们第一次申请身份证的时候所在的省份、接下来的四位可以确定我们所在的区县,然后还可以知道我们出生的年月以及性别。

在我们的计算机应用中,也处处存在的ID, 比如订单编号、商品ID、微博ID、微信消息ID、书的ISDN号、商品条码等等。通过ID,可以迅速定位到对象实体、为对象之间建立关联、跟踪对象在不同服务之间的流转等等。

有的ID是无意义的唯一的标识,有的ID还能提供额外的信息,比如时间和机房信息等等。为了确保唯一性,有的ID使用很长的字节数,比如256个字节,有的通过递增的long类型,只需要8个字节来表示。考虑到存储、信息包含量、性能、安全等因素,一个好的ID的设计至关重要。

介绍ID生成和分布式的方案的文章已经非常非常多了,比如文末中的参考资料中的文章,所以我在本文中简洁的汇总各个方案的优缺点,然后介绍一个分布式的ID生成器项目rpcxio/did,它可以实现单节点百万级的ID生成。

阅读全文