本书的各个章节环环相扣,我们将引导Go语言中高级开发人员构建一款简单但功能齐备的分布式键值存储。我们将学习选用Go作为开发语言来解决云原生管理和部署问题的最Z佳实践。本书的主要内容有:了解云原生应用程序与其他软件架构有何不同。了解如何利用Go语言解决设计可扩展的分布式服务的各种难题。利用Go语言的底层特性(例如通道和go协程)来实现可靠的云原生服务。探讨什么是服务可靠性及其与云原生的关系。利用各种模式、抽象和工具来构建和管理复杂的分布式系统。
编辑推荐
Docker、Kubernetes和Prometheus的共同点是什么?所有这些云原生技术都是用Go语言编写的。这本实用指南将向你展示如何利用Go语言的优势在不可预期的环境中开发可扩展且富有弹性的云原生服务。我们将探索这些应用程序的组成和结构,从Go语言的底层特性到中级设计模式,再到高级架构的考虑因素。
专家推荐
本书很好地将云原生的高级概念带到现实,并使用现代计算语言Go来实现。这两个概念的结合效果很好,带给我们许多灵感。
Lee Atchison,
Atchison Technology LLC的所有者
这是我读到的第D一本以如此实用的方式、如此广度及深度介绍现代云原生实践的书籍。作者通过清晰的示例呈现了可帮助工程师解决日常面临的实际问题的各种模式。
Alvaro Atienza,
Flatiron Health网站可靠性工程师
前言对于技术专家来说,现如今是一段多么美好的时光。我们使用Docker 来构建容器,使用Kubernetes 来编排容器;使用Prometheus 来监控容器;使用Consul 来发现容器;使用Jaeger 来追踪容器之间的关系。这只是几个例子,这类的工具还有很多很多,它们代表了新一代技术:它们都是云原生,并且都是用Go 编写的。感觉上云原生是一个略带歧义的流行术语,但实际上它有非常具体的定义。根据云原生计算基金会(Linux 基金会的子基金会),云原生应用程序的设计目标是在面对急剧变化的负载时可扩展、在面对环境的不确定性时具有很好的韧性、在面对不断变化的需求时可管理。换句话说,云原生应用程序是为残酷、不确定的宇宙中的生命构建的。Go 创建于大约十年前,吸取了多年来构建基于云的软件的经验教训,是第一款专门为云原生软件开发而设计的主流语言。Go 的诞生主要是因为当时使用的通用服务器语言根本不适合编写谷歌大量产出的分布式、进程密集型应用程序。从那以来,Go 成为云原生开发的通用语言,被广泛用于各个领域,从Docker 到Harbor、从Kubernetes 到Consul、从InfluxDB 到CockroachDB。云原生计算基金会的15 个毕业项目中有10 个是用Go 语言编写的,而在所有62 个注1 项目中有42 个大部分或全部是用Go 编写的。而且这个数字每天都在增加。本书面向的读者对象本书主要面向中高级开发人员,特别是Web 应用程序工程师和DevOps 专家及网站可靠性工程师。可能许多人都在使用Go 来构建Web 服务,但并不熟悉云原生开发的微妙之处,甚至不清楚什么是云原生,然后发现自己的服务很难管理、部署或观察。本书不仅可以为这些读者学习如何构建云原生服务提供坚实的基础,而且还将展示为什么这些技术如此重要,并提供具体的示例来解说这个有些抽象的主题。许多读者可能更熟悉其他语言,但被Go 作为云原生开发语言的名号所吸引。本书可以为这些读者提供有关采用Go 作为云原生开发语言的最佳实践,而且还可以帮助他们解决云原生的管理和部署问题。本书的创作原因应用程序的设计、构建和部署方式正在发生变化。扩展的需求迫使开发人员将服务分散到大量服务器上,软件行业正在走向云原生。但这引入了许多新问题:如何开发、部署或管理在十台、一百台、一千台服务器上运行的服务?不幸的是,云原生领域的现有书籍都侧重于抽象设计原则,而且只介绍如何执行这些操作的基本示例,有些甚至连示例都没有。本书旨在满足这部分的市场需求:演示复杂的云原生设计原理。使用代码示例你可以通过如下链接下载本书的补充材料(代码示例,练习等):https://github.com/cloud-native-go/examples。本书的目的是帮助你完成工作。一般来说,你可以在自己的程序或者文档中使用本书附带的示例代码。你无需联系我们获得使用许可,除非你要复制大量的代码。例如,使用本书中的多个代码片段编写程序就无需获得许可。但以CD-ROM 的形式销售或者分发OReilly 书中的示例代码则需要获得许可。回答问题时援引本书内容以及书中示例代码,无需获得许可。在你自己的项目文档中使用本书大量的示例代码时,则需要获得许可。我们不强制要求署名,但如果你这么做,我们深表感激。署名一般包括书名、作者、出版社和国际标准图书编号。例如:Cloud Native Go by Matthew A. Titmus(OReilly). Copyright 2021 Matthew A. Titmus, 978-1-492-07633-9。如果你觉得自身情况不在合理使用或上述允许的范围内,请通过邮件和我们联系,地址是permissions@oreilly.com。OReilly 在线学习平台(OReilly Online Learning)近40 年来,OReilly Media 致力于提供技术和商业培训、知识和卓越见解,来帮助众多公司取得成功。公司独有的专家和改革创新者网络通过OReilly 书籍、文章以及在线学习平台,分享他们的专业知识和实践经验。OReilly 在线学习平台按照您的需要提供实时培训课程、深入学习渠道、交互式编程环境以及来自OReilly 和其他200 多家出版商的大量书籍与视频资料。更多信息,请访问网站:https://www.oreilly.com/。联系我们任何有关本书的意见或疑问,请按照以下地址联系出版社。美国:OReilly Media, Inc.1005 Gravenstein Highway NorthSebastopol, CA 95472中国:北京市西城区西直门南大街2 号成铭大厦C 座807 室(100035)奥莱利技术咨询(北京)有限公司这本书有专属网页,你可以在那儿找到本书的勘误、示例和其他信息。地址是https://oreil.ly/cloud-native-go。如果你对本书有一些评论或技术上的建议,请发送电子邮件到errata@oreilly.com.cn。要了解OReilly 图书、培训课程、会议和新闻的更多信息,请访问我们的网站,地址是http://www.oreilly.com。我们的Facebook:http://facebook.com/oreilly。我们的Twitter:http://twitter.com/oreillymedia。我们的Youtube:http://youtube.com/oreillymedia。致谢首先,我要感谢我的妻子和儿子。自从进入我的生活以来,你们就成为了我做好每一件事的动力,你们就像启明星指引着我前进的方向,吸引着我的目光望向天空。致父亲,最近他离我们而去。在我认识的所有人中,只有你最像文艺复兴时期的人,同时你也是我认识的最善良、最谦虚的人。我希望长大以后能成为你一样的人。致Mary。父亲的离世带给你的感触最深。你是我的家人,永远都是我的家人,即使我打电话给你的次数并不多。父亲一定会为你的力量和优雅感到自豪。致Sarah。你的力量和勇气总让我感到惊叹。从牙牙学语开始,敏锐的头脑就让你成为我最坚定的盟友,同时也是最凶猛的对手。不要告诉Nathan,兄弟姐妹们当中我最喜欢的人是你。致Nathan。如果说我们都继承了父亲三分之一的天赋,那么你得到的是他的心。虽然我不会经常宣之于口,但我为你以及你的成就感到骄傲。不要告诉Sarah,兄弟姐妹们当中我最喜欢的人是你。致母亲。你坚强、聪明、多才多艺、不因循守旧。感谢你教导我做真正需要做的事情,不要在乎别人的想法。请继续保持你的个性,记得喂鸡。致Albert。你有一颗博大的心和无限的耐心。感谢你加入我们的大家庭,这个家因为有你而变得更美好。致我的其他家人。虽然见面的机会并不多,但我非常想念你们。每当我需要你们时,你们总会在我身边。感谢你们与我一起庆祝胜利,并在我失败时给予支持。感谢Walt 和Alvaro,感谢你们始终陪伴在侧,即便换工作也离不开你们。感谢你们在需要时给予热情的支持,并让我及时认清现实。你们帮助我成为一名更好的工程师。另外,感谢你们把Will Wight 的《Cradle》系列介绍给我,我已经深陷其中不能自拔。致Jeff Classic、New Jeff、Alex、Markan、Priyanka、Sam、Owen、Matt M.、Marius、Peter、Rohit,以及我在Flatiron Health 的所有朋友和同事。感谢你们的包容,让我集中注意力撰写本书,感谢你们对我和我的工作的支持,你们担任着我的参谋、测试版读者和评论家,并鼓励我,推动我前进。致纽约及世界各地CoffeeOps 的所有朋友。感谢你们倾听我的想法,允许我挑战你们,而你们也挑战了我。感谢你们的投入,让这本书变得更好。致著名的可观测性专家和预言家 Liz Fong-Jones。感谢您的指导,您的代码示例非常宝贵,如果没有您的慷慨,本书的创作会更困难,而且结果也不如人意。感谢我的技术审阅人员Lee Atchison、Alvaro Atienza、David Nicponski、Natalie Pistunovich 和James Quigley。感谢你们耐心地阅读我写的每一个字(甚至是脚注)。多亏了你们敏锐的眼光和辛勤的工作,本书得到了极大提升。最后,感谢OReilly Media 编辑以及艺术家团队的辛勤劳动,很荣幸能与你们合作,特别感谢Amelia Blevins、Danny Elfanbaum 和Zan McQuade。今年是非常有趣的一年,你们的善良、耐心和支持让我渡过了难关。
Matthew A. Titmus是一位经验丰富的软件开发行业资深人士,拥有分子生物学学位。作为云原生技术和Go语言的早期采用者和倡导者,他对如何构建生产级质量的系统充满热情。他付诸大量心血来实现观察和编排分布式系统的策略。
目录
第Ⅰ部分 云原生概述
第1 章 什么是云原生应用程序 11
1.1 迄今为止的故事 12
1.2 什么是云原生? 14
1.2.1 可扩展性 .15
1.2.2 松散耦合 .16
1.2.3 韧性 17
1.2.4 可管理性 .19
1.1.5 可观察性 .20
1.3 为什么云原生很重要? .21
1.4 小结 .22
第2 章 为什么Go 语言统治云原生世界 23
2.1 Go 语言诞生的动机 .23
2.2 云原生世界的特性 24
2.2.1 组合与结构化类型 .25
2.2.2 可理解性 .27
2.2.3 CSP 风格的并发 27
2.2.4 快速构建 .28
2.2.5 语言稳定性 29
2.2.6 内存安全 .30
2.2.7 性能 31
2.2.8 静态链接 .32
2.2.9 静态类型 .33
2.3 小结 .34
第Ⅱ部分 云原生Go 结构
第3 章 Go 语言基础 39
3.1 基本数据类型 .39
3.1.1 布尔值 40
3.1.2 简单的数字 40
3.1.3 复数 41
3.1.4 字符串 42
3.2 变量 .42
3.2.1 简短的变量声明 43
3.2.2 零值 44
3.2.3 空标识符 .45
3.2.4 常量 46
3.3 容器类型:数组、切片和映射 47
3.3.1 数组 .47
3.3.2 切片 48
3.3.3 映射 53
3.4 指针 .54
3.5 控制结构56
3.5.1 for 循环 56
3.5.2 if 语句 59
3.5.3 switch 语句 .60
3.6 错误处理62
3.7 可变参函数和闭包 63
3.7.1 函数 64
3.7.2 可变参函数 68
3.7.3 匿名函数和闭包 70
3.8 结构、方法和接口 72
3.8.1 结构 72
3.8.2 方法 73
3.8.3 接口 75
3.8.4 通过类型嵌入实现组合 77
3.9 并发 .80
3.9.1 Go 协程 80
3.9.2 通道 80
3.9.3 select 语句 83
3.10 小结 85
第4 章 云原生模式 87
4.1 Context 包 .88
4.1.1 Context 可以做什么 89
4.1.2 创建Context 90
4.1.3 定义Context 的截止日期和超时 .91
4.1.4 定义请求作用域的值.91
4.1.5 使用Context 92
4.2 本章的主要内容 93
4.3 稳定性模式 94
4.3.1 断路器模式 94
4.3.2 防抖模式 .97
4.3.3 重试模式 102
4.3.4 节流模式 104
4.3.5 超时模式 108
4.4 并发模式. 111
4.4.1 扇入模式 112
4.4.2 扇出模式 114
4.4.3 未来模式 117
4.4.4 分片模式 122
4.5 小结 128
第5 章 构建云原生服务 129
5.1 构建一个服务! .129
5.2 需求 130
5.2.1 什么是幂等性,为什么幂等性很重要? 131
5.2.2 最终目标 133
5.3 第0 代:核心功能 .133
5.4 第一代:单体架构 .135
5.4.1 使用net/http 构建HTTP 服务器 135
5.4.2 使用gorilla/mux 构建HTTP 服务器 137
5.4.3 构建RESTful 服务 141
5.4.4 确保数据结构的并发安全 146
5.5 第2 代:持久保存资源状态 .148
5.5.1 什么是事务日志? 150
5.5.2 将状态存储到事务日志文件 151
5.5.3 将状态存储到外部数据库 165
5.6 第3 代:实现传输层安全 .174
5.6.1 传输层安全 .175
5.6.2 私钥和证书文件 176
5.6.3 使用HTTPS 保护Web 服务 177
5.6.4 传输层总结 .179
5.7 键值存储的容器化 .179
5.7.1 Docker 的基础知识 .181
5.7.2 构建键值存储容器 188
5.7.3 外部化容器数据 193
5.8 小结 194
第Ⅲ部分 云原生属性
第6 章 可信任性 . 197
6.1 云原生的意义 198
6.2 可信任性.198
6.3 什么是可信任性以及为什么可信任性如此重要? 199
6.4 实现可信任性 203
6.4.1 故障预防 205
6.4.2 容错 .206
6.4.3 故障排除 207
6.4.4 故障预测 208
6.5 十二要素应用 209
6.5.1 基准代码 210
6.5.2 依赖 .210
6.5.3 配置 . 211
6.5.4 依赖服务 213
6.5.5 构建、发布、运行 214
6.5.6 进程 .215
6.5.7 数据分离 216
6.5.8 可扩展性 217
6.5.9 易处理性 217
6.5.10 开发环境与生产环境等价 .218
6.5.11 日志 219
6.5.12 管理进程 219
6.6 小结 221
第7 章 可扩展性 . 223
7.1 什么是可扩展性 .225
7.2 四个常见瓶颈 226
7.3 状态与无状态 228
7.3.1 应用程序状态与资源状态 228
7.3.2 无状态的优势 .229
7.4 推迟扩展:效率 .230
7.4.1 使用LRU 缓存的高效缓存 .231
7.4.2 高效同步 234
7.4.3 内存泄漏可能会致命错误:运行时:内存不足 .240
7.4.4 高效 .244
7.5 服务架构.244
7.5.1 单体系统架构 .245
7.5.2 微服务系统架构 246
7.5.3 无服务器架构 .248
7.6 小结 253
第8 章 松散耦合 . 255
8.1 紧密耦合.256
8.2 服务之间的通信 .260
8.3 请求响应消息 261
8.3.1 常见的请求响应实现262
8.3.2 通过net/http 发送HTTP 请求 263
8.3.3 使用gRPC 实现远程过程调用 267
8.4 利用插件实现本地资源的松散耦合280
8.4.1 带有插件包的进程内插件 281
8.4.2 基于RPC 的HashiCorp 插件系统 288
8.5 六边形架构 297
8.5.1 架构 .297
8.5.2 实现六边形服务 299
8.6 小结 307
第9 章 韧性 . 309
9.1 为什么韧性很重要 .310
9.2 系统失效是什么意思? 311
9.3 级联失效.313
9.4 重试请求.321
9.4.1 退避算法 322
9.4.2 断路器 325
9.4.3 超时 .327
9.4.4 幂等性 333
9.5 服务冗余.337
9.5.1 设计系统时考虑冗余338
9.5.2 自动扩展 340
9.6 健康检查.341
9.6.1健康的实例意味着什么? .342
9.6.2 三种类型的健康检查343
9.6.3 故障打开 348
9.7 小结 348
第10 章 可管理性 351
10.1 什么是可管理性,为什么我应该关注可管理性? 352
10.2 配置应用程序 354
10.2.1 有关配置的良好实践 355
10.2.2 环境变量配置 355
10.2.3 命令行参数配置 .357
10.2.4 配置文件 363
10.2.5 Viper:配置包中的瑞士军刀 381
10.3 利用特性标志管理功能 386
10.3.1 特性标志的进化 .387
10.3.2 第零代:最初的实现 388
10.3.3 第一代:硬编码特性标志 .388
10.3.4 第二代:可配置标志 390
10.3.5 第三代:动态特性标志 391
10.4 小结 395
第11 章 可观察性 397
11.1 什么是可观察性? 398
11.1.1 为什么我们需要可观察性? .399
11.1.2 可观察性与传统的监控有何不同? 399
11.2 可观察性的三大支柱 400
11.3 OpenTelemetry 402
11.4 追踪 404
11.4.1 追踪的概念 405
11.4.2 使用OpenTelemetry 进行追踪 407
11.4.3 整合:追踪 420
11.5 指标 427
11.5.1 推式与拉式指标集合 429
11.5.2 OpenTelemetry 的指标 432
11.5.3 整合:指标 444
11.6 日志记录 447
11.6.1 更好的日志记录实践 448
11.6.2 使用Go 标准的log 包记录日志 .452
11.6.3 Zap 日志包 455
11.7 小结 462