为什么须要一个 SDK?
- 频繁遇到签名报错问题,排查起来费时费力;
- 对接人程度参差不齐,遇到天选之人,让人头大;
比方,有老哥不晓得 query 参数须要本义,有人甚至不晓得要把 http 响应 body 读取并解析 - 简化环境对齐步骤,升高对本服务部署形式、域名抉择等常识的了解老本
- 打消客户端、服务器因为实现语言不同而带来的技术细节问题
实现一个什么指标?
暗藏申请签名和申请解决的复杂性,让对接的人闭嘴,让本人省心省力。
最终将业务性能封装成一个本地办法调用,传入参数对象,失去后果对象。
DoYourWork(request) response
一个 SDK 中有什么?
-
Http Client
应用http.Client
,golang 规范库外面有个全局的变量DefaultClient
,倡议不要间接应用,因为很可能会被整个我的项目共用,如果须要对此 Client 做配置,则可能存在抵触。
倡议自定义一个 Client 示例,或者克隆一个
httpClient := &http.Client{Transport: http.DefaultTransport.(*http.Transport).Clone(), // 克隆 DefaultTransport}
规范库中对于 DefaultTransport
的设置如下:
var DefaultTransport RoundTripper = &Transport{
Proxy: ProxyFromEnvironment,
DialContext: defaultTransportDialContext(&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}),
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
一些能够设置的选项:
- 申请的连贯建设超时
- 申请的读写超时: 对于 golang 而言,能够用申请的 context 管制
- HTTP 申请的 KeepAlive 超时
- 闲暇连贯超时
-
Signer
每个业务的签名算法可能不太一样,然而基本上都是对 http 申请签名,能够做一个相似上面的签名办法:
AWS: public void sign(SignableRequest<?> request, AWSCredentials credentials);
腾讯:func signRequest(request tchttp.Request, credential CredentialIface, method string) (err error)
-
Logger
通常,咱们能够把 SDK 的所有报错信息都返回给调用方。
然而,如果实现的 SDK 比较复杂,或者心愿有调试信息帮忙排查问题,能够定义一个 Logger 接口,让调用方去实现,而后在 SDK 外面应用 Logger 的办法来打印一些重要日志。
// 比方腾讯云 SDK 中定义了一个 Logger 接口
type Logger interface {Printf(format string, args ...interface{})
}
一个策略是,如果接入方不提供,就不打印相干日志;
另一方面,SDK 中能够筹备一个内置的日志打印形式。
然而,自行设计日志打印时关注两个问题:
- 打印到哪里,是规范输入、规范谬误还是某个文件,最好还是让接入方传入一个
Writer
- 并发打印问题,通常应该在写入时加把锁
mu.Lock()
defer mu.Unlock()
w.Write(logs)
-
包装申请、响应、谬误
申请、响应中,尽可能减少用于追踪的 trace_id,比方减少 request_id
按照具体业务,精细化谬误分类。
-
申请重试 Retry
思考几个问题:
- 确定业务场景是否能够重试,重试会不会给业务带来副作用;
-
确定哪些谬误类型是能够重试的;
- 网络超时
- IO 谬误
- 限流谬误
- 网关谬误:5xx 谬误,比方 AWS 将 500,502,503,504 作为可重试场景
- 由谁来重试更好,是接入方自行重试,还是内置重试策略。
最大重试次数:
对于个别的 HTTP 申请而言,重试次数不应该设置很大,AWS 默认设置为 2;
举个 AWS SDK 中的例子,退却策略:
- 固定延时退却(Fixed Delay Backoff)
- 指数退却(Exponential Backoff)
- 齐全随机退却策略(Full Jitter Backoff)
- 等距离随机退却策略(Equal Jitter Backoff)
-
断路器 Breaker
首先确定业务场景是否反对,须要你的服务有备选计划。个别断路器能够依据最近一段时间内申请的错误率,来判断某个连贯地址以后是否可用,如果不可用,则切换备用地址,或者做降级解决。
// 一个腾讯云的例子
type breakerSetting struct {
// backupEndpoint
// the default is "ap-guangzhou.tencentcloudapi.com"
backupEndpoint string
// max fail nums
// the default is 5
maxFailNum int
// max fail percentage
// the default is 75/100
maxFailPercentage int
// windowInterval decides when to reset counter if the state is StateClosed
// the default is 5minutes
windowInterval time.Duration
// timeout decides when to turn StateOpen to StateHalfOpen
// the default is 60s
timeout time.Duration
// maxRequests decides when to turn StateHalfOpen to StateClosed
maxRequests int
}
代码格局上的一些思考
-
仓库组织
更具体的介绍见 golang 官网博客
每个仓库对应一个服务的 sdk
每个仓库对应多个服务的 sdk
- Module path:
example.com/mymodules/module1
- Version tag:
module1/v1.2.3
- Package path imported by a user:
example.com/mymodules/module1/package1
- Module path as given in a user’s require directive:
example.com/mymodules/module1
` module1/v1.2.3`
-
版本更新和兼容性
更具体的介绍见 golang 官网博客
对于兼容性,援用 golang 官网答复:
If an old package and a new package have the same import path, the new package must be backwards compatible with the old package.
如果两个包导入门路雷同,则肯定要放弃向后兼容。
如果呈现了不兼容,则须要更改导入门路,比方 xxx/v2,减少了 v2 后缀。
呈现 v2 版本之后,怎么组织和保护代码呢?
- 应用 v2 文件夹
- 应用分支
-
正文、文档和测试用例
更具体的介绍见 golang 官网博客
通常想要疾速理解一个包对外裸露的接口、对象、常量等,咱们能够应用 go doc
命令。
该命令会将文档中的具备 Export 属性的内容依照标准模式显示进去,所以在写咱们本人的 sdk 时,咱们也要留神一下 go doc
的输入模式。