配置格式
1 | { |
示例
1 | { |
1 | { |
1 | { |
接口设计应以一些目标为导向,这些目标包含且不限于,易读、易懂、易用、清晰(意义明确,不易误用)、易维护、易扩展、功能强大且满足需求。要达到如上目标,在设计 API 时应考虑如下细节。
从形式来讲,API 不仅有 HTTP/WEB,还有 gRPC、Thrift。
对于思考设计良好的接口,可从下面两个视角着手。
Errors 是指客户端向服务发送错误数据,服务正确拒绝该数据。Errors 不会影响服务可用性。
Faults 是指服务对合法的请求无法正常返回结果。Faults 会影响服务可用性。
由于限流或配额失败(事先设定)引起的调用失败,不能算作 faults。如果是由于服务自我保护造成的请求失败,算作 faults,比如快速失败策略。
Latency 是指完成特定 API 调用消耗的时间,尽可能接近客户端计量。对于长操作请求,该指标记为初始请求耗时。
对于暴露长操作的服务,必须对这些指标跟踪 “Time to complete” 指标。
对于长操作,初始请求和检索请求都可能正常,但如果最终操作失败,必须汇总至总体的可用性指标中。
忽略服务端返回的多余字段。
忽略服务端返回数据字段的顺序。
URL 应该易读且易构造。
HTTP 1.1 RFC 7230 并未定义 URL 长度限制,如果服务接收到的请求 URL 长度大于其定义的限制长度,应返回 414 状态码。
所以,对于长度大于 2083 个字符的 URL ,应考虑服务是否可以接受。
方法 | 描述 | 是否幂等 |
---|---|---|
GET | 返回当前对象值 | 是 |
PUT | 替换或创建对象 | 是 |
DELETE | 删除对象 | 是 |
POST | 根据提供的数据创建新对象,或提交命令 | 否 |
HEAD | 为 GET 响应返回对象的元数据,资源支持 GET 请求,也应支持 HEAD 请求 | 是 |
PATCH | 对对象应用重要的更新 | 否 |
OPTIONS | 获取请求的信息 | 是 |
跟定 API 的基本操作,不能指定自定义 Headers。
返回值数据结构应分级,不应将业务数据放在第一级。
1 | # 异常 |
对于 code,应进行细致的划分,比如。
状态码 | 说明 | HTTP Status Code |
---|---|---|
0 | 请求正常返回 | 200 |
1000+ | 请求错误(参数、数据不存在等) | 400 |
2000+ | 元数据读取异常(不存在、格式异常) | 200 |
3000+ | 处理时异常 | 500 |
4000+ | 数据写入时异常 | 500 |
5000+ | 未知服务异常 | 500 |
对于 message 格式也应进行统一(避免英文/中文混用,有的 message 为英文,有的为中文),务必保证 code 不为 0 时返回有效 message。
有一些设计细节,很难判定那种方式实现比较好,这里做下讨论。
对于功能相似的多个接口,是使用一个接口 + 字段标识,还是拆分成多个接口。
1 | c 展示详细 COMMAND |
指定单个
1 | top -p <pid> # macos 使用 -pid 参数 |
指定多个
1 | top -p `pgrep -d ',' python3` # 非 macos |
1 | top -u wii # 只显示指定用户进程, macos 使用 -U 参数 |
1 | http_archive( |
1 | com_google_googleapis 包含了 common protos; 暂时保留 |
1 | 参数 |
1 | 参数 |
1 | 示例 |
1 | 格式 |
1 | 示例 |
1 | tr: translate characters, 转换和删除字符 |
1 | 排序 |
1 | 删除重复行,一般与sort结合使用 |
1 | format |
1 | 美化 json 字符串 |
1 | 统计程序运行时间 |
1 | java -cp "./*.jar:lib/*.jar" path.to.my.class.Main # windows: "./*.jar;lib/*.jar" |
由程序负责任务切换,可以减少线程/进程上下文切换的消耗。用户态实现任务切换,无需进入内核态。
虽然 Python 有多线程的概念,但是由于 GIL 的存在,并不能利用多核资源。如果易不能充分利用单进程资源,可能会带来严重的性能问题。
python 默认只为主线程创建 loop。如下 tornado 代码实现了自动为创建 loop 的功能,使用 asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy())
来生效。
1 | if sys.platform == "win32" and hasattr(asyncio, "WindowsSelectorEventLoopPolicy"): |
下面是使用协程实现的定时器。
1 | # coding: utf-8 |
下看下抛出异常的代码。
1 | def ensure_future(coro_or_future, *, loop=None): |
ServiceDiscovery
,创建 ServiceProvider
对象,首先需要有 ServiceDiscovery
;所有请求直接访问 zkServiceProvider
, 特定服务发现的封装,并集成了负载均衡策略;集成了 ServiceCache
,有节点监听和缓存ServiceCache
,会在本地内存缓存,并使用 watcher 来保持数据最新ServiceDiscovery
、ServiceProvider
需要调用 start
方法后可用。
ServiceDiscovery
的 registerService
注册服务后,只要 ServiceDiscovery
不 stop
,会一直保持节点注册stop
,没有及时调用 unregisterService
接口来取消注册,zk 节点会保存一段时间(几秒),然后由 zk 摘除ServiceProvider
的接口,会实时调用 zk 查询数据,ServiceCacheListener
有两个方法。
cacheChanged
当服务节点变化时,会调用该方法stateChanged
当 zk 连接状态变化时,会调用该方法