![]()
内容推荐 Docker、Kubernetes和Prometheus的共同点是什么?所有这些云原生技术都是用Go语言编写的。这本实用指南将向你展示如何利用Go语言的优势在不可预期的环境中开发可扩展且富有弹性的云原生服务。我们将探索这些应用程序的组成和结构,从Go语言的底层特性到中级设计模式,再到高级架构的考虑因素。 本书的各个章节环环相扣,我们将引导Go语言中高级开发人员构建一款简单但功能齐备的分布式键值存储。我们将学习选用Go作为开发语言来解决云原生管理和部署问题的很好实践。 ·了解云原生应用程序与其他软件架构有何不同。 ·了解如何利用Go语言解决设计可扩展的分布式服务的各种难题。 ·利用Go语言的底层特性(例如通道和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 |