├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── .vuepress ├── client.js ├── config.js ├── layouts │ └── layout.vue ├── public │ ├── assets │ │ └── favicon.ico │ └── icon.png └── styles │ └── index.scss ├── Observability ├── Observability-vs-Monitoring.md ├── OpenTelemetry.md ├── What-is-Observability.md ├── conclusion.md ├── dumps.md ├── logging.md ├── metrics.md ├── profiles.md ├── signals.md ├── summary.md └── tracing.md ├── README.md ├── ServiceMesh ├── MicroService-history.md ├── The-future-of-ServiceMesh.md ├── What-is-ServiceMesh.md ├── conclusion.md ├── control-plane.md ├── data-plane.md ├── overview.md └── summary.md ├── about.md ├── application-centric ├── Controller.md ├── Helm.md ├── Kustomize.md ├── OAM.md ├── Operator.md ├── app-model.md ├── application-centric.md ├── conclusion.md └── summary.md ├── architecture ├── Immutable.md ├── MicroService.md ├── ServiceMesh.md ├── arc.md ├── architect.md ├── background.md ├── cloud-native-tech.md ├── conclusion.md ├── container.md ├── declarative-api.md ├── define-cloud-native.md ├── devops.md ├── history.md ├── summary.md └── target.md ├── assets ├── 2021-02-secrets-management.svg ├── 6-b.png ├── ABA.svg ├── Ambient-Mesh-2.png ├── Ambient-Mesh.png ├── Ambient-Mesh.svg ├── BASE.svg ├── Borg.jpeg ├── CA.svg ├── CI.png ├── CNI.png ├── CNI.webp ├── CRD.webp ├── CSI.png ├── ClickHouse-benchmark.jpeg ├── Cluster-AutoScaler.png ├── Dapper-trace-span.png ├── Device-plugin.webp ├── DevicePlugin.svg ├── ELK.png ├── Flannel-UDP-TUN.webp ├── Flannel-UDP.webp ├── HPA.svg ├── Immutable.png ├── JuiceFS.png ├── Monitoring-vs-Observability.png ├── Monolith-vs-MicroService.png ├── Netfilter-packet-flow.svg ├── OAM-how-it-works.png ├── OAM.jpg ├── OCSP-Stapling.png ├── Pinpoint.png ├── RDMA.png ├── Replicated-state-machine.webp ├── RoCE_Header_format.png ├── ServiceMesh-summary.png ├── SoftwareEatingTheWorld.jpg ├── SpringCloud.webp ├── TCC.svg ├── TCP.svg ├── TriggerFlow.svg ├── VXLAN.png ├── Volcano-arch.png ├── XDP.svg ├── active_and_passive_arch.png ├── agile-model.png ├── agile-word.png ├── ambient-layers.png ├── ambient-mesh-arch.png ├── application-centric.png ├── arc-1.svg ├── argocd-demo.png ├── argocd.png ├── argocd_architecture.png ├── artifact-hub.jpg ├── balance-summary.png ├── balancer-4.svg ├── balancer-edge-proxy.svg ├── balancer-ha-2.svg ├── balancer-ha.svg ├── balancer-sdk.svg ├── balancer-sidecar.svg ├── balancer.svg ├── balancer4-NAT.svg ├── balancer4-dsr.svg ├── balancer4-tunnel.svg ├── balancer4.svg ├── balancer7.svg ├── basic-paxos.png ├── bbr-2.png ├── bbr-cc.png ├── bbr-status.png ├── bbr.png ├── bench_tcp_crr_32_processes.png ├── bench_tcp_crr_32_processes_cpu (1).png ├── bench_tcp_crr_32_processes_cpu.png ├── bench_tcp_stream_32_streams_cpu.png ├── borg-arch.png ├── bridge-call-iptables.svg ├── brotli.jpeg ├── brotli.png ├── byzantine-1.svg ├── byzantine-2.svg ├── byzantine-3.svg ├── byzantine-4.svg ├── byzantine-5.svg ├── byzantine-6.svg ├── calico-bgp.svg ├── cap-theorem.png ├── cc.png ├── cd.png ├── chroot.png ├── cicd-push.png ├── cicd-tools.svg ├── cicd.png ├── cilium-istio-benchmark.webp ├── cilium.svg ├── cloud-history-1.svg ├── cloud-history-2.png ├── cloud-history-2.svg ├── cloud-history-3.png ├── cloud-history-3.svg ├── cloud-native-goals-2.png ├── cloud-native-goals.png ├── cloud-native.png ├── cloud-summary.png ├── cloud.svg ├── cloudflare-dns.png ├── cncf-cloud-native.svg ├── cncf-observability.png ├── cni-plugin.png ├── cni0.svg ├── column-database.png ├── compress.png ├── conntrack-nat.png ├── conntrack-nat.svg ├── conntrack.png ├── consensus-summary.png ├── consensus.png ├── container-2.jpeg ├── container-summary.png ├── containerd-arch.png ├── containerd-built-in-plugin.png ├── containerd-cri.png ├── cri-arc.png ├── cri-architecture.png ├── csi-k8s.png ├── custom-chain.png ├── dapper-log.png ├── declarative.svg ├── definition-cap.png ├── deployment-controller.png ├── device-plugin.png ├── devops-2.jpg ├── devops-wall.png ├── devops.jpeg ├── distributed-transaction.png ├── dns-1.png ├── dns-2.png ├── dns-example.png ├── dns-tree.webp ├── docker-arc.png ├── docker-file-system.png ├── docker-image.png ├── docker.png ├── dockerfile.png ├── dpdk.png ├── dpvs-performance.png ├── dragonfly.png ├── dsa.png ├── ebpf-go.webp ├── ebpf.webp ├── ecc.png ├── envoy-resource.png ├── es-vs-clickhouse.png ├── facebook-404-error.jpeg ├── flagger.png ├── flannel-route.svg ├── flannel-vxlan.svg ├── four-metrics-type.png ├── github-tekton.png ├── gitops-workflow.webp ├── global-lb.png ├── global-load-balancer.svg ├── grafana-dashboard-english.png ├── helm.webp ├── how_mtls_works-what_is_mutual_tls.png ├── how_tls_works.png ├── http-process.png ├── http-quic.png ├── http-summary.png ├── http3.png ├── httpdns.png ├── https-1.png ├── https-2.png ├── https-3.png ├── https-4.png ├── https-5.png ├── hybrid-cloud.svg ├── id-service.png ├── infra-container.svg ├── ip.svg ├── iptables-chain.png ├── iptables-vs-ipvs.png ├── iptables.png ├── istio-iptables.svg ├── k8s-1.png ├── k8s-arch.svg ├── k8s-ca.svg ├── k8s-chain.png ├── k8s-cri-o.png ├── k8s-cri.png ├── k8s-metadata.jpeg ├── k8s-resource.svg ├── k8s-runtime-v1.svg ├── k8s-runtime-v2.png ├── k8s-runtime-v3.png ├── k8s-runtime-v4.svg ├── k8s-selector.png ├── k8s-service.png ├── k8s-service.svg ├── k8s-sidecar.png ├── k8s-volume.svg ├── kaniko.png ├── kata-container-diff.png ├── kata-container.jpeg ├── kata-container.jpg ├── kata-container.png ├── keda-arch.png ├── kube-scheduler.png ├── kube-scheduler.svg ├── kubelet.png ├── kubernetes-container.png ├── kubernetes_operator.webp ├── kubevela.jpg ├── l4-connection-v2.svg ├── l4-connection.png ├── l4-connection.svg ├── l7-lb.png ├── l7-lb.webp ├── label.png ├── label2.png ├── landscape.png ├── latencies_p50.svg ├── latency-200rps.png ├── lb-via-client-lib.webp ├── lb-via-sidecar.webp ├── linkerd-control-plane.png ├── linkerd-envoy.png ├── linkerd-resource.png ├── linux-bridge.svg ├── linux-namespace.svg ├── linux-summary.png ├── linux-veth.svg ├── linux-vxlan.svg ├── loadbalancer.png ├── lock.png ├── log.png ├── logging.png ├── loki-arch.png ├── loki-arch.svg ├── loki-dashboard.jpeg ├── loki_architecture_components.svg ├── loud-summary.png ├── lua-cpu-flame-graph.webp ├── lvs-ha.svg ├── macvlan-veth.svg ├── macvlan.png ├── macvlan.svg ├── mesh3.png ├── mesos-arch.jpeg ├── micro-service-1.png ├── micro-service-2.png ├── monitoring.png ├── multi_paxos.png ├── multus-pod-image.svg ├── nat.png ├── netfilter-hook.svg ├── netfilter-k8s.svg ├── network-lb-overview.png ├── network-namespace.svg ├── network-summary.png ├── networking.svg ├── nginx-conf.png ├── nydus-performance.png ├── nydus.png ├── oam_model.png ├── observability-knowns.png ├── observability.jpg ├── observability.png ├── opentracing-vs-opencensus.jpg ├── operatorhub.io.png ├── otel-diagram.svg ├── overfs.jpeg ├── overlay-network.png ├── overlay.jpeg ├── overlay.png ├── overlay.svg ├── overlay_constructs.webp ├── paxos-conflict-2.png ├── paxos-conflict3.png ├── paxos-consensus.svg ├── paxos-liveness.png ├── paxos-p1.png ├── paxos-p2.png ├── paxos-p3.png ├── paxos-p4.png ├── paxos.png ├── paxos.svg ├── paxos_2pc_choice.png ├── paxos_conflict_choices.png ├── paxos_split_votes.png ├── pivotal-cloud-native-update.svg ├── pivotal-cloud-native.svg ├── pod.svg ├── ppt4.jpg ├── prometheus-arch.png ├── prometheus-exporter.png ├── prometheus-storage.jpeg ├── protobuf_message.svg ├── proxyless.svg ├── pvc-flow.png ├── qos.webp ├── qrcode-v2.png ├── quic-1.png ├── quic-3.png ├── quic-connection.png ├── quic-handshake.png ├── quic-head-block.png ├── quorum-base.png ├── raft-ConfChange.png ├── raft-append-entries.svg ├── raft-election.svg ├── raft-log-commit.png ├── raft-log-fix-action.svg ├── raft-log-fix.svg ├── raft-log.svg ├── raft-single-server.png ├── raft-single-server.svg ├── raft-state-machine.png ├── raft-term.svg ├── requests-limits.png ├── rootfs-1.jpeg ├── row-database.png ├── runtime.png ├── saga.svg ├── scheduling-framework-extensions.png ├── scheduling-framework-extensions.svg ├── service-mesh-2.png ├── service-mesh-3.png ├── service-mesh-4.png ├── service-mesh-arc.svg ├── service-mesh-kernel.jpg ├── service-mesh-overview.png ├── service-mesh-tcp-1.png ├── service-mesh-tcp.png ├── service-mesh.png ├── servicemesh-sidecar.png ├── servicemesh.png ├── sidecar-example.jpg ├── sidecar.svg ├── sidecarless.png ├── sidecarless.svg ├── skywalking-ui.jpeg ├── ssl-domain-info.png ├── ssl-test.png ├── star-history-20231218.png ├── swarm-diagram.webp ├── tcp_disconnect.svg ├── tekton-dashboard-ui.jpeg ├── tls1.2.png ├── tls1.3.png ├── tracing.png ├── tsdb.svg ├── tun.svg ├── types-of-encryption-asymmetric-encryption.png ├── types-of-encryption-symmetric-encryption.png ├── types-of-mounts-volume.webp ├── uber-microservice.png ├── veth.svg ├── vlan-router.svg ├── vlan-sub-interface.svg ├── volume-list.png ├── volume.svg ├── vxlan-data.png ├── vxlan-router.svg ├── vxlan_header.png ├── waterfall-model.svg ├── what-is-koordinator.svg ├── what-is-kubevela.jpg ├── www.thebyte.com.cn_.png ├── xaas.svg └── xdp.png ├── balance ├── balance-features.md ├── balance-topology.md ├── balance.md ├── balance4.md ├── balance7.md ├── conclusion.md ├── global-load-balancer.md └── summary.md ├── consensus ├── Basic-Paxos.md ├── Paxos-history.md ├── Paxos.md ├── Replicated-State-Machine.md ├── conclusion.md ├── consensus.md ├── raft-ConfChange.md ├── raft-leader-election.md ├── raft-log-replication.md ├── raft.md └── summary.md ├── container ├── CRI.md ├── Extended-Resource.md ├── Resource-scheduling.md ├── auto-scaling.md ├── borg-omega-k8s.md ├── conclusion.md ├── container-network.md ├── image.md ├── kube-scheduler.md ├── orchestration.md ├── resource.md ├── storage.md └── summary.md ├── distributed-transaction ├── ACID.md ├── BASE.md ├── CAP.md ├── Saga.md ├── TCC.md ├── conclusion.md ├── idempotent.md ├── summary.md └── transaction.md ├── http ├── Edge-Acceleration.md ├── compress.md ├── conclusion.md ├── congestion-control.md ├── dns-ha.md ├── dns.md ├── http-dns.md ├── https-latency.md ├── https-summary.md ├── https.md ├── latency.md ├── quic.md ├── ssl.md └── summary.md ├── intro.md ├── network ├── DPDK.md ├── RDMA.md ├── XDP.md ├── conclusion.md ├── conntrack.md ├── iptables.md ├── kernel-bypass.md ├── linux-bridge.md ├── linux-kernel-networking.md ├── linux-vritual-net.md ├── netfilter.md ├── network-layer.md ├── network-namespace.md ├── networking.md ├── summary.md ├── tuntap.md ├── virtual-nic.md └── vxlan.md ├── noun.md ├── package.json └── review.md /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build app and deploy 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v4 12 | - name: use Node.js 20.0.0 13 | uses: actions/setup-node@v4 14 | with: 15 | node-version: 20 16 | - name: Install and Build 17 | run: | 18 | npm cache clean --force 19 | npm install 20 | npm run build 21 | # 部署到阿里云 22 | - name: Deploy to Aliyun 23 | uses: easingthemes/ssh-deploy@v4.1.8 24 | env: 25 | SSH_PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} 26 | 27 | ARGS: "-rlgoDzvc -i" 28 | SOURCE: ".vuepress/dist/" 29 | REMOTE_HOST: "110.40.229.45" 30 | REMOTE_USER: "root" 31 | TARGET: "/home/www/thebyte.com.cn" 32 | SCRIPT_BEFORE: | 33 | whoami 34 | ls -al -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .temp 3 | .cache 4 | yarn.lock 5 | .DS_store 6 | # Node rules: 7 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 8 | .grunt 9 | package-lock.json 10 | yarn-error.log 11 | node_modules 12 | yarn.lock 13 | 14 | dist 15 | 16 | # eBook build output 17 | *.epub 18 | *.mobi 19 | *.pdf 20 | .cache 21 | chrome 22 | 23 | .vuepress -------------------------------------------------------------------------------- /.vuepress/client.js: -------------------------------------------------------------------------------- 1 | import { defineClientConfig } from '@vuepress/client' 2 | import Layout from './layouts/layout.vue' 3 | 4 | export default defineClientConfig({ 5 | enhance ({ router }) { 6 | 7 | }, 8 | layouts: { 9 | Layout 10 | } 11 | }) -------------------------------------------------------------------------------- /.vuepress/layouts/layout.vue: -------------------------------------------------------------------------------- 1 | 24 | 60 | -------------------------------------------------------------------------------- /.vuepress/public/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/.vuepress/public/assets/favicon.ico -------------------------------------------------------------------------------- /.vuepress/public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/.vuepress/public/icon.png -------------------------------------------------------------------------------- /.vuepress/styles/index.scss: -------------------------------------------------------------------------------- 1 | .custom-container { 2 | img { 3 | margin-right:auto; 4 | margin-left:auto; 5 | } 6 | 7 | } 8 | .custom-container .center { 9 | text-align: center; 10 | } 11 | 12 | .center { 13 | text-align: center; 14 | } 15 | 16 | .custom-container { 17 | .right { 18 | text-align: right; 19 | } 20 | } 21 | 22 | .page-nav,.page .page-meta,.page .theme-default-content { 23 | max-width: 90%; 24 | } 25 | 26 | table { 27 | width: 100%; 28 | display: table; 29 | } 30 | 31 | @media print{ 32 | .navbar, 33 | .sidebar, 34 | .sidebar-mask, 35 | .page-nav, 36 | .page .page-meta, 37 | .page-info { 38 | display: none; 39 | } 40 | .page { 41 | padding-left: inherit; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /Observability/Observability-vs-Monitoring.md: -------------------------------------------------------------------------------- 1 | # 9.2 可观测性与传统监控 2 | 3 | 了解什么是可观测性后,接踵而来的问题是,它与传统监控有何区别?业内专家 Baron Schwartz 曾用一句简洁的话总结了两者的关系,不妨来看他的解释。 4 | 5 | :::tip 可观测性与监控的关系 6 | 监控告诉我们系统哪些部分是正常的,可观测性告诉我们系统为什么不正常了。 7 | 8 | :::right 9 | ——by《高性能 MySQL》作者 Baron Schwartz 10 | ::: 11 | 12 | 如图 9-1,我们把系统的理解程度、可收集信息之间的关系象限化分析,说明可观测性与传统监控的区别。 13 | 14 | :::center 15 | ![](../assets/observability-knowns.png)
16 | 图 9-1 可观测性帮助工程师解决未知的未知(Unknown Unknowns) 17 | ::: 18 | 19 | X 轴的右侧(Known Knows 和 Known Unknowns)表示确定性的已知和未知,图中给出了相应的例子。这类信息通常是系统上线前就能预见,并能够监控的基础性、普适性事实(如 CPU Load、内存、TPS、QPS 等指标)。传统的监控系统大部分围绕这些确定的因素展开。 20 | 21 | 但是很多情况下,上述信息很难全面描述和衡量系统的状态。比如坐标的左上角的 Unknown Knowns(未知的已知,通俗理解为假设),举个例子,通常会引入限流策略来保证服务可用性。假设请求量突然异常暴增,限流策略牺牲小部分用户、保证绝大部分用户的体验。但注意,这里的“假设”(请求量突然暴增)并未实际发生。因此,平常情况下的监控看不出任何异常。 22 | 23 | 但如果请求量突然暴增了,同时那些“假设”又未经过验证(如限流逻辑写错了),就会导致我们碰见最不愿见到的情况 —— Unknown Unknowns(未知的未知,毫无征兆且难以理解)。 24 | 25 | 经验丰富(翻了无数次车)的工程师根据以往经验,逐步缩小 Unknown Unknowns 的排查范围,从而缩短故障修复时间。但更合理的做法是,根据系统的细微输出(如 metrics、logs、traces,也就是遥测数据),以低门槛且直观的方式(如监控大盘、链路追踪拓扑等)描绘出系统的全面状态。如此,当发生 Unknown Unkowns 情况时,才能具象化的一步步定位到问题的根因。 26 | 27 | [^1]: 参见 https://blog.sciencenet.cn/blog-829-1271882.html 28 | -------------------------------------------------------------------------------- /Observability/OpenTelemetry.md: -------------------------------------------------------------------------------- 1 | # 9.4 可观测标准的演进 2 | 3 | Dapper 论文发布后,市场上涌现出大量追踪系统,如 Jaeger、Pinpoint、Zipkin 等。这些系统都基于 Dapper 论文实现,功能上无本质差异,但实现方式和技术栈不同,导致它们难以兼容或协同使用。 4 | 5 | 为解决追踪系统各自为政的乱象,一些老牌应用性能监控(APM)厂商(如 Uber、LightStep 和 Red Hat)联合定义了一套跨语言的、平台无关分布式追踪标准协议 —— OpenTracing。 6 | 7 | 开发者只需按照 OpenTracing 规范实现追踪接口,便可灵活替换、组合探针、存储和界面组件。2016 年,CNCF 将 OpenTracing 收录为其第三个项目,前两个分别是大名鼎鼎的 Kubernetes 和 Prometheus。这一举措标志着 OpenTracing 作为分布式系统可观测性领域的标准之一,获得了业界的广泛认可。 8 | 9 | OpenTracing 推出后不久,Google 和微软联合推出了 OpenCensus 项目。OpenCensus 起初是 Google 内部的监控工具,开源的目的并非与 OpenTracing 竞争,而是希望为分布式系统提供一个统一的、跨语言的、开箱即用的可观测性框架,不仅仅处理链路追踪(tracing)、还要具备处理指标(metrics)的能力。 10 | 11 | 虽说 OpenTracing 和 OpenCensus 推动了可观测性系统的发展,但它们作为协议标准,彼此之间的竞争和分裂不可避免地消耗了大量社区资源。对于普通开发者而言,一边是老牌 APM 厂商,另一边是拥有强大影响力的 Google 和微软。选择困难症发作时,一个新的设想不断被讨论:“能否有一个标准方案,同时支持指标、追踪和日志等各类遥测数据?”。 12 | 13 | 2019 年,OpenTracing 和 OpenCensus 的维护者决定将两个项目整合在一起,形成了现在的 OpenTelemetry 项目。OpenTelemetry 做的事情是,提供各类遥测数据统一采集解决方案。 14 | 15 | 如图 9-17 所示,集成了 OpenTelemetry 的可观测系统: 16 | 17 | - 应用程序只需要一种 SDK 就可以实现所有类型遥测数据的生产; 18 | - 集群只需要部署一个 OpenTelemetry Collector 便可以采集所有的遥测数据。 19 | 20 | :::center 21 | ![](../assets/otel-diagram.svg)
22 | 图 9-17 集成 OpenTelemetry 的可观测架构 [图片来源](https://opentelemetry.io/docs/) 23 | ::: 24 | 25 | 至于遥测数据采集后如何存储、展示、使用,OpenTelemetry 并不涉及。你可以使用 Prometheus + Grafana 做指标的存储和展示,也可以使用 Jaeger 做链路追踪的存储和展示。这使得 OpenTelemetry 既不会因动了“数据的蛋糕”,引起生态抵制,也保存了精力,专注实现兼容“所有的语言、所有的系统”的“遥测数据采集器”(OpenTelemetry Collector)。 26 | 27 | 自 2019 年发布,OpenTelemetry 便得到了社区的广泛支持。绝大部分云服务商,如 AWS、Google Cloud、Azure、阿里云等均已支持和推广 OpenTelemetry,各种第三方工具(如 Jaeger、Prometheus、Zipkin)也逐步集成 OpenTelemetry,共同构建了丰富的可观测性生态系统。 -------------------------------------------------------------------------------- /Observability/What-is-Observability.md: -------------------------------------------------------------------------------- 1 | # 9.1 什么是可观测性 2 | 3 | 什么是可观测性?观测的又是什么? 4 | 5 | Google Cloud 在介绍可观测标准项目 OpenTelemetry 时提到一个概念 —— “遥测数据”(telemetry data)[^1]。 6 | 7 | :::tip 遥测数据 8 | 9 | 遥测数据(telemetry data)是指采样和汇总有关软件系统性能和行为的数据,这些数据(接口的响应时间、请求错误率、服务资源消耗等)用于监控和了解系统的当前状态。 10 | ::: 11 | 12 | “遥测数据”看起来陌生,但你肯定无意间听过。观看火箭发射的直播时,你应该听到过类似的指令:“东风光学 USB 雷达跟踪正常,遥测信号正常” 。随着火箭升空,直播画面还会特意切换到一个看起来“高大上”仪表控制台。 13 | 14 | 实际上,软件领域的观测与上述火箭发射系统相似,都是通过全面收集系统运行数据(遥测数据),以了解内部状态。所以说,可观测性是指系统的内部状态能够通过外部输出(如日志、指标、追踪等)来进行观察和理解的能力。换句话说,系统的可观测性使得我们能够从系统的外部获取足够的信息,以便分析和解决可能存在的问题,预测系统行为,或者优化系统性能。 15 | [^1]: 参见 https://cloud.google.com/learn/what-is-opentelemetry 16 | -------------------------------------------------------------------------------- /Observability/conclusion.md: -------------------------------------------------------------------------------- 1 | # 9.5 小结 2 | 3 | 通过本章的内容,相信你已经理解了什么是可观测性?简单来说,就是通过系统的外部输出推断其内部状态的能力。 4 | 5 | 系统的外部输出称为“遥测数据”,主要包括日志、指标和追踪数据。建立良好的可观测性机制,实质上是对这些数据进行统一收集、关联和分析。这其中还有两个关键:首先,要低开销。可观测性的一大目的就是发现性能问题,因此不应对业务造成明显的性能负担。对于对延迟敏感的业务,任何微小的性能损耗都可能产生明显的影响。其次,业务透明性至关重要。观测能力通常是在运维阶段加入的,因此应以非侵入或最小侵入的方式实现,尽量避免对业务开发造成干扰。 6 | 7 | -------------------------------------------------------------------------------- /Observability/dumps.md: -------------------------------------------------------------------------------- 1 | # 9.3.5 核心转储 2 | 3 | 核心转储(Core dump)中的 “core” 代表程序的关键运行状态,“dump” 的意思是导出。 4 | 5 | 核心转储历史悠久,很早就在各类 Unix 系统中出现。在任何安装了《Linux man 手册》的 Linux 发行版中,都可以运行 man core 命令查阅相关信息。 6 | 7 | ```bash 8 | $ man core 9 | ... 10 | A small number of signals which cause abnormal termination of a process 11 | also cause a record of the process's in-core state to be written to disk 12 | for later examination by one of the available debuggers. (See 13 | sigaction(2).) 14 | ... 15 | ``` 16 | 17 | 上面的大致意思是,当程序异常终止时,Linux 系统会将程序的关键运行状态(如程序计数器、内存映像、堆栈跟踪等)导出到一个“核心文件”(core file)中。工程师通过调试器(如 gdb)打开核心文件,查看程序崩溃时的运行状态,从而帮助定位问题。 18 | 19 | :::tip 注意 20 | 复杂应用程序崩溃时,可能会生成几十 GB 大小的核心文件。默认情况下,Linux 系统会限制核心文件的大小。如果你想解除限制,可通过命令 ulimit -c unlimited,告诉操作系统不要限制核心文件的大小。 21 | ::: 22 | 23 | 值得一提的是,虽然 CNCF 发布的可观测性白皮书仅提到了 core dump。实际上,重要的 dumps 还有 Heap dump(Java 堆栈在特定时刻的快照)、Thread dump(特定时刻的 Java 线程快照)和 Memory dump(内存快照)等等。 24 | 25 | 最后,尽管 CNCF 将 dumps 纳入了可观测性体系,但仍有许多技术难题,如容器配置与操作系统全局配置的冲突、数据持久化的挑战(Pod 重启前将数 Gb 的 core 文件写入持久卷)等等,导致处理 dumps 数据还得依靠传统手段。 -------------------------------------------------------------------------------- /Observability/profiles.md: -------------------------------------------------------------------------------- 1 | # 9.3.4 性能剖析 2 | 3 | 可观测性领域的性能剖析(Profiling)的目标是分析运行中的应用,生成详细的性能数据(Profiles),帮助工程师全面了解应用的运行行为和资源使用情况,从而识别代码中的性能瓶颈。 4 | 5 | 性能数据通常以火焰图或堆栈图的形式呈现,分析这些数据是从“是什么”到“为什么”过程中的关键环节。例如,通过链路追踪识别延迟源(是什么),然后根据火焰图进一步分析,定位到具体的代码行(为什么)。2021 年,某网站发生崩溃事件,工程师通过分析火焰图发现 Lua 代码存在异常,最终定位到问题源头。[^1]。 6 | 7 | :::center 8 | ![](../assets/lua-cpu-flame-graph.webp)
9 | 图 9-16 Lua 代码的 CPU 火焰图(由于函数调用按层叠加,火焰图呈现出类似火焰的形状) 10 | ::: 11 | 12 | :::tip 火焰图分析说明 13 | 14 | - 纵轴:表示函数调用的堆栈深度(或层级)。纵向越高表示调用链越深,底部通常是程序的入口函数(如 main 函数),上层是被下层函数调用的函数。 15 | - 横轴:表示函数在特定时间段内所占用的 CPU 时间或内存空间,条形的宽度越大,表示该函数消耗的时间或资源越多。 16 | 17 | 分析火焰图的关键是观察横向条形的宽度,宽度越大,函数占用的时间越多。如果某个函数的条形图出现“平顶”现象,表示该函数的执行时间过长,可能成为性能瓶颈。 18 | ::: 19 | 20 | 性能数据有多种类型,每种类型由不同的分析器(Profiler)生成,常见的分析器包括: 21 | 22 | - **CPU 分析器**:跟踪程序中每个函数或代码块的运行时间,记录函数调用堆栈信息,生成调用图,并展示函数之间的调用关系和时间分布; 23 | - **堆分析器(Heap Profiler)**:监控程序的内存使用情况,帮助定位内存泄漏或不必要的内存分配。例如,Java 工程师通过堆分析器定位导致内存溢出的具体对象; 24 | - **GPU 分析器**:分析 GPU 的使用情况,主要用于图形密集型应用(如游戏开发),优化渲染性能; 25 | - **互斥锁分析器**:检测程序中互斥锁的竞争情况,帮助优化线程间的并发性能,减少锁争用引发的性能瓶颈; 26 | - **I/O 分析器**:评估 I/O 操作的性能,包括文件读写延迟和网络请求耗时,帮助识别数据传输瓶颈并提高效率; 27 | - **特定编程语言分析器**:例如 JVM Profiler,用于分析在 Java 虚拟机上运行的应用程序,挖掘与编程语言特性相关的性能问题。 28 | 29 | 过去,由于分析器资源消耗较高,通常仅在紧急情况下启用。随着低开销分析技术的发展,如编程语言层面的 Java Flight Recorder 和 Async Profiler 技术、操作系统层面的 systemTap 和 eBPF 技术的出现,让在生产环境进行持续性能分析(Continuous Profiling)成为可能,解决线上“疑难杂症”也变得更加容易。 30 | 31 | [^1]: 参见《2021.07.13 我们是这样崩的》https://www.bilibili.com/read/cv17521097/ 32 | 33 | -------------------------------------------------------------------------------- /Observability/signals.md: -------------------------------------------------------------------------------- 1 | # 9.3 遥测数据的分类与处理 2 | 3 | 业界将系统输出的数据总结为三种独立的类型,它们的含义与区别如下: 4 | 5 | - **指标**(metric):量化系统性能和状态的“数据点”,每个数据点包含度量对象(如接口请求数)、度量值(如 100 次/秒)和发生的时间,多个时间上连续的数据点便可以分析系统性能的趋势和变化规律。指标是发现问题的起点,例如你半夜收到一条告警:“12 点 22 分,接口请求成功率下降到 10%”,这表明系统出现了问题。接着,你挣扎起床,分析链路追踪和日志数据,找到问题的根本原因并进行修复。 6 | 7 | - **日志**(log):系统运行过程中,记录离散事件的文本数据。每条日志详细描述了事件操作对象、操作结果、操作时间等信息。例如下面的日志示例,包含了时间、日志级别(ERROR)以及事件描述。 8 | ```bash 9 | [2024-12-27 14:35:22] ERROR: Failed to connect to database. Retry attempts exceeded. 10 | ``` 11 | 日志为问题诊断提供了精准的上下文信息,与指标形成互补。当系统故障时,“指标”告诉你应用程序出现了问题,“日志”则解释了问题出现的原因。 12 | 13 | - **链路追踪**(trace):记录请求在多个服务之间的“调用链路”(Trace),以“追踪树”(Trace Tree)的形式呈现请求的“调用”(span)、耗时分布等信息。 14 | 15 | ```bash 16 | // 追踪树 17 | Trace ID: 12345 18 | └── Span ID: 1 - API Gateway (Duration: 50ms) 19 | └── Span ID: 2 - User Service (Duration: 30ms) 20 | └── Span ID: 3 - Database Service (Duration: 20ms) 21 | ``` 22 | 23 | 上述 3 类数据各自侧重不同,但并非孤立存在,它们之间有着天然的交集与互补。比如指标监控(告警)帮助发现问题,日志和链路追踪则帮助定位根本原因。这三者之间的关系如图 9-2 的韦恩图所示。 24 | 25 | :::center 26 | ![](../assets/observability.jpg)
27 | 图 9-2 指标、链路追踪、日志三者之间的关系 [图片来源](https://peter.bourgon.org/blog/2017/02/21/metrics-tracing-and-logging.html) 28 | ::: 29 | 30 | 31 | 2021 年,CNCF 发布了可观测性白皮书[^1],里面新增了性能剖析(Profiling)和核心转储(Core dump)2 种数据类型。接下来,笔者将详细介绍这 5 类遥测数据的采集、存储和分析原理。 32 | 33 | [^1]: 参见 https://github.com/cncf/tag-observability/blob/main/whitepaper.md -------------------------------------------------------------------------------- /Observability/summary.md: -------------------------------------------------------------------------------- 1 | # 第九章:系统可观测性 2 | :::tip 3 | given enough eyeballs, all bugs are shallow. 4 | 5 | 足够多的眼睛,就可让所有问题浮现。 6 | 7 | :::right 8 | —— by Linus Torvalds 9 | ::: 10 | 11 | 随着系统规模扩大、组件复杂化以及服务间依赖关系的增加,确保系统稳定性已超出绝大多数 IT 团队的能力极限。 12 | 13 | 复杂性失控问题在工业领域同样出现过。19 世纪末起,电气工程的细分领域迅速发展,尤其是 20 世纪 50 年代的航空领域,研发效率要求越来越高、运行环境越来越多样化,系统日益复杂对稳定性提出了巨大挑战。在这一背景下,匈牙利裔工程师 Rudolf Emil Kálmán 提出了“可观测性”概念,其理念的核心是“通过分析系统向外部输出的信号,判断工作状态并定位缺陷的根因”。 14 | 15 | 借鉴电气系统的观测理念,我们也可以通过系统输出各类信息,实现软件系统的可观测。2018 年,CNCF 率先将“可观测性”概念引入 IT 领域,强调它是云原生时代软件的必备能力!从生产所需到概念发声,加之 Google 在内的众多大厂一拥而上,“可观测性”逐渐取代“监控”,成为云原生领域最热门的话题之一。 16 | 17 | 本章内容安排如图 9-0 所示。 18 | :::center 19 | ![](../assets/observability.png)
20 | 图 9-0 本章内容导读 21 | ::: -------------------------------------------------------------------------------- /Observability/tracing.md: -------------------------------------------------------------------------------- 1 | # 9.3.3 分布式链路追踪 2 | 3 | Uber 是实施微服务架构的先驱,他们曾经撰写博客介绍过它们的打车系统,该系统约由 2,200 个相互依赖的微服务组成。引用资料中的配图,直观感受铺面而来的复杂性。 4 | :::center 5 | ![](../assets/uber-microservice.png)
6 | 图 9-10 Uber 使用 Jaeger 生成的追踪链路拓扑 [图片来源](https://www.uber.com/en-IN/blog/microservice-architecture/) 7 | ::: 8 | 9 | 上述微服务由不同团队使用不同编程语言开发,部署在数千台服务器上,横跨多个数据中心。这种规模使系统行为变得难以全面掌控,且故障排查路径异常复杂。因此,理解复杂系统的行为状态,并析性能问题的需求显得尤为迫切。 10 | 11 | 2010 年 4 月,Google 工程师发表了论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》[1],论文总结了他们治理分布式系统的经验,并详细介绍了 Google 内部分布式链路追踪系统 Dapper 的架构设计和实现方法。 12 | 13 | Dapper 论文的发布,让治理复杂分布式系统迎来了转机,链路追踪技术开始在业内备受推崇! 14 | 15 | ## 1. 链路追踪的基本原理 16 | 17 | 如今的链路追踪系统大多以 Dapper 为原型设计,因为它们也统一继承了 Dapper 的核心概念: 18 | 19 | - **追踪(trace)**:Trace 表示一次完整的分布式请求生命周期,它是一个全局上下文,包含了整个调用链所有经过的服务节点和调用路径。例如,用户发起一个请求,从前端服务到后端数据库的多次跨服务调用构成一个 Trace。 20 | - **跨度(Span)**:Span 是 Trace 中的一个基本单元,表示一次具体的操作或调用。一个 Trace 由多个 Span 组成,按时间和因果关系连接在一起。Span 内有描述操作的名称 span name、记录操作的开始时间和持续时间、Trace ID、当前 Span ID、父 Span ID(构建调用层级关系)等信息。 21 | 22 | 总结链路追踪系统的基本原理是,为每个操作或调用记录一个跨度,一个请求内的所有跨度共享一个 trace id。通过 trace id,便可重建分布式系统服务间调用的因果关系。换言之,链路追踪(Trace)是由若干具有顺序、层级关系的跨度组成一棵追踪树(Trace Tree),如图 9-1 所示。 23 | 24 | :::center 25 | ![](../assets/Dapper-trace-span.png)
26 | 图 9-11 由不同跨度组成的追踪树 27 | ::: 28 | 29 | 从链路追踪系统的实现来看,核心是在服务调用过程中收集 trace 和 span 信息,并汇总生成追踪树结构。接下来,笔者将从数据采集、数据展示(分析)两个方面展开,解析主流链路追踪系统的设计原理。 30 | 31 | ## 2. 数据采集 32 | 33 | 目前,追踪系统的主流实现有三种,具体如下: 34 | 35 | - **基于日志的追踪**(Log-Based Tracing):直接将 Trace、Span 等信息输出到应用日志中,然后采集所有节点的日志汇聚到一起,再根据全局日志重建完整的调用链拓扑。这种方式的优点是没有网络开销、应用侵入性小、性能影响低;但其缺点是,业务调用与日志归集不是同时完成的,有可能业务调用已经结束,但日志归集不及时,导致追踪失真。 36 | 37 | 根据图 9-13,总结 Dapper 基于日志实现的追踪如下: 38 | 39 | 1. 将 Span 数据写入本地日志文件。 40 | 2. Dapper 守护进程(Dapper Daemon)和采集器(Dapper Collectors)从主机节点读取日志。 41 | 3. 将日志写入 Bigtable 仓库,每行代表一个 Trace,每列代表一个 Span。 42 | :::center 43 | ![](../assets/dapper-log.png)
44 | 图 9-13 基于日志实现的追踪 45 | ::: 46 | 47 | - **基于服务的追踪**(Service-Based Tracing):通过某些手段给目标应用注入追踪探针(Probe),然后通过探针收集服务调用信息并发送给链路追踪系统。探针通常被视为一个嵌入目标服务的小型微服务系统,具备服务注册、心跳检测等功能,并使用专用的协议将监控到的调用信息通过独立的 HTTP 或 RPC 请求发送给追踪系统。 48 | 49 | 以 SkyWalking 的 Java 追踪探针为例,它实现的原理是将需要注入的类文件(追踪逻辑代码)转换成字节码,然后通过拦截器注入到正在运行的应用程序中。比起基于日志实现的追踪,基于服务的追踪在资源消耗和侵入性(但对业务工程师基本无感知)上有所增加,但其精确性和稳定性更高。现在,基于服务的追踪是目前最为常见的实现方式,被 Zipkin、Pinpoint、SkyWalking 等主流链路追踪系统广泛采用。 50 | 51 | - **基于边车代理的追踪**(Sidecar-Based Tracing):这是服务网格中的专属方案,基于边车代理的模式无需修改业务代码,也没有额外的开销,是最理想的分布式追踪模型。总结它的特点如下: 52 | - 对应用完全透明:有自己独立数据通道,追踪数据通过控制平面上报,不会有任何依赖或干扰; 53 | - 与编程语言无关:无论应用采用什么编程语言,只要它通过网络(如 HTTP 或 gRPC)访问服务,就可以被追踪到。 54 | 55 | 目前,市场占有率最高的边车代理 Envoy 就提供了链路追踪数据采集功能,但 Envoy 没有自己的界面端和存储端,需要配合专门的 UI 与存储系统来使用。不过,Zipkin、SkyWalking、Jaeger 和 LightStep Tracing 等等系统都能够接收来自 Envoy 的链路追踪数据,充当其界面和存储端。 56 | 57 | ## 3. 数据展示 58 | 59 | 追踪数据通常以两种形式呈现:调用链路图和调用拓扑图,具体如下: 60 | 61 | - **调用链路图**:主要突出调用的深度、每一次调用的延迟。调用链路图通常用来定位故障。例如,当某次请求失败时,通过调用链路图可以追踪调用经过的各个环节,定位是哪一层调用失败。 62 | :::center 63 | ![](../assets/skywalking-ui.jpeg)
64 | 图 9-14 Skywalking 的调用链路图 65 | ::: 66 | 67 | - **调用拓扑图**:主要突出系统内各个子服务的全局关系、调用依赖关系。作为全局视角图,它帮助工程师理解全局系统、并识别瓶颈。例如,若某服务压力过高,调用拓扑图的拓展区(右侧)会显示该服务详细情况(延迟、load、QPS 等)。 68 | :::center 69 | ![](../assets/Pinpoint.png)
70 | 图 9-15 Pinpoint 的调用拓扑图 71 | ::: 72 | 73 | 74 | [^1]: 参见《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》https://research.google/pubs/dapper-a-large-scale-distributed-systems-tracing-infrastructure/ 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 深入高可用系统原理与设计 2 | 3 | 4 | ## 这是什么? 5 | 6 | 这是一本关于架构设计的开源书籍,已经完稿。如果阅读文章发现问题,欢迎在 github 给我提交 PR 或者 issue。 7 | 8 | 以下为我的公众号,欢迎与我讨论技术。 9 |
10 | 11 |
12 | 13 | 14 | ## ⭐️ 为什么要写这个? 15 | 16 | 这几年互联网基础设施技术出现了很大的更新迭代,比如容器技术(Container、Kubernetes)、服务网格(ServiceMesh)、无服务器(Serverless)、高性能网络(DPDK、XDP、RDMA)等等,我对这些技术有一些浅薄的见解和实践,但远没达到深刻理解的境界,我尝试使用 `费曼学习法` 把这些东西体系化地总结输出。一方面加深自我的学习认知,另一方面也希望这些输出对其他人有所帮助。 17 | 18 | 整个系列的内容主要集中在 `网络`、`集群以及服务治理`、`FinOps` 这三个主题,这也代表着基础架构的几个核心:稳定、效率、成本。 19 | 20 | 我会持续更新这个仓库的内容,如果想要关注可以点 `star` 。 21 | 22 | 23 | :::center 24 | 25 | [![Star History Chart](https://api.star-history.com/svg?repos=isno/thebytebook&type=Date)](https://star-history.com/#isno/thebytebook&Date) 26 |

https://github.com/isno/theByteBook

27 | ::: 28 | 29 | 30 | 31 | ## 如何阅读 32 | 33 | - **在线阅读**:本文档在线阅读地址为:[https://www.thebyte.com.cn](https://www.thebyte.com.cn) 【为防止缓存,阅读前请先强制刷新】 34 | 35 | - **离线阅读**: 36 | 37 | - 部署离线站点:文档基于 [VuePress 2](https://v2.vuepress.vuejs.org/zh/) 构建,如你希望在本地搭建文档站点,请使用如下命令: 38 | 39 | ```bash 40 | # 克隆获取源码 41 | $ git clone https://github.com/isno/theByteBook.git && cd theByteBook 42 | 43 | # 安装工程依赖 44 | $ npm install 45 | 46 | # 运行网站,地址默认为 http://localhost:8080 47 | $ npm run dev 48 | ``` 49 | 50 | 51 | ## ©️ 转载 52 | 53 | 知识共享许可协议
作品isno 创作,采用知识共享署名 4.0 国际许可协议进行许可。 54 | 55 | 56 | -------------------------------------------------------------------------------- /ServiceMesh/What-is-ServiceMesh.md: -------------------------------------------------------------------------------- 1 | # 8.1 什么是服务网格 2 | 3 | 2016 年,William Morgan 离开 Twiiter,组建了一个小型技术公司 Buoyant。不久之后,他在 Github 上发布了创业项目 Linkerd,业界第一款服务网格诞生! 4 | 5 | 那么,服务网格(Service Mesh)到底是什么?服务网格的概念最早由 William Morgan 在其博文《What’s a service mesh? And why do I need one?》中提出。作为服务网格的创造者,引用他的定义无疑是最官方和权威的。 6 | 7 | :::tip 服务网格的定义 8 | 9 | 服务网格是一个处理服务通讯的专门的基础设施层。它的职责是在由云原生应用组成服务的复杂拓扑结构下进行可靠的请求传送。在实践中,它是一组和应用服务部署在一起的轻量级的网络代理,对应用服务透明。 10 | 11 | :::right 12 | —— What’s a service mesh?And why do I need one?,William Morgan 13 | ::: 14 | 15 | 通过下述,感受服务网格从无到有、被社区接受、巨头入局、众人皆捧的发展历程: 16 | 17 | - 2016 年 9 月:在 SF MicroServices 大会上,术语“服务网格”首次在公开场合提出,服务网格的概念从 Buoyant 公司内部走向社区。 18 | - 2017 年 1 月:Linkerd 加入 CNCF,被归类到 CNCF 新设立的“Service Mesh”分类,这表明**服务网格的设计理念得到了主流社区认可**。 19 | - 2017 年 4 月:Linkerd 发布 1.0 版本,服务网格实现了关键里程碑 —— 被客户接受,在生产环境中大规模应用。**服务网格从“虚”转“实”**。 20 | - 2017 年 5 月:Google、IBM 和 Lyft 联合发布 Istio 0.1 版本,以 Istio 为代表的**第二代服务网格登场**。 21 | - 2018 年 7 月:CNCF 发布了最新的云原生定义,将服务网格与微服务、容器、不可变基础设施等技术并列,**服务网格的地位空前提升**。 22 | - 2022 年 7 月,Cilium 发布了“无边车模式”的服务网格,2 个月之后,Isito 发布了全新的数据平面模式 “Ambient Mesh”,服务网格的形态开始多元化。 -------------------------------------------------------------------------------- /ServiceMesh/conclusion.md: -------------------------------------------------------------------------------- 1 | # 8.7 小结 2 | 3 | 在本章第二节,我们回顾了服务间通信的演变,并阐述了服务网格出现的背景。相信你已经理解,服务网格之所以备受推崇,关键不在于它提供了多少功能(这些功能传统 SDK 框架也有),而在于其将非业务逻辑从应用程序中剥离的设计思想。 4 | 5 | 从最初 TCP/IP 协议的出现,我们看到网络传输相关的逻辑从应用层剥离,下沉至操作系统,成为操作系统的网络层。分布式系统的崛起,又带来了特有的分布式通信语义(服务发现、负载均衡、限流、熔断、加密...)。为了降低治理分布式通信的心智负担,面向微服务的 SDK 框架出现了,但这类框架与业务逻辑耦合在一起,带来门槛高、无法跨语言、升级困难三个固有问题。 6 | 7 | 而服务网格的出现为分布式通信治理带来了全新的解决思路:通信治理逻辑从应用程序内部剥离至边车代理,下沉至 Kubernetes、下沉至各个云平台。沿着上述“分离/下沉”的设计理念,服务网格的形态不再局限于边车代理,开始多元化,陆续出现了 Proxyless、Sidecarless、Ambient Mesh 等多种模式。 8 | 9 | 无论通信治理逻辑下沉至哪里、服务网格以何种形态存在,核心都是把非业务逻辑从应用程序中剥离,让业务开发更简单。这正是业内常提到的“以应用为中心”设计理念的体现。 -------------------------------------------------------------------------------- /ServiceMesh/control-plane.md: -------------------------------------------------------------------------------- 1 | # 8.4 控制平面的设计 2 | 3 | 本节,笔者继续以 Istio 的架构为例,探讨控制平面的设计。 4 | 5 | Istio 自发布首个版本以来,有着一套“堪称优雅”的架构设计,它的架构由数据面和控制面两部分组成,前者通过代理组件 Envoy 负责流量处理;后者根据功能职责不同,由多个微服务(如 Pilot、Galley、Citadel、Mixer)组成。 6 | 7 | Istio 控制面组件的拆分设计看似充分体现了微服务架构的优点,如职责分离、独立部署和伸缩能力,但在实际场景中,并未实现预期的效果。 8 | 9 | :::tip Isito 控制平面的问题 10 | 当业务调用出现异常时,由于接入了服务网格,工程师首先需要排查控制面内各个组件的健康状态:首先检查 Pilot 是否正常工作,配置是否正确下发至 Sidecar;然后检查 Galley 是否正常同步服务实例信息;同时,还需要确认 Sidecar 是否成功注入。 11 | 12 | 一方面,控制面组件的数量越多,排查问题时需要检查的故障点也就越多。另一方面,过多的组件设计也会增加部署、维护的复杂性。 13 | ::: 14 | 15 | 服务网格被誉为下一代微服务架构,用来解决微服务间的运维管理问题。但在服务网格的设计过程中,又引入了一套新的微服务架构,这岂不是**用一种微服务架构设计的系统来解决另一种微服务架构的治理问题**。那么,谁来解决 Istio 系统本身的微服务架构问题呢? 16 | 17 | 在 Istio 推出三年后,即 Istio 1.5 版本,开发团队对控制面架构进行了重大调整,摒弃了之前的设计,转而采用了“复古”的单体架构。组件 istiod 整合了 Pilot、Citadel 和 Galley 的功能,以单个二进制文件的形式部署,承担起之前组件的所有职责: 18 | 19 | - **服务发现与配置分发**:从 Kubernetes 等平台获取服务信息,将路由规则和策略转换为 xDS 协议下发至 Envoy 代理; 20 | - **流量管理**:管理流量路由规则,包括负载均衡、分流、镜像、熔断、超时与重试等功能; 21 | - **安全管理**:生成、分发和轮换服务间的身份认证证书,确保双向 TLS 加密通信、基于角色的访问控制(RBAC)和细粒度的授权策略,限制服务间的访问权限; 22 | - **可观测性支持**:协助 Envoy 采集系统输出的遥测数据(日志、指标、追踪),并将数据发送到外部监控系统(如 Prometheus、Jaeger、OpenTelemetry 等); 23 | - **配置验证与管理**:验证用户提交的网格配置,并将其分发到数据平面,确保一致性和正确性; 24 | 25 | :::center 26 | ![](../assets/service-mesh-arc.svg)
27 | 图 8-12 Istio 架构及各个组件 28 | ::: 29 | 30 | Istio 1.5 版本的架构变化,实际上是将原有的多进程设计转换为单进程模式,以最小的成本实现最高的运维收益。 31 | 32 | - 运维配置变得更加简单,用户只需要部署或升级一个单独的服务组件。 33 | - 更加容易排查错误,因为不需要再横跨多个组件去排查各种错误。 34 | - 更加利于做灰度发布,因为是单一组件,可以非常灵活切换至不同的控制面。 35 | - 避免了组件间的网络开销,因为组件内部可直接共享缓存、配置等,也会降低资源开销。 36 | 37 | 通过以上分析,你是否对 Istio 控制平面的拆分架构有了新的理解?看似优雅的架构设计,落地过程中往往给工程师带来意料之外的困难。正如一句老话,没有完美的架构,只有最合适的架构! -------------------------------------------------------------------------------- /ServiceMesh/overview.md: -------------------------------------------------------------------------------- 1 | # 8.5 服务网格的产品与生态 2 | 3 | 2016 年,Buoyant 公司发布了 Linkerd。Matt Klein 离开 Twitter 并加入 Lyft,启动了 Envoy 项目。第一代服务网格稳步发展时,世界另一角落,Google 和 IBM 两个巨头联手,与 Lyft 一起启动了第二代服务网格 Istio。 4 | 5 | - 以 Linkerd 为代表的第一代服务网格,通过边车代理控制微服务间的流量; 6 | - 以 Istio 为代表的第二代服务网格,新增控制平面,管理了所有边车代理。于是,Istio 对微服务系统掌握了前所未有的控制力。 7 | 8 | 依托行业巨头的背书与创新的控制平面设计理念,让 Istio 得到极大关注和发展,并迅速成为业界落地服务网格的主流选择。 9 | 10 | ## 8.5.1 Linkerd2 出击 11 | 12 | 在 Istio 受到广泛追捧的同时,服务网格概念的创造者 William Morgan 自然不甘心出局。William Morgan 瞄准 Istio 的缺陷(过于复杂)、借鉴 Istio 的设计理念(新增控制平面),开始重新设计他们的服务网格产品。 13 | 14 | Buoyant 公司的第二代服务网格使用 Rust 构建数据平面 linkerd2-proxy ,使用 Go 开发了控制平面 Conduit,主打轻量化,目标是世界上最轻、最简单、最安全的 Kubernetes 专用服务网格。该产品最初以 Conduit 命名,Conduit 加入 CNCF 后不久,宣布与原有的 Linkerd 项目合并,被重新命名为 Linkerd 2[^1]。 15 | 16 | Linkerd2 的架构如图 8-13 所示,增加了控制平面,但整体相对简单: 17 | - 控制层面组件只有 destination(类似 Istio 中的 Pilot 组件)、identity(类似 Istio 中的 Citadel)和 proxy injector(代理注入器); 18 | - 数据平面中 linkerd-init 设置 iptables 规则拦截 Pod 中的 TCP 连接,linkerd-proxy 实现对所有的流量管控(负载均衡、熔断..)。 19 | 20 | :::center 21 | ![](../assets/linkerd-control-plane.png)
22 | 图 8-13 Linkerd2 架构及各个组件 23 | ::: 24 | 25 | ## 8.5.2 其他参与者 26 | 27 | 能明显影响微服务格局的新兴领域,除了头部的 Linkerd2、Istio 玩家外,又怎少得了传统的 Proxy 玩家。 28 | 29 | 先是远古玩家 Nginx 祭出自己新一代的产品 Nginx ServiceMesh,理念是简化版的服务网格。接着,F5 Networks 公司顺势推出商业化产品 Aspen Mesh,定位企业级服务网格。随后,API 网关独角兽 Kong 推出了 Kuma,主打通用型服务网格。有意思的是,Kong 选择了 Envoy 作为数据平面,而非它自己内核 OpenResty。 30 | 31 | 与 William Morgan 死磕 Istio 策略不同,绝大部分在 Proxy 领域根基深厚玩家,从一开始就没有想过做一套完整服务网格,而是选择实现 xDS 协议或基于 Istio 扩展,作为 Istio 的数据平面出现。 32 | 33 | 至 2023 年,经过 8 年的发展,服务网格的产品生态如图 8-14 所示。虽然有众多的选手,但就社区活跃度而言,Istio 和 Linkerd 还是牢牢占据了头部地位。 34 | 35 | :::center 36 | ![](../assets/service-mesh-overview.png)
37 | 图 8-14 CNCF 下 服务网格领域生态 38 | ::: 39 | 40 | ## 8.5.3 Istio 与 Linkerd2 性能对比 41 | 42 | 2019 年,云原生技术公司 Kinvolk 发布了一份 Linkerd2 与 Istio 的性能对比报告。报告显示,Linkerd 在延迟和资源消耗方面明显优于 Istio[^2]。 43 | 44 | 两年之后,Linkerd 与 Istio 都发布了多个更成熟的版本,两者的性能表现如何?笔者引用 William Morgan 文章《Benchmarking Linkerd and Istio》[^3]中的数据,向读者介绍 Linkerd v2.11.1、Istio v1.12.0 两个项目之间延迟与资源消耗的表现。 45 | 46 | 首先是网络延迟的对比。如图 8-15 所示,在中位数(P50)延迟上,Linkerd 在 6ms 的基准延迟基础上增加了 6ms,而 Istio 增加了 15ms。值得注意的是,从 P90 开始,两者的差异明显扩大。在最极端的 Max 数据上,Linkerd 在 25ms 的基准延迟上增加了 25ms,而 Istio 则增加了 5 倍,达到 253ms 的额外延迟。 47 | 48 | :::center 49 | ![](../assets/latency-200rps.png)
50 | 图 8-15 Linkerd 与 Istio 的延迟对比 51 | ::: 52 | 53 | 接下来是资源消耗的对比。如图 8-16 所示,Linkerd 代理的最大内存消耗为 26MB,而 Istio 的 Envoy 代理则为 156.2MB,是 Linkerd 的 6 倍。此外,Linkerd 的最大代理 CPU 时间为 36ms,而 Istio 的代理 CPU 时间为 67ms,比前者多出 85%。 54 | 55 | :::center 56 | ![](../assets/linkerd-resource.png)
57 | 图 8-16 Istio 与 Linkerd 资源消耗对比 58 | ::: 59 | 60 | Linkerd 和 Istio 在性能和资源成本上的显著差异,要归因于 Linkerd2-proxy,该代理为 Linkerd 的整个数据平面提供动力。因此。上述基准测试很大程度上反映了 Linkerd2-proxy 与 Envoy 之间的性能和资源消耗对比。 61 | 62 | 虽然 Linkerd2-proxy 性能卓越,但使用的编程语言 Rust 相对小众,开源社区的贡献者数量稀少。截至 2024 年 6 月,Linkerd2-proxy 的贡献者仅有 53 人,而 Envoy 的贡献者则高达 1,104 人。此外,Linkerd2-proxy 不支持服务网格领域的 xDS 控制协议,其未来发展将高度依赖于 Linkerd 本身的进展。 63 | 64 | [^1]: 参见 https://github.com/linkerd/linkerd2 65 | [^2]: 这项测试工作还诞生服务网格基准测试工具 service-mesh-benchmark,以便任何人都可以复核结果。https://github.com/kinvolk/service-mesh-benchmark,以便任何人都可以复核结果。 66 | [^3]: 基于 Kinvolk 模仿现实场景,延迟数据从客户端的角度测量,而不是内部的代理时间。详见 https://linkerd.io/2021/05/27/linkerd-vs-istio-benchmarks/ -------------------------------------------------------------------------------- /ServiceMesh/summary.md: -------------------------------------------------------------------------------- 1 | # 第八章:服务网格技术 2 | 3 | :::tip 4 | 计算机科学中的所有问题都可以通过增加一个间接层来解决。如果不够,那就再加一层。 5 | 6 | :::right 7 | —— by David Wheeler[^1] 8 | ::: 9 | 10 | Kubernetes 的崛起意味着虚拟化的基础设施,开始解决分布式系统软件层面的问题。Kubernetes 最早提供的应用副本管理、服务发现和分布式协同能力,实质上将构建分布式应用的核心需求,利用 Replication Controller、kube-proxy 和 etcd “下沉”到基础设施中。然而,Kubernetes 解决问题的粒度通常局限于容器层面,容器以下的服务间通信治理(如服务发现、负载均衡、限流、熔断和加密等问题)仍需业务工程师手动处理。 11 | 12 | 在传统分布式系统中,解决上述问题通常依赖于微服务治理框架(如 Spring Cloud 或 Apache Dubbo),这类框架将业务逻辑和技术方案紧密耦合。而在云原生时代,解决这些问题时,在 Pod 内注入代理型边车(Sidecar Proxy) ,业务对此完全无感知,显然是最“Kubernetes Native”的方式。边车代理将非业务逻辑从应用程序中剥离,服务间的通信治理由此开启了全新的进化,并最终演化出一层全新基础设施层 —— 服务网格(ServiceMesh)。 13 | 14 | 本章,我们将回顾服务间通信的演化历程,从中理解服务网格出现的背景、以及它所解决的问题。然后解读服务网格数据面和控制面的分离设计,了解服务网格领域的产品生态(主要介绍 Linkerd 和 Istio)。最后,我们直面服务网格的缺陷(网络延迟和资源占用问题),讨论如何解决,并展望服务网格的未来。本章内容组织如图 8-0 所示。 15 | 16 | 本章内容安排如图 8-0 所示。 17 | :::center 18 | ![](../assets/ServiceMesh-summary.png)
19 | 图 8-0 本章内容导读 20 | ::: 21 | 22 | [^1]: David Wheeler 计算机科学的先驱之一,子程序(subroutine)发明者,在数据压缩、安全性和加密领域有杰出的贡献。 -------------------------------------------------------------------------------- /about.md: -------------------------------------------------------------------------------- 1 | # 作者 2 | 3 | 软件工程师,上海 4 | 5 | 著作: 6 | - 《深入高可用系统原理与设计》已完稿 7 | - 《创造智慧 - AI 系统的原理与实现》编写中 8 | 9 | ## 兴趣 10 | 11 | - Networking 12 | - Cloud、AI Infra、Container、Serverless... 13 | 14 | ## 公众号 15 | 16 | 发一些我的闲唠叨,闲得无聊可以关注。 17 |
18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /application-centric/Controller.md: -------------------------------------------------------------------------------- 1 | # 10.2 声明式管理的本质 2 | 3 | Kubernetes 与其他基础设施的最大不同是,它是基于声明式管理的系统。很多人容易将“声明式风格的 API”和“声明式管理”混为一谈,这实际上是对声明式管理缺乏正确认识。想要真正理解声明式管理,首先需要弄清楚 Kubernetes 的控制器模式。 4 | 5 | ## 10.1.1 控制器模式 6 | 7 | 分析 Kubernetes 的工作原理可以发现,无论是 kube-scheduler 调度 Pod,还是 Deployment 管理 Pod 部署,亦或是 HPA 执行弹性伸缩,它们的整体设计都遵循“控制器模式”。 8 | 9 | 例如,用户定义一个 Deployment 资源,指定运行的容器镜像和副本数量。Deployment 控制器根据这些定义,在 Kubernetes 节点上创建相应的 Pod,并持续监控它们的运行状态。如果某个副本 Pod 异常退出,控制器会自动创建新的 Pod,确保系统的“实际状态”始终与用户定义的“预期状态”(如 8 个副本)保持一致。 10 | 11 | :::center 12 | ![](../assets/deployment-controller.png)
13 | 图 10-1 Kubernetes 的控制器模式 14 | ::: 15 | 16 | 总结控制器模式的核心是,用户通过 YAML 文件定义资源的“预期状态”,然后“控制器”监视资源的实际状态。当实际状态与预期状态不一致时,控制器会执行相应操作,确保两者一致。在 Kubernetes 中,这个过程被称为“调谐”(Reconcile),即不断执行“检查 -> 差异分析 -> 执行”的循环。 17 | 18 | 调谐过程的存在,确保了系统状态始终向预期终态收敛。这个逻辑很容易理解:系统在第一次提交描述时达到了期望状态,但这并不意味着一个小时后的情况也是如此。 19 | 20 | 所以说,声明式管理的核心在于“调谐”,而声明式风格的 API 仅仅是一种对外的交互方式。 21 | 22 | ## 10.1.2 基础设施即数据思想 23 | 24 | “控制器模式”体系的理论基础,是一种叫做 IaD(Infrastructure as Data,基础设施即数据)的思想。 25 | 26 | IaD 思想主张,基础设施的管理应该脱离特定的编程语言或配置方式,而采用纯粹、格式化、系统可读的数据,描述用户期望的系统状态。这种思想的优势在于,对基础设施的所有操作本质上等同于对数据的“增、删、改、查”。更重要的是,这些操作的实现方式与基础设施本身无关,不依赖于特定编程语言、协议或 SDK,只要生成符合格式要求的“数据”,便可以“随心所欲”地采用任何你偏好的方式管理基础设施。 27 | 28 | IaD 思想在 Kubernetes 上的体现,就是执行任何操作,只需要提交一个 YAML 文件,然后对 YAML 文件增、删、查、改即可,而不是必须使用 Kubernetes SDK 或者 Restful API。这个 YAML 文件其实就对应了 IaD 中的 Data。从这个角度来看,Kubernetes 暴露出来的各种 API 对象,本质是一张张预先定义好 Schema 的“表”(table)(见表 10-1 )。唯一跟传统数据库不太一样的是,Kubernetes 并不以持久化这些数据为目标,而是监控数据变化驱动“控制器”执行相应操作。 29 | 30 | :::center 31 | 表 10-1 Kubernetes 是个“数据库” 32 | ::: 33 | 34 | |关系型数据库|Kubernetes (as a database)|说明| 35 | |:--|:--|:--| 36 | |DATABASE|cluster|一套 K8s 集群就是一个 database | 37 | |TABLE| Kind |每种资源类型对应一个表| 38 | |COLUMN|property|表里面的列,有 string、boolean 等多种类型| 39 | |rows|resources|表中的一个具体记录| 40 | 41 | 本质上,Kubernetes v1.7 版本引入的 CRD(自定义资源定义)功能,其实是赋予用户管理自定义“数据”、将特定业务需求抽象为 Kubernetes 原生对象的能力。 42 | 43 | 例如,可以通过 CRD 定义持续交付领域中的 Task(任务)和 Pipeline(流水线)。这意味着,用户完全可以在 Kubernetes 的基础上,利用其内置能力扩展出一套全新的 CI/CD 系统。 44 | ```yaml 45 | apiVersion: tekton.dev/v1beta1 46 | kind: Task 47 | metadata: 48 | name: example-task 49 | spec: 50 | steps: 51 | - name: echo-hello 52 | image: alpine:3.14 53 | script: | 54 | #!/bin/sh 55 | echo "Hello, Tekton!" 56 | ``` 57 | 58 | 借助 CRD,工程师可以突破 Kubernetes 内置资源的限制,根据需求创建自定义资源类型,如数据库、CI/CD 流程、消息队列或数字证书等。配合自定义控制器,特定的业务逻辑和基础设施能力可以无缝集成到 Kubernetes 中。 59 | 60 | 最终,云原生生态圈那些让人兴奋的技术,通过插件、接口、容器设计模式、Mesh 形式,以“声明式管理”为基础下沉至 Kubernetes 中,并通过声明式 API 暴露出来。虽然 Kubernetes 的复杂度不断增加,但声明式 API 的优势在于,它能确保在基础设施复杂度指数级增长的同时,用户交互界面的复杂度仅以线性方式增长。否则的话,Kubernetes 早就变成一个既难学又难用的系统了。 61 | 62 | 63 | -------------------------------------------------------------------------------- /application-centric/Helm.md: -------------------------------------------------------------------------------- 1 | # 10.3.2 Helm 与 Chart 2 | 3 | 相信读者朋友们知道 Linux 的包管理工具和封装格式,如 Debian 系的 apt-get 和 dpkg,RHEL 系的 yum 和 rpm。在 Linux 系统中,有了包管理工具,我们只要知道应用名称,就能从仓库中下载、安装、升级或回滚。而且,包管理工具掌握应用的依赖和版本信息,应用依赖的第三方库,在安装时都会一并处理好。 4 | 5 | 2015 年,Deis(后被 Microsoft 收购)创建了 Helm,它借鉴了各大 Linux 发行版的应用管理方式,引入了与 Linux 包管理对应的 Chart 格式和 Repository 仓库概念。对于用户而言,使用 Helm 无需手动编写部署文件、无需了解 Kubernetes 的 YAML 语法,只需一行命令,即可在 Kubernetes 集群内安装所需应用。 6 | 7 | :::center 8 | ![](../assets/helm.webp)
9 | 图 10-2 Helm 的工作原理 10 | ::: 11 | 12 | Chart 是一个包含描述 Kubernetes 相关资源的文件集合。以官方仓库中 WordPress 应用为例,它的 Chart 目录结构是这样的。 13 | 14 | ```bash 15 | WordPress 16 | |—— charts // 存放依赖的chart 17 | ├── templates // 存放应用一系列 Kubernetes 资源的 YAML 模板,通过渲染变量得到部署文件 18 | │ ├── NOTES.txt // 为用户提供一个关于 chart 部署后使用说明的文件 19 | | |—— _helpers.tpl // 存放能够复用的模板 20 | │ ├── deployment.yaml 21 | │ ├── externaldb-secrets.yaml 22 | │ └── ingress.yaml 23 | │ └── .... 24 | └── Chart.yaml // chart 的基本信息(名称、版本、许可证、自述、说明、图标,等等) 25 | └── requirements.yaml // 应用的依赖关系,依赖项指向的是另一个应用的坐标(名称、版本、Repository 地址) 26 | └── values.yaml // 存放全局变量,templates 目录中模板文件中用到变量的值 27 | ``` 28 | 29 | 以模版目录中的 deployment.yaml 为例,它的内容如下。 30 | 31 | ```yaml 32 | apiVersion: apps/v1 33 | kind: Deployment 34 | metadata: 35 | name: {{ .Release.Name }}-nginx 36 | spec: 37 | replicas: {{ .Values.replicaCount }} 38 | template: 39 | spec: 40 | containers: 41 | - name: nginx 42 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 43 | ports: 44 | - containerPort: 80 45 | ``` 46 | 部署应用时,Helm 会先将管理员指定的值覆盖 values.yaml 中的默认值,然后通过字符串替换将这些值传递给 templates 目录中的资源模板,最终渲染为 Kubernetes 资源文件,在 Kubernetes 集群中以 Release 的形式管理。 47 | 48 | Release 是 Helm Chart 的运行实例,它将多个 Kubernetes 资源抽象为一个整体,用户无需单独操作每个资源,而是通过 Helm 提供的命令(如 helm install、helm upgrade、helm rollback 等)进行统一管理。 49 | 50 | 51 | Helm 提供了应用生命周期、版本、依赖项的管理能力,还支持与 CI/CD 流程的集成,强大的功能使它在业内备受瞩目,业内流行的应用纷纷提供 Helm Chart 格式的版本。2020 年,CNCF 牵头开发了 Artifact Hub,该项目已经成为全球规模最大的 Helm 仓库,用户可以在这里找到数以千计的 Helm Charts,一键部署各种应用(如数据库、消息队列、监控工具、CI/CD 系统、日志处理工具)。 52 | 53 | 不过,需要明确的是,Helm 本质是简化 Kubernetes 应用安装与配置的工具。对于“有状态应用”(Stateful Application)来说,Helm 无法进行精细的生命周期管理。例如,它无法处理数据备份、扩缩容、分区重平衡、动态扩展等操作,这些都是在管理复杂有状态应用时所必须考虑的细节! 54 | 55 | 如何对复杂有状态应用提供全生命周期的管理,是接下将要介绍的 Operator 的课题。 56 | 57 | 58 | -------------------------------------------------------------------------------- /application-centric/Kustomize.md: -------------------------------------------------------------------------------- 1 | # 10.3.1 Kustomize 2 | 3 | Kubernetes 官方对应用的定义是一组具有相同目标资源合集。这种设定下,只要应用规模稍大,尤其是不同环境(如开发和生产环境)之间的差异较小时,资源配置文件就开始泛滥。尤其是当不同环境(如开发和生产环境)之间的差异较小时,你就会发现通过 kubectl 管理应用十分“蛋疼”。 4 | 5 | Kubernetes 对此的观点是,如果逐一配置和部署资源文件过于繁琐,那就将应用中的稳定信息与可变信息分离,并自动生成一个多合一(All-in-One)的配置包。完成这一任务的工具名为 Kustomize。 6 | 7 | Kustomize 可以看作是 YAML 模板引擎的变体,由它组织的应用结构有两个部分:base 和 overlays。base 目录存放原始的 Kubernetes YAML 模板文件,overlays 目录用于管理不同环境的差异。每个目录下都有一个 kustomization.yaml 配置文件,描述如何组合和修改 Kubernetes 资源。 8 | 9 | ```bash 10 | . 11 | ├── base/ 12 | │ ├── deployment.yaml 13 | │ ├── service.yaml 14 | │ └── kustomization.yaml 15 | ├── overlays/ 16 | │ ├── dev/ 17 | │ │ ├── kustomization.yaml 18 | │ │ └── patch-deployment.yaml 19 | │ ├── staging/ 20 | │ │ ├── kustomization.yaml 21 | │ │ └── patch-deployment.yaml 22 | │ └── prod/ 23 | │ ├── kustomization.yaml 24 | │ └── patch-deployment.yaml 25 | ``` 26 | 只要为每个环境创建对应的 kustomization.yaml 文件,使用 kubectl kustomize 命令,可以将多个资源文件(如 Deployments、Services、ConfigMaps)合并为一个最终的 YAML 配置包。这样,使用 kubectl apply -k 命令,就能一次性部署所有相关资源。 27 | 28 | ``` 29 | // 合并后的配置文件 all-in-one.yaml 30 | --- 31 | apiVersion: v1 32 | kind: Namespace 33 | metadata: 34 | name: my-namespace 35 | --- 36 | apiVersion: v1 37 | kind: ConfigMap 38 | metadata: 39 | name: my-app-config 40 | namespace: my-namespace 41 | data: 42 | config.yaml: | 43 | ... 44 | --- 45 | apiVersion: v1 46 | kind: Secret 47 | metadata: 48 | name: my-app-secret 49 | namespace: my-namespace 50 | data: 51 | ... 52 | --- 53 | apiVersion: apps/v1 54 | kind: Deployment 55 | metadata: 56 | name: my-app 57 | namespace: my-namespace 58 | spec: 59 | replicas: 3 60 | template: 61 | spec: 62 | containers: 63 | - name: my-app-container 64 | image: my-app-image:v1.2.3 65 | ... 66 | --- 67 | apiVersion: v1 68 | kind: Service 69 | metadata: 70 | name: my-app-service 71 | namespace: my-namespace 72 | spec: 73 | ports: 74 | - ... 75 | selector: 76 | ... 77 | --- 78 | apiVersion: networking.k8s.io/v1 79 | kind: Ingress 80 | metadata: 81 | name: my-app-ingress 82 | namespace: my-namespace 83 | spec: 84 | rules: 85 | - host: my-app.example.com 86 | ... 87 | ``` 88 | 不难看出,kustomize 使用 Base、Overlay 生成最终配置文件的思路跟 Docker 分层镜像的思路非常相似,只要建立多个 Kustomization 文件,开发人员就能基于基准进行派生(Base and Overlay),对不同的模式(比如生产模式、调试模式)、不同的项目(同一个产品对不同客户的客制化)定制出一个多合一配置包。 89 | 90 | 不过呢,回头看 Kustomize 只能算作一个辅助应用部署的“小工具”,配置包里面的资源一个也没有少写,只是减少了不同场景下的重复配置。对于一个应用而言,其管理需求远不止部署阶段,还涉及更新、回滚、卸载、多版本管理、多实例支持以及依赖关系维护等操作。要解决这些问题,还需要更高级的“工具”,这就是接下来要介绍的 Helm。 -------------------------------------------------------------------------------- /application-centric/OAM.md: -------------------------------------------------------------------------------- 1 | # 10.3.4 OAM 与 KubeVela 2 | 3 | 2019 年 10 月,阿里云与微软在上海 QCon 大会上联合发布了全球首个开放应用模型(OAM,Open Application Model)。该项目有两个部分:OAM 规范以及 OAM 规范的 Kubernetes 实现。 4 | 5 | 在 OAM 的规范中,应用由一组具有运维特征(Trait)的组件(Component)组成,并且限定在一个或多个应用边界(Application Scope)内。上述并非是完全抽象的概念,而是可实际使用的自定义资源(CRD)。这些概念的具体含义如下: 6 | 7 | - **组件**(Component):只要有编程经验的人,应该都知道组件的含义,组件是应用的基本构建块,具备可复用性,用于定义核心功能单元。在 OAM 中,每个组件代表一个独立的、可部署的微服务或资源(例如:数据库、缓存、API 网关等)。 8 | - **运维特征**(Trait):既然应用功能可以复用,那某些运维逻辑自然也可以封装复用。运维特征是可以随时绑定给待部署组件的、模块化、可拔插的运维能力,比如:副本数调整(手动、自动)、数据持久化、 设置网关策略、自动设置 DNS 解析等。 9 | - **应用边界**(Application Scopes):定义应用级别的部署特征,比如健康检查规则、安全组、防火墙、SLO、检验等模块。相对于运维特征而言,应用边界作用于一个应用的整体,而运维特征作用于应用中的某个组件。 10 | - **应用**(Application):将 Component(必需)、Trait(必需)和 Scope(可选)组合并实例化,形成了一个完整的应用描述。 11 | 12 | OAM 通过上述自定义资源将原本复杂的 Kubernetes All-in-one 配置进行了一定程度的解耦。应用研发人员负责管理 Component,运维人员将 Component 组合并绑定 Trait,形成 Application。平台或基础设施提供方则负责 OAM 的解释能力,将这些自定义资源映射到实际的基础设施上。各种角色的关注点恰当地分离,不同角色更聚焦更专业的做好本角色的工作。 13 | 14 | 整个过程如图 10-3 所示。 15 | :::center 16 | ![](../assets/OAM-how-it-works.png)
17 | 图 10-3 OAM 工作原理 18 | ::: 19 | 20 | KubeVela 是 OAM 规范在 Kubernetes 上的完整实现,它起源于 OAM 社区,由阿里巴巴、微软等技术专家共同维护。 21 | 22 | 对于平台工程师(Platform Builder)来说,KubeVela 是一个具备无限扩展性的 Kubernetes 原生应用构建引擎。他们负责准备应用部署环境、维护稳定可靠的基础设施,并将这些基础设施能力作为 KubeVela 模块注册到集群中。对于最终用户(End User,研发人员或运维人员)来说,只需选择部署环境、挑选能力模块并填写业务参数,就可以在不同运行环境上把应用随时运行起来! 23 | 24 | 25 | KubeVela 工作流程如图 10-4。 26 | :::center 27 | ![](../assets/kubevela.jpg)
28 | 图 10-4 KubeVela 工作原理 29 | ::: 30 | 31 | :::tip 企业落地 Kubernetes 的难题 32 | 33 | 很多企业落地 Kubernetes 的时候采用了 “PaaS” 化的思路,即在 Kubernetes 之上,开发一个类 PaaS 平台。但这个平台设计理念、模型和使用方式往往都是自己的,这些设计会“盖住” Kubernetes 的能力,使其声明式 API、容器设计模式、控制器模式根本无法发挥原本的实力,也难以与广泛的生态系统对接。 34 | 35 | 上述问题的直接表现就是,这个 PaaS 系统不具备扩展性。假设我们要满足以下诉求: 36 | 37 | - 能不能帮我运行一个定时任务 38 | - 能不能帮我运运行一个 MySQL Operator 39 | - 能不能根据自定义 metrics 定义水平扩容策略 40 | - 能不能基于 Istio 来帮我做渐进式灰度发布 41 | 42 | 这里的关键点在于,上述能力在 Kubernetes 生态中都是常见且广泛支持的,有些甚至是 Kubernetes 内置功能。但是到了 PaaS 这里,要实现这些能力往往需要重新开发,而且由于先前的设计假设,可能还需要进行大规模的重构。 43 | ::: 44 | 45 | KubeVela 本质上是在 Kubernetes 上安装了一个 OAM 插件,使平台工程师能够依据 OAM 规范,将 Kubernetes 生态中的各种能力和插件整合成一个应用交付平台。所以说,KubeVela 为最终用户提供了类似 PaaS 的使用体验,同时也为平台工程师带来了 Kubernetes 原生的高可扩展性和平台构建规范。 46 | 47 | 48 | 不过,目前来看,KubeVela 背后的理论还是过于抽象,落地有一定的技术门槛!但 KubeVela 这种构建以”应用为中心“的上层平台的思想,毫无疑问代表着云原生技术未来的发展方向! 49 | 50 | 51 | 52 | [^1]: https://zh.wikipedia.org/wiki/%E4%BF%A1%E6%81%AF%E7%83%9F%E5%9B%B1 53 | -------------------------------------------------------------------------------- /application-centric/app-model.md: -------------------------------------------------------------------------------- 1 | # 10.3 从“封装配置”到“应用模型” 2 | 3 | 在 Kubernetes 时代,“软件”不再是一个由应用开发者掌控的单一交付物,而是多个 Kubernetes 对象的集合。使用 Kubernetes 原生对象构建一套微服务应用,是一件高度碎片化且充满挑战的事情。 4 | 5 | 举个例子,如果你要在 Kubernetes 中部署一套微服务系统,那你需要为每个子服务配置 Service(提供服务发现和负载均衡)、Deployment(管理无状态服务)、HPA(自动扩缩容)、StatefulSet(管理有状态服务)、PersistentVolume(持久化存储)、NetworkPolicy(网络访问控制规则)等等。上述工作“繁琐”还在其次,关键难点是写出合适 YAML 元数据描述,这要求操作人员既要懂研发(理解服务运行、镜像版本、依赖关系等需求),又要懂运维(理解扩缩容、负载均衡、安全、监控等策略),还要懂平台(网络、存储、计算),一般的开发人员根本无从下手。 6 | 7 | 上述问题的根源在于,Docker 容器镜像封装了单一服务,Kubernetes 则通过资源封装了服务集群,却没有一个载体真正封装整个应用。封装应用的难点是:要屏蔽底层基础设施的复杂性,不要暴露给最终用户;同时,还要将开发、运维、平台等各种角色的关注点恰当地分离,使得不同角色可以更聚焦更专业的做好本角色的工作。 8 | 9 | 目前,业内对于如何封装应用还没有最终的结论,但经过不断探索,也出现了几种主流的应用封装与交付方案。接下来,笔者将介绍它们供你参考。 10 | 11 | -------------------------------------------------------------------------------- /application-centric/application-centric.md: -------------------------------------------------------------------------------- 1 | # 10.1 “以应用为中心”的设计思想 2 | 3 | 回顾过去十几年间的技术演进历程,精彩纷呈! 4 | 5 | 从单体系统到分布式系统,系统能力大幅提升,但也引入了更多的不确定性。比如节点可能随时宕机、网络有不等的延迟、消息可能丢失。为了解决这些不确定性,业界提出了诸多的分布式理论和协议,如 CAP 定理、BASE 理论以及共识算法(Paxos、Raft 等),以保障系统稳定运行。 6 | 7 | 进入微服务时代,这些理论推动基础设施能力演进,这些能力(服务发现、负载均衡、故障转移、动态扩容)从业务逻辑中抽象出来,以 SDK(中间件)形式提供给应用开发者。中间件的出现其实体现了一种朴素的“关注点分离”的思想,使得你可以在不需要深入了解具体基础设施能力细节的前提下,以最小的代价学习和使用这些基础设施能力! 8 | 9 | 不过,基础设施能力的演进,也伴随着云计算和开源社区的发展,带来了全新的升级。这个变化,正是从云原生技术改变中间件格局开始。更确切地说,原先通过中间件提供和封装的能力,现在全部被 kubernetes 从应用层拽到基础设施层。比如,Kubernetes 最早提供的应用副本管理、服务发现和分布式协同能力,其实把构建分布式应用最迫切的需求,利用 Replication Controller、kube-proxy 和 etcd “下沉”到基础设施中,也就是 kubernetes 中。 10 | 11 | 值得注意的是,kubernetes 不直接提供这些能力,它的角色定位是通过声明式 API 和控制器模式对用户暴露更底层基础设施的能力。从这个角度来看,Kubernetes 设计的重点在于“如何标准化地接入底层资源,无论是容器、虚拟机、负载均衡等,并通过声明式 API 将这些能力暴露给用户”。所以说,Kubernetes 的核心价值不在于容器编排或资源调度,而在于声明式 API。声明式 API 的最大优势是将“简单的交给用户,将复杂的留给系统”。通过声明式 API,Kubernetes 用户只需关心应用的最终状态,无需关注底层基础设施的配置和实现细节。 12 | 13 | 这种设计理念,以一言蔽之,就是以应用中心。正是因为以应用为中心,整个云原生技术体系无限强调基础设施更好地服务于应用,以更高效的方式为应用提供基础设施能力,而不是反其道行之。而相应的,Kubernetes 也好、Docker 也好、Istio 也好,这些在云原生生态中起到了关键作用的开源项目,就是让这种思想落地的技术手段。 -------------------------------------------------------------------------------- /application-centric/conclusion.md: -------------------------------------------------------------------------------- 1 | # 10.4 小结 2 | 3 | 云原生技术与理念发展至今,在推动现代应用架构演进方面取得了空前的成就! 4 | 5 | 以 Kubernetes 为代表的基础设施,将传统中间件的功能(如服务发现、负载均衡和自动化伸缩)从应用层剥离,转移至基础设施层。而服务网格进一步将“服务间流量治理”这一关键功能也下沉至基础设施层。 6 | 7 | 当然,基础设施的最终目标是创造业务价值,帮助用户更快、更好、更有信心地开发和交付应用。无论是 Kubernetes 还是 Istio,它们都是实现这一目标的工具,而非目的。而今出现的 Helm、Operator、OAM、KubeVela 等,则是以“以应用为中心”,将底层基础设施能力以更友好的方式“输送”给业务用户。 8 | 9 | 随着底层基础设施能力的日趋完善,相信不久的未来,一个应用要在世界上任何一个地方运行起来,唯一要做的,就是声明“我是什么”、“我要什么”。在那个时候,所有基础设施的概念,无论是 Kubernetes 还是 Istio,将统统消失不见。 10 | 11 | -------------------------------------------------------------------------------- /application-centric/summary.md: -------------------------------------------------------------------------------- 1 | # 第十章 应用封装与交付 2 | 3 | :::tip
4 | 没有银弹,但有时会有很好用的弓箭。 5 | :::right 6 | —— 改自于著作《没有银弹》[^1] 7 | ::: 8 | 9 | 很多企业开始落地 Kubernetes,很多业务工程师也开始“被迫”学习各种“抽象”的概念(如 Pod、YAML 文件、声明式 API、Operator)。落地前充满期待,结果却往往适得其反。 10 | 11 | 导致上面问题的根源在于,Kubernetes 的定位是基础设施项目、是“平台的平台”(The Platform for Platform)。它的声明式 API 设计、CRD Operator 体系,是为了接入和构建新基础设施能力而设计的。这就导致作为这些能力的最终用户 —— 业务工程师,跟 Kubernetes 核心定位之间存在明显的错位。 12 | 13 | 大家抱怨 Kubernetes 过于复杂,但“复杂”是任何基础设施项目的天生特质,而非缺点。不过,基础设施“复杂”不意味着应该由使用者承受。这就好比,Linux 内核是世界上最复杂的软件之一,但我们使用 Linux 系统却没有太多心智负担,这是因为 Linux 系统通过高度抽象屏蔽了底层的复杂性。既然 Kubernetes 被称为“云原生时代的操作系统”,现在也该考虑学习 Linux 抽象方式,寻找一种应用层的软件交付模型和抽象,以更友好的方式服务最终用户了。 14 | 15 | 本章内容安排如图 10-0 所示。 16 | :::center 17 | ![](../assets/application-centric.png)
18 | 图 10-0 本章内容导读 19 | ::: 20 | 21 | 22 | [^1]:《没有银弹:软件工程的本质性与附属性工作》是 IBM 大型机之父 Frederick P. Brooks, Jr. 的著作。书中通过引述《伦敦狼人》等电影的剧照,探讨了“银弹”在软件工程中的传说。Brooks 强调,由于软件本质上的复杂性,使真正的“银弹”(即完美解决所有问题的技术或方法)并不存在。 -------------------------------------------------------------------------------- /architecture/Immutable.md: -------------------------------------------------------------------------------- 1 | # 1.5.4 不可变基础设施 2 | 3 | 如果你对一位开发工程师说:“你的软件有 bug”,他大概率这样回:“我本地跑好好的,怎么到你那就不行?”,或者你是个运维工程师,维护线上系统时,肯定吐槽过:“谁又改了配置文件...”。 4 | 5 | 本节,我们讨论上述问题的根源 —— 基础设施的“可变”与“不可变”。 6 | 7 | ## 1.可变的基础设施 8 | 9 | 从管理基础设施的层面看:“可变”的基础设施与传统运维操作相关。例如,有一台服务器部署的是 Apache,现在想换成 Nginx。传统手段是先卸载掉 Apache,重新安装一个 Nginx,再重启系统让这次变更生效。 10 | 11 | 上述的过程中,装有 Apache 的 Linux 操作系统为了满足业务需求,进行了一次或多次变更,该 Linux 操作系统就是一个可变的基础设施。可变的基础设施会导致以下问题: 12 | 13 | - **重大故障时,难以快速重新构建服务**:持续过多的手动操作并且缺乏记录,会导致很难由标准初始化的服务器来重新构建起等效的服务; 14 | - **不一致风险**:类似于程序变量因并发修改而带来的状态不一致风险。服务运行过程中,频繁的修改基础设施配置,同样会引入中间状态,导致出现无法预知的问题。 15 | 16 | ::: tip 可变的基础设施带来的运维之痛,引得业内技术专家 Chad Fowler 这样吐槽: 17 | 要把一个不知道打过多少个升级补丁,不知道经历了多少任管理员的系统迁移到其他机器上,毫无疑问会是一场灾难。 18 | ::: 19 | 20 | ## 2.不可变基础设施 21 | 22 | 2013 年 6 月,Chad Fowler 撰写了一篇名为 《Trash Your Servers and Burn Your Code: Immutable Infrastructure and Disposable Components》的文章,提出了 Immutable Infrastructure(不可变基础设施)的概念[^1]。这一前瞻性的构想,伴随着 Docker 容器技术的兴起、微服务架构的流行,得到了事实上的检验。 23 | 24 | 不可变基础设施思想的核心是,**任何基础设施的运行实例一旦创建之后就变成只读状态**。如需修改或升级,应该先修改基础设施的配置模版(例如 yaml、Dockerfile 配置),之后再使用新的运行实例替换。例如上面提到的 Nginx 升级案例,应该准备一个新的装有 Nginx 的 Linux 操作系统,而不是在 Linux 操作系统上原地更新。 25 | 26 | :::center 27 | ![](../assets/Immutable.png)
28 | 图 1-25 基础设施可变与不可变对比 29 | ::: 30 | 31 | 此刻,读者是否灵光一现想起前面介绍的容器技术。构建镜像运行容器之后,如果出现问题,我们不会在容器内修改解决,而是修改 Dockerfile 在容器构建阶段去解决。 32 | 33 | 从容器的角度看,**镜像就是一个不可变基础设施**。工程师交付的产物从有着各种依赖条件的安装包变成一个不依赖任何环境的镜像文件,当软件需要升级或者修改配置时,我们修改镜像文件,新起一个容器实例替换,而不是在运行容器内修改。有了镜像之后,本地与测试环境不一致、测试环境与正式环境不一致问题消失殆尽了。 34 | 35 | 相比可变基础设施,不可变基础设施通过标准化描述文件(如 yaml、dockerfile 等)统一定义,同样的配置拉起的服务,绝对不可能出现不一致的情况。从此,我们可以快速拉起成千上万一模一样的服务,服务的版本升级、回滚也成为常态。 36 | 37 | 38 | [^1]: 参见 http://chadfowler.com/2013/06/23/immutable-deployments.html -------------------------------------------------------------------------------- /architecture/ServiceMesh.md: -------------------------------------------------------------------------------- 1 | # 1.5.3 服务网格 2 | 3 | 服务网格(Service Mesh)的概念最早由 Buoyant 公司的创始人 William Morgan 于 2016 年提出。 4 | 5 | 2017 年 4 月,该公司发布了首个服务网格产品 Linkerd。同年,Morgan 的文章《What’s a service mesh? And why do I need one?》[^1]在互联网中开始广泛流传,这篇文章内的解读被认定为服务网格的权威定义。 6 | 7 | :::tip 服务网格的定义 8 | 9 | 服务网格(ServiceMesh)是一个**基础设施层**,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证**请求在这些拓扑中可靠地穿梭**。在实际应用当中,服务网格通常是由一系列轻量级的**网络代理**组成的,它们与应用程序部署在一起,但**对应用程序透明**。 10 | 11 | :::right 12 | —— by William Morgan 13 | ::: 14 | 15 | ServiceMesh 之所以称为“服务网格”,是因为每个节点同时运行着业务逻辑和具备通信治理能力的网络代理(如 Envoy、Linkerd-proxy)。这个代理被形象地称为“边车代理”(Sidecar),其中业务逻辑相当于主驾驶,处理辅助功能的代理软件相当于边车。 16 | 17 | :::center 18 | ![](../assets/sidecar-example.jpg)
19 | 图 1-22 边车示例 20 | ::: 21 | 22 | 具有通信治理能力的代理软件以边车形式部署,服务之间通过边车发现和调用目标服务。如果我们把节点和业务逻辑从视图剥离,边车之间呈现图 1-23 所示网络状依赖关系,服务网格由此得名。 23 | 24 | :::center 25 | ![](../assets/service-mesh.png)
26 | 图 1-23 服务网格形象示例 27 | ::: 28 | 29 | 业内绝大部分服务网格产品通常由“数据平面”和“控制平面”两部分组成,以服务网格的代表实现 Istio 架构为例,如图 1-24 所示。 30 | 31 | - **数据平面(Data plane)**:通常采用轻量级的网络代理(如 Envoy)作为 Sidecar,网络代理负责协调和控制服务之间的通信和流量处理,解决微服务之间服务熔断、负载均衡、安全通讯等问题。 32 | - **控制平面(Control plane)**:包含多个控制组件,它们负责配置和管理 Sidecar ,并提供服务发现(Discovery)、配置管理(Configuration)、安全控制(Certificates)等功能。 33 | 34 | 35 | :::center 36 | ![](../assets/service-mesh-arc.svg)
37 | 图 1-24 Istio 架构 38 | ::: 39 | 40 | 41 | 值得注意的是,尽管服务网格的特点是 Sidecar 模式,但 Sidecar 模式并非服务网格专有。 42 | 43 | Sidecar 是一种常见的容器设计模式,Kubernetes 的工作负载 Pod 内可配置多个容器,业务容器之外的其他所有容器均可称为“边车容器”(Sidecar container)。如日志收集 Sidecar、请求代理 Sidecar 和链路追踪 Sidecar 等等。 44 | 45 | 如图 1-25 所示,app-container 是一个主业务容器,logging-agent 是一个日志收集容器。主业务容器完全感知不到 logging-agent 的存在,它只负责输出日志,无需关心后续日志该怎么处理。你思考这样开发一个高内聚、低耦合的系统是否更加容易? 46 | 47 | :::center 48 | ![](../assets/k8s-sidecar.png)
49 | 图 1-25 Kubernetes Pod 中 Sidecar 容器收集应用日志,并转发至日志后端 50 | ::: 51 | 52 | 至此,相信你已经清楚服务网格不是什么黑科技,也没有什么耀眼的新技术。 53 | 54 | 服务网格本质是通过 iptables 劫持发送到应用容器的流量,将原本在业务层处理的分布式通信治理相关的技术问题,下沉到网络代理型边车中处理,实现业务与非业务逻辑解耦的目的。 55 | 56 | 笔者将在第八章完整介绍服务网格技术,阐述服务间通信的演变、服务网格的生态以及服务网格的未来。 57 | 58 | 59 | [^1]: 参见 https://www.infoq.cn/news/2017/11/WHAT-SERVICE-MESH-WHY-NEED/ 60 | -------------------------------------------------------------------------------- /architecture/arc.md: -------------------------------------------------------------------------------- 1 | # 1.6 云原生架构的演进 2 | 3 | 架构演进的目的一定是解决某一类问题,我们就从“解决问题”的角度出发,如图 1-33 所示,讨论传统架构向云原生架构的演进之路。 4 | 5 | - 为了解决单体架构“复杂度问题”,使用微服务架构。 6 | - 为了解决微服务间“通讯异常问题”,使用治理框架 + 监控。 7 | - 为了解决微服务架构下大量应用“部署问题”,使用容器。 8 | - 为了解决容器的“编排和调度问题”,使用 Kubernetes。 9 | - 为了解决微服务框架的“侵入性问题”,使用服务网格。 10 | - 为了让服务网格有“更好的底层支撑”,将服务网格运行在 Kubernetes 上。 11 | 12 | :::center 13 | ![](../assets/arc-1.svg)
14 | 图 1-33 传统架构与云原生架构对比 15 | ::: 16 | 17 | 从研发应用的角度看,研发的复杂度降低了。在“强大底层系统”支撑的情况下,应用监控、通信治理、编排调度相关的逻辑从应用中剥离,并下沉到底层系统,已经符合云原生架构。但站在整个系统的角度看,复杂度并没有减少和消失,要实现“强大底层系统”付出的成本(人力成本、资源成本、技术试错成本)是非常昂贵的。为了降低成本,选择上云托管,将底层系统的复杂度交给云基础设施,让云提供保姆式服务,最终演变为无基础架构设计。 18 | 19 | 最后,通过 YAML 文件以声明式的方式,描述底层的基础设施以及各类中间件资源,即应用要什么,云给我什么,企业最终走向开放、标准的“云”技术体系。 -------------------------------------------------------------------------------- /architecture/architect.md: -------------------------------------------------------------------------------- 1 | # 1.7 云原生架构技术栈 2 | 3 | 云原生架构是优雅的、灵活的、弹性的...,但不能否认这些优势的背后是它的学习曲线相当陡峭。 4 | 5 | 如果你有志投入云原生领域,希望构建一个高可用(高研发效率、低资源成本,且兼具稳定可靠)的云原生架构,对能力要求已提升到史无前例的程度。总结来说,除了掌握基础的 Docker 和 Kubernetes 知识外,熟知图 1-34 所示的几个领域也是必备要求。 6 | 7 | :::center 8 | ![](../assets/cloud.svg)
9 | 图 1-34 云原生代表技术栈 10 | ::: 11 | 12 | 1. 容器运行时:Docker、Containerd、CRI-O、Kata Containers。 13 | 2. 镜像和仓库:Harbor、Dragonfly、Nydus。 14 | 3. 应用封装:Kustomize、Helm、Operator、OAM。 15 | 4. 持续集成:Gitlab、Tekton。 16 | 5. 持续部署:ArgoCD、FluxCD。 17 | 6. 容器编排:Kubernetes。 18 | 7. 服务网格: Istio、Envoy、Linkerd。 19 | 7. 网关:Ingress-Nginx、Kong、Traefik。 20 | 8. 日志:Grafana Loki、Elastic Stack、ClickHouse。 21 | 9. 监控/观测:Prometheus、Grafana、OpenTelemetry。 22 | 10. 机器学习/离在线业务混合部署:Volcano、Koordinator...。 23 | 24 | 25 | 以上方案或相似或不同:适应什么场景?、解决了什么问题?、如何以最佳的姿势匹配业务?容笔者在本书后续章节一一解答。 -------------------------------------------------------------------------------- /architecture/background.md: -------------------------------------------------------------------------------- 1 | # 1.2 云原生出现的背景 2 | 3 | 了解云计算的技术演进后,我们再回过头看看世界的变化,思考世界变化对软件开发的影响。 4 | 5 | ## 1.2.1 软件正在吞噬世界 6 | 7 | Mark Andreessen 是风险投资公司 Andreessen-Horowitz 的联合创始人(如图 1-6 所示),该公司投资了 Facebook、Groupon、Skype、Twitter、Zynga、Foursquare 等公司。 8 | 9 | :::center 10 | ![](../assets/SoftwareEatingTheWorld.jpg)
11 | 图 1-6 《Software is Eating The World》 —— by Mark Andreessen, in 2011 12 | ::: 13 | 14 | 2011 年 8 月 20 日华尔街日报上,Mark Andreessen 发表了名为“Why Software Is Eating the World”的文章,内容主要阐述了软件如何影响各个行业,援引其中部分内容: 15 | 16 | :::tip 《软件正在吞噬世界》内容节选 17 | 18 | 我们处于戏剧性和广泛的技术和经济转变的中间,软件公司准备接管大量的经济。 19 | 20 | 为什么现在发生这种情况? 21 | 22 | 计算机革命六十年,微处理器发明四十年,现代互联网兴起二十年,通过软件转变行业所需的所有技术终于有效,并可在全球范围内广泛传播。 23 | ::: 24 | 25 | 文中列出了被重塑的产业,具体有最大的书店 Amazon、最多人订阅的 Video service Netflix、最大的音乐公司 iTunes、Spotify 和 Pandora 等、成长最快的娱乐领域 videogame、最好的电影制片厂 Pixar、最大的行销平台 Google、Groupon、Facebook 等、成长最快的电信公司 Skype 、成长最快招聘公司 LinkedIn。 26 | 27 | 文章发表于 2011 年,2023 年再来回顾,互联网冲击已经无所不在,**部分软件已经变成水电煤一样的社会经济中的基础设施**,感触更加深刻。思考这样的软件如果宕机,对社会产生什么影响? 28 | 29 | ## 1.2.2 移动互联网在加剧变化 30 | 31 | 还是那篇文章,Mark Andreessen 展望互联网规模时,写道“在接下来的 10 年里,我预计全球至少有 50 亿人拥有智能手机,每个人每天都可以随时随地使用手机充分利用互联网”。 32 | 33 | 现在,我们已经可以确认 Mark Andreessen 的预测很正确,移动互联网时代的用户规模已经开始向人口基数看齐,开始出现各类亿级 DAU 规模的移动应用。**移动互联网如此巨大的用户规模会对软件开发有什么影响?** 34 | 35 | 援引 Netflix 的一页 PPT,如图 1-7 所示,这里按照规模和变更速度将软件企业划分为四个象限/四种类型: 36 | 37 | - 企业 IT(Enterprise IT):规模小、变化慢,容易处理。 38 | - 电信(Telcos):规模大、变化慢,主要应对硬件失败。 39 | - 初创公司(Startups):规模小、变化快,主要应对软件失败。 40 | - 互联网企业(Web-Scale):规模大、变化快,软硬件或者说所有东西都会出问题。 41 | 42 | :::center 43 | ![](../assets/ppt4.jpg)
44 | 图 1-7 Netflix 按照规模和变更速度对软件企业划分的总结 45 | ::: 46 | 47 | 十年前乃至二十年前的**互联网时代,大多数软件企业都位于图 1-7 左边的两个象限:“规模或许有大有小,但是变更速度相对今天都不快”**。当企业发展壮大时,体现的也更多是在规模上,变更速度并不会发生质的变化。 48 | 49 | 而今天的**移动互联网时代,则都位于图 1-7 右边的两个象限:“无论规模是大是小,变更速度都要求非常快”**。当企业逐步发展壮大,规模十倍百倍增长时,对变更速度的要求并不会降低,甚至会要求更快。 50 | 51 | 移动互联网时代,能够成长并发展起来的这些公司,它们的共同点是: 52 | 53 | - 快速变更,不断创新,随时调整。 54 | - 提供持续可用的服务,应对各种可能的错误和中断。 55 | - 弹性可扩展的系统,应对用户规模的快速增长。 56 | - 提供新的用户体验,以移动为中心。 57 | 58 | 这样的背景下,对软件质量有了更高的要求,软件开发的方式也不得不跟随时代而变化,首当其冲是:**如何解决规模越来越大,变更越来越快的难题**。 59 | 60 | 61 | ## 1.2.3 云原生的诞生 62 | 63 | 前面谈到了**软件对各行各业的渗透和对世界的改变,以及移动互联网时代巨大的用户基数下快速变更和不断创新的需求**对软件开发方式带来的巨大推动力,1.1 节描述的过去二十年间云计算的发展演进和软件上云的趋势,我们清晰地看到如此波澜壮阔的技术浪潮: 64 | 65 | - 软件正在改变世界。 66 | - 移动互联网让这个变革影响到每一个人。 67 | - 传统软件开发方式受到巨大挑战。 68 | - 云计算普及,软件上云成为趋势。 69 | - 云的形态持续在演进。 70 | 71 | 72 | 过去二十年间,云的底层基础设施和平台越来越强大,软件架构的发展也逐渐和云匹配: 73 | - 通过不可变基础设施(镜像)解决本地和远程一致性问题; 74 | - 通过服务网格(ServiceMesh)将非业务逻辑从应用程序中剥离; 75 | - 通过声明式 API 描述应用程序的状态,而不用管中间的处理过程; 76 | - 通过 DevOps 理论以及配套的工具来提升研发/运维效率; 77 | - 通过 ...。 78 | 79 | 应用程序中的非业务逻辑不断被剥离,并下沉到云/基础设施层,代码越来越轻量。由此,工程师的开发工作回归本质(软件开发的本质是解决业务需求,各类“高深”、“复杂”的技术难题是业务需求的副产物,并不是软件开发的主题)。 80 | 81 | 最终,上帝的归上帝,凯撒的归凯撒,云原生就此诞生! 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /architecture/cloud-native-tech.md: -------------------------------------------------------------------------------- 1 | # 1.5 云原生代表技术 2 | 3 | 接下来的内容,我们将深入讨论容器技术、微服务、服务网格、不可变基础设施、声明式设计以及 DevOps 等云原生代表技术。 -------------------------------------------------------------------------------- /architecture/conclusion.md: -------------------------------------------------------------------------------- 1 | # 1.8 小结 2 | 3 | 通过本章的介绍,相信你已经深刻理解,什么是云原生? 4 | 5 | 云原生不是简单使用云计算平台运行现有的应用程序,也不是某个开源项目或者某种技术,而是一套指导软件和基础设施架构设计的思想。基于这套思想构建出来的应用,能够天然地与“云”融合,充分发挥“云”的能力和价值。相应的,云原生生态中的开源项目 Kubernetes、Docker、Istio 等,就是这种思想落地的技术手段。 6 | 7 | 最后,笔者还要补充的是,并不是因为云计算/容器技术的发展才出现云原生的概念,而是软件规模变得越来越大、越来越复杂的同时,对软件的可靠性、迭代效率、资源成本的要求也越来越高,这才有了云原生技术出现的契机和发展。 8 | 9 | 从根本上讲,驱动技术发展的动力有很多种,但能让技术大行其道的动力,都是来源于业务发展的需要。 -------------------------------------------------------------------------------- /architecture/declarative-api.md: -------------------------------------------------------------------------------- 1 | # 1.5.5 声明式设计 2 | 3 | 声明式设计是指一种软件设计理念:“我们描述一个事物的目标状态,而非达成目标状态的流程”。至于目标状态如何达成,则由相应的工具在其内部实现。 4 | 5 | 和声明式设计相对的是命令式设计(又叫过程式设计),两者的区别是: 6 | 1. 命令式设计:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现; 7 | 2. 声明式设计:告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。 8 | 9 | 很多常用的编程语言都是命令式。例如,有一批图书的列表,你会编写下面类似的代码来查询列表中名为“深入高可用系统原理与设计”的书籍: 10 | 11 | ```bash 12 | function getBooks() { 13 | var results = [] 14 | for( var i=0; i< books.length; i++) { 15 | if(books[i].name == "深入高可用系统原理与设计") { 16 | results.push(books) 17 | } 18 | } 19 | return results 20 | } 21 | ``` 22 | 命令式语言告诉计算机以特定的顺序执行某些操作,实现最终目标:“查询名为《深入高可用系统原理与设计》的书籍”,必须完全推理整个过程。 23 | 24 | 再来看声明式的查询语言(如 SQL)是如何处理的呢? 25 | 26 | 使用 SQL,只需要指定所需的数据、结果满足什么条件以及如何转换数据(如排序、分组和聚合),数据库直接返回我们想要的结果。这远比自行编写处理过程去获取数据容易的多。 27 | ```sql 28 | SELECT * FROM books WHERE author = 'xiaoming' AND name LIKE '深入高可用系统原理与设计%'; 29 | ``` 30 | 31 | 接下来,再看以声明式设计为核心的 Kubernetes。 32 | 33 | 下面的 YAML 文件中定义了一个名为 nginx-deployment 的 Deployment 资源。其中 spec 部分**声明**了部署后的具体状态(以 3 个副本的形式运行)。 34 | 35 | ```yaml 36 | apiVersion: apps/v1 37 | kind: Deployment 38 | metadata: 39 | name: nginx-deployment 40 | labels: 41 | app: nginx 42 | spec: 43 | replicas: 3 44 | selector: 45 | matchLabels: 46 | app: nginx 47 | template: 48 | metadata: 49 | labels: 50 | app: nginx 51 | spec: 52 | containers: 53 | - name: nginx 54 | image: nginx:1.14.2 55 | ports: 56 | - containerPort: 80 57 | ``` 58 | 该 YAML 文件提交给 Kubernetes 之后,Kubernetes 会创建拥有 3 个副本的 nginx 服务实例,将持续保证我们所期望的状态。 59 | 60 | 通过编写 YAML 文件表达我们的需求和意图,资源如何创建、服务如何关联,至于具体怎么实现,我们完全不需要关心,全部甩手给 Kubernetes。 61 | 62 | 只描述想要什么,中间流程、细节不需关心。工程师们专注于 what,正是我们开发软件真正的目标。 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /architecture/define-cloud-native.md: -------------------------------------------------------------------------------- 1 | # 1.3 云原生的定义 2 | 3 | 即使在今天,当需要解释“什么是云原生?”,还是会有些困难。 4 | 5 | 过去几年间,云原生的定义一直在变化和发展演进,不同时期不同的公司对此的理解和诠释也不尽相同,因此往往带来一些疑惑和误解。本节内容,我们看看云原生定义在不同时期的变化。 6 | 7 | ## 1.3.1 Pivotal 对云原生的定义 8 | 9 | 2015 年,Pivotal[^1] 公司的技术产品经理 Matt Stine 首次提出了“云原生”(Cloud Native)的概念。 10 | 11 | 在 Matt Stine 所著的《迁移到云原生应用架构》书中,他提出云原生架构应该具备 5 个主要特征,如图 1-8 所示。 12 | 13 | :::center 14 | ![](../assets/pivotal-cloud-native.svg)
15 | 图 1-8 云原生架构的早期特征 16 | ::: 17 | 18 | 随着时间的推移,详细解释这些早期的特征已经没有什么必要了,只要知道这些内容研究的是“用更恰当的姿势上云”即可。 19 | 20 | 2017 年 10 月,还是 Matt Stine,他接受 InfoQ 采访时,对云原生的定义做了小幅调整,更新后的云原生架构特征如图 1-9 所示。 21 | 22 | :::center 23 | ![](../assets/pivotal-cloud-native-update.svg)
24 | 图 1-9 Matt Stine 更新后的云原生架构特征 25 | ::: 26 | 27 | 现在,在 Pivotal 官方网站中[^2],对云原生的介绍则是关注如图 1-10 所示的 4 个要点:DevOps(开发运维)、Continuous Delivery(持续交付)、Microservices(微服务)、Containers(容器化),这也是大家最熟悉的版本。 28 | 29 | :::center 30 | ![](../assets/cloud-native.png)
31 | 图 1-10 Pivotal 对云原生的定义 32 | ::: 33 | 34 | 可见云原生的定义在 Pivotal 内部也是不断更迭的,很多概念被放弃或者抽象,并且有新的东西加入。 35 | 36 | ## 1.3.2 CNCF 对云原生的定义 37 | 38 | 2015 年 CNCF(Cloud Native Computing Foundation,云原生计算基金会)成立,开始围绕云原生的概念打造生态体系。 39 | 40 | :::tip CNCF 简介 41 | 42 | CNCF 是 Linux 基金会旗下的基金会,可以理解为一个非营利组织,成立于 2015 年 12 月 11 日。 43 | 44 | 成立这个组织的初衷或者愿景,简单说:推动云原生计算可持续发展;帮助云原生技术开发人员快速地构建出色的产品。 45 | ::: 46 | 47 | 起初,CNCF 对云原生的定义包含以下三个方面: 48 | 49 | - **应用容器化**:容器化是云原生的基础。 50 | - **面向微服务架构**:实施微服务是构建大规模系统的必备要素。 51 | - **应用支持容器的编排调度**:编排调度是指能够对容器应用的部署、扩展、运行和生命周期进行自动化管理。 52 | 53 | 由此可见,云原生并不是简单地使用云平台运行现有的应用程序,而是能充分利用云计算优势对应用程序进行设计、实现、部署、交付的理念。 54 | 55 | 随着社区对云原生理念的广泛认可和云原生生态的不断扩大,还有 CNCF 项目和会员的大量增加,起初的定义已经不再适用,因此 CNCF 对云原生进行了重新定位。2018 年 6 月,CNCF 正式对外公布云原生定义 v1.0 版本[^3]。 56 | 57 | :::tip CNCF 云原生的定义 v1.0 版本 58 | 59 | 云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。 60 | 61 | 这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。 62 | ::: 63 | 64 | 图 1-11 描述了新定义中的代表技术:不可变基础设施、容器、服务网格、微服务、声明式 API。 65 | - 容器和微服务在不同时期、不同定义中都有出现; 66 | - 而服务网格这个在 2017 年才被社区接纳的新技术被醒目的列出来。 67 | 68 | 服务网格和微服务并列,这表明服务网格已经超越了其原初的角色 —— 仅作为实现微服务的新方法,已经发展为云原生的又一个关键领域。 69 | 70 | :::center 71 | ![](../assets/cncf-cloud-native.svg)
72 | 图1-11 CNCF 定义的云原生代表技术 73 | ::: 74 | 75 | ## 1.3.3 云原生定义之外 76 | 77 | 从上面可以看到,云原生的内容和具体形式随着时间的推移一直在变化,而且云原生这个词汇最近被过度使用,混有各种营销色彩,容易发生偏离。即便是 CNCF 最新推出的云原生定义也非常明确的标注为 v1.0,相信未来我们很有机会看到 v1.1、v2 版本。 78 | 79 | 最后总结,**云原生是什么并不重要,关键还是理解实施云原生有什么好处,以及实施云原生的理论指导、涉及的技术/工具等**。 80 | 81 | 了解云原生的定义之后,1.4 节继续讨论云原生技术的目标。 82 | 83 | [^1]: Pivotal 是云原生概念提出的鼻祖,还推出了 Pivotal Cloud Foundry 和 Spring 系列开发框架,是行业先驱和探路者。2019 年,Pivotal 被 VMware 收购。 84 | [^2]: 参见 https://pivotal.io/cloud-native 85 | [^3]: 参见 https://github.com/cncf/toc/blob/main/DEFINITION.md 86 | -------------------------------------------------------------------------------- /architecture/devops.md: -------------------------------------------------------------------------------- 1 | # 1.5.6 DevOps 2 | 3 | DevOps 是个很复杂的概念,几句话很难解释清楚。我们延用之前的惯例,如果要理解一个复杂的概念,就先去了解它出现的背景,以及发展的历史。 4 | 5 | DevOps 核心本质是解决软件开发生命周期中的管理问题,我们先从一种名为“瀑布模型”的项目管理方法说起。 6 | 7 | ## 1.瀑布开发 8 | 9 | 1970 年,计算机科学家 Winston Royce 发表《Managing the development of large software systems》论文,首次描述了软件开发的分阶段流程,包括需求分析、设计、实现、测试和维护等阶段。 10 | 11 | 如图 1-27 所示,Royce 描述软件开发流程如瀑布流水一般,由一个阶段“流动”到下一个阶段,这种逐步递进的流程后来被称为“瀑布模型”(Waterfall Model)。 12 | 13 | :::center 14 | ![](../assets/waterfall-model.svg)
15 | 图 1-27 瀑布模型示例,一环接着一环,就像自然界瀑布流水一般。 16 | ::: 17 | 18 | 瀑布模型基于工程学的理念将整个过程分成不同的阶段,提供了软件开发的基本框架,便于人员间的分工协作。同时,也可对不同阶段的质量和成本进行严格把控。 19 | 20 | 但这种模式存在一些缺陷,瀑布模型产生于硬件领域,它是从制造业的角度去看软件开发的,产品迭代的频率经常按月为单位进行,在需求变化不多的年代,瀑布模型拥有其价值。随着软件行业的快速爆发,针对市场的快速变化和响应成了新的目标。这种场景下,需求无法得到快速验证是最大的风险,有可能花费数月开发的产品早已不符合市场需求。 21 | 22 | 寻求一种新的模式满足对产品生命周期迭代更迅速的管理,变得尤为迫切。于是,敏捷开发登上舞台。 23 | 24 | ## 2.敏捷开发 25 | 26 | 2001 年,Martin Fowler,Jim Highsmith 等 17 位著名的软件开发专家齐聚在美国犹他州雪鸟滑雪圣地,举行了一次敏捷方法发起者和实践者的聚会。这次会议中,他们正式提出了 Agile Software Development(敏捷开发)这个概念,还有模有样地签署了《敏捷宣言》,如图 1-28 所示。 27 | 28 | :::center 29 | ![](../assets/agile-word.png)
30 | 图 1-28 敏捷宣言 31 | ::: 32 | 33 | 相比于传统的瀑布开发,敏捷开发是一种持续增量、不断迭代的开发模式。 34 | 35 | 开发者快速发布一个可运行但不完美的版本投入市场,在后续迭代中根据用户的反馈改进产品,从而逼近产品的最终形态。 36 | 37 | 迭代是敏捷开发理论的核心。坦白地说,迭代开发并不是新鲜的概念,但敏捷研发方法大大完善了迭代开发的理论,使之能够被广大的软件开发团队认可。具体的敏捷研发方法有极限编程、精益软件开发、Scrum 等,如图 1-29 所示。 38 | 39 | :::center 40 | ![](../assets/agile-model.png)
41 | 图 1-29 敏捷开发框架 Scrum,通过持续迭代的方式交付软件 42 | ::: 43 | 44 | 虽然敏捷开发提升了开发效率,但它的范围仅限于开发和测试环节,并没有覆盖到部署环节。显然,运维部门并没有收益。相反的,甚至可以说“敏捷”加重了运维的负担。运维追求的目标是稳定,频繁变更是破坏稳定的根源。 45 | 46 | 如图 1-30 所示的混乱之墙,就是我们常说的开发与运维之间的根因冲突。 47 | 48 | :::center 49 | ![](../assets/devops-wall.png)
50 | 图 1-30 开发与运维之间的混乱之墙 51 | ::: 52 | 53 | 那么,如何要化解开发与运维的矛盾呢?现在,到了 DevOps 上场的时间。 54 | 55 | ## 3.DevOps 56 | 57 | DevOps 运动始于 2007 年左右,当时技术社区对开发/运维分工协作的方式、以及由此引发的冲突感到担忧。随着越来越多问题的出现,大家逐渐认识到:为了保证产品研发的效率、软件交付的质量,开发和运维必须紧密配合。 58 | 59 | 2009 年,比利时根特市举办了首届 DevOpsDays 大会,这届会议出乎意料的成功,引起人们广泛的讨论。DevOps 理论就此诞生! 60 | 61 | :::tip DevOps 的定义 62 | DevOps(Development 和 Operations 的合成词)是一种重视“软件开发人员(Dev)”和“IT 运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。 63 | 64 | 通过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。 65 | 66 | :::right 67 | —— from 维基百科 68 | ::: 69 | 70 | 2009 年,引入 DevOps 概念之时,基于“Development“和“Operations”合成一个新词“DevOps”,强调开发(指交付前的广义上的研发活动,包括设计、测试等)与运维融合,打破开发和运维之间的隔阂、加快软件研发效率、提高软件交付质量。 71 | 72 | 从存在的意义上说,DevOps 完善了敏捷开发存在的短板,实现了研发流程真正的闭环。如图 1-31 所示,开发和运维不再是“孤立”的团队,两者在软件的整个生命周期内相互协作,紧密配合。由此带来的效益,是软件的品质不仅高、交付的速度还快。 73 | 74 | :::center 75 | ![](../assets/devops-2.jpg)
76 | 图 1-31 Devops 打破开发和运维的对立 77 | ::: 78 | 79 | 不过,话虽如此,要实现这一点却不容易,因为这并非只是一次升级,而是需要在原有的文化和流程上大刀阔斧的改革: 80 | 81 | - 首先是推行协作文化,研发和运维之间不再是对立的关系,应该是互相协作、深度交流并且彼此体谅的状态。 82 | - 开发流程方面,以往研发和运维各搞各的模式也需要改变: 83 | - 运维需要在项目开发的初始阶段提前介入,了解开发所使用的系统架构和技术路线,并制定好相关的运维方案。 84 | - 开发人员也需要参与到后期的系统部署和日常维护中,并提供优化建议。不仅仅是把代码甩给运维了事。 85 | 86 | DevOps 的成功实践离不开工具上的支持,这其中包括最重要的自动化 CI/CD 流水线,通过自动化的方式打通软件从构建、测试到部署发布的整个流程。还有实时监控、事件管理、配置管理、协作平台等一系列工具/系统的配合,如图 1-32 所示。 87 | 88 | :::center 89 | ![](../assets/devops.jpeg)
90 | 图 1-32 DevOps 技术体系以及各阶段工具概览 91 | ::: 92 | 93 | 近年来,微服务架构理念、容器技术和云计算的发展,让 DevOps 的实施更加便捷。这也解释了 DevOps 理念在十多年前就已提出,但直到近几年才开始被企业广泛关注和实践的原因。 -------------------------------------------------------------------------------- /architecture/summary.md: -------------------------------------------------------------------------------- 1 | # 第一章:云原生技术概论 2 | :::tip
3 | 4 | 你知道比拓展 Web 服务更难的是什么吗? 是寻找持续 20 年且仍然感觉良好的架构设计思想。 5 | 6 | ::: right 7 | —— by Shopify 创始人 Tobias Lütke[^1] 8 | ::: 9 | 10 | 云原生是一个很抽象的概念,业内解读云原生往往用更抽象的描述解释抽象。例如,用“不可变基础设施”、“声明式 API”和“容器”类似的描述,这会让云原生的概念更加难以理解。本章将换一种方式解读云原生,从技术发展的历史、需求产生的背景开始,用朴素的话讨论云技术十几年间的演进历程,并深入思考这些技术试图解决的问题。 11 | 12 | 思想先行,技术随后。在本章,笔者将从解决问题的角度出发,解释云原生技术的变革,介绍云原生代表技术,建立后续章节所需的基本要点。在接下来的章节中,笔者将基于“设计良好的架构”主题层层推进,深入讨论设计一套兼具稳定(高可用)、成本(少花钱)和效率(敏捷开发)的系统时,所面临的抉择和权衡。 13 | 14 | 本章内容安排如图 1-0 所示。 15 | :::center 16 | ![](../assets/cloud-summary.png)
17 | 图 1-0 本章内容导读 18 | ::: 19 | 20 | [^1]: Tobias Lütke,著名的技术创业者。他在 2006 年创建的 Shopify 已成为全球最大的电子商务平台之一。 -------------------------------------------------------------------------------- /architecture/target.md: -------------------------------------------------------------------------------- 1 | # 1.4 云原生的目标 2 | 3 | 根据前面对云计算历史的追溯、云原生出现的背景分析、以及不同时期云原生定义的总结,这里给出云原生的 4 个关键目标,如图 1-12 所示。 4 | 5 | :::center 6 | ![](../assets/cloud-native-goals.png)
7 | 图 1-12 云原生技术的关键目标 8 | ::: 9 | 10 | - **可用**(Available):通过各种机制来实现应用的高可用,以保证服务提供的连续性。 11 | - **规模**(Scale):要求云原生服务能够适应不同的规模(包括但不限于用户规模/部署规模/请求量),并能够在部署时动态分配资源,以便在不同的规模之间快速和平滑的伸缩。典型场景如: 12 | - 初创公司或新产品线快速成长,用户规模和应用部署规模在短时间内十倍百倍增长。 13 | - 促销、季节性、节假日带来的访问量波动。 14 | - 高峰时间段的突发流量等。 15 | - **敏捷**(Agility):快速响应市场需求。 16 | - **成本**(Cost):充分有效的利用资源。 17 | 18 | 这 4 个核心目标之间,存在彼此冲突的情况,如图 1-13 所示。 19 | 20 | :::center 21 | ![](../assets/cloud-native-goals-2.png)
22 | 图 1-13 云原生关键目标冲突关系 23 | ::: 24 | 25 | - 规模和敏捷之间的冲突:**规模大而又要求敏捷**,我们比喻为“巨人绣花”。 26 | - 规模和可用性之间的冲突:**规模大而要求可用性高**,我们比喻为“大象起舞”。 27 | - 敏捷和可用性之间的冲突:**敏捷而要求高可用**,我们比喻为“空中换发”。 28 | 29 | 而云原生架构必须要在**同时满足这 3 个彼此冲突目标的前提下,还要实现成本控制**。 30 | 31 | 知晓云原生目标之后,接下来探讨利用云原生技术实现这 4 个核心目标。 -------------------------------------------------------------------------------- /assets/2021-02-secrets-management.svg: -------------------------------------------------------------------------------- 1 | CNCF Technology RadarSecret Management, February 2021ASSESSGCP SecretsManagementSopsTRIALBitnami SealedSecretsEncryptedrepositoriesADOPTcert-managerAWS SecretsManagerHashicorpVaultAWS KMS -------------------------------------------------------------------------------- /assets/6-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/6-b.png -------------------------------------------------------------------------------- /assets/Ambient-Mesh-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Ambient-Mesh-2.png -------------------------------------------------------------------------------- /assets/Ambient-Mesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Ambient-Mesh.png -------------------------------------------------------------------------------- /assets/Borg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Borg.jpeg -------------------------------------------------------------------------------- /assets/CI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/CI.png -------------------------------------------------------------------------------- /assets/CNI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/CNI.png -------------------------------------------------------------------------------- /assets/CNI.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/CNI.webp -------------------------------------------------------------------------------- /assets/CRD.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/CRD.webp -------------------------------------------------------------------------------- /assets/CSI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/CSI.png -------------------------------------------------------------------------------- /assets/ClickHouse-benchmark.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ClickHouse-benchmark.jpeg -------------------------------------------------------------------------------- /assets/Cluster-AutoScaler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Cluster-AutoScaler.png -------------------------------------------------------------------------------- /assets/Dapper-trace-span.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Dapper-trace-span.png -------------------------------------------------------------------------------- /assets/Device-plugin.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Device-plugin.webp -------------------------------------------------------------------------------- /assets/ELK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ELK.png -------------------------------------------------------------------------------- /assets/Flannel-UDP-TUN.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Flannel-UDP-TUN.webp -------------------------------------------------------------------------------- /assets/Flannel-UDP.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Flannel-UDP.webp -------------------------------------------------------------------------------- /assets/Immutable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Immutable.png -------------------------------------------------------------------------------- /assets/JuiceFS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/JuiceFS.png -------------------------------------------------------------------------------- /assets/Monitoring-vs-Observability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Monitoring-vs-Observability.png -------------------------------------------------------------------------------- /assets/Monolith-vs-MicroService.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Monolith-vs-MicroService.png -------------------------------------------------------------------------------- /assets/OAM-how-it-works.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/OAM-how-it-works.png -------------------------------------------------------------------------------- /assets/OAM.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/OAM.jpg -------------------------------------------------------------------------------- /assets/OCSP-Stapling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/OCSP-Stapling.png -------------------------------------------------------------------------------- /assets/Pinpoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Pinpoint.png -------------------------------------------------------------------------------- /assets/RDMA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/RDMA.png -------------------------------------------------------------------------------- /assets/Replicated-state-machine.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Replicated-state-machine.webp -------------------------------------------------------------------------------- /assets/RoCE_Header_format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/RoCE_Header_format.png -------------------------------------------------------------------------------- /assets/ServiceMesh-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ServiceMesh-summary.png -------------------------------------------------------------------------------- /assets/SoftwareEatingTheWorld.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/SoftwareEatingTheWorld.jpg -------------------------------------------------------------------------------- /assets/SpringCloud.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/SpringCloud.webp -------------------------------------------------------------------------------- /assets/VXLAN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/VXLAN.png -------------------------------------------------------------------------------- /assets/Volcano-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/Volcano-arch.png -------------------------------------------------------------------------------- /assets/active_and_passive_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/active_and_passive_arch.png -------------------------------------------------------------------------------- /assets/agile-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/agile-model.png -------------------------------------------------------------------------------- /assets/agile-word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/agile-word.png -------------------------------------------------------------------------------- /assets/ambient-layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ambient-layers.png -------------------------------------------------------------------------------- /assets/ambient-mesh-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ambient-mesh-arch.png -------------------------------------------------------------------------------- /assets/application-centric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/application-centric.png -------------------------------------------------------------------------------- /assets/argocd-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/argocd-demo.png -------------------------------------------------------------------------------- /assets/argocd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/argocd.png -------------------------------------------------------------------------------- /assets/argocd_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/argocd_architecture.png -------------------------------------------------------------------------------- /assets/artifact-hub.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/artifact-hub.jpg -------------------------------------------------------------------------------- /assets/balance-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/balance-summary.png -------------------------------------------------------------------------------- /assets/basic-paxos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/basic-paxos.png -------------------------------------------------------------------------------- /assets/bbr-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/bbr-2.png -------------------------------------------------------------------------------- /assets/bbr-cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/bbr-cc.png -------------------------------------------------------------------------------- /assets/bbr-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/bbr-status.png -------------------------------------------------------------------------------- /assets/bbr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/bbr.png -------------------------------------------------------------------------------- /assets/bench_tcp_crr_32_processes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/bench_tcp_crr_32_processes.png -------------------------------------------------------------------------------- /assets/bench_tcp_crr_32_processes_cpu (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/bench_tcp_crr_32_processes_cpu (1).png -------------------------------------------------------------------------------- /assets/bench_tcp_crr_32_processes_cpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/bench_tcp_crr_32_processes_cpu.png -------------------------------------------------------------------------------- /assets/bench_tcp_stream_32_streams_cpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/bench_tcp_stream_32_streams_cpu.png -------------------------------------------------------------------------------- /assets/borg-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/borg-arch.png -------------------------------------------------------------------------------- /assets/brotli.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/brotli.jpeg -------------------------------------------------------------------------------- /assets/brotli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/brotli.png -------------------------------------------------------------------------------- /assets/cap-theorem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cap-theorem.png -------------------------------------------------------------------------------- /assets/cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cc.png -------------------------------------------------------------------------------- /assets/cd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cd.png -------------------------------------------------------------------------------- /assets/chroot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/chroot.png -------------------------------------------------------------------------------- /assets/cicd-push.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cicd-push.png -------------------------------------------------------------------------------- /assets/cicd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cicd.png -------------------------------------------------------------------------------- /assets/cilium-istio-benchmark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cilium-istio-benchmark.webp -------------------------------------------------------------------------------- /assets/cloud-history-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cloud-history-2.png -------------------------------------------------------------------------------- /assets/cloud-history-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cloud-history-3.png -------------------------------------------------------------------------------- /assets/cloud-native-goals-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cloud-native-goals-2.png -------------------------------------------------------------------------------- /assets/cloud-native-goals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cloud-native-goals.png -------------------------------------------------------------------------------- /assets/cloud-native.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cloud-native.png -------------------------------------------------------------------------------- /assets/cloud-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cloud-summary.png -------------------------------------------------------------------------------- /assets/cloudflare-dns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cloudflare-dns.png -------------------------------------------------------------------------------- /assets/cncf-observability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cncf-observability.png -------------------------------------------------------------------------------- /assets/cni-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cni-plugin.png -------------------------------------------------------------------------------- /assets/column-database.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/column-database.png -------------------------------------------------------------------------------- /assets/compress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/compress.png -------------------------------------------------------------------------------- /assets/conntrack-nat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/conntrack-nat.png -------------------------------------------------------------------------------- /assets/conntrack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/conntrack.png -------------------------------------------------------------------------------- /assets/consensus-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/consensus-summary.png -------------------------------------------------------------------------------- /assets/consensus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/consensus.png -------------------------------------------------------------------------------- /assets/container-2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/container-2.jpeg -------------------------------------------------------------------------------- /assets/container-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/container-summary.png -------------------------------------------------------------------------------- /assets/containerd-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/containerd-arch.png -------------------------------------------------------------------------------- /assets/containerd-built-in-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/containerd-built-in-plugin.png -------------------------------------------------------------------------------- /assets/containerd-cri.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/containerd-cri.png -------------------------------------------------------------------------------- /assets/cri-arc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cri-arc.png -------------------------------------------------------------------------------- /assets/cri-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/cri-architecture.png -------------------------------------------------------------------------------- /assets/csi-k8s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/csi-k8s.png -------------------------------------------------------------------------------- /assets/custom-chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/custom-chain.png -------------------------------------------------------------------------------- /assets/dapper-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/dapper-log.png -------------------------------------------------------------------------------- /assets/definition-cap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/definition-cap.png -------------------------------------------------------------------------------- /assets/deployment-controller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/deployment-controller.png -------------------------------------------------------------------------------- /assets/device-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/device-plugin.png -------------------------------------------------------------------------------- /assets/devops-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/devops-2.jpg -------------------------------------------------------------------------------- /assets/devops-wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/devops-wall.png -------------------------------------------------------------------------------- /assets/devops.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/devops.jpeg -------------------------------------------------------------------------------- /assets/distributed-transaction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/distributed-transaction.png -------------------------------------------------------------------------------- /assets/dns-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/dns-1.png -------------------------------------------------------------------------------- /assets/dns-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/dns-2.png -------------------------------------------------------------------------------- /assets/dns-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/dns-example.png -------------------------------------------------------------------------------- /assets/dns-tree.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/dns-tree.webp -------------------------------------------------------------------------------- /assets/docker-arc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/docker-arc.png -------------------------------------------------------------------------------- /assets/docker-file-system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/docker-file-system.png -------------------------------------------------------------------------------- /assets/docker-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/docker-image.png -------------------------------------------------------------------------------- /assets/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/docker.png -------------------------------------------------------------------------------- /assets/dockerfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/dockerfile.png -------------------------------------------------------------------------------- /assets/dpdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/dpdk.png -------------------------------------------------------------------------------- /assets/dpvs-performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/dpvs-performance.png -------------------------------------------------------------------------------- /assets/dragonfly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/dragonfly.png -------------------------------------------------------------------------------- /assets/dsa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/dsa.png -------------------------------------------------------------------------------- /assets/ebpf-go.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ebpf-go.webp -------------------------------------------------------------------------------- /assets/ebpf.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ebpf.webp -------------------------------------------------------------------------------- /assets/ecc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ecc.png -------------------------------------------------------------------------------- /assets/envoy-resource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/envoy-resource.png -------------------------------------------------------------------------------- /assets/es-vs-clickhouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/es-vs-clickhouse.png -------------------------------------------------------------------------------- /assets/facebook-404-error.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/facebook-404-error.jpeg -------------------------------------------------------------------------------- /assets/flagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/flagger.png -------------------------------------------------------------------------------- /assets/four-metrics-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/four-metrics-type.png -------------------------------------------------------------------------------- /assets/github-tekton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/github-tekton.png -------------------------------------------------------------------------------- /assets/gitops-workflow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/gitops-workflow.webp -------------------------------------------------------------------------------- /assets/global-lb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/global-lb.png -------------------------------------------------------------------------------- /assets/grafana-dashboard-english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/grafana-dashboard-english.png -------------------------------------------------------------------------------- /assets/helm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/helm.webp -------------------------------------------------------------------------------- /assets/how_mtls_works-what_is_mutual_tls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/how_mtls_works-what_is_mutual_tls.png -------------------------------------------------------------------------------- /assets/how_tls_works.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/how_tls_works.png -------------------------------------------------------------------------------- /assets/http-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/http-process.png -------------------------------------------------------------------------------- /assets/http-quic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/http-quic.png -------------------------------------------------------------------------------- /assets/http-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/http-summary.png -------------------------------------------------------------------------------- /assets/http3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/http3.png -------------------------------------------------------------------------------- /assets/httpdns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/httpdns.png -------------------------------------------------------------------------------- /assets/https-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/https-1.png -------------------------------------------------------------------------------- /assets/https-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/https-2.png -------------------------------------------------------------------------------- /assets/https-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/https-3.png -------------------------------------------------------------------------------- /assets/https-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/https-4.png -------------------------------------------------------------------------------- /assets/https-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/https-5.png -------------------------------------------------------------------------------- /assets/id-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/id-service.png -------------------------------------------------------------------------------- /assets/iptables-chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/iptables-chain.png -------------------------------------------------------------------------------- /assets/iptables-vs-ipvs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/iptables-vs-ipvs.png -------------------------------------------------------------------------------- /assets/iptables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/iptables.png -------------------------------------------------------------------------------- /assets/k8s-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/k8s-1.png -------------------------------------------------------------------------------- /assets/k8s-chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/k8s-chain.png -------------------------------------------------------------------------------- /assets/k8s-cri-o.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/k8s-cri-o.png -------------------------------------------------------------------------------- /assets/k8s-cri.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/k8s-cri.png -------------------------------------------------------------------------------- /assets/k8s-metadata.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/k8s-metadata.jpeg -------------------------------------------------------------------------------- /assets/k8s-runtime-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/k8s-runtime-v2.png -------------------------------------------------------------------------------- /assets/k8s-runtime-v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/k8s-runtime-v3.png -------------------------------------------------------------------------------- /assets/k8s-selector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/k8s-selector.png -------------------------------------------------------------------------------- /assets/k8s-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/k8s-service.png -------------------------------------------------------------------------------- /assets/k8s-sidecar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/k8s-sidecar.png -------------------------------------------------------------------------------- /assets/kaniko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/kaniko.png -------------------------------------------------------------------------------- /assets/kata-container-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/kata-container-diff.png -------------------------------------------------------------------------------- /assets/kata-container.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/kata-container.jpeg -------------------------------------------------------------------------------- /assets/kata-container.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/kata-container.jpg -------------------------------------------------------------------------------- /assets/kata-container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/kata-container.png -------------------------------------------------------------------------------- /assets/keda-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/keda-arch.png -------------------------------------------------------------------------------- /assets/kube-scheduler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/kube-scheduler.png -------------------------------------------------------------------------------- /assets/kubelet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/kubelet.png -------------------------------------------------------------------------------- /assets/kubernetes-container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/kubernetes-container.png -------------------------------------------------------------------------------- /assets/kubernetes_operator.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/kubernetes_operator.webp -------------------------------------------------------------------------------- /assets/kubevela.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/kubevela.jpg -------------------------------------------------------------------------------- /assets/l4-connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/l4-connection.png -------------------------------------------------------------------------------- /assets/l7-lb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/l7-lb.png -------------------------------------------------------------------------------- /assets/l7-lb.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/l7-lb.webp -------------------------------------------------------------------------------- /assets/label.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/label.png -------------------------------------------------------------------------------- /assets/label2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/label2.png -------------------------------------------------------------------------------- /assets/landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/landscape.png -------------------------------------------------------------------------------- /assets/latency-200rps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/latency-200rps.png -------------------------------------------------------------------------------- /assets/lb-via-client-lib.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/lb-via-client-lib.webp -------------------------------------------------------------------------------- /assets/lb-via-sidecar.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/lb-via-sidecar.webp -------------------------------------------------------------------------------- /assets/linkerd-control-plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/linkerd-control-plane.png -------------------------------------------------------------------------------- /assets/linkerd-envoy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/linkerd-envoy.png -------------------------------------------------------------------------------- /assets/linkerd-resource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/linkerd-resource.png -------------------------------------------------------------------------------- /assets/linux-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/linux-summary.png -------------------------------------------------------------------------------- /assets/loadbalancer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/loadbalancer.png -------------------------------------------------------------------------------- /assets/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/lock.png -------------------------------------------------------------------------------- /assets/log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/log.png -------------------------------------------------------------------------------- /assets/logging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/logging.png -------------------------------------------------------------------------------- /assets/loki-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/loki-arch.png -------------------------------------------------------------------------------- /assets/loki-dashboard.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/loki-dashboard.jpeg -------------------------------------------------------------------------------- /assets/loud-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/loud-summary.png -------------------------------------------------------------------------------- /assets/lua-cpu-flame-graph.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/lua-cpu-flame-graph.webp -------------------------------------------------------------------------------- /assets/macvlan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/macvlan.png -------------------------------------------------------------------------------- /assets/mesh3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/mesh3.png -------------------------------------------------------------------------------- /assets/mesos-arch.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/mesos-arch.jpeg -------------------------------------------------------------------------------- /assets/micro-service-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/micro-service-1.png -------------------------------------------------------------------------------- /assets/micro-service-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/micro-service-2.png -------------------------------------------------------------------------------- /assets/monitoring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/monitoring.png -------------------------------------------------------------------------------- /assets/multi_paxos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/multi_paxos.png -------------------------------------------------------------------------------- /assets/nat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/nat.png -------------------------------------------------------------------------------- /assets/network-lb-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/network-lb-overview.png -------------------------------------------------------------------------------- /assets/network-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/network-summary.png -------------------------------------------------------------------------------- /assets/nginx-conf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/nginx-conf.png -------------------------------------------------------------------------------- /assets/nydus-performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/nydus-performance.png -------------------------------------------------------------------------------- /assets/nydus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/nydus.png -------------------------------------------------------------------------------- /assets/oam_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/oam_model.png -------------------------------------------------------------------------------- /assets/observability-knowns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/observability-knowns.png -------------------------------------------------------------------------------- /assets/observability.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/observability.jpg -------------------------------------------------------------------------------- /assets/observability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/observability.png -------------------------------------------------------------------------------- /assets/opentracing-vs-opencensus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/opentracing-vs-opencensus.jpg -------------------------------------------------------------------------------- /assets/operatorhub.io.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/operatorhub.io.png -------------------------------------------------------------------------------- /assets/overfs.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/overfs.jpeg -------------------------------------------------------------------------------- /assets/overlay-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/overlay-network.png -------------------------------------------------------------------------------- /assets/overlay.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/overlay.jpeg -------------------------------------------------------------------------------- /assets/overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/overlay.png -------------------------------------------------------------------------------- /assets/overlay_constructs.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/overlay_constructs.webp -------------------------------------------------------------------------------- /assets/paxos-conflict-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos-conflict-2.png -------------------------------------------------------------------------------- /assets/paxos-conflict3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos-conflict3.png -------------------------------------------------------------------------------- /assets/paxos-liveness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos-liveness.png -------------------------------------------------------------------------------- /assets/paxos-p1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos-p1.png -------------------------------------------------------------------------------- /assets/paxos-p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos-p2.png -------------------------------------------------------------------------------- /assets/paxos-p3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos-p3.png -------------------------------------------------------------------------------- /assets/paxos-p4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos-p4.png -------------------------------------------------------------------------------- /assets/paxos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos.png -------------------------------------------------------------------------------- /assets/paxos_2pc_choice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos_2pc_choice.png -------------------------------------------------------------------------------- /assets/paxos_conflict_choices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos_conflict_choices.png -------------------------------------------------------------------------------- /assets/paxos_split_votes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/paxos_split_votes.png -------------------------------------------------------------------------------- /assets/ppt4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ppt4.jpg -------------------------------------------------------------------------------- /assets/prometheus-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/prometheus-arch.png -------------------------------------------------------------------------------- /assets/prometheus-exporter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/prometheus-exporter.png -------------------------------------------------------------------------------- /assets/prometheus-storage.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/prometheus-storage.jpeg -------------------------------------------------------------------------------- /assets/pvc-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/pvc-flow.png -------------------------------------------------------------------------------- /assets/qos.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/qos.webp -------------------------------------------------------------------------------- /assets/qrcode-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/qrcode-v2.png -------------------------------------------------------------------------------- /assets/quic-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/quic-1.png -------------------------------------------------------------------------------- /assets/quic-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/quic-3.png -------------------------------------------------------------------------------- /assets/quic-connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/quic-connection.png -------------------------------------------------------------------------------- /assets/quic-handshake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/quic-handshake.png -------------------------------------------------------------------------------- /assets/quic-head-block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/quic-head-block.png -------------------------------------------------------------------------------- /assets/quorum-base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/quorum-base.png -------------------------------------------------------------------------------- /assets/raft-ConfChange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/raft-ConfChange.png -------------------------------------------------------------------------------- /assets/raft-log-commit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/raft-log-commit.png -------------------------------------------------------------------------------- /assets/raft-single-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/raft-single-server.png -------------------------------------------------------------------------------- /assets/raft-state-machine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/raft-state-machine.png -------------------------------------------------------------------------------- /assets/requests-limits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/requests-limits.png -------------------------------------------------------------------------------- /assets/rootfs-1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/rootfs-1.jpeg -------------------------------------------------------------------------------- /assets/row-database.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/row-database.png -------------------------------------------------------------------------------- /assets/runtime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/runtime.png -------------------------------------------------------------------------------- /assets/scheduling-framework-extensions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/scheduling-framework-extensions.png -------------------------------------------------------------------------------- /assets/service-mesh-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/service-mesh-2.png -------------------------------------------------------------------------------- /assets/service-mesh-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/service-mesh-3.png -------------------------------------------------------------------------------- /assets/service-mesh-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/service-mesh-4.png -------------------------------------------------------------------------------- /assets/service-mesh-kernel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/service-mesh-kernel.jpg -------------------------------------------------------------------------------- /assets/service-mesh-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/service-mesh-overview.png -------------------------------------------------------------------------------- /assets/service-mesh-tcp-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/service-mesh-tcp-1.png -------------------------------------------------------------------------------- /assets/service-mesh-tcp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/service-mesh-tcp.png -------------------------------------------------------------------------------- /assets/service-mesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/service-mesh.png -------------------------------------------------------------------------------- /assets/servicemesh-sidecar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/servicemesh-sidecar.png -------------------------------------------------------------------------------- /assets/servicemesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/servicemesh.png -------------------------------------------------------------------------------- /assets/sidecar-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/sidecar-example.jpg -------------------------------------------------------------------------------- /assets/sidecarless.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/sidecarless.png -------------------------------------------------------------------------------- /assets/skywalking-ui.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/skywalking-ui.jpeg -------------------------------------------------------------------------------- /assets/ssl-domain-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ssl-domain-info.png -------------------------------------------------------------------------------- /assets/ssl-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/ssl-test.png -------------------------------------------------------------------------------- /assets/star-history-20231218.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/star-history-20231218.png -------------------------------------------------------------------------------- /assets/swarm-diagram.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/swarm-diagram.webp -------------------------------------------------------------------------------- /assets/tekton-dashboard-ui.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/tekton-dashboard-ui.jpeg -------------------------------------------------------------------------------- /assets/tls1.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/tls1.2.png -------------------------------------------------------------------------------- /assets/tls1.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/tls1.3.png -------------------------------------------------------------------------------- /assets/tracing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/tracing.png -------------------------------------------------------------------------------- /assets/types-of-encryption-asymmetric-encryption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/types-of-encryption-asymmetric-encryption.png -------------------------------------------------------------------------------- /assets/types-of-encryption-symmetric-encryption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/types-of-encryption-symmetric-encryption.png -------------------------------------------------------------------------------- /assets/types-of-mounts-volume.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/types-of-mounts-volume.webp -------------------------------------------------------------------------------- /assets/uber-microservice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/uber-microservice.png -------------------------------------------------------------------------------- /assets/volume-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/volume-list.png -------------------------------------------------------------------------------- /assets/vxlan-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/vxlan-data.png -------------------------------------------------------------------------------- /assets/vxlan_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/vxlan_header.png -------------------------------------------------------------------------------- /assets/what-is-kubevela.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/what-is-kubevela.jpg -------------------------------------------------------------------------------- /assets/www.thebyte.com.cn_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/www.thebyte.com.cn_.png -------------------------------------------------------------------------------- /assets/xdp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isno/theByteBook/2a6979be06d968db9061ca5172ee32650fc7109f/assets/xdp.png -------------------------------------------------------------------------------- /balance/balance-features.md: -------------------------------------------------------------------------------- 1 | # 4.2 负载均衡器总体功能 2 | 3 | 现代负载均衡器的功能已远超其初衷。本节将简要介绍负载均衡器的常见功能,以帮助读者对其有个整体性的认识。 4 | 5 | ## 4.2.1 服务发现 6 | 7 | 服务发现是负载均衡器识别后端服务器的一种机制,不同的实现方式差异较大,以下是几种常见的实现方式: 8 | 9 | - **静态配置文件**:通过手动维护配置来实现基础的服务发现。 10 | - **DNS**:将后端服务器的 IP 地址以 SRV 记录或 A 记录形式注册到 DNS 服务器,客户端查询 DNS 记录来获取后端服务器的 IP 地址。 11 | - **服务注册中心**(如 Zookeeper、Etcd、Consul 等):后端服务器启动时将服务名称、地址、端口及健康检查信息注册到这些系统中。客户端通过查询 API 获取服务信息。这些系统通常内置健康检查机制,定期监控服务状态,并自动更新服务列表。 12 | - **服务网格领域的数据平面 API**:提供标准化的数据平面接口(xDS 协议),支持跨平台、跨环境的服务发现(详见本书第八章 8.3 节)。 13 | 14 | ## 4.2.2 健康检查 15 | 16 | 健康检查用于评估后端服务器是否能够正常处理请求,识别不可用的服务器并将流量重新分配。健康检查有两种方式: 17 | 18 | - **主动健康检查**:负载均衡器定期向后端发送健康探测请求,根据响应状态判断后端服务器是否健康。例如,某些七层负载均衡器会请求特定的健康检查路径(如 /health 或 /status),通过 HTTP 状态码来判断后端服务的健康状态。 19 | - **被动健康检查**:负载均衡器通过持续监控请求、响应和连接的状态,分析异常情况来判断后端服务器的健康状态。如果在一段时间内发现某个后端出现多次连接失败或超时等问题,负载均衡器会将该后端标记为不健康。 20 | 21 | ## 4.2.3 粘性会话 22 | 23 | 对于某些特定应用,确保属于同一会话的请求被路由到相同的后端服务器至关重要。 24 | 25 | 会话的定义因业务而异,可能基于 HTTP cookies、客户端地址、请求头或其他相关属性来确定。大部分七层负载均衡器支持通过配置 HTTP cookies 或 IP 哈希来实现“粘性会话”(sticky session)。 26 | 27 | 值得注意的是,粘性会话涉及缓存、临时状态管理,实现粘性会话的设计通常很脆弱(赖于特定服务器、无法动态扩展、不可预测的负载分配问题等)。一旦处理会话的后端出现故障,整个服务都会受到影响。因此,设计具有该特性的系统时,需要格外谨慎! 28 | 29 | ## 4.2.4 TLS 卸载 30 | 31 | TLS 卸载(TLS Termination)是指将 TLS 加密/解密、证书管理等操作由负载均衡器统一处理。这样做的好处是: 32 | 33 | - **减轻后端负载**:后端服务器无需处理加密/解密操作,可以专注于业务逻辑处理。 34 | - **减少运维负担**:负载均衡器集中管理 SSL 证书的配置和更新,避免每个后端服务器单独管理证书。 35 | - **提升请求效率**:负载均衡器通常具备硬件加速能力,并经过优化,能更高效地处理 TLS 连接(详见本书第二章 2.5.2 节)。 36 | 37 | ## 4.2.5 安全和 DDoS 防御 38 | 39 | 作为集群的唯一入口,负载均衡器不仅是流量的调度中心,也是系统安全的第一道防线。 40 | 41 | 负载均衡器可以作为访问控制点,拦截来自不受信任的来源的请求,防止恶意流量进入内部系统。此外,负载均衡器可以通过部署 IP 黑/白名单、流量限速、请求鉴权等功能,强化对外部攻击的防护能力。 42 | 43 | 另一方面,负载均衡器通过支持高级安全功能(如 SSL/TLS 终端加密和 Web 应用防火墙)进一步增强了系统的安全性。在面临 DDoS 攻击时,负载均衡器能够通过流量分散、智能限速等手段,有效减轻攻击压力,保护内部资源不受影响。 44 | 45 | ## 4.2.6 可观测性 46 | 47 | 从基本的统计信息(如流量、连接数和错误率)到与微服务架构集成的调用链追踪,不同层次的负载均衡器输出的可观测性数据各异: 48 | 49 | - 四层负载均衡器的观测数据集中在连接、流量、延迟等网络层面的分析。 50 | - 七层负载均衡器的观测数据集中在 HTTP 请求、HTTP 错误码、会话保持、路由分配等应用层面的分析。 51 | 52 | 需要注意的是,输出可观测性数据并非没有代价,负载均衡器需要进行额外处理来生成这些数据,但所带来的收益远超过那一点性能损失。 53 | 54 | ## 4.2.7 负载均衡 55 | 56 | 负载均衡器字面意思是,给到一组健康的后端,选择谁来处理用户请求?也就是负载均衡器的调度算法。 57 | 58 | 负载均衡调度算法是一个相对活跃的研究领域,从简单的随机选择,到更复杂的考虑各种延迟和后端负载状态的算法,笔者无法逐一展开,这里仅从功能和应用的角度简要介绍一些常见的负载均衡算法。 59 | 60 | - **轮询均衡算法**(Round-Robin):按依次循环的方式将请求调度到不同的服务器上,该算法最大的特点是实现简单。轮询算法假设所有的服务器处理请求的能力都一样,调度器会将所有的请求平均分配给每个真实服务器。 61 | 62 | - **最小连接均衡算法**(Least-Connection):该算法中调度器需要记录各个服务器已建立连接的数量,然后把新的连接请求分配到当前连接数最小的服务器。 63 | 64 | 最小连接均衡算法特别适合于服务器处理时间不一致的场景。例如,当某些请求可能占用较长时间,而另一些请求很快就会完成时,最小连接算法可以有效避免某些服务器因处理大量复杂请求而过载。 65 | 66 | - **一致性哈希均衡算法**(Consistency Hash):将请求中的某些特征数据(例如 IP、MAC 或者更上层应用的某些信息)作为特征值来计算需要落在的节点。一致性哈希算法会保证同一个特征值的请求每一次都会落在相同的服务器上。 67 | 68 | - **随机均衡算法**(Random):此种负载均衡算法类似于轮询调度,不过在分配处理请求时是随机的过程。由概率论可以得知,随着客户端调用服务端的次数增多,其实际效果趋近于平均分配请求到服务端的每一台服务器,也就是达到轮询的效果。 69 | 70 | 以上算法假设的是所有服务器处理能力均相等,并不管服务器的负荷和响应速度。如果集群内各个服务器处理能力不一致呢?如服务器 A 每秒可处理 10 个请求,服务器 B 每秒可处理 100 个请求,不考虑服务器的处理能力的负载均衡算法,实际上是一种“伪均衡”算法。 71 | 72 | 考虑各个服务器的处理能力存在差异,负载均衡算法又有了对服务器“**加权**”的补充。 73 | 74 | 加权负载均衡算法通过按权值高低分配请求,使权重较高的服务器处理更多连接,从而保证集群内后端服务器的负荷整体均衡。常用的加权负载均衡算法有加权轮询(Weighted Round Robin)、加权最小连接(Weighted Least-Connection)和加权随机(Weighted Random)等等,笔者就不再逐一介绍了。 75 | -------------------------------------------------------------------------------- /balance/balance-topology.md: -------------------------------------------------------------------------------- 1 | # 4.3 负载均衡部署拓扑 2 | 3 | 本节将介绍四种负载均衡部署拓扑,不同的部署拓扑决定了流量如何被分配、如何实现冗余和高可用性,进而影响系统的性能、可扩展性和容错能力。 4 | 5 | ## 4.3.1 中间代理型 6 | 7 | 第一种是中间代理型部署拓扑,如图 4-5 所示。这是最常见的负载均衡部署方式,负载均衡器位于客户端与后端服务器之间,负责将请求转发至多个后端服务器。 8 | 9 | 在这种拓扑中,负载均衡器可以分为以下三类: 10 | 11 | - 硬件设备:由 Cisco、Juniper、F5 Networks 等公司提供的硬件负载均衡设备; 12 | - 纯软件:如 Nginx、HAProxy、Envoy 和 Traefik 等开源软件负载均衡器; 13 | - 云服务:包括阿里云的 SLB(Server Load Balancer)、AWS 的 ELB(Elastic Load Balancer)、Azure 的 Load Balancer 和 Google Cloud 的 Cloud Load Balancing 等云平台提供的负载均衡服务。 14 | 15 | 总结中间代理型优缺点: 16 | - 优点:配置简便,用户只需通过 DNS 连接到负载均衡器,无需关心后端细节,使用体验简单直观; 17 | - 缺点:存在单点故障的风险,负载均衡器一旦出现故障,会导致整个系统无法访问。 18 | 19 | :::center 20 | ![](../assets/balancer.svg)
21 | 图 4-5 中间代理型 22 | ::: 23 | 24 | ## 6.3.2 边缘代理型 25 | 26 | 边缘代理型实际上是中间代理型拓扑的一个变种。 27 | 28 | 一个典型的边缘代理示例是本书第二章 2.7 节中提到的动态请求‘加速’技术。Akamai 在全球多个数据中心部署边缘节点,这些节点具备代理功能,用户请求会被路由至最近的节点。收到请求后,边缘节点会执行安全检查(如 DDoS 防护),根据缓存策略决定是返回缓存内容(CDN 技术),或者将请求转发至源服务器(请求加速技术)。 29 | 30 | 总结边缘代理型优缺点: 31 | - 优点:通过将负载均衡、缓存和安全策略集中在网络边缘,边缘代理显著降低延迟、提高响应速度,并增强安全性(如 DDoS 防护); 32 | - 缺点:虽然边缘代理减少了单点故障的风险,但若某个边缘节点发生故障,仍会影响到该节点服务的用户。 33 | 34 | :::center 35 | ![](../assets/balancer-edge-proxy.svg)
36 | 图 4-6 网络边缘型 37 | ::: 38 | 39 | ## 4.3.3 客户端内嵌 40 | 41 | 为解决中间代理型拓扑的单点故障问题,出现了更复杂的解决方案,其中之一是将负载均衡器以 SDK 库形式嵌入客户端(如图 4-7 所示)。这些 SDK 库如 Finagle、Eureka、Ribbon 和 Hystrix 等,它们优缺点是: 42 | 43 | - 优点:将负载均衡器功能“转移”至客户端,避免了单点故障问题; 44 | - 缺点:需要为每种编程语言实现相应的 SDK,且在项目复杂时,处理版本依赖和兼容性问题变得棘手(微服务框架的相关问题将在本书第八章 8.2 节中详细讨论,读者可参考进一步了解)。 45 | 46 | :::center 47 | ![](../assets/balancer-sdk.svg)
48 | 图 4-7 客户端内嵌型 49 | ::: 50 | 51 | ## 4.3.4 边车代理型 52 | 53 | 边车代理型拓扑近年来在微服务架构中得到广泛应用,并发展成为一种被称为“服务网格”(Service Mesh)的架构模式。 54 | 55 | 边车代理的基本原理是在应用容器或服务旁边部署一个独立的代理容器,用于实现请求的负载均衡和流量管理。目前,像 Envoy 和 Linkerd 等网络型边车代理已被广泛应用。关于服务网格的技术原理,笔者将在第八章中进行详细阐述。 56 | 57 | :::center 58 | ![](../assets/balancer-sidecar.svg)
59 | 图 4-8 边车代理型 60 | ::: 61 | 62 | 总体而言,中间代理型负载均衡器正逐步演变为功能更强大的“网关”,所有请求通过单一入口(即网关)进入集群。在这种架构下,负载均衡器作为网关,不仅负责基本的请求转发,还承担更高级的请求管理与安全控制,包括 TLS 卸载、请求限制、身份验证和复杂内容路由等。同时,针对东西向流量(即服务间通信),边车代理模式“透明”地接管了服务间的通信治理,正逐渐成为主流选择。 -------------------------------------------------------------------------------- /balance/balance.md: -------------------------------------------------------------------------------- 1 | # 4.1 负载均衡与代理 2 | 3 | 在讨论负载均衡时,"负载均衡器"(Load Balancer)和"代理"(Proxy)这两个术语常被混用。严格来说,并非所有代理都属于负载均衡器,但大多数代理的核心功能都涵盖负载均衡。为了简化表述,本文将这两个术语视为大致等同,不作严格区分。 4 | 5 | 图 4-1 展示了负载均衡高层架构图,客户端(Client)的请求通过负载均衡器(Load Balancer)转发至某个后端服务器(Backend)。从整体架构来看,负载均衡器承担以下职责: 6 | 7 | - **服务发现**:识别系统中可用的后端服务器,并获取它们的地址,以便与后端进行通信。 8 | - **健康检查**:监测后端服务器的状态,确保只有健康的服务器能够接收请求。 9 | - **负载均衡**:根据适合的分配算法,将请求均匀分配到健康的后端服务器上,提高系统的整体性能与可靠性。 10 | 11 | :::center 12 | ![](../assets/balancer.svg)
13 | 图 4-1 负载均衡高层架构图 14 | ::: 15 | 16 | 合理使用负载均衡能为分布式系统带来多方面的好处: 17 | 18 | - **命名抽象**:客户端通过统一的访问机制(如 DNS 或内置库)连接到负载均衡器,无需关心后端服务器的拓扑结构或配置细节。 19 | - **容错能力**:通过健康检查和负载均衡算法,将请求分配至正常运行的后端服务器。故障服务器会被自动移出负载均衡池,为运维人员提供足够的修复窗口。 20 | - **成本和性能收益**:后端服务器通常分布在多个网络区域(Zone/Region),负载均衡器根据策略将请求保持在同一网络区域内,从而提高服务性能(减少延迟)并降低资源成本(减少跨区域带宽费用)。 21 | 22 | 从网络层次的角度来看,所有负载均衡器可以分为两类:四层负载均衡和七层负载均衡,分别对应 OSI 模型的第四层(传输层)和第七层(应用层)。 23 | ## 4.1.1 四层负载均衡 24 | 25 | 需要注意的是,所谓的“四层负载均衡”并非严格限定于 OSI 模型的第四层(传输层)。实际上,它的工作模式涉及多个网络层次: 26 | - **第二层**(数据链路层):通过修改帧头中的 MAC 地址,将请求从一个物理网络节点转发到另一个节点。这种方式通常用于同一广播域内的转发,例如交换机或桥接设备完成的二层转发操作。 27 | - **第三层**(网络层):通过修改 IP 地址,实现跨子网的请求路由和转发。这是路由器的核心功能,通过修改数据包的源或目的 IP 地址,实现子网之间的通信和流量转发。 28 | - **第四层**(传输层):通过修改 TCP/UDP 端口号或连接的目标地址,利用网络地址转换(NAT)技术隐藏内部网络结构,将请求从一个入口转发至多个后端服务。 29 | 30 | 如图 4-2 所示,上述各个网络层次的共同特点是维持了传输层协议(如 TCP、UDP)的连接特性。如果读者在其他资料中看到“二层负载均衡”或“三层负载均衡”的说法,应该理解到这是负载均衡器在不同网络层次上的工作模式。 31 | 32 | :::center 33 | ![](../assets/balancer4.svg)
34 | 图 4-2 四层负载均衡器“转发”客户端的 TCP 连接 35 | ::: 36 | 37 | 典型情况下,四层负载均衡器处理的是 TCP、UDP 等连接协议,它并不关心传输字节所代表的具体应用内容,这些字节可能来自 Web 应用、数据库服务或其他网络服务。因此,四层负载均衡器具有广泛的应用范围,能够适应各种不同类型的网络服务。 38 | 39 | 由于建立连接的开销较大(例如 TCP 三次握手,尤其在启用 TLS 加密时),许多网络协议(如 TCP、HTTP/2、QUIC 和 WebSockets)在演进过程中逐步引入了“多路复用”(multiplexing)和“连接保持”(connection keep-alive)等特性,也就是将同一连接或会话的流量始终转发到相同的后端服务器,从而避免频繁的连接建立过程。 40 | 41 | 不过,这种“连接保持”机制也存在潜在问题。以下是一个示例场景: 42 | 43 | - Client A 和 Client B 两个 HTTP/2 客户端通过四层负载均衡器和后端服务器建立持久连接。。 44 | - Client A 的 TCP 连接每分钟发送 40 个 HTTP 请求,而 Client B 的 TCP 连接每秒发送 1 个 HTTP 请求。 45 | 46 | 四层负载均衡器将 Client A 的所有 TCP 请求转发至同一台服务器,导致该服务器过载,而其他服务器则处于闲置状态。这种资源利用不均的问题在电气工程领域被称为“阻抗不匹配”现象。 47 | 48 | :::center 49 | ![](../assets/l4-connection-v2.svg)
50 | 图 4-3 四层负载均衡器下的“连接保持”问题 51 | ::: 52 | 53 | 随着用户规模扩大,四层负载均衡器面临的“阻抗不匹配”问题将变得更加明显。 54 | 55 | 不过也不要担心,引用一句计算机领域内流传颇广的俚语“计算机科学中的所有问题都可以通过增加一个间接层来解决。如果不够,那就再加一层”。因此,我们在四层负载均衡器之上添加了一个二级分发器 —— 七层负载均衡: 56 | 57 | - 四层负载均衡器工作在传输层,根据连接特性完成初步的请求转发; 58 | - 七层负载均衡器工作在应用层,根据请求内容进一步优化请求转发。 59 | 60 | 通过两次分发,请求的“阻抗不匹配”问题就消失了。 61 | 62 | ## 6.1.2 七层负载均衡 63 | 64 | 七层负载均衡器工作在应用层,这意味着负载均衡器必须与后端服务器建立新的传输层连接,并将客户端的请求代理到后端服务器。 65 | 66 | 图 4-4 展示了七层负载均衡器的工作原理。当客户端发送 HTTP 请求(stream)时: 67 | 68 | - 请求 1(stream1)被代理至第一个后端服务器; 69 | - 请求 2(stream2)被代理至第二个后端服务器。 70 | :::center 71 | ![](../assets/balancer7.svg)
72 | 图 4-4 七层负载均衡器新建 TCP 连接至后端服务器 73 | ::: 74 | 75 | 七层负载均衡器能够处理更复杂的操作,原因在于它工作在应用层,能够检测和处理请求内容,具体包括: 76 | 77 | - 安全层 TLS 协议:TLS 的归属层次在网络领域存在争议,本文为便于讨论假设属于应用层。 78 | - 物理 HTTP 协议:涵盖 HTTP/1、HTTP/2、HTTP/3 等版本。 79 | - 逻辑 HTTP 协议:包括请求的头部、主体和尾部数据。 80 | - 消息协议:如 gRPC、RESTful API、SOAP、AMQP、MQTT 等。 81 | 82 | 因此,七层负载均衡能够根据应用层信息做出更精细的路由决策,并支持内容缓存、压缩、TLS/SSL 卸载等高级功能。 83 | -------------------------------------------------------------------------------- /balance/balance7.md: -------------------------------------------------------------------------------- 1 | # 4.5 从七层负载均衡到网关 2 | 3 | 早期的七层负载均衡器(如 Nginx)依赖静态配置,仅具备基本的请求代理功能。随着微服务架构兴起,负载均衡器开始承担更多职责,逐步从“流量工具”演变为“系统的边界控制层” —— 网关。 4 | 5 | 业界较流行的网关系统(高级负载均衡器)如表 4-1 所示。 6 | 7 | :::center 8 | 表 4-1 业内网关系统代表 9 | ::: 10 | 名称|简介| 11 | |:--|:--| 12 | OpenResty| 基于 Nginx 的高性能 Web 平台,集成了大量模块,用来处理 HTTP 请求,被许多企业作为内部网关的基础框架。| 13 | |Kong| 构建在 OpenResty 上的网关平台,有丰富的插件体系,支持身份认证、限流、日志记录、监控等功能。| 14 | |Spring Cloud Gateway| Spring 框架下的 API 网关解决方案,与 Spring Cloud 生态(如 Eureka、Config Server)深度集成,广泛应用于 Java 技术栈的微服务项目。| 15 | |Traefik| 专为容器化系统设计,可与 Kubernetes、Docker 无缝集成。支持自动服务发现、动态配置路由、请求限流、身份验证、可观测等。| 16 | |Envoy | Envoy 是 Lyft 开发的一款面向服务网格的高性能网络代理,支持高级的路由控制、负载均衡策略、服务发现和健康检查等。Envoy 与 Istio 紧密结合,通常作为服务网格的数据平面出现。| 17 | 18 | 这些网关(高级负载均衡器)各有各的特点,实现的功能也非常强大,笔者不再逐一介绍,简单列举部分功能,以便读者对“强大”有个直观的感受。 19 | 20 | - **协议支持**:负载均衡器对应用层协议了解的越多,就可以处理更复杂的事情,包括系统可观测、高级负载均衡和内容路由等。以 Envoy 为例,它支持 HTTP/1、HTTP/2、HTTP/3(QUIC)、gRPC、TCP、TLS、WebSocket、PostgreSQL、Redis、MongoDB、DynamoDB 等协议。 21 | 22 | - **动态配置**:随着系统的动态性不断增强,需要在两个方面进行投入,一是动态控制,即实时调整系统行为;二是响应式控制,即根据环境变化做出快速反应。以 Istio 为例,它的架构分为控制平面和数据平面: 23 | - 数据平面:专注于动态控制,负责执行微服务之间的请求转发、负载均衡、熔断、重试、超时等流量管理策略。 24 | - 控制平面:专注于响应式控制,通过集中式配置和管理,为数据平面提供统一接口,用于定义和修改流量管理策略。 25 | 26 | - **流量治理**:在分布式架构中,服务间通信治理(如超时、重试、限速、熔断、流量镜像、缓存等)是系统稳定性的重要保障。作为集群的入口,负载均衡器将服务间通信治理需求统一收敛,这极大降低了业务系统的运维难度。 27 | - **可观测**:目前,指标监控、链路追踪和日志记录已成为高级七层负载均衡器的标配功能。如上面提到的 Envoy 和 Traefik,均支持与 Prometheus、Grafana、Jaeger 等监控系统集成。 28 | 29 | - **可扩展**:网关系统通常是插件化的,开发者可以根据需求灵活加载特定插件。例如,在 OpenResty 上,通过编写 Lua 脚本或集成第三方插件,可实现数据缓存、身份认证、安全防护、日志监控等自定义功能。 30 | 31 | - **高可用及无状态设计**:网关系统强调“无状态”(stateless)架构设计,即每个请求都被视为独立的,不依赖于任何先前的请求或存储在服务器上的会话信息。通过消除服务器状态依赖,系统能够轻松实现水平扩展! 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /balance/conclusion.md: -------------------------------------------------------------------------------- 1 | # 4.7 小结 2 | 3 | 负载均衡作为分布式系统的入口,直接影响整个系统的行为。因此,这一领域的竞争异常激烈,技术创新不断涌现。 4 | 5 | 在四层负载均衡领域,传统的硬件负载均衡设备(如 F5)正逐步被基于通用服务器和专用软件(如 IPVS、DPDK、fd.io)的解决方案所取代。例如,基于 DPDK 的流量转发和数据包处理技术,即使普通的物理机,也能轻松实现每秒百万至数千万的每秒数据包处理能力。在七层负载均衡领域,随着微服务架构的快速发展,传统代理软件(如 NGINX、HAProxy)逐渐被更适应动态微服务环境的解决方案(如 Envoy、Traefik)所取代。 6 | 7 | 总体而言,随着技术架构逐步向云厂商主导的 IaaS、CaaS 和 FaaS 模式演进,工程师未来将很少需要关注物理网络的工作原理,隐藏在 XaaS 模式之下的各类网络技术,正逐渐演变为“黑科技”。 -------------------------------------------------------------------------------- /balance/global-load-balancer.md: -------------------------------------------------------------------------------- 1 | # 4.6 全局负载均衡设计 2 | 3 | 近年来,负载均衡系统的发展趋势是将单个负载均衡器视为通用的标准化组件,由一个全局控制系统统一管理。 4 | 5 | 图 4-14 展示了全局负载均衡系统设计。 6 | - 边车代理(Sidecar Proxy)和位于三个 Zone 的后端通信。 7 | - 边车代理、后端定期向全局负载均衡器(Global Load Balancer)汇报请求延迟、自身的负载等状态,全局负载均衡器根据状态做出最合适的配置策略。 8 | - 全局负载均衡器向边车代理下发转发策略,可以看到 90% 的流量到了 Zone C,Zone A 和 B 各只有 5%。 9 | 10 | :::center 11 | ![](../assets/global-load-balancer.svg)
12 | 图 4-14 全局负载均衡系统 13 | ::: 14 | 15 | 全局负载均衡器能够实现很多单个负载均衡器无法完成的功能,比如下面这些。 16 | 17 | - 某个区域故障或负载过高时,全局负载均衡器自动将流量切换到其他可用区。 18 | - 利用机器学习、神经网络技术检测并缓解流量异常问题。比如识别并治理 DDoS 攻击。 19 | - 收拢边车代理配置,提供全局运维视角,帮助工程师直观理解、维护整个分布式系统。 20 | 21 | 全局负载均衡器在服务网格领域表现的形式称为“控制平面”(Control Plane),控制平面与边车代理协作的关键在于配置动态化。这部分内容,笔者将在第八章 8.3 节详细阐述。 -------------------------------------------------------------------------------- /balance/summary.md: -------------------------------------------------------------------------------- 1 | # 第四章:负载均衡与代理技术 2 | 3 | :::tip
4 | 5 | 一个篮子装不下所有的鸡蛋,那么就多用几个篮子来装。 6 | 7 | :::right 8 | —— 分布式系统的基本思想 9 | ::: 10 | 11 | 出于扩展服务能力或提高容错性的考虑,大多数系统通常以集群形式对外提供服务。 12 | 13 | 当以集群形式提供服务时,外部请求无论由哪台服务器处理,都应返回一致的结果。同时,集群对外应保持高度透明,内部节点的增加或移除不应被外部察觉,也无需外部进行任何配置更改。换句话说,外部在与集群交互时,应如同面对一台高性能、高可用的服务器。 14 | 15 | 为集群提供访问入口并实现上述职责的组件称为“负载均衡器”(或称代理)。负载均衡器是业内最活跃的领域之一,产品层出不穷(例如专用网络设备、软件实现等),部署拓扑多样(如中间代理型、边缘代理型、客户端内嵌型等)。无论形式或部署拓扑如何,所有负载均衡器的核心职责无外乎“选择处理外界请求的目标”(即负载均衡算法)和“将外界请求转发至目标”(即负载均衡的工作模式)。本章将围绕这两个核心职责展开,帮助你理解负载均衡器的工作原理。 16 | 17 | 本章内容安排如图 4-0 所示。 18 | :::center 19 | ![](../assets/balance-summary.png)
20 | 图 4-0 本章内容导读 21 | ::: 22 | -------------------------------------------------------------------------------- /consensus/Paxos-history.md: -------------------------------------------------------------------------------- 1 | # 6.3.1 Paxos 算法起源 2 | 3 | Paxos 算法最初的论文名称为《The Part-Time Parliament》,翻译成中文为《兼职议会》。论文的开头描述了一个虚构的古希腊岛屿考古发现故事。如果不事先说明,你可能不会意识到这是一篇关于分布式的论文。 4 | :::tip 《The Part-Time Parliament》节选 5 | 6 | 公元十世纪初,爱情海上的 Paxos 小岛是一个繁荣的商业中心。随着财富的积累,政治变得愈加复杂,Paxon 的公民用议会制政府取代了古老的神权政治。然而,商业利益高于公民义务,没人愿意将一生投入到议会事务中。因此,Paxon 议会必须在议员频繁进出议会的情况下,保持正常运作…… 7 | ::: 8 | 9 | 为了说明 Paxos 算法并增强演讲效果,Lamport 演讲中多次扮演《夺宝奇兵》中的主角印第安纳·琼斯。遗憾的是,Paxos 论文中采用的希腊民主议会的比喻显然不太成功。Lamport 像写小说一样,把一个复杂的数学问题写成了一篇带有考古色彩的历史小说,听众没有记住 Paxos 算法,仅仅记住了印第安纳·琼斯。 10 | 11 | 1990 年,Lamport 将《The Part-Time Parliament》论文提交给 TOCS 期刊。根据 Lamport 的本人的回忆[^1],TOCS 审稿人阅读后认为“这篇论文不怎么重要,但还有些意思”,并建议删掉与 Paxos 相关的故事背景。Lamport 对这些缺乏幽默感的审稿人颇为不爽,拒绝对论文进行修改。于是,论文的发表被搁置。 12 | 13 | 虽然论文没有发表,但不代表没有人关注这个算法。Bulter W.Lampson(1991 年图灵奖获得者)认识到 Paxos 算法的重要性,在他的论文《How to Build a Highly Availability System using Consensus》对 Paxos 算法进行了讲述。后来,De Prisco、Lynch 和 Lampson 几人联合在《理论计算机科学》期刊发表了论文《Revisiting the PAXOS algorithm》对 Paxos 算法进行了详细地描述和证明。经过 Lampson 等人的大力宣传,Paxos 算法逐渐被学术界重视。 14 | 15 | 另一方面,这些介绍 Paxos 算法的论文使 Lamport 觉得《The Part-Time Parliament》重新发表的时间到了。 16 | 17 | 或许作为玩笑的延续,或许为保留原有的工作,更直白的说法是 Lamport 认为论文描述和证明足够清晰,根本不需要任何修改,这次论文的发布仅增加了一段编辑的注解。有意思的是,编辑也风趣了一把。 18 | 19 | :::tip 20 | 21 | 最近在 TOCS 编辑办公室的文件柜发现了这份投稿。尽管年代久远,主编仍认为值得发表。由于作者目前在希腊的群岛进行实地考察,无法联系,委托我准备文稿以发表。作者似乎是一位考古学家,对计算机科学只有短暂的兴趣。。。 22 | 23 | :::right 24 | —— TOCS 编辑 Keith Marzullo 的注解 25 | 26 | ::: 27 | 《The Part-Time Parliament》[^2] 论文最终在 1998 年公开发表。 28 | 29 | 《The Part-Time Parliament》论文发表之后,还是有很多人抱怨看不懂,人们只记住了那个奇怪的故事,而不是 Paxos 算法。Lamport 走到哪都要被人抱怨一通。于是他忍无可忍,在 2001 年使用计算机领域的概念重新描述了一遍算法,发表了论文 《Paxos Made Simple》[^3]。 30 | 31 | 这是一篇很短的论文,摘要只有一句话:“The Paxos algorithm, when presented in plain English, is very simple.”!语气完全无法掩盖作者对 Paxos 的策略没有奏效的失望。 32 | 33 | :::center 34 | ![](../assets/paxos.png)
35 | 图 6-4 《Paxos Made Simple》论文摘要 36 | ::: 37 | 38 | 然而,这篇论文还是非常难以理解,引用斯坦福大学学者 Diego Ongaro 和 John Ousterhout 在设计 Raft 时的论文[^4]中对 Paxos 的描述。 39 | 40 | :::tip 《In Search of an Understandable Consensus Algorithm》节选 41 | 42 | Unfortunately, Paxos has two significant drawbacks. The first drawback is that **Paxos is exceptionally difficult to understand**... 43 | 44 | we were not able to understand the complete protocol until after reading several simplified explanations and designing our own alternative protocol, a process that took almost a year. 45 | ::: 46 | 47 | 上面大致的含义是,“Paxos 真的太难懂了...”。 48 | 49 | 连斯坦福的教授和博士都感觉难以理解。所以,他们的论文取名《In Search of an Understandable Consensus Algorithm》,意思是“易懂的共识算法还在寻找中”,根本不像 Lamport 说的那么简单。 50 | 51 | 注意,Raft 论文发表于 2013 年,而论文《Paxos Made Simple》是 2001 年发表的。也就是说,Paxos 算法已经被研究了十几年。直到 Google 的分布式锁服务 Chubby 横空出世,Chubby 使用 Paxos 共识算法实现强一致性,帮助 Google 解决了分布式系统中的资源协调问题。得益于 Google 的行业影响力,辅以 Chubby 作者 Mike Burrows 那略显夸张但足够吸引眼球的评价推波助澜,Paxos 算法从理论进入工业实践,逐渐被大家熟知和认可。 52 | 53 | 最终,Lamport 凭借他在分布式领域的贡献,于 2013 年获得图灵奖。 54 | 55 | [^1]: 参见 https://lamport.azurewebsites.net/pubs/pubs.html#lamport-paxos 56 | [^2]: 参见 https://lamport.azurewebsites.net/pubs/lamport-paxos.pdf 57 | [^3]: 参见 https://lamport.azurewebsites.net/pubs/paxos-simple.pdf 58 | [^4]: 参见 https://raft.github.io/raft.pdf 59 | -------------------------------------------------------------------------------- /consensus/Paxos.md: -------------------------------------------------------------------------------- 1 | # 6.3 Paxos 算法 2 | 3 | Paxos 算法由 Leslie Lamport[^1] 于 1990 年提出,是一种基于消息传递、具备高度容错特性的共识算法。该算法是当今分布式系统最重要的理论基础,几乎就是“共识系统”的代名词。 4 | 5 | Paxos 算法因其复杂广为人知,围绕它发生过许多有趣的故事,这些已成为人们津津乐道的一段轶事。直接切入 Paxos 算法未免望文生畏,我们不妨从这段轶事开始学习 Paxos 算法之旅。 6 | 7 | [^1]: Lamport 在分布式系统理论方面有非常多的成就,比如 Lamport 时钟、拜占庭将军问题、Paxos 算法等等。除了计算机领域之外,其他领域的无数科研工作者也要成天和 Lamport 开发的一套软件打交道,目前科研行业应用最广泛的论文排版系统 —— LaTeX (名字中的 La 就是指 Lamport) -------------------------------------------------------------------------------- /consensus/Replicated-State-Machine.md: -------------------------------------------------------------------------------- 1 | # 6.2 日志与复制状态机 2 | 3 | 如果统计分布式系统有多少块基石,“日志”一定是其中之一。 4 | 5 | 这里“日志”并不是常见的通过 log4j 或 syslog 输出的文本。而是 MySQL 中的 binlog(Binary Log)、MongoDB 中的 Oplog(Operations Log)、Redis 中的 AOF(Append Only File)、PostgreSQL 中的 WAL(Write-Ahead Log)...。它们虽然名称不同,但共同特点是**只能追加、完全有序的记录序列**。 6 | 7 | 图 6-1 展示了日志的结构,可以看出,日志是有序且持久化的记录序列。新记录会从末尾追加,而读取时则按“从左到右”的顺序进行扫描。 8 | 9 | :::center 10 | ![](../assets/log.png)
11 | 图 6-1 日志是有序的、持久化的记录序列 [图片来源](https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying) 12 | ::: 13 | 14 | 有序的日志记录了“何时发生了什么”,这一点可以通过以下两种数据复制模型来理解。 15 | - **主备模型**(Primary-backup):又称“状态转移”模型,主节点(Master)负责执行如“+1”、“-2”的操作,将操作结果(如“1”、“3”、“6”)记录到日志中,备节点(Slave)根据日志直接同步结果。 16 | - **复制状态机模型**(State-Machine Replication):又称“操作转移”模型,日志记录的不是最终结果,而是具体的操作指令,如“+1”、“-2”。指令按照顺序被依次复制到各个节点(Peer)。如果每个节点按顺序执行这些指令,各个节点最终将达到一致的状态。 17 | 18 | :::center 19 | ![](../assets/active_and_passive_arch.png)
20 | 图 6-2 分布式系统的两种数据复制模型 21 | ::: 22 | 23 | 无论哪一种模型,它们都揭示了:“**顺序是节点之间保持一致性的关键因素**”。如果打乱了操作的顺序,就会得到不同的运算结果。 24 | 25 | 接下来,进一步解释基于“复制状态机”(State Machine Replication)工作模型构建的分布式系统,其基本原理如图 6-3 所示。 26 | 27 | :::tip 复制状态机的基本原理 28 | 两个“相同的” (identical)、“确定的” (deterministic) 进程: 29 | 30 | - 相同的:进程的代码、逻辑、以及配置完全一致,它们在设计和实现上完全相同; 31 | - 确定的:进程的行为是完全可预测的,不能有任何非确定性的逻辑,比如随机数生成或不受控制的时间依赖。 32 | 33 | 如果它们以相同的状态启动,按相同的顺序获取相同的输入。那么,它们一定会达到相同的状态。 34 | ::: 35 | 36 | 共识算法(图中的 Consensus Module,Paxos 或者 Raft 算法)通过消息,将日志广播至所有节点,它们就日志什么位置,记录什么(序号为 9,执行 set x=3)达成共识。换句话说,所有的节点中,都有着相同顺序的日志序列, 37 | 38 | ```json 39 | // 日志 40 | { "index": 9, "command": "set x=3" } 41 | ``` 42 | 43 | 节点内的进程(图中的 State Machine)按顺序执行日志序列,操作具有全局顺序。因此,所有节点最终将达到一致的状态。多个这样的进程结合有序日志,就构成了 Apache Kafka、Zookeeper、etcd、CockroachDB 等分布式系统中的关键组件。 44 | 45 | :::center 46 | ![](../assets/Replicated-state-machine.webp)
47 | 图 6-3 复制状态机工作模型 [图片来源](https://raft.github.io/raft.pdf) 48 | ::: 49 | 50 | [^1]: https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying -------------------------------------------------------------------------------- /consensus/conclusion.md: -------------------------------------------------------------------------------- 1 | # 6.5 小结 2 | 3 | 尽管 Paxos 算法已提出几十年,但它为分布式系统中的一致性与容错性问题提供了理论框架,开创了分布式共识研究的先河。 4 | 5 | Paxos 基于“少数服从多数”(Quorum 机制)原则,通过“请求阶段”和“批准阶段”在不确定环境下,解决了单个“提案”的共识问题。多次运行 Paxos,便可实现一系列“提案”的共识,这就是 Multi-Paxos 的核心思想。Raft 算法在 Multi-Paxos 的基础上,在一致性、安全性和可理解性之间找到平衡,成为业界广泛采用的主流选择。 6 | 7 | 接下来,再思考一个问题,Raft 算法属于“强领导者”(Strong Leader)模型,领导者负责所有写入操作,它的写瓶颈就是 Raft 集群的写瓶颈。那么,该如何突破 Raft 集群的写瓶颈呢? 8 | 9 | 一种方法是使用哈希算法将数据划分成多个独立部分(分片)。例如,将一个 100TB 规模数据的系统分成 10 部分,每部分只需处理 10TB。这种根据规则(范围或哈希)将数据分散处理的策略,被称为“分片机制”(Sharding)。分片机制广泛应用于 Prometheus、Elasticsearch 、ClickHouse 等大数据系统(详见本书第九章)。理论上,只要机器数量足够,分片机制就能支持任意规模的数据。 10 | -------------------------------------------------------------------------------- /consensus/consensus.md: -------------------------------------------------------------------------------- 1 | # 6.1 什么是共识 2 | 3 | 在业内讨论 Paxos 或 Raft 算法时,通常使用“分布式一致性协议”或“分布式一致性算法”来描述。例如,Google Chubby 系统的作者 Mike Burrows 曾评价 Paxos:“There is only one consensus protocol...”,这句话常被翻译为“世界上只有一种共识算法”。在汉语中,“共识”和“一致”意思相似,但在计算机领域,它们具有截然不同的含义。 4 | 5 | - **共识**(Consensus):指所有节点就某项操作(如选主、原子事务提交、日志复制、分布式锁管理等)达成一致的实现过程。 6 | - **一致性**(Consistency):描述多个节点的数据是否保持一致,关注数据最终达到稳定状态的结果。 7 | 8 | 本书第五章介绍的 CAP 定理中的 C 和数据库 ACID 模型中的 C 描述的是数据“一致性”属性。而 Paxos、Raft 或者 ZAB 等算法研究的是如何达成一致。因此,将 Paxos 等算法归类为“共识算法”更准确。 9 | 10 | 在分布式系统中,节点故障是不可避免的,但部分节点故障不应该影响系统整体状态。通过增加节点数量,依据“少数服从多数”原则,只要多数节点(至少 $\mathit{N/2+1}$)达成一致,其状态即可代表整个系统。这种依赖多数节点实现容错的机制称为 Quorum 机制。 11 | 12 | :::tip Quorum 机制 13 | 14 | - 3 节点集群:Quorum 为 2,允许 1 个节点故障。 15 | - 4 节点集群:Quorum 为 $\mathit{⌈4/2⌉+1 = 3}$,允许 1 个节点故障。 16 | - 5 节点集群:Quorum 为 $\mathit{⌈5/2⌉+1 = 3}$,允许 2 个节点故障。 17 | 18 | 集群节点个数为 $\mathit{N}$ ,能容忍 $\mathit{(N-1)/2}$ 个节点故障。你注意到了吗?3 节点和 4 节点集群的故障容忍能力一样。因此,通常情况下,针对容错的分布式系统无需使用 4 个节点。 19 | ::: 20 | 21 | 基于 Quorum 的机制,通过“少数服从多数”协商机制达成一致的决策,从而对外表现为一致的运行结果。这一过程被称为节点间的“协商共识”。一旦解决共识问题,便可提供一套屏蔽内部复杂性的抽象机制,为应用层提供一致性保证,满足多种需求。 22 | - **主节点选举**:在主从复制数据库中,所有节点需要就“谁来当主节点”达成一致。如果由于网络问题导致节点间无法通信,很容易引发争议。若争议未解决,可能会出现多个节点同时认为自己是主节点的情况,这就是分布式系统中最棘手的问题之一 —— “脑裂”。 23 | - **原子事务提交**:对于支持跨节点或跨分区事务的数据库,可能会发生部分节点事务成功、部分节点事务失败的情况。为维护事务的原子性(即 ACID 特性),所有节点必须就事务的最终结果达成一致。 24 | - **分布式锁管理**:当多个请求尝试访问共享资源时,共识机制可确保所有节点一致认定“谁成功获取了锁”。即使发生网络故障或节点异常,也能避免锁争议,从而防止并发冲突或数据不一致。 25 | - **日志复制**:日志复制指将主节点的操作日志同步到从节点。在这一过程中,所有节点必须确保日志条目的顺序一致,即日志条目必须以相同顺序写入(顺序非常重要,笔者将在下一节详细说明)。 -------------------------------------------------------------------------------- /consensus/raft-ConfChange.md: -------------------------------------------------------------------------------- 1 | # 6.4.3 成员变更 2 | 3 | 在前面的内容中,我们假设集群节点数固定,即集群的 Quorum 也保持不变。然而,在生产环境中,集群通常需要进行节点变更,例如因故障移除节点或扩容增加节点等。对于旨在实现容错能力的算法来说,显然不能通过“关闭集群、更新配置并重启系统”的方式来实现。 4 | 5 | 在讨论如何实现成员动态变更之前,我们需要先搞明白 Raft 集群中“配置”(configuration)的概念。 6 | 7 | :::tip 配置 8 | 配置说明集群由哪些节点组成。例如,一个集群有三个节点(Server 1、Server 2、Server 3),该集群的配置就是 [Server1、Server2、Server3]。 9 | ::: 10 | 11 | 如果把“配置”当成 Raft 中的“特殊日志”。这样一来,成员动态变更需求就可以转化为“配置日志”的一致性问题。但需要注意的是,各个节点中的日志“应用”(apply)到状态机是异步的,不可能同时操作。这种情况下,apply “配置日志”很容易导致“脑裂”问题。 12 | 13 | 举个具体例子,假设有一个由三个节点 [Server1、Server2 和 Server3] 组成的 Raft 集群,当前的配置为 C~old~。现在,我们计划增加两个节点 [Server1、Server2、Server3、Server4、Server5],新的配置为 C~new~。 14 | 15 | 由于日志提交是异步处理的,假设 Server1 和 Server2 比较迟钝,仍在使用老配置 C~old~,而 Server3、Server4、Server5 的状态机已经应用了新配置 C~new~: 16 | 17 | - 假设 Server5 触发选举并赢得 Server3、Server4、Server5 的投票(满足 C~new~ 配置下的 Quorum 3 要求),成为领导者; 18 | - 同时,假设 Server1 也触发选举并赢得 Server1、Server2 的投票(满足 C~old ~配置下的 Quorum 2 要求),成为领导者。 19 | 20 | 一个集群存在两个领导者也就是“脑裂”,同一个日志索引可能会对应不同的日志条目,最终导致集群数据不一致。 21 | 22 | :::center 23 | ![](../assets/raft-ConfChange.png)
24 | 图 6-15 某一时刻,集群存在两个 Quorum 25 | ::: 26 | 27 | 上述问题的根本原因在于,成员变更过程中形成了两个没有交集的 Quorum,即 [Server1, Server2] 和 [Server3, Server4, Server5] 各自为营。 28 | 29 | Raft 的论文中,对此提出过一种基于两阶段的“联合共识”(Joint Consensus)成员变更方案,但这种方案实现较为复杂,Diego Ongaro 后来又提出一种更为简化的方案 — “单成员变更”(Single Server Changes)。该方案思想的核心是,既然同时提交多个成员变更可能引发问题,那么每次只提交一个成员变更,需要添加多个成员,就执行多次单成员变更操作。这样不就没有问题了么! 30 | 31 | 单成员变更方案很容易穷举所有情况,如图 6-16 所示,穷举奇/偶数集群下节点添加/删除情况。如果每次只操作一个节点,C~old~ 的 Quorum 和 C~new~ 的 Quorum 一定存在交集。交集节点只会进行一次投票,要么投票给 C~old~,要么投票给 C~new~。因此,不可能出现两个符合条件的 Quorum,也就不会出现两个领导者。 32 | 33 | 以图 6-16 第二种情况为例,C~old~ 为 [Server1、Server2、Server3],该配置的 Quorum 为 2,C~new~ 为 [Server1、Server2、Server3、Server4],该配置的 Quorum 为 3。假设 Server1、Server2 比较迟钝,还在用 C~old~ ,其他节点的状态机已经应用 C~new~: 34 | - 假设 Server1 触发选举,赢得 Server1,Server2 的投票,满足 C~old~ Quorum 要求,当选领导者; 35 | - 假设 Server3 也触发选举,赢得 Server3,Server4 的投票,但**不满足 C~new~ 的 Quorum 要求,选举失效**。 36 | 37 | :::center 38 | ![](../assets/raft-single-server.svg)
39 | 图 6-16 穷举奇/偶数集群下节点添加/删除情况 40 | ::: 41 | 42 | 目前,绝大多数 Raft 算法的实现和系统,如 HashiCorp Raft 和 etcd,均采用单节点变更方案。由于联合共识方案的复杂性和实现难度,本文不再深入讨论,有兴趣的读者可以参考 Raft 论文以了解更多细节。 -------------------------------------------------------------------------------- /consensus/raft-leader-election.md: -------------------------------------------------------------------------------- 1 | # 6.4.1 领导者选举 2 | 3 | Paxos 算法中“节点众生平等”,每个节点都可以发起提案。多个提议者并行发起提案,是活锁、以及其他异常问题的源头。那如何不破坏 Paxos 的“节点众生平等”基本原则,又能在提案节点中实现主次之分,约束提案权利? 4 | 5 | 理解上面的问题,是先搞清楚 Raft 算法中节点的分类。Raft 提出了领导者角色,通过选举机制“分享”提案权利。 6 | 7 | - **领导者**(Leader):负责处理所有客户端请求,将请求转换为“日志”复制到其他节点,不断地向所有节点广播心跳消息:“你们的领导还在,不要发起新的选举”。 8 | - **跟随者**(Follower):接收、处理领导者的消息,并向领导者反馈日志的写入情况。当领导者心跳超时时,他会主动站起来,推荐自己成为候选人。 9 | - **候选人**(Candidate):候选人属于过渡角色,他向所有的节点广播投票消息,如果他赢得多数选票,那么他将晋升为领导者。 10 | 11 | 联想到现实世界中的领导人都有一段不等的任期。自然,Raft 算法中也对应的概念 —— “任期”(term)。Raft 中的任期是一个递增的数字,贯穿于 Raft 的选举、日志复制和一致性维护过程中。 12 | 13 | - **选举过程**:任期确保了领导者的唯一性。在一次任期内,只有获得多数选票的节点才能成为领导者。 14 | - **日志一致性**:任期号会附加到每条日志条目中,帮助集群判断日志的最新程度。 15 | - **冲突检测**:通过比较任期号,节点可以快速判断自己是否落后,并切换到跟随者状态。 16 | 17 | :::center 18 | ![](../assets/raft-term.svg) 19 | 图 6-11 Raft 中的任期 20 | ::: 21 | 22 | 图 6-12 概述了 Raft 集群 Leader 选举过程。 23 | 24 | :::center 25 | ![](../assets/raft-election.svg) 26 | 图 6-12 Raft 选举过程 27 | ::: 28 | 29 | 初始状态下,所有的节点处于跟随者状态。如果跟随者在某个时限(通常是 150-300 毫秒的随机超时时间)未收到领导者心跳,则触发触发选举。节点的角色转为候选者,任期号递增,然后向其他节点广播“投票给我”的消息(RequestVote RPC)。 30 | 31 | RequestVote RPC 消息示例如下: 32 | 33 | ```json 34 | { 35 | "term": 5, // 候选者的当前任期号,用于通知接收方当前选举属于哪个任期。 36 | "candidateId": 3, // 候选者的节点 ID,标识请求投票的节点。 37 | "lastLogIndex": 12, // 候选者日志的最后一条日志的索引,用于比较日志的完整性。 38 | "lastLogTerm": 4//候选者日志的最后一条日志的任期号,用于进一步比较日志的新旧程度。 39 | } 40 | ``` 41 | 42 | 其他节点收到投票消息后,根据下面的条件判断是否投票: 43 | 44 | - 候选者的日志至少与投票者的日志一样新(根据最后一条日志的任期号和索引号判断)。 45 | - 当前节点尚未在本任期投票。 46 | 47 | RequestVote 响应的示例如下: 48 | 49 | ```json 50 | { 51 | "term": 5, //接收方的当前任期号,用于告知候选者最新的任期号。如果候选者发现该值比自己大,会转为跟随者。 52 | "voteGranted": true//是否投票给候选者,true 表示同意,false 表示拒绝。 53 | } 54 | ``` 55 | 56 | 如果候选者获得多数(超过半数)投票,即成为领导者。之后,领导者向其他节点广播心跳消息,维持领导者地位。如果没有获得多数票,进入下一轮选举,任期号递增,重新发起投票。如果选举过程中收到任期号更高的心跳或投票请求,则转为跟随者。 57 | 58 | 基于“少数服从多数”原则,获得多数选票的领导者代表了整个集群的意志。现在,你思考,代表集群意志的领导者发起提案时,是否还需要 Paxos 第一轮中 “准备阶段” ? 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /consensus/raft-log-replication.md: -------------------------------------------------------------------------------- 1 | # 6.4.2 日志复制 2 | 3 | 一旦选出一个公认的领导者,那领导者顺理成章地承担起“**处理系统发生的所有变更,并将变更复制到所有跟随者节点**”的职责。 4 | 5 | 在 Raft 算法中,日志承载着系统所有变更。图 6-13 展示了 Raft 集群的日志模型,每个“日志条目”(log entry)包含索引、任期、指令等关键信息: 6 | 7 | - **指令**: 表示客户端请求的具体操作内容,也就是待“状态机”(State Machine)执行的操作。 8 | - **索引值**:日志条目在仓库中的索引值,是单调递增的数字。 9 | - **任期编号**:日志条目是在哪个任期中创建的,用于解决“脑裂”或日志不一致问题。 10 | 11 | :::center 12 | ![](../assets/raft-log.svg)
13 | 图 6-13 Raft 集群的日志模型(x ← 3 代表x赋值为3) 14 | ::: 15 | 16 | Raft 算法中,领导者通过广播消息(AppendEntries RPC)将日志条目复制到所有跟随者。AppendEntries RPC 的示例如下: 17 | ```json 18 | { 19 | "term": 5, // 领导者的任期号 20 | "leaderId": "leader-123", 21 | "prevLogIndex": 8, // 前一日志条目的索引 22 | "prevLogTerm": 4, // 前一日志条目的任期 23 | "entries": [ 24 | { "index": 9, "term": 5, "command": "set x=4" }, // 要复制的日志条目 25 | ], 26 | "leaderCommit": 7// Leader 的“已提交”状态的日志条目索引号 27 | } 28 | ``` 29 | 30 | 根据图 6-14 所示,当 Raft 集群收到客户端请求(例如 set x=4)时,日志复制的过程如下: 31 | 32 | - 若当前节点非领导者,将请求转发至领导者; 33 | - 领导者接收请求后: 34 | - 将请求转化为日志条目,写入本地存储系统,初始状态为“未提交”(uncommitted); 35 | - 生成日志复制消息(AppendEntries RPC),并广播至所有跟随者; 36 | - 跟随者收到日志复制消息后,验证任期(确保本地任期不大于领导者任期)、日志一致性(通过 prevLogIndex 检查日志是否匹配)。若验证通过,跟随者将日志条目追加至本地存储系统,并发送确认响应;。 37 | - 领导者确认日志条目已成功复制至多数节点后,将其状态标记为“已提交”(committed),并向客户端返回结果。已提交的日志条目不可回滚,指令永久生效,且可安全地“应用”(apply)至状态机。 38 | 39 | :::center 40 | ![](../assets/raft-append-entries.svg)
41 | 图 6-14 日志复制的过程 42 | ::: 43 | 44 | 45 | 领导者向客户端返回结果,并不意味着日志复制过程已完全结束,跟随者尚不清楚日志条目是否已被大多数节点确认。Raft 的设计通过心跳或后续日志复制请求中携带更新的提交索引(leaderCommit),通知跟随者提交日志。此机制将“达成共识的过程”优化为一个阶段,减少了客户端约一半的等待时间。 46 | 47 | :::tip 如何选择节点的数量? 48 | 49 | Raft 日志复制过程需要等待多数节点确认。节点越多,等待的延迟也相应增加。所以说,以 Raft 构建的分布式系统并不是节点越多越好。如 etcd,推荐使用 3 个节点,对高可用性要求较高,且能容忍稍高的性能开销,可增加至 5 个节点,如果超出 5 个节点,可能得不偿失。 50 | ::: 51 | 52 | 我们来看日志复制的另一种情况。在上述例子中,只有 follower-1 成功追加日志,follower-2 因为日志不连续,追加失败。日志的连续性至关重要,如果日志条目没有按正确顺序应用到状态机,各个 follower 节点的状态肯定不一致。 53 | 54 | 日志不连续的问题是这样解决的:follower-2 收到日志复制请求后,它会通过 prevLogIndex 和 prevLogTerm 检查本地日志的连续性。如果日志缺失或存在冲突,follower-2 返回失败响应,指明与领导者日志不一致的部分。 55 | 56 | ```json 57 | { 58 | "success": false, 59 | "term": 4, 60 | "conflictIndex": 4, // 表示发生缺失的日志索引,Follower 的日志中最大索引为 3,所以缺失的索引是 4。 61 | "conflictTerm": 3//缺失日志的“上一个有效日志条目”的任期号 62 | } 63 | ``` 64 | 当领导者收到失败响应,根据 conflictIndex 和 conflictTerm 找到与跟随者日志的最大匹配索引(例如,6)。随后,领导者从该索引开始重新向跟随者(如 follower-2)发送日志条目,逐步修复日志的不一致性,直至同步完成。 -------------------------------------------------------------------------------- /consensus/raft.md: -------------------------------------------------------------------------------- 1 | # 6.4 Raft 算法 2 | 3 | :::tip 额外知识 4 | Raft 是 Re{liable|plicated|dundant} And Fault-Tolerant,即可靠、复制、冗余和容错,组合起来的单词。同时,Raft 在英文有“筏”的含义,隐喻一艘帮助你逃离 Paxos 小岛的救生筏。 5 | ::: 6 | 7 | 不可否认,Paxos 是一个划时代的共识算法。 8 | 9 | Raft 算法出现之前,绝大多数共识系统都是基于 Paxos 算法或者受其影响。同时,Paxos 算法也成为教学领域里讲解共识问题时的范例。不幸的是,Paxos 算法理解起来非常晦涩。此外,论文虽然提到了 Multi Paxos,但缺少实现细节。因此,无论是学术界还是工业界普遍对 Paxos 算法感到十分头疼。 10 | 11 | 那段时期,虽然所有的共识系统都是从 Paxos 算法开始的,但工程师们实现过程中有很多难以逾越的难题,往往不得已开发出与 Paxos 完全不一样的算法,这导致 Lamport 的证明并没有太大价值。所以,很长的一段时间内,实际上并没有一个被大众广泛认同的 Paxos 算法。 12 | 13 | :::tip
14 | Paxos 算法的理论描述与实际工程实现之间存在巨大鸿沟,最终实现的系统往往建立在一个尚未完全证明的算法基础之上。 15 | :::right 16 | —— Chubby 作者评论 Paxos 17 | ::: 18 | 19 | 考虑到共识问题在分布式系统的重要性,同时为了提供一种更易于理解的教学方法,斯坦福大学的学者们决定重新设计一个替代 Paxos 的共识算法。 20 | 21 | 2013 年,斯坦福大学的学者 Diego Ongaro 和 John Ousterhout 发表了论文 《In Search of an Understandable Consensus Algorithm》[^1],提出了 Raft 算法。Raft 论文开篇描述了 Raft 的证明和 Paxos 等价,详细阐述了算法如何实现。也就是说,Raft 天生就是 Paxos 算法的工程化。 22 | 23 | :::tip 《In Search of an Understandable Consensus Algorithm》节选 24 | Raft is a consensus algorithm for managing a replicated log. It produces a result **equivalent to (multi-)Paxos, and it is as efficient as Paxos,** but its structure is different from Paxos; 25 | ::: 26 | 27 | 此后,Raft 算法成为分布式系统领域的首选共识算法。 28 | 29 | 接下来,笔者将从领导选举、日志复制、成员变更三个方面展开,讨论 Raft 算法是如何妥善解决分布式系统一致性需求的。 30 | 31 | [^1]: 论文参见 https://raft.github.io/raft.pdf -------------------------------------------------------------------------------- /consensus/summary.md: -------------------------------------------------------------------------------- 1 | # 第六章:分布式共识及算法 2 | 3 | :::tip 4 | 世界上只有一种共识算法,就是 Paxos,其他所有的共识算法都是 Paxos 的退化版本。 5 | 6 | :::right 7 | —— Mike Burrows,Google Chubby 作者 8 | ::: 9 | 10 | 分布式系统中充满了各种潜在的错误场景,网络数据包可能丢失、顺序紊乱、重复发送或者延迟,节点还可能宕机。“在充满不确定性的环境中,就某个决策达成共识”是软件工程领域最具挑战性的问题之一。 11 | 12 | 这一章,我们迎难而上,从解决问题的角度出发理解什么是共识,沿着 Paxos 算法的思路讨论如何达成共识,以工程实践为目的学习 Raft 算法的设计思想。最后,理解了问题以及如何解题,自然能体会到 Apache Kafka、 Zookeeper、etcd、Consul 等分布式系统核心组件的设计原理,掌握构建大规模分布式系统的关键要素。 13 | 14 | 本章内容安排如图 6-0 所示。 15 | :::center 16 | ![](../assets/consensus-summary.png)
17 | 图 6-0 本章内容导图 18 | ::: -------------------------------------------------------------------------------- /container/Resource-scheduling.md: -------------------------------------------------------------------------------- 1 | # 7.7 资源模型及编排调度 2 | 3 | 过去的集群管理平台(如 Mesos、Swarm)擅长的是,通过特定规则将容器调度到最佳节点上,这一功能称为“调度”。而 Kubernetes 擅长的,是根据系统规则和用户需求,自动化地处理好容器间的各种关系,这个功能就是我们常听到的 “编排”。 4 | 5 | 接下来,笔者将围绕 Kubernetes 资源模型、异构资源扩展以及默认调度器(kube-scheduler),深入讨论 Kubernetes 的容器编排功能。 -------------------------------------------------------------------------------- /container/conclusion.md: -------------------------------------------------------------------------------- 1 | # 7.9 小结 2 | 3 | 本章,笔者从 Google 内部容器系统演进作为开篇,从网络、计算、存储、调度等方面展开,深入分析了 Kubernetes 的设计原理和应用。希望能让你在学习 Kubernetes 这个复杂而庞大的项目时,抓住其核心主线,理解其设计理念。 4 | 5 | 在笔者看来,Kubernetes 作为基础设施,它的设计理念有两个核心: 6 | - 其一,从 API 到容器运行时的每一层,都为开发者暴露可供扩展的插件机制。通过 CNI 插件把网络功能解耦,让外部的开发社区、厂商参与容器网络的实现;通过 CSI 插件建立了一套庞大的存储生态;通过设备插件机制把物理资源的支持扩展到 GPU、FPGA、DPDK、RDMA 等各类异构设备。凭借这种开放性设计,Kubernetes 社区涌现出成千上万的插件,帮助运维工程师轻松构建强大的基础设施平台。从这一点讲,这也是 CNCF 基于 Kubernetes 能构建出一个庞大生态的原因。所以说,Kubernetes 并不是一个简单的容器编排平台,而是一个分量十足的“接入层”,是云原生时代真真正正的“操作系统”。 7 | - 其二,在这一开放性底层之上,Kubernetes 将各类资源统一抽象为“资源”,并通过 YAML 文件描述。这种设计使得一个 YAML 文件即可表达复杂基础设施的最终状态,并自动管理应用程序的运维。Kubernetes 隐藏了底层实现细节,屏蔽了不同平台的差异,以一致、友好、跨平台的方式将底层基础设施能力“输送”给业务工程师,正是它的设计理念的精髓所在。 8 | 9 | 接下来,笔者将介绍基于“容器设计模式”的二次创新,也就是近几年热度极高的“服务网格”(ServiceMesh)技术。 -------------------------------------------------------------------------------- /container/summary.md: -------------------------------------------------------------------------------- 1 | # 第七章:容器编排技术 2 | 3 | :::tip
4 | 5 | 世界上有两个设计软件的方法,一种方法是设计的尽量简单,以至于明显没有什么缺陷,另外一种方式是使他尽量的复杂,以至于其缺陷不那么明显。 6 | 7 | :::right 8 | —— by 计算机科学家 C.A.R. Hoare[^1] 9 | ::: 10 | 11 | 随着容器化架构大规模应用,手动管理大量容器的方式变得异常艰难。为了减轻管理容器的心智负担,实现容器调度、扩展、故障恢复等自动化机制,容器编排系统应运而生。 12 | 13 | 过去十年间,Kubernetes 发展成为容器编排系统的事实标准,也成为大数据分析、机器学习以及在线服务等领域广泛认可的最佳技术底座。然而,Kubernetes 在解决复杂问题的同时,本身也演变成当今最复杂的软件系统之一。目前,包括官方文档在内的大多数 Kubernetes 资料都聚焦于“怎么做”,鲜有解释“为什么这么做”。自 2015 年起,Google 陆续发布了《Borg, Omega, and Kubernetes》及《Large-scale cluster management at Google with Borg》等论文,分享了 Google 内部开发 Borg、Omega 和 Kubernetes 系统的经验与教训。本章,我们将从这几篇论文展开,讨论容器编排系统中关于网络通信、持久化存储、资源模型和编排调度等方面的设计原理和应用。 14 | 15 | 本章内容安排如图 7-0 所示。 16 | :::center 17 | ![](../assets/container-summary.png)
18 | 图 7-0 本章内容导图 19 | ::: 20 | 21 | [^1]: Charles Antony Richard Hoare(缩写为 C. A. R. Hoare),著名的计算科学家,图灵奖获得者,以设计快速排序算法、霍尔逻辑、通信顺序进程闻名。 -------------------------------------------------------------------------------- /distributed-transaction/ACID.md: -------------------------------------------------------------------------------- 1 | # 5.1 数据一致性 2 | 3 | 引入事务的目的,是为了保证数据的“一致性”(Consistency)。 4 | 5 | **这里的一致性指的是,对数据有特定的预期状态,任何数据更改操作必须满足这些状态约束(或者恒等条件)**。例如,处理一个转账业务,其中 A 向 B 转账 ¥50 元。无论是转账前、转账过程中、还是转账完成后,A 和 B 的总金额要求始终保持不变。这意味着数据在整个过程中都保持一致,符合业务约束。 6 | 7 | 根据数据库的经典理论,想要达成数据的一致性,需要 3 个方面的努力。 8 | 9 | - **原子性(A**tomic):“原子”通常指不可分解为更小粒度的东西。这里原子性描述的是,客户端发起一个请求(请求包含多个操作)在异常情况下的行为。例如,只完成了一部分写入操作,系统出现故障了(进程崩溃、网络中断、节点宕机)。把多个操作纳入到一个原子事务,万一出现上述故障导致无法完成最终提交时,则中止事务,丢弃或者撤销那些局部修改。 10 | - **隔离性(I**solation): 11 | 同时运行的事务不应互相干扰。例如,当一个事务执行多次写入操作时,其他事务应仅能观察到该事务的最终完成结果,而非中间状态。隔离性旨在防止多个事务交叉操作导致的数据不一致问题。 12 | - **持久性(D**urability):事务处理完成后,对数据的修改应当是永久性的,即使系统发生故障也不会丢失。在单节点数据库中,持久性意味着数据已写入存储设备(如硬盘或 SSD)。而在分布式数据库中,持久性要求数据成功复制到多个节点。为确保持久性,数据库必须在完成数据复制后,才能确认事务已成功提交。 13 | 14 | 这也就是常说的事务的“ACID 特性”。值得一提的是,**对于一致性而言,更多的是指数据在应用层的外部表现。应用程序借助数据库提供的原子性、隔离性和持久性,来实现一致性目标。也就是说,A、I、D 是手段,C 是 3 者协作的目标,弄到一块完全是为了读起来更顺口。** 15 | 16 | 当事务仅涉及本地操作时,一致性通过代码实现起来水到渠成。但倘若事务的操作对象扩展到外部系统,例如跨越多个微服务、数据源甚至数据中心时,再依赖传统的 A、I、D 手段来解决一致性问题变得非常困难。但是,一致性又是在分布式系统中不可回避且必须解决的核心问题。这种情况下,我们就需要转变观念,将一致性视为一个多维度的问题,而非简单的“是或否”的二元问题。根据不同场景的需求,对一致性的强度进行分级,在确保代价可承受的前提下,尽可能保障系统的一致性。 17 | 18 | 一致性的强弱程度直接影响系统设计权衡。由此,事务从一个具体操作层面的“编程问题”转变成一个需要全局视角的“架构问题”。在探索这些架构设计的过程中,出现了许多思路和理论,其中最著名的便是一致性与可用性之间的权衡 —— 即 CAP 定理。 -------------------------------------------------------------------------------- /distributed-transaction/BASE.md: -------------------------------------------------------------------------------- 1 | # 5.3.1 可靠事件队列 2 | 3 | 2008 年,eBay 架构师 Dan Pritchett 在 ACM 发表了论文《Base: An Acid Alternative》[^1],在文中,作者总结了基于实践经验的一种独立于 ACID 的数据一致性技术方案,利用消息队列和幂等机制实现数据一致性,并首次提出了“最终一致性”这一概念。 4 | 5 | 从论文标题可以看出,最终一致性的概念与 ACID 强一致性对立。因为 ACID 在英文中有的“酸”的含义,这一事务模型的名字刻意拼凑成 BASE(BASE 在英文中有碱的含义)。有酸 vs 碱这个浑然天成的梗加成,《Base: An Acid Alternative》论文被广泛传播,BASE 理论和最终一致性的概念也被大家熟悉。 6 | 7 | BASE 是“Basically Available”、“Soft State”和“Eventually Consistent”的缩写。 8 | 9 | - **基本可用**(Basically Available):系统保证在大多数情况下能够提供服务,即使某些节点出现故障时,仍尽可能保持可用性。这意味着系统优先保障可用性,而非一致性。 10 | - **柔性状态**(Soft state):系统状态允许在一段时间内处于不一致状态。与 ACID 强一致性的要求不同,BASE 允许系统在更新过程处于“柔性”状态,即数据在某些节点上可以暂时不一致。 11 | - **最终一致性**(Eventually consistent):最终一致性强调,即使在网络分区或系统故障的情况下,在经过足够的时间和多次数据同步操作后,所有节点的数据一定会一致。 12 | 13 | 14 | 总结 BASE 理论是对 CAP 定理中 AP(可用性和分区容错性)方案的进一步发展,强调即使无法实现强一致性,分布式系统也可以通过适当的机制最终达到一致性。适当的机制可概括为**基于可靠事件队列的事件驱动模式**。接下来,以一个具体的例子帮助你理解“可靠事件队列”的具体做法。 15 | 16 | 假设有一个电商系统,下单操作依赖于三个服务:支付服务(进行银行扣款)、库存服务(扣减商品库存)和积分服务(为用户增加积分)。下单过程中,我们优先处理最核心、风险最高的服务,按照支付扣款、仓库出库以及为用户增加积分的顺序执行。下单的整个流程如图 5-2 所示。 17 | 18 | :::center 19 | ![](../assets/BASE.svg)
20 | 图 5-2 可靠事件队列事务模型 21 | ::: 22 | 23 | 首先,用户向商店发送了一个交易请求,如购买一件价值 ¥100 的商品。 24 | 25 | 接着,支付服务创建一个本地扣款事务。如果扣款事务执行成功,系统将在消息队列中新增一条待处理消息。消息的大致结构如下: 26 | 27 | ```go 28 | struct Message { 29 | 事务 ID; 30 | 扣款 ¥100(状态:已完成); 31 | 仓库出库(状态:待处理); 32 | 赠送积分(状态:待处理) 33 | } 34 | ``` 35 | 36 | 系统中有一个持续运行的服务,定期轮询消息队列,检查是否存在待处理的消息。如果发现待处理消息,它将通知库存服务和积分服务进行相应的处理。 37 | 38 | 此时,会出现以下几种情况: 39 | 40 | - **仓库服务和积分服务顺利完成任务**:这两个服务成功执行了出库和积分操作,并将结果反馈给支付服务。随后,支付服务将消息状态更新为“已完成”,整个事务顺利完成,最终实现一致性。 41 | - **网络问题导致消息未送达**:如果仓库服务或积分服务因网络问题未收到支付服务的消息,此时,支付服务中的消息状态将保持为“待处理”。消息服务会在每次轮询时继续向未响应的服务节点重复发送消息,直到通信恢复正常。为了确保出库和积分操作仅被执行一次,所有接收消息的服务必须具备幂等性(有关幂等性的设计,详见5.4节)。 42 | - **服务无法完成操作**:如果仓库服务或积分服务由于某种原因无法完成操作(例如,仓库库存不足),消息服务将持续发送消息,直到操作成功(如库存补充)或通过人工干预终止。 43 | 44 | 由此可见,在可靠消息队列方案中,一旦第一步扣款成功,就不再考虑失败回滚的情况,后面只有成功一条路可选。 45 | 46 | 这种依赖持续重试来确保可靠性的解决方案在计算机领域被广泛应用,它还有专有的名称 —— “最大努力交付”(Best-Effort Delivery)。因此,可靠事件队列也称为“最大努力一次提交”(Best-Effort 1PC)机制,也就是将最容易出错的业务通过本地事务完成后,借助不断重试的机制促使同一个事务中其他操作也顺利完成。 47 | 48 | [^1]: 参见 https://queue.acm.org/detail.cfm?id=1394128 49 | -------------------------------------------------------------------------------- /distributed-transaction/CAP.md: -------------------------------------------------------------------------------- 1 | # 5.2 一致性与可用性的权衡 2 | 3 | CAP 是一致性与可用性权衡的理论,是理解分布式系统的起点。 4 | 5 | 1999 年,美国工程院院士 Eric A.Brewer 发表了论文《Harvest, Yield, and Scalable Tolerant Systems》[^1] ,首次提出了“CAP 原理”(CAP Principle)。不过,彼时的 CAP 仅是一种猜想,尚未得到理论上的证明。2002 年,麻省理工学院的 Seth Gilbert 和 Nancy Lynch 用严谨的数学推理证明了 CAP 的正确性。此后,CAP 从原理转变成定理,在分布式系统领域产生了深远的影响。 6 | 7 | :::center 8 | ![](../assets/cap-theorem.png)
9 | 图 5-1 CAP 定理 10 | ::: 11 | 12 | CAP 定理描述的是**一个分布式系统中,涉及共享数据问题时,以下三个特性最多只能满足两个**。 13 | 14 | - **一致性**(**C**onsistency):意味着数据在任何时刻、任何节点上看到的都是符合预期的。为了确保定义的严谨性,学术研究中通常将一致性定义为“强一致性”(Strong Consistency),也称为“线性一致性”(Linearizability)。 15 | - **可用性**(**A**vailability):意味着即使部分节点故障,系统仍然能够接受和处理请求,并在**有限时间内**返回结果。也就是说,系统不能出现无限期的等待或超时。 16 | - **分区容错性**(**P**artition tolerance):当部分节点由于网络故障或通信中断而无法相互联系,形成“网络分区”时,系统仍能够继续正确地提供服务。 17 | 18 | 由于 CAP 定理已有严格的证明,我们不再探讨为何 CAP 不可兼得,直接分析舍弃 C、A、P 时所带来的不同影响。 19 | 20 | - **放弃分区容忍性**(CA without P):意味着我们将假设节点之间通信永远可靠。永远可靠的通信在分布式系统中必定不成立,只要依赖网络共享数据,分区现象就不可避免地存在。如果没有 P(分区容错性),也就谈不上是真正的分布式系统。 21 | - **放弃可用性**(CP without A):意味着我们将假设一旦网络发生分区,节点之间的信息同步时间可以无限制延长。在现实中,选择放弃可用性系统(又称为 CP 系统)适用于对数据一致性有严格要求的场景,如金融系统、库存管理系统等。这些应用场景中,数据的一致性和准确性通常比系统的可用性更为重要。 22 | - **放弃一致性**(AP without C):意味着在网络分区发生时,节点之间的数据可能会出现不一致。这种情况下,系统会优先保证可用性,而不是一致性。选择放弃一致性系统(又称 AP 系统)已经成为设计分布式系统的主流选择,因为分区容错性(P)是分布式网络的固有属性,不可避免;而可用性(A)通常是建设分布式系统的目标。如果系统在节点数量增加时可用性降低,则其分布式设计的价值也会受到质疑。除了像银行和证券这样的金融交易服务,这些场景中数据一致性至关重要,通常需要保证一致性而可能接受部分中断之外,大多数系统更倾向于在节点增多时保持高可用性,而不是牺牲可用性以维持一致性。 23 | 24 | :::tip 额外知识 25 | 对于分布式系统而言,必须实现分区容错性(P)。因此,CAP 定理实际上要求在可用性(A)和一致性(C)之间选择,即在 AP 和 CP 之间权衡取舍。 26 | ::: 27 | 28 | 从上述分析可以看出,原本事务的主要目的是保证“一致性”,但在分布式环境中,一致性往往不得不成为牺牲的属性,AP 类型的系统反而成为了分布式系统的主流。 29 | 30 | 但无论如何,我们设计系统终究还是要确保操作结果至少在最终交付的时刻是正确的,这个意思是允许数据中间不一致,但应该在输出时被修正过来。为此,工程师们又重新给一致性下了定义,**将 CAP、ACID 中讨论的一致性(C)称为“强一致性”,而把牺牲了 C 的 AP 系统但又要尽可能获得正确结果的行为称为追求“弱一致性”**。不过,若只是单纯地谈论“弱一致性”,通常意味着不保证一致性。在弱一致性中,工程师们进一步总结出了一种较强的特例,称为“最终一致性”(Eventual Consistency),它由 eBay 的系统架构师 Dan Pritchett 在 BASE 理论中提出。 31 | 32 | :::tip 额外知识 33 | ACID 在英文中有的“酸”的含义,强调强一致性。BASE 在英文中有“碱”的含义,强调放弃强一致性保证可用性。酸 vs 碱衍生出 AP 型可用性架构和 CP 型强一致性架构。所以,CAP 理论又被戏称度量分布式系统的“ph试纸”。 34 | ::: 35 | 36 | 37 | [^1]: 参见 https://ieeexplore.ieee.org/document/798396 38 | [^2]: 参见 https://dl.acm.org/doi/10.1145/343477.343502 39 | [^3]: 参见 https://dl.acm.org/doi/abs/10.1145/564585.564601 40 | 41 | -------------------------------------------------------------------------------- /distributed-transaction/Saga.md: -------------------------------------------------------------------------------- 1 | # 5.3.3 Saga 2 | 3 | Saga 源于1987年普林斯顿大学的 Hector Garcia-Molina 和 Kenneth Salem 在 ACM 发表的论文《SAGAS》[^1]。该论文提出了一种改善“长时间事务”(Long Lived Transaction)效率的方法,核心思路是将大事务拆分为多个可并行执行的子事务,并在每个子事务中引入补偿操作。补偿(也称为逆向恢复)是在分布式事务发生异常时,通过一系列操作将事务状态回滚到之前的状态,从而避免不一致的情况发生。 4 | 5 | Saga 事务模型由两部分组成: 6 | 7 | 1. 一部分是**将大事务 T 拆分成若干小事务**,命名为 T~1~,T~2~,T~n~,每个子事务都具备原子性。如果分布式事务 T 能够正常提交,那么它对数据的影响应该与连续按顺序成功提交子事务 T~i~ 等价。 8 | 2. 另一部分是**为每个子事务设计对应的补偿动作**,命名为 C~1~,C~2~,C~n~。T~i~ 与 C~i~ 满足以下条件: 9 | - T~i~ 与 C~i~ 具备幂等性。 10 | - T~i~ 与 C~i~ 满足交换律,即无论先执行 T~i~ 还是先执行 C~i~,其结果都是一样的。 11 | - C~i~ 必须保证成功提交,即不考虑 C~i~ 的失败回滚情况。如果出现失败,则持续重试直至成功或者被人工介入为止。 12 | 13 | 如果 T~1~ 到 T~n~ 均执行成功,那么整个事务顺利完成,否则根据下面两种机制之一进行事务恢复: 14 | 15 | - **正向操作**(Forward Recovery):如果 T~i~ 提交失败,则一直对 T~i~ 进行重试,直至成功为止(使用最大努力交付机制)。这种恢复方式不需要进行补偿,适用于事务最终都要执行成功的情况。如订单服务中银行已经扣款,那么就一定要发货。 16 | - **逆向恢复**(Backward Recovery):如果 T~i~ 提交失败,则执行对应的补偿 C~i~,直至恢复到 T~i~ 之前的状态,这里要求 C~i~ 必须成功(使用最大努力交付机制)。 17 | 18 | :::center 19 | ![](../assets/saga.svg) 20 | 图 5-4 Saga 事务模型 21 | ::: 22 | 23 | Saga 非常适合处理流程较长、且需要保证事务最终一致性的业务场景。例如,在一个旅游预订平台中,用户可能同时预订机票、酒店和租车服务,这些服务可能由不同的微服务或第三方供应商提供。在这种场景下,Saga 事务模型允许系统逐步执行每个操作,并在任一步骤失败时有序地执行补偿操作,从而确保系统的一致性并提升用户体验。 24 | 25 | 与 TCC 相比,Saga 通常采用事件驱动设计,即每个服务都是异步执行的,无需设计资源的冻结状态或处理撤销冻结的操作。但缺点是不具备隔离性,多个 Saga 小事务操作同一数据源时,无法保证操作的原子性,可能出现数据被覆盖的情况。 26 | 27 | 最后,尽管补偿操作较易实现,但确保正向操作与补偿操作的严格执行仍需要大量精力。因此,Saga 事务通常不通过裸编码实现,而是在事务中间件的支持下完成。前面提到的 Seata 中间件也支持 Saga 事务模型。 28 | 29 | [^1]: 参见 https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf 30 | -------------------------------------------------------------------------------- /distributed-transaction/TCC.md: -------------------------------------------------------------------------------- 1 | # 5.3.2 TCC 2 | 3 | TCC(Try、Confirm、Cancel)事务模型源自 Pat Helland 在论文《Life beyond Distributed Transactions: an Apostate’s Opinion》[^1] 中提出的概念。TCC 引入了一种新的事务模型,允许业务层自定义事务,并根据业务需求控制锁的粒度,从而解决了复杂业务中跨表、跨库等大粒度资源锁定的问题。 4 | 5 | 如同 TCC 事务模型的名字,它由三个阶段组成: 6 | 7 | 1. **Try 阶段**:该阶段的主要任务是预留资源或执行初步操作,但不提交事务。Try 阶段确保所有相关操作可以成功执行且没有资源冲突。例如,在预订系统中,这一阶段可能包括检查商品库存并暂时锁定商品。 8 | 2. **Confirm 阶段**:如果 Try 阶段成功,系统进入 Confirm 阶段。在此阶段,系统会提交所有操作,确保事务最终生效。由于 Try 阶段已保证资源的可用性和一致性,Confirm 阶段的执行是无条件的,不会发生失败。 9 | 3. **Cancel 阶段**:如果 Try 阶段失败,或需要回滚事务,系统进入 Cancel 阶段。此时,系统会撤销 Try 阶段中的所有预留操作并释放资源。Cancel 阶段确保事务无法完成时,系统能够恢复最初的状态。 10 | 11 | 以一个具体的例子帮助你理解 TCC 事务模型。我们沿用 5.3.1 节下单的案例,稍微简化下单的逻辑,去除积分服务(不重要),只保留支付和仓库服务。 12 | 13 | :::center 14 | ![](../assets/TCC.svg)
15 | 图 5-3 TCC 事务模型 16 | ::: 17 | 18 | 首先,用户向商店发送购买某商品的交易请求,金额为 ¥100。请看下面的过程: 19 | 20 | 1. Try 阶段:创建事务,生成事务 ID,并记录在事务日志中,进入 Try 阶段。该阶段主要预留业务资源,以及做一些初始化工作: 21 | - 与支付服务通信,确认用户是否有足够的余额。若余额足够,将用户的 100 元设置为冻结状态,并通知进行 Confirm 阶段;如果不可行,通知进入 Cancel 阶段。 22 | - 与仓库服务通信,确认商品的库存是否满足。若库存充足,将仓库中该商品的一条库存设置为冻结状态,并通知进行 Confirm 阶段;如果不可行,通知进入 Cancel 阶段。 23 | 24 | 2. Confirm 阶段:如果所有服务反馈业务可行,将事务日志状态更新为 Confirm,进入 Confirm 阶段。 25 | - 支付服务:扣除冻结的 100 元。 26 | - 仓库服务:标记冻结的库存为出库状态,并扣减库存。 27 | 28 | 3. Cancel 阶段:如果 Try 阶段任何一方反馈失败,将事务日志状态更新为 Cancel,进入 Cancel 阶段: 29 | - 支付服务:释放被冻结的 100 元。 30 | - 仓库服务:释放被冻结的库存。 31 | 32 | 值得注意的是,按照 TCC 事务模型的规定,Confirm 和 Cancel 阶段只返回成功,不会返回失败。如果 Try 阶段之后,出现网络问题或者服务器宕机,那么事务管理器要不断重试 Confirm 阶段或者 Cancel 阶段,直至完成整个事务流程。 33 | 34 | 由上述操作过程可见,TCC 事务模型其实有点类似两阶段提交(2PC)的准备阶段和提交阶段,但 TCC 位于业务层面,而不是数据库层面,这为它的实现带来了较高的灵活性,可以根据需要设计资源锁定的粒度。 35 | 36 | 不过,感知各个阶段的执行情况以及推进执行下一个阶段需要编写大量的逻辑代码,不仅仅是调用一下 Confirm/Cancel 接口那么简单。通常的情况,我们没必要裸编码实现 TCC 事务模型,而是利用分布式事务中间件(如 Seata、ByteTCC)降低编码工作,提升开发效率。 37 | 38 | 39 | 40 | [^1]: 参见 http://adrianmarriott.net/logosroot/papers/LifeBeyondTxns.pdf -------------------------------------------------------------------------------- /distributed-transaction/conclusion.md: -------------------------------------------------------------------------------- 1 | # 5.5 小结 2 | 3 | 4 | 通过本章的内容,你是否已经领会到“分布式事务的思想”?无论是 BASE、TCC 还是 SAGA,它们的核心想想是将“事务逻辑”从数据库资源层转移到业务层,将事务拆分为多个“子事务”,减少资源锁定,从而提高系统可用性。 5 | 6 | 分布式事务能够保证数据最终达到一致性,但这种保证非常脆弱,它无法确定何时能够达到一致性。在一致性达成之前,读请求可能返回任意值或失败,这对业务工程师来说是一个重大挑战。 7 | 8 | 在下一章,笔者将介绍一种实现强一致性(也称为线性化)的算法,该算法的特点是,一旦写操作成功提交,所有后续的读操作将立即看到该写入的结果。这意味着,客户端成功写入数据后,其他客户端的读请求将立刻获取到最新的写入值,不会再出现“最终一致性系统”中数据不一致问题。 -------------------------------------------------------------------------------- /distributed-transaction/idempotent.md: -------------------------------------------------------------------------------- 1 | # 5.4 服务幂等性设计 2 | 3 | 幂等性是一个数学概念,后被引入计算机领域,用于描述某个操作可以安全地重试,并且无论执行多少次,结果始终保持一致。 4 | 5 | 在前文中提到的柔性事务通常基于“最大努力交付”机制,这意味着在网络故障、节点宕机或进程崩溃时,系统会通过重复请求来实现容错。因此,如果某些关键服务不具备幂等性,重复请求可能会导致数据不一致或其他问题。例如,重复请求一个不具备幂等性的退款接口,可能会导致重复退款。 6 | 7 | 接下来,笔者将介绍两种实现服务幂等性的方法,供读者参考。 8 | 9 | ## 5.4.1 全局唯一 ID 方案 10 | 11 | 全局唯一 ID 方案的核心思想是为每个操作生成一个独一无二的标识符,用以判断该操作是否已经执行过,避免重复执行。 12 | 13 | 全局唯一 ID 方案的操作步骤如下: 14 | 15 | 1. **生成唯一 ID**:每次执行操作前,根据业务操作生成一个全局唯一ID,这个 ID 可以利用 UUID、雪花算法(Snowflake) 16 | 、Uidgenerator 或 Leaf 等算法生成。 17 | 2. **附加到请求**: 将生成的唯一 ID 附加到请求中,作为请求的一个参数、HTTP 头或请求体的一部分。 18 | 3. **处理请求**: 服务器端接收到请求后,首先检查唯一 ID: 19 | - 如果 ID 已存在:说明该请求已经被处理过,服务器直接返回之前的响应结果,避免重复处理。 20 | - 如果 ID 不存在:执行请求的操作,并将操作结果和该 ID 存储在数据存储中(如数据库、缓存等),以供后续请求检查。 21 | 22 | 值得一提的是,snowflake 算法取自世界上没有两片相同的雪花之意。使用分布式部署的 Snowflake 每秒可生成数百万个唯一且递增的 ID,广泛应用于需要生成唯一标识符的各类场景。 23 | 24 | ## 5.4.2 乐观锁方案 25 | 26 | 接下来,再看数据库中关于修改数据的操作。 27 | 28 | 假设有一个账户表 accounts,包含字段 id(账户ID)和 balance(账户余额)。现在要给账户 ID 为 1 的账户增加余额 29 | 30 | ```sql 31 | UPDATE accounts SET balance = balance + 100 WHERE id = 1; 32 | ``` 33 | 如果这个SQL语句执行一次,那么账户的余额会增加 100。但由于某些原因(比如网络重试或者程序逻辑错误),这个 SQL 语句被执行了两次,账户的余额将会增加 200,而不是预期的 100。 34 | 35 | 每次执行这个语句都会对账户余额产生不同的影响,属于典型的非幂等性操作。对于此类的非幂等性操作,我们来看使用乐观锁(Optimistic Locking)如何解决。 36 | 37 | 乐观锁基本思想是,假设并发操作发生冲突的概率较低,允许多个事务或线程在不加锁的情况下同时读取数据,但在写入数据时再进行冲突检测。如果在写入前检测到数据已被其他事务修改,则放弃当前操作,避免数据不一致的情况。 38 | 39 | 结合上述增加余额的 SQL,请看下面具体的操作: 40 | 41 | - **增加版本号字段**:在涉及更新的数据表中增加一个 version 字段,更新数据时,版本号随之增加。 42 | - **更新时检查版本号**:执行更新操作时,通过 WHERE 子句检查当前版本号是否与读取时的版本号一致,如果一致则执行更新,并更新版本号。 43 | - **重试机制**:如果更新操作失败,意味着数据库内的数据已经被修改。此时,业务层面请求最新的数据,更新本地 version 并发起重试,直至成功或达到最大重试次数。 44 | 45 | 46 | ```sql 47 | UPDATE accounts 48 | SET balance = balance + ?, 49 | version = version + 1 50 | WHERE id = ? AND version = ?; 51 | ``` 52 | 53 | 上面乐观锁的操作模式,是一种典型的 CAS(Compare And Swap | Compare And Set,比较并交换)操作。 54 | 55 | CAS 有时也被称为“轻量级事务”。由于乐观锁不需要在读取和写入时持有锁,在并发冲突不频繁的情况下(也就是读多写少的场景),使用乐观锁除保证一致性之外,还可提供更好的并发性能。 56 | 57 | -------------------------------------------------------------------------------- /distributed-transaction/summary.md: -------------------------------------------------------------------------------- 1 | # 第五章:数据一致性与分布式事务 2 | 3 | :::tip
4 | 5 | 网络是不稳定的,延迟是不可预测的,带宽是有限的,拓扑是动态的,一切都会失败。 6 | 7 | :::right 8 | —— 改自于分布式计算八大谬误[^1] 9 | ::: 10 | 11 | 12 | 事务(transaction)最早指本地事务,也就是对数据库的多个读写操作捆绑为一个操作单元。该操作单元作为一个执行整体要么全部成功,要么全部中止,从而保证某些极端情况下(进程崩溃、网络中断、节点宕机)数据一致性。随着分布式系统的广泛应用,所有需要保证数据一致性的应用场景,包括但不限于缓存、消息队列、存储、微服务架构之下的数据一致性保证等等,都需要用到事务的机制进行处理。 13 | 14 | 在单体系统时代,如何实现事务仅仅是个编码问题。但在分布式系统时代,事务操作跨越了多个节点,保证多个节点间的数据一致性便成了架构设计问题。2000 年以前,人们曾经希望基于“两阶段提交”(2PC, Two-Phase Commit Protocol)[^2]的事务机制,也能在现代分布式系统中良好运行,但这个愿望被 CAP 定理粉碎。本章,我们深入理解分布式环境下数据一致性和可用性的矛盾,掌握各个分布式事务模型原理。 15 | 16 | 本章内容安排如图 5-0 所示。 17 | :::center 18 | ![](../assets/distributed-transaction.png) 19 | 图 5-0 本章内容导图 20 | ::: 21 | 22 | [^1]: 分布式计算八大谬误出现背景是,人们在设计和开发分布式系统时,常常将中心化系统的经验和假设直接应用到分布式环境中,忽视了分布式环境的复杂性和特殊需求。这些谬误可以视为分布式系统设计时需要考虑的架构需求。 23 | [^2]: 两阶段提交(2PC)是一种在多节点之间实现事务原子提交的算法,用来确保所有的节点要么全部提交、要么全部中止。它是分布式数据中的经典算法之一。2PC 在某些数据库内部使用,或者以 XA 事务形式提供给应用程序。 -------------------------------------------------------------------------------- /distributed-transaction/transaction.md: -------------------------------------------------------------------------------- 1 | # 5.3 分布式事务模型 2 | 3 | 既然一致性被重新定义了,事务的概念自然也被拓展了。人们把符合 ACID 特性的事务称为“刚性事务”,把后面将要介绍的可靠事件队列、TCC、Saga 实现的事务,统称为“柔性事务”。 4 | -------------------------------------------------------------------------------- /http/Edge-Acceleration.md: -------------------------------------------------------------------------------- 1 | # 2.7 对请求进行“动态加速” 2 | 3 | 动态加速是一种通过实时监测网络状态,并根据流量、延迟、丢包率等关键指标动态调整传输策略的优化技术。 4 | 5 | 主流技术服务商(如 Akamai、Fastly、Amazon CloudFront 和 Microsoft Azure)在全球各地部署了大量边缘服务器,构建了覆盖广泛的全球加速网络。使用这些服务商的“动态加速”服务非常简单,只需将域名 CNAME 到服务商提供的地址,即可自动实现加速。 6 | 7 | 操作流程大致如下: 8 | 9 | 1. “源站”(Origin)将域名 CNAME 到 CDN 服务商提供的域名。例如,将 www.thebyte.com.cn CNAME 到 thebyte.akamai.com。 10 | 2. 源站提供一个约 20KB 的文件资源,用于探测网络质量。 11 | 3. CDN 服务商在源站附近选择一批“转发节点”(Relay Nodes)。 12 | 4. 转发节点对测试资源执行下载测试,根据丢包率、RTT、路由的 hops 数等,选定“客户端”(End Users)到源站的最佳路径。 13 | 14 | :::center 15 | ![](../assets/dsa.png)
16 | 图 2-23 动态加速原理 [图片来源](https://www.cdnetworks.com/cn/web-performance/dynamic-web-acceleration/) 17 | ::: 18 | 19 | 笔者使用过 Akamai 的加速服务,根据表 2-4 所示的实践结果来看,HTTPS 请求延迟降低了 30% 左右。 20 | 21 | :::center 22 | 表 2-4 网络直连与使用动态加速的效果对比 23 | ::: 24 | 客户端| 源站| 客户端直接访问源站的延迟| 客户端使用 Akamai 加速后的延迟| 效果提升 25 | :---|:--:|:--:|:--:|:-- 26 | 泰国,曼谷|香港|0.58s|0.44s|31% 27 | 印尼,雅加达|香港|0.57s|0.44s|31% 28 | 马来西亚,吉隆坡|香港|0.52s|0.38|36% 29 | 台北|香港|0.51s|0.40s|37% 30 | 越南,河内|香港|0.54s|0.41s|30% 31 | 新加坡|香港|0.58s|0.39s|48% 32 | 香港|香港|0.38s|0.24s|58% 33 | 日本,东京|香港|0.60s|0.45s|32% 34 | 印尼,泗水|香港|0.67s|0.52s|29% 35 | 菲律宾,马尼拉|香港|0.46s|0.34s|36% 36 | 37 | 利用边缘节点加速请求是一种典型的“网络边缘代理”技术。有关各类代理技术的原理,笔者将在本书第六章详细介绍。 38 | 39 | [^1]: AS(Autonomous System,自治系统)具有统一路由策略的巨型网络或网络群组,每个自治系统被分配一个唯一的 AS 号,各个 AS 之间使用 BGP 协议进行识别和通告路由,全世界最大规模的 AS 网络就是互联网。 40 | [^2]: 笔者曾在上海使用 mtr 工具测试一个新加坡节点路由状态,数据包先到香港 AS,香港转到美国 AS,再从美国转到新加坡 AS。 41 | -------------------------------------------------------------------------------- /http/compress.md: -------------------------------------------------------------------------------- 1 | # 2.4 使用 Brotli 压缩传输内容 2 | 3 | 压缩传输内容是提升 HTTP 服务可用性的关键手段。比如使用 Gzip 压缩一个 100KB 的文件,通常会减少到 30KB,不仅能提高网络传输效率,还能减少带宽成本。 4 | 5 | 所有现代浏览器、客户端和 HTTP 服务器软件都支持压缩技术,它们之间使用协商机制确定采用的压缩算法(如图 2-8 所示): 6 | - 首先,HTTP 客户端发送 Accept-Encoding 首部,其中列出它支持的压缩算法及其优先级; 7 | - 服务器则从中选择一种兼容的算法对响应主体进行压缩,并通过 Content-Encoding 首部告知客户端所选的压缩算法。 8 | 9 | :::center 10 | ![](../assets/compress.png)
11 | 图 2-8 HTTP 压缩算法协商过程 12 | ::: 13 | 14 | 默认情况下,一般使用 Gzip 对内容进行压缩,但针对 HTTP 类型的文本内容还有一个更高压缩率的算法 Brotli。 15 | 16 | Brotli 是 Google 推出的开源无损压缩算法,它内部有一个预定义的字典,涵盖了超过 1,300 个 HTTP 领域常用单词和短语。Brotli 会将这些常见的词汇和短语作为整体匹配,从而大幅提升文本型内容( HTML、CSS 和 JavaScript 文件)的压缩密度。 17 | 18 | 如图 2-9 所示,各类型压缩算法在不同压缩等级下的效果对比。可以看到,Brotli 压缩效果比常用的 Gzip 高出 17% 至 30%。 19 | 20 | :::center 21 | ![](../assets/brotli.png)
22 | 图 2-9 Brotli、Zopfli、gzip 不同压缩等级下的压缩率对比 23 | ::: 24 | 25 | 在服务端安装了 Brotli 模块(如 ngx_brotli)后,可以与 gzip 一同启用,以最大化兼容性。以下是 Nginx 中启用 Brotli 的配置示例: 26 | 27 | ```nginx 28 | http { 29 | brotli on; // 开启 brotli 压缩 30 | brotli_comp_level 6; // 设置压缩等级 31 | brotli_buffers 16 8k; // 设置缓冲的数量和大小 32 | brotli_min_length 20; // 压缩的最小长度 33 | brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml; // 压缩类型 34 | 35 | // gzip 配置 36 | ... 37 | } 38 | ``` -------------------------------------------------------------------------------- /http/conclusion.md: -------------------------------------------------------------------------------- 1 | # 2.9 小结 2 | 3 | 本章详细分析了 HTTPS 请求过程,讲解了主要环节的原理与优化方法。相信你对于构建足够快的网络服务,有了足够的认识。 4 | 5 | 总结来说,要构建“足够快”的网络服务,首先保证域名解析不能失败,然后请求要足够快(使用 QUIC、Brotli 压缩),还要足够安全(使用 TLS1.3 协议 + ECC 证书,即快又安全),还要充分利用带宽(使用 BBR 提高网络吞吐率)。最后,技术无法解决的(长链路、弱网、海外网络),那就要舍得花钱(使用 CDN、建立边缘网络、建立当地数据中心)。 6 | 7 | 最后,说一千道一万,不如亲手做一遍。现在,你准备好在自己的业务中付诸实践了吗? -------------------------------------------------------------------------------- /http/dns-ha.md: -------------------------------------------------------------------------------- 1 | # 2.3.3 Facebook 故障分析与总结 2 | 3 | Facebook “史诗级故障”发生在 2021 年 10 月 4 日,故障绕过了所有的高可用设计,让 Facebook 公司旗下的 Facebook、Instagram、WhatsApp 等众多服务出现了长达 7 个小时宕机。故障的影响范围极广,差点导致严重的二次故障,搞崩半个互联网。 4 | 5 | 如此大规模服务瘫痪不是 DNS 就是 BGP 出现了问题。这次,Facebook 很倒霉,DNS 和 BGP 一起出现了问题。 6 | 7 |
8 | 9 |

图 2-4 Facebook宕机

10 |
11 | 12 | Facebook 官方发布的故障原因是,运维人员修改 BGP 路由规则时,错误地删除了 Facebook 自治域 AS32934 [^1]内的“权威域名服务器”的路由配置!这个操作导致所有 Facebook 域名的解析请求被丢弃,世界各地“DNS 解析器”无法正常解析 Facebook 相关的域名。 13 | 14 | ## 1.故障现象 15 | 16 | 故障期间使用 dig 命令查询 Facebook 域名解析记录,出现 SERVFAIL 错误。 17 | 18 | ```bash 19 | ➜ ~ dig @1.1.1.1 facebook.com 20 | ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 31322 21 | ;facebook.com. IN A 22 | ➜ ~ dig @8.8.8.8 facebook.com 23 | ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 31322 24 | ;facebook.com. IN A 25 | ``` 26 | 根据上一篇内容的介绍,这是“权威解析服务器”出现了问题。那影响范围可就大了,世界上所有的用户都无法再正常打开 Facebook 相关的网站、APP。 27 | 28 | 用户无法正常登录 APP 时,通常会“疯狂”地发起重试。Facebook 用户太多了,云服务商 Cloudflare 的 DNS 解析器(1.1.1.1)请求瞬间增大了 30 倍。如果 1.1.1.1 宕机,恐怕半个互联网都会受到影响。 29 | 30 |
31 | 32 |

图 2-5 Cloudflare 的域名解析服务器 1.1.1.1 在 Facebook 故障时请求瞬间增大 30 倍

33 |
34 | 35 | 此次故障还影响到 Facebook 内部,员工的工作邮箱、门禁系统统统失效,Facebook 从外到内完全停摆。据 Facebook 员工回忆当天的情形:“ 今天大家都很尴尬,不知道发生了什么,也不知道该做什么,只好假装什么都没有发生”。 36 | 37 | 故障从美国东部标准时间上午 11 点 51 分开始,最终 6 个小时以后服务恢复。 38 | 39 | ## 2.故障总结 40 | 41 | 此次故障实际上是 Facebook BGP 路由系统和 DNS 系统一系列设计缺陷叠加,而从放大了故障影响: 42 | 43 | - 运维人员发布了错误的 BGP 路由公告; 44 | - 恰巧 Facebook 的权威域名服务器的 IP 包含在这部分路由中。 45 | 46 | 这就导致域名解析请求无法路由到 Facebook 内部网络。 47 | 48 | 因为是 DNS 出现问题,运维人员也受故障影响,很难再通过远程的方式修复,修复团队只能是紧急跑到数据中心修复(道听途说打了“飞的”过去)。 49 | 50 | Facebook 这次故障带给我们以下 DNS 系统的设计思考: 51 | 52 | - **部署形式思考**:可选择将“权威域名服务器”放在 SLB(Server Load Balancer,负载均衡)后方,或采用 OSPF Anycast [^2]的部署形式避免单点问题。 53 | - **部署位置思考**:可选择自建集群 + 公有云服务混合部署,利用云增强 DNS 系统可靠性。 54 | 55 | 如图 2-6 所示,amazon.com 和 facebook.com 的权威域体系对比:amazon.com 的权威解析服务器有多套不同的地址,分散于不同的 TLD 域名服务器,所以它的抗风险能力肯定强于 Facebook。 56 | 57 |
58 | 59 |
60 |
61 | 62 |

图 2-6 amazon.com 与 facebook.com 域名系统对比

63 |
64 | 65 | ## 3.运维操作的警示 66 | 67 | 部分运维操作具有很大风险,比如更改 BGP 通告、修改路由、修改防火墙策略等。如果操作失误,极可能造成远程连接无法使用。这时候想远程修复就难了,只能接近物理机才能处理。 68 | 69 | 这对我们的思考是,如果生产环境要进行很大风险性的操作,除了慎之又慎外,应该使用一种二次确认的方式,比如修改 iptables 规则,修改之后引入 10 分钟“观察期”,观察期结束后,系统自动恢复原来的配置。运维人员分析观察期内的数据变化,确认没有任何问题之后,再执行正式操作。 70 | 71 | [^1]: AS(Autonomous System,自治域)是具有统一路由策略的巨型网络或网络群组。各个开放的 AS 连接起来就成了互联网。连接到互联网的每台计算机或设备都需要连接到一个 AS。 72 | [^2]: OSPF Anycast 是一种网络服务部署技术,它通过借助于动态路由协议实现服务的负载均衡和冗余,提高了服务的可用性和效率。 在 OSPF Anycast 中,一个目标地址可以分配给多个接口,每个接口连接一个服务器节点。当客户端访问该目标地址时,数据包会被发送到最近的服务器节点,从而实现负载均衡和冗余备份。 73 | 74 | -------------------------------------------------------------------------------- /http/http-dns.md: -------------------------------------------------------------------------------- 1 | # 2.3.4 使用 HTTPDNS 解决“中间商”问题 2 | 3 | “域名解析器”是 DNS 查询的第一站,充当客户端与“域名服务器”之间的中介,帮助我们解析“整棵 DNS 树”。 4 | 5 | 但作为一个“中间商”,“域名解析器”很容易出现域名劫持、解析时间过长、解析调度不精准等问题。这些问题的根源在于,域名解析经过了多个中间环节,导致服务质量不可控。为了解决上述问题,一种新型的 DNS 解析模式 —— HTTPDNS 应运而生。 6 | 7 | HTTPDNS 的工作原理如图 2-7 所示。客户端内部集成 HTTPDNS 模块,绕过操作系统默认的域名解析服务(图中的 LocalDNS,通常基于 UDP 协议),改为通过 HTTPS 协议向更可靠的“软件定义的解析服务”(图中的 6.6.6.6)发起请求。 8 | 9 | :::center 10 | ![](../assets/httpdns.png)
11 | 图 2-7 HTTPDNS 模式下 DNS 解析原理 12 | ::: 13 | 14 | HTTPDNS 好处是避免了“中间商赚差价”。软件定义的解析服务直接从权威域名服务器同步解析记录,逻辑更加可控,同时能够准确识别客户端的地区和运营商,从而提供更精准的解析结果。 15 | 16 | 通过使用 HTTPDNS,并结合客户端解析缓存、热点域名预解析等优化手段,可以显著改善传统域名解析所带来的各种问题。根据笔者的实践经验,采用 HTTPDNS 后,HTTP 服务的初次请求延迟下降约 25%,同时域名解析劫持、页面无法打开和请求失败等故障率也大幅降低。 -------------------------------------------------------------------------------- /http/https-summary.md: -------------------------------------------------------------------------------- 1 | # 2.5 HTTPS 加密原理及优化实践 2 | 3 | 相信读者知道 HTTPS(SSL/TLS)一些基本逻辑,但在面对数字签名、数字证书、对称与非对称加密等术语时,除了了解它们“它是什么”,你是否想过“为什么是它”。搞清楚后者非常重要,否则你只是单纯地记住了被灌输的知识,而未真正理解它。 -------------------------------------------------------------------------------- /http/latency.md: -------------------------------------------------------------------------------- 1 | # 2.1 了解各类延迟指标 2 | 3 | 既然目标是“足够快”,首先需要对计算机中“快”的概念有一个基本的认识。 4 | 5 | 伯克利大学有个动态网页[^1],里面汇总了历年计算机中各类操作延迟(也称时延)的变化。笔者整理了 2020 年的数据供读者参考,如表 2-1 所示。这些延迟数据与软件设计和性能调优息息相关。例如,由于物理距离的限制,无论如何优化,也无法将从上海到美国的 HTTPS 请求延迟降到 750ms 以下。 6 | 7 | :::center 8 | 表 2-1 计算机中各类延迟数据参考 9 | ::: 10 | 操作|延迟 11 | |:---|:--:| 12 | CPU 从一级缓存中读取数据| 1 ns 13 | CPU 分支预测错误(Branch mispredict)| 3 ns 14 | CPU 从二级缓存中读取数据 | 4 ns 15 | 线程间,共享资源加锁/解锁 | 17 ns 16 | 在 1Gbps 的网络上发送 2KB 数据 | 44 ns 17 | 访问一次主存 | 100 ns 18 | 使用 Zippy 压缩 1KB 数据 | 2,000 ns ≈ 2 μs 19 | 从内存顺序读取 1 MB 数据 | 3,000 ns ≈ 3 μs 20 | 一次 SSD 随机读 | 16,000 ns ≈ 16 μs 21 | 从 SSD 顺序读取 1 MB 数据 | 49,000 ns ≈ 49 μs 22 | 一个数据包在同一个数据中心往返 | 500,000 ns ≈ 0.5 ms 23 | 从磁盘顺序读取 1 MB 数据 | 825,000 ns ≈ 0.8 ms 24 | 一次磁盘寻址 | 2,000,000 ns ≈ 2 ms 25 | 一次 DNS 解析查询 | 50,000,000 ns ≈ 50 ms 26 | 把一个数据包从美国发送到欧洲 | 150,000,000 ns ≈ 150 ms 27 | 在宿主机中冷启动一个常规容器 | 5,000 ms ≈ 5 s 28 | 29 | 秒(s)、毫秒(ms)、微秒 (μs)、纳秒 (ns)之间关系:1s = 103ms=106μs=109ns 30 | 31 | [^1]: 参见 https://colin-scott.github.io/personal_website/research/interactive_latency.html -------------------------------------------------------------------------------- /http/quic.md: -------------------------------------------------------------------------------- 1 | # 2.8 QUIC 设计原理与实践 2 | 3 | QUIC(Quick UDP Internet Connection,快速 UDP 网络连接)是一种基于 UDP 封装的安全可靠传输协议,旨在取代 TCP 成为新一代互联网的主流传输协议。 4 | 5 | 很多人可能以为是 IETF 在推动 QUIC 替代 TCP。实际上,这项工作始于 Google。 6 | 7 | 早在 2013 年,Google 就在自家服务(如 Google.com、YouTube.com)及 Chrome 浏览器中启用了名为“QUIC”(业内称为 gQUIC)的全新传输协议。2015 年,Google 将 gQUIC 提交给 IETF,经 IETF 规范化后的 QUIC 被称为“iQUIC”。早期的 iQUIC 有多个“草稿”版本,如 h3-27、h3-29 和 h3 v1。2018 年末,IETF 启动 HTTP/3 的标准化工作,并在 5 年后 (2022 年 6 月)将其正式定义为 RFC 9114,成为 HTTP 的第三个主要版本。 8 | 9 | 根据图 2-24,可以看出 HTTP/3 最大的特点是底层基于 QUIC/UDP、默认集成了 TLS 安全协议。 10 | 11 | :::center 12 | ![](../assets/http-quic.png)
13 | 图 2-24 各个版本 HTTP 协议对比 14 | ::: 15 | 16 | ## 2.8.1 QUIC 出现的背景 17 | 18 | QUIC 出现之前,HTTP 采用 TCP 作为底层协议来实现可靠的数据传输。 19 | 20 | 作为四十年前开发的传输层协议,TCP 的设计者显然没有预见今天移动设备盛行的场景。在移动网络环境中,TCP 先天设计缺陷不断被放大。 21 | 22 | - **建立连接时延迟大**:HTTPS **初次连接(TCP 握手 + TLS 握手)至少需要 3 个 RTT** 才能建立。 23 | - **队头阻塞问题**:以 HTTP/2 为例,一个 TCP 连接上的所有 stream(流,HTTP/2 传输的数据单元)**必须按顺序依次传输**。如果一个 stream 丢失,后面的 stream 将被阻塞,直到丢失的数据重传。 24 | - **协议僵化问题**:作为一个运行了接近 40 多年的协议,许多中间设备(如防火墙和路由器)**已经变得依赖某些隐式规则**,打补丁或者说推动 TCP 协议更新脱离现实。 25 | 26 | ## 2.8.2 QUIC 的特点 27 | 28 | 在借鉴 TCP 设计经验并考虑当前网络环境的基础上,QUIC 基于 UDP 实现了一种全新的可靠传输机制,具备更低的延迟、更高的吞吐量。下面列举 QUIC 的部分重要特性,这些特性是 QUIC 被寄予厚望的关键。 29 | 30 | ### 1. 支持连接迁移 31 | 32 | 当用户的网络环境发生变化时,比如从 WIFI 切换到 4G,基于四元组的 TCP 连接无法保持存活。而 **QUIC 使用 Connection ID 标识连接**,不受环境变化影响。因此,QUIC 可以实现网络变化的无缝切换,保证连接存活和数据正常收发。 33 | 34 | :::center 35 | ![](../assets/quic-connection.png)
36 | 图 2-25 QUIC 支持连接迁移 37 | ::: 38 | 39 | ### 2. 低时延连接 40 | 41 | 以 HTTPS 请求为例,即使是最新的 TLS 1.3 协议,**初次连接也至少需要 2-RTT 才能开启数据传输**。此外,像 TCP Fastopen 类补丁方案,由于协议僵化原因,实际上不会在复杂网络起到作用。 42 | 43 | QUIC 内部集成了 TLS 安全协议,无需像 TCP 先经过三次握手,再经过 TLS 握手才开启数据传输。**QUIC 初次连接只需要 1- RTT 就能开启数据传输**。 44 | 45 | :::center 46 | ![](../assets/quic-handshake.png)
47 | 图 2-26 不同协议开启数据传输时,需要的 RTT数 48 | ::: 49 | 50 | ### 3. 可插拔拥塞控制 51 | 52 | 笔者曾推动升级某核心网络系统的 TCP 拥塞控制算法,过程艰难,主要因为需要升级操作系统内核版本。 53 | 54 | **大多数 QUIC 实现工作在用户空间,支持灵活“插拔”不同的拥塞控制算法**,如 Cubic、BBR 和 PCC 等。这让工程师在无需深入内核开发的情况下,能灵活调整可靠传输机制和拥塞控制策略。如 Cloudflare 开发的开源 QUIC 实现 quiche,提供了 setSendAlgorithm 方法,工程师可直接选择合适的拥塞控制算法,无需经过操作系统内核。 55 | 56 | ### 4. 降低对丢包的影响 57 | 58 | 先来看 HTTP/2 Stream 的处理。 59 | 60 | 如图 2-27 所示,若一个属于 Stream2 的 TCP 数据包丢失(如图中标记为 5 的圆圈),将导致后续数据包的传输阻塞。该问题就是业界常常提到的“队头阻塞”(head-of-line blocking)。 61 | 62 | 相比之下,**QUIC 为每个 Stream 设计了独立的控制机制,Stream 之间没有先后依赖**。这意味着,如果一个属于 Stream2 的 UDP 数据包丢失,它只会影响 Stream2 的处理,不会阻塞 Stream1 和 Stream3 的传输。 63 | 64 | 这样的设计有效避免了 TCP 协议中的队头阻塞问题。 65 | 66 | :::center 67 | ![](../assets/quic-head-block.png)
68 | 图 2-27 QUIC Stream 的设计减小了丢包的影响 69 | ::: 70 | 71 | 此外,还需提及 QUIC 实现的另一个特性 —— QPACK。QPACK 通过更高效的头部压缩技术,减少了网络传输中的冗余数据量。这种压缩机制不仅提升了数据传输的效率,还能缓解前面提到的“队头阻塞”。 72 | 73 | 经过上述全方面的优化设计,QUIC 确保了在当今网络环境中比 TCP 更安全、更快速的连接以及更高的传输效率。 74 | 75 | ## 2.8.3 QUIC 实践 76 | 77 | 撰写本文时,距 HTTP/3 发布已有三年之久。那它的实际表现如何呢?2022 年,爱奇艺基础架构团队对 HTTP/1.1、HTTP/2 和 HTTP/3 在不同网络条件下的性能差异进行了测试。笔者将测试数据在此分享,供读者参考。 78 | 79 | 从请求耗时表现来看(图 2-28),相同的网络质量下,HTTP/3 的耗时比 HTTP/2 降低了近一半,证明了上述讨论不虚。 80 | :::center 81 | ![](../assets/quic-1.png)
82 | 图 2-28 不同网络质量下,各协议耗时表现(耗时单位 ms) 83 | ::: 84 | 85 | 不过,根据图 2-29 所示的网络请求成功率来看,HTTP/3 的失败率明显高于 HTTP/2。笔者“猜测”有两方面的原因: 86 | - 某些网络环境下(如网络设备配置不当、防火墙限制),UDP 数据包更容易被丢弃。 87 | - QUIC 作为较新的协议,在一些边缘场景(如企业内部网络、陈旧的网络设备)中,兼容性不够完善。 88 | 89 | :::center 90 | ![](../assets/quic-3.png)
91 | 图 2-29 不同网络质量下,各协议失败率表现 92 | ::: 93 | 94 | 综上所述,无论是服务端还是客户端,集成 QUIC 协议并非易事。 95 | 96 | - 服务端层面:不仅需要适配 QUIC 协议,还要确保与 TCP 协议兼容。此外,TCP 经过多年的深度优化,QUIC 实际的效能表现是否能够与 TCP 相媲美? 97 | - 客户端层面:需要在适配、收益之间进行成本权衡。采用 QUIC 协议的客户端必须具备降级容错能力,并准备长时间同时维护新旧两种网络库。 98 | -------------------------------------------------------------------------------- /http/summary.md: -------------------------------------------------------------------------------- 1 | # 第二章: 构建“足够快”的网络服务 2 | 3 | :::tip
4 | 5 | 永远不要低估一辆满载着硬盘的卡车,在高速公路上飞驰时的带宽。 6 | 7 | :::right 8 | —— by《计算机网络》作者 Andrew S. Tanenbaum [^1] 9 | ::: 10 | 11 | 不少人的第一直觉是“路由的 hops、运营商线路的质量,决定网络的延迟以及吞吐量”,由此盲目断定网络因开发者不可控而无法插手。实际上,应用层的网络请求是否与传输协议提倡的方式匹配,这对提升网络吞吐量、降低网络延迟也施加不小的影响。最能体现这一点的,便是各类网络优化技巧。 12 | 13 | 本章,我们将分析应用层 HTTPS 请求的完整过程,探讨其中 DNS、SSL、QUIC 以及网络拥塞控制的原理,研究各种网络优化技巧,讨论实现“构建足够快的网络服务”目标! 14 | 15 | 本章内容安排如图 2-0 所示。 16 | 17 | :::center 18 | ![](../assets/http-summary.png)
19 | 图 2-0 本章内容导读 20 | ::: 21 | 22 | [^1]: Andrew S. Tanenbaum,荷兰阿姆斯特丹 Vrije 大学的计算机科学系教授。他著作的《计算机网络》是国内外使用最广泛、最权威的计算机网络经典教材。 -------------------------------------------------------------------------------- /intro.md: -------------------------------------------------------------------------------- 1 | # 前言 2 | 3 | 如果你是一位互联网从业者,我猜出这几年你大概率被这些层出不穷的概念包围:云计算、边缘计算、PaaS、FaaS、CaaS、ServiceMesh、Serverless,当然不能遗漏了各种 Ops,诸如 DevOps、GitOps、MLOps、FinOps 等等。 4 | 5 | 近几年来,软件开发技术经历了翻天覆地的变革,对构建业务应用的方式产生了重大影响。在讨论如何为业务赋能之前,我们不妨先思考一下,推动这一波技术浪潮的核心驱动力是什么? 6 | 7 | ## 软件在吞噬世界 8 | 9 | 互联网投资人 Mark Andreessen 曾在文章《软件正在吞噬世界》中探讨了软件如何改变各个行业。以下是文章中的部分内容: 10 | 11 | :::tip 《软件在吞噬世界》节选 12 | 13 | 我们处于戏剧性和广泛的技术和经济转变的中间,软件公司准备接管大量的经济。... 14 | 十年前,当我在创办的 Netscape 公司时,大概只有 500 万人使用宽带互联网,而现在有超过 20 亿人使用宽带互联网... 15 | ::: 16 | 17 | 文章发表于 2011 年,2023 年再来回顾互联网的冲击,感触更加深刻,部分软件变成像水、电、媒一样的基础设施。 18 | 19 | 在展望互联网规模时,作者曾预测:“在未来 10 年,全球至少有 50 亿人将拥有智能手机,每个人都可以随时随地利用互联网”。如今,我们可以确认,Mark Andreessen 的预测很准确:移动互联网时代的用户规模已经接近全球人口基数,亿级 DAU 规模的移动应用不断涌现。 20 | 21 | 软件对各行各业的渗透和对世界的改变,以及移动互联网时代巨大的用户基数下快速变更和不断创新的需求对软件开发方式带来巨大的推动力,我们清晰地看到如此波澜壮阔的技术浪潮: 22 | 23 | - 软件正在改变世界。 24 | - 移动互联网让这个变革影响到每一个人。 25 | - 传统软件开发方式受到巨大的挑战。 26 | - 因为云计算以及相关技术的普及,软件上云成为趋势。 27 | - 云计算的形态,与之对应的软件技术在持续演进。 28 | 29 | 过去二十年,软件的规模和质量要求不断提升,云基础设施和平台日益强大,软件技术逐渐发展成为它本来该有的模样,形成了与云环境匹配的架构,并催生了相应的开发流程和方法论。 30 | 31 | ## 大时代下的个体 32 | 33 | 视角转回到个体,不管你是否接受,软件行业解决问题的技术一直在变化。 34 | 35 | 这种变化并非简单的升级,而是剧烈的革新替代。例如,容器替代虚拟机,服务网格替代 Spring Cloud,观测替代监控,Network Policy 替代 iptables 等等。这种替代打破了软件开发中许多固有的假设。在如此剧烈的变革中,如果我们只关注眼前的工作,不抬头“看天”,当大革命来临时,曾经关注的细节可能再也没有意义。 36 | 37 | 38 | 所以,本书很少描述某个软件如何安装、如何使用,而是聚焦问题本质,剖析不同方案的核心原理,并探索技术发展的规律。例如,网络优化受限于物理世界的约束,分布式系统的演进则是对 CAP 定理的权衡,受时间和空间法则的制约。近几年流行的容器、服务网格也不是什么黑科技,只是把计算机的基本原理、方法重新组合,换种形式解决业务变化带来的新问题。 39 | 40 | 读完本书,相信你将对系统的整体运作有全新的理解,能够从容选择方案,轻松应对各种复杂问题。 41 | 42 | ## 本书适合哪些读者 43 | 44 | 本书主要面向软件工程师、架构师和技术负责人,特别适合那些需要在系统架构中做出权衡的技术决策者。即便你不直接参与这些决策,本书也能帮助你深入理解各种技术的优缺点。 45 | 46 | 阅读本书时,最好了解一些请求/响应型(Web)系统原理,熟悉一些常见的网络协议(譬如 TCP、HTTP 等)。如果再有一些后端开发经验,这将加深对本书内容的理解,至于你熟悉何种编程语言倒没有太大关系。 47 | 48 | 总体上讲,若以下条件适用你,你将从本书获取收益。 49 | 50 | - 想了解行业技术发展趋势和动态。 51 | - 需要在系统架构中做出权衡,避免常见设计陷阱。 52 | - 需要构建可靠、高效率、低成本的系统。 53 | - 对互联网系统的整体运作有着天然的兴趣,并乐于探索其中的奥秘。 54 | 55 | ## 如何阅读本书 56 | 57 | 本书将围绕“构建高可用系统”展开。互联网技术在中国发展了 20 余年,如果“高可用”的目标还仅仅关注不宕机,那显然要求过低。本书将“高可用”的定义延伸至更可靠、更高效率、更低成本。接下来,笔者将从下面六个部分展开探讨: 58 | 59 | 1. 第一部分,是全书的绪论。内容只有第 1 章。我们将从需求的背景、解决问题的角度讨论这几年技术架构演进的趋向。该部分适合所有读者,尤其是希望了解近期技术发展概况的人士。 60 | 61 | 2. 第二部分,主题是网络。我们将从一道经典的面试题“浏览器打开 url 到页面展现,中间发生了什么?”出发,了解贯穿其中的整个网络请求链路,并努力实现“足够快”目标(第 2 章)。紧接着,我们将跟随网络数据包进入内核,学习操作系统的基本规则,了解内核各模块和设备的协作及其对应用层的影响(第3章)。最后,我们将根据网络数据包的转发/处理的逻辑,讨论四层/七层负载均衡的设计原理(第 4 章)。 62 | 63 | 3. 第三部分,主题是分布式系统。首先,我们将了解数据一致性的基本概念,接着讨论 CAP 定理及其影响下的各类分布式事务模型(第5章)。随后,我们将探讨分布式副本容错模型,这是实现分布式系统可靠性的关键,重点关注如何在网络不可靠和节点可能宕机的环境中实现共识(第6章)。读完本部分内容,相信您将对分布式系统有全新的理解。 64 | 4. 第四部分,主题是基础设施。我们将先了解 Google 内部系统的演变,并学习 Kubernetes 在计算、网络 65 | 存储、容器编排调度的设计原理(第7章)。随后,我们将回顾过去十几年服务通信的发展历程,探讨服务网格技术的出现的背景,弄清楚它到底解决了什么问题(第8章)。 66 | 67 | 5. 第五部分(第9章):主题是确保复杂系统的可靠运行。这其中的关键是,统一收集、关联和分析系统输出(日志、指标、追踪),从而构建出能推断其内部状态的能力。 68 | 6. 最后一部分(第 10 章),我们将深入探讨 Kubernetes 等基础设施的演进,剖析声明式管理的本质,领会“以应用为中心”的设计理念,探索几种流行的应用层软件交付模型与抽象(如 Kustomize、Helm、Operator 和 OAM),帮助我们更加高效、自信地开发和交付应用。 69 | 70 | ## 致谢 71 | 72 | 首先,我要感谢我的爱人。在我决定开始写作时,她毫不犹豫地承担起照顾两个孩子的责任,并在三年里忍耐我将所有空闲时间投入到写作中。没有她的支持,我无法完成该作!同时,要感谢我的工作单位爱奇艺,公司为我提供了宝贵的工作、学习、实践机会。其次,还要感谢 gtihub 上我校验书稿的网友(限于篇幅无法一一列出),他们帮我指出了大量的笔误、不严谨的内容,提升了书稿的质量。 73 | 74 | 最后,谨将本书献给我的家人以及热爱技术的朋友们。 75 | 76 | ## 勘误 77 | 78 | 由于笔者的认知和精力有限,本书难免存在一些错误,所以开通了读者邮箱(weifeng1210#outlook.com)与大家交流,如在阅读过程中发现问题,欢迎提出宝贵意见。本书勘误,将在网址 https://www.thebyte.com.cn/ 发布。 79 | 80 | -------------------------------------------------------------------------------- /network/DPDK.md: -------------------------------------------------------------------------------- 1 | # 3.4.1 数据平面开发套件 DPDK 2 | 3 | 2010 年,Intel 主导开发了 DPDK(Data Plane Development Kit,数据平面开发套件),基于“内核旁路”理念构建高性能网络应用方案,并逐步发展为一套成熟的技术体系。 4 | 5 | 最初,DPDK 是 Intel 为推销自家硬件而开发的高性能网络驱动组件,专门针对 Intel 处理器和网卡。随着 DPDK 开源,越来越多厂商开始贡献代码,DPDK 扩展了对更多硬件的支持:不仅支持 Intel 处理器,还兼容 AMD、ARM 等厂商的处理器;网卡支持范围也涵盖了 Intel、Mellanox、ARM 集成网卡等。因此,DPDK 也逐渐具有广泛的适用性。 6 | 7 | 图 3-6 展示了 DPDK(Fast Path)与传统内核网络(Slow Path)之间的区别。在 Linux 系统中,DPDK 的库和应用程序在用户空间的编译、链接和加载方式与普通程序相同,但它们的数据包传输路径却大相径庭: 8 | 9 | - **传统内核网络**(图左侧):网络数据包从网络接口卡(NIC)出发,经驱动程序、内核协议栈处理,最终通过 Socket 接口传递给用户空间的业务层。 10 | - **DPDK 加速网络**(图右侧):在该方案中,网络数据包通过用户空间 I/O(UIO)技术,直接绕过内核协议栈,从网卡传输至 DPDK 基础库,再传递至业务逻辑。也就是说,DPDK 绕过了 Linux 内核协议栈的数据包处理过程,在用户空间直接进行收发和处理。 11 | 12 | :::center 13 | ![](../assets/dpdk.png)
14 | 图 3-6 DPDK 与传统内核网络对比 15 | ::: 16 | 17 | 爱奇艺开源的 DPVS 是 DPDK 技术在负载均衡领域的成功应用。图 3-7 展示了 DPVS 与标准 LVS 的性能对比。从每秒转发数据包数量(Packet Per Second,PPS)的指标来看,DPVS 的性能表现比 LVS 高出 300%。 18 | 19 | :::center 20 | ![](../assets/dpvs-performance.png)
21 | 图 3-7 DPVS 与 LVS 的 PPS 性能指标对比(结果越高,性能越好)[图片来源](https://github.com/iqiyi/dpvs) 22 | ::: 23 | 24 | 对于海量用户规模的互联网应用,通常需要部署数千甚至数万台服务器。如果能将单机性能提升十倍甚至百倍,无论从硬件投入还是运营成本角度,都能实现显著的成本节约。这种技术变革带来的潜在效益,毫无疑问非常诱人。 25 | 26 | DPDK 是由硬件厂商主导的“内核旁路”技术。在下一节,笔者将介绍由社区开发者主导的另一类“内核旁路”技术。 -------------------------------------------------------------------------------- /network/RDMA.md: -------------------------------------------------------------------------------- 1 | # 3.4.3 远程直接内存访问 RDMA 2 | 3 | 近年来,人工智能、分布式训练和分布式存储技术快速发展,对网络传输性能提出了更高要求。但传统以太网在延迟、吞吐量和 CPU 资源消耗方面存在先天不足。在这一背景下,RDMA(Remote Direct Memory Access,远程直接内存访问)技术凭借卓越的性能,逐渐成为满足高性能计算需求的优选方案。 4 | 5 | RDMA 设计起源于 DMA(Direct Memory Access)技术[^1],它的工作原理如图 3-10 所示,应用程序通过 RDMA Verbs API 直接访问远程主机内存,而无需经过操作系统或 CPU 参与数据拷贝,从而极大地降低延迟和 CPU 开销,提高数据传输效率。 6 | :::center 7 | ![](../assets/RDMA.png)
8 | 图 3-10 RDMA 的技术原理 9 | ::: 10 | 11 | RDMA 网络的协议实现有三类,它们的含义及区别如下。 12 | 13 | - **Infiniband**(无限带宽)),是一种专门为 RDMA 而生的技术,由 IBTA(InfiniBand Trade Association, 14 | InfiniBand 贸易协会)在 2000 年提出,因其极致的性能(能够实现小于 3 μs 时延和 400Gb/s 以上的网络吞吐),在高性能计算领域中备受青睐。 15 | 但注意的是,构建 Infiniband 网络需要配置全套专用设备,如专用网卡、专用交换机和专用网线,限制了其普及性。其次,它的技术架构封闭,不兼容现有的以太网标准。这意味着,绝大多数通用数据中心都无法兼容 Infiniband 网络。 16 | 17 | 尽管存在这些局限,InfiniBand 仍因其极致的性能成为特定领域的首选。例如,全球流行的人工智能应用 ChatGPT 背后的分布式机器学习系统,就是基于 Infiniband 网络构建的。 18 | 19 | - **iWRAP**(Internet Wide Area RDMA Protocol,互联网广域 RDMA 协议)是一种将 RDMA 封装在 TCP/IP 协议中的技术。RDMA 旨在提供高性能传输,而 TCP/IP 侧重于可靠性,其三次握手、拥塞控制等机制削弱了 iWRAP 的 RDMA 技术优势,导致其性能大幅下降。因此,iWRAP 由于先天设计上的局限性,逐渐被业界淘汰。 20 | 21 | - 为降低 RDMA 的使用成本,并推动其在通用数据中心的应用,IBTA 于 2010 年发布了 **RoCE**(RDMA over Converged Ethernet,融合以太网的远程直接内存访问)技术。RoCE 将 Infiniband 的数据格式(IB Payload)“移植”到以太网,使 RDMA 能够在标准以太网环境下运行。只需配备支持 RoCE 的专用网卡和标准以太网交换机,即可享受 RDMA 技术带来的高性能。 22 | 23 | 如图 3-11 所示,RoCE 在发展过程中演化出两个版本: 24 | - **RoCEv1**:基于二层以太网,仅限于同一子网内通信,无法跨子网传输; 25 | - **RoCEv2**:基于三层 IP 网络,支持跨子网通信,提高了灵活性和可扩展性。 26 | 27 | RoCEv2 克服了 RoCEv1 不能跨子网的限制,并凭借其低成本和良好的兼容性,在分布式存储、并行计算等通用数据中心场景中得到广泛应用。根据微软 Azure 公开信息,截至 2023 年,Azure 数据中心中 RDMA 流量已占总流量的 70%[^1]。 28 | :::center 29 | ![](../assets/RoCE_Header_format.png)
30 | 图 3-11 RoCE v1 只能在广播域内通信,RoCE v2 支持 L3 路由 31 | ::: 32 | 33 | RDMA 网络对丢包极为敏感,任何数据包丢失都可能触发大量重传,严重影响传输性能。Infiniband 依赖专用设备确保网络可靠性,而 RoCE 构建在标准以太网上,实现 RDMA 通信。因此,RoCE 网络需要无损以太网支持,以避免丢包对性能造成重大影响。 34 | 35 | 目前,大多数数据中心采用 DCQCN(由微软与 Mellanox 提出)或 HPCC(由阿里巴巴提出)算法,为 RoCE 网络提供可靠性保障。由于这些算法涉及底层技术,超出本书讨论范畴,感兴趣的读者可参考其他资料以进一步了解。 36 | 37 | [^1]: 参见 https://www.usenix.org/system/files/nsdi23-bai.pdf 38 | 39 | -------------------------------------------------------------------------------- /network/XDP.md: -------------------------------------------------------------------------------- 1 | # 3.4.2 eBPF 和 快速数据路径 XDP 2 | 3 | 由于 DPDK 完全基于“内核旁路”的思想,它天然无法与 Linux 内核生态很好地结合。 4 | 5 | 2016 年,Linux Netdev 会议,Linux 内核开发者 David S. Miller[^1] 喊出了“DPDK is not Linux”的口号。同年,随着 eBPF 技术成熟,Linux 内核终于迎来了属于自己的“高速公路” —— XDP(eXpress Data Path,快速数据路径)。XDP 因其媲美 DPDK 的性能、背靠 Linux 内核,无需第三方代码库和许可、无需专用 CPU 等多种优势,一经推出便备受关注。 6 | 7 | DPDK 技术完全绕过内核,直接将数据包透传至用户空间处理。XDP 正好相反,它在内核空间根据用户的逻辑处理数据包。 8 | 9 | 在内核执行用户逻辑的关键在于 BPF(Berkeley Packet Filter,伯克利包过滤器)技术 —— 一种允许在内核空间运行经过安全验证的代码的机制。Linux 内核 2.5 版本起,Linux 系统就开始支持 BPF 技术了,但早期的 BPF 主要用于网络数据包的捕获和过滤。到了 Linux 内核 3.18 版本,开发者推出了一套全新的 BPF 架构,也就是我们今天所说的 eBPF(Extended Berkeley Packet Filter)。与早期的 BPF 相比,eBPF 的功能不再局限于网络分析,它几乎能访问所有 Linux 内核关联的资源,逐渐发展成一个多功能的通用执行引擎。 10 | 11 | 至此,相信读者已经能够察觉到,eBPF 访问 Linux 内核资源的方式与 Netfilter 开放钩子的机制相似。两者的主要区别在于,Netfilter 提供的钩子数量有限,主要面向 Linux 的其他内核模块;而 eBPF 则面向普通开发者,Linux 系统提供了大量钩子供开发者挂载 eBPF 程序。 12 | 13 | 笔者列举部分钩子供读者参考: 14 | 15 | - **TC**(Traffic Control)钩子:位于内核的网络流量控制层,用于处理流经 Linux 内核的网络数据包。它可以在数据包进入或离开网络栈的各个阶段触发。 16 | - Tracepoints 钩子:Tracepoints 是内核代码中的静态探测钩子,分布在内核的各个子系统中。主要用于内核的性能分析、故障排查、监控等。例如,可以在调度器、文件系统操作、内存管理等处进行监控。 17 | - **LSM**(Linux Security Modules)钩子:位于 Linux 安全模块框架中,允许在内核执行某些安全相关操作(如文件访问、网络访问等)时触发 eBPF 程序。主要用于实现安全策略和访问控制。例如,可以编写 eBPF 程序来强制执行自定义的安全规则或监控系统的安全事件。 18 | - **XDP** 钩子:位于网络栈最底层的钩子,直接在网卡驱动程序中触发,用于处理收到的网络数据包,主要用于实现超高速的数据包处理操作,例如 DDoS 防护、负载均衡、数据包过滤等。 19 | 20 | 从上述钩子可见,XDP 本质上是 Linux 内核在网络路径上设置的钩子,位于网卡驱动层,在数据包进入网络协议栈之前。当 XDP 执行完 eBPF 程序后,通过“返回码”来指示数据包的最终处理决定。 21 | 22 | XDP 的 5 种返回码及其含义如下: 23 | 24 | - **XDP_ABORTED**:表示 XDP 程序处理数据包时遇到错误或异常。 25 | - **XDP_DROP**:在网卡驱动层直接将该数据包丢掉,通常用于过滤无效或不需要的数据包,如实现 DDoS 防护时,丢弃恶意数据包。 26 | - **XDP_PASS**:数据包继续送往内核的网络协议栈,和传统的处理方式一致。这使得 XDP 可以在有需要的时候,继续使用传统的内核协议栈进行处理。 27 | - **XDP_TX**:数据包会被重新发送到入站的网络接口(通常是修改后的数据包)。这种操作可以用于实现数据包的快速转发、修改和回环测试(如用于负载均衡场景)。 28 | - **XDP_REDIRECT**:数据包重定向到其他的网卡或 CPU,结合 AF_XDP[^2]可以将数据包直接送往用户空间。 29 | 30 | :::center 31 | ![](../assets/xdp.png)
32 | 图 3-8 XDP 钩子在 Linux 系统的位置与 5 个动作 33 | ::: 34 | 35 | eBPF 运行在内核空间,能够极大地减少数据的上下文切换开销,再结合 XDP 钩子,在 Linux 系统收包的早期阶段介入处理,就能实现高性能网络数据包处理和转发。以业内知名的容器网络方案 Cilium 为例,它在 eBPF 和 XDP 钩子(也有其他的钩子)基础上,实现了一套全新的 conntrack 和 NAT 机制。并以此为基础,构建出如 L3/L4 负载均衡、网络策略、观测和安全认证等各类高级功能。 36 | 37 | 由于 Cilium 实现的底层网络功能独立于 Netfilter,它的连接追踪数据和 NAT 规则不再存储在 Linux 内核默认的 conntrack 表和 NAT 表中。因此,常规的 Linux 命令(如 conntrack、netstat、ss 和 lsof)无法查看这些数据。必须使用 Cilium 提供的查询命令,例如: 38 | 39 | ```bash 40 | $ cilium bpf nat list // 列出 Cilium 中配置的 NAT 规则。 41 | $ cilium bpf ct list global // 列出 Cilium 中的连接追踪条目 42 | ``` 43 | 44 | [^1]: Linux Netdev,专注于 Linux 网络栈和网络技术的会议。David S. Miller 是 Linux 内核网络子系统的主要维护者之一,也是 Linux 内核开发领域的知名人物。 45 | [^2]: 相较 AF_INET 是基于传统网络的 Linux socket,AF_XDP 则是一套基于 XDP 的高性能 Linux socket。 46 | -------------------------------------------------------------------------------- /network/conclusion.md: -------------------------------------------------------------------------------- 1 | # 3.6 小结 2 | 3 | 道家经典《庄子》中有一则庖丁解牛的故事。梁惠王因庖丁解牛的技术惊叹:“你的技术咋会高超到这种程度?”,庖丁回:“我所追求的是宰牛的道理啊,道理要比技艺更高一筹...”。 4 | 5 | 软件开发技术其实和解牛技术是相通的。当你不懂底层原理时,你只能看到表面的现象。技术精进后,达到庖丁境界时,就如同佩戴了透视镜,能洞察系统的内在脉络,理解各个模块的“有机”协作,进而对整个系统架构有个全局视野,准确把握设计与技术选型的核心。 6 | 7 | 此刻,再回顾近几年引领技术潮流的容器、服务网格、Cilium 等等,你是否体会到它们不是什么“黑科技”,只是把计算机的基本原理、方法重新组合,换种形式解决业务变化带来的新问题。 -------------------------------------------------------------------------------- /network/conntrack.md: -------------------------------------------------------------------------------- 1 | # 3.3.3 连接跟踪模块 conntrack 2 | 3 | conntrack 是“连接跟踪”(connection tracking)的缩写,顾名思义,它用于跟踪 Linux 内核中的通信连接。需要注意的是,conntrack 跟踪的“连接”不仅限于 TCP 连接,还包括 UDP、ICMP 等类型的连接。当 Linux 系统收到数据包时,conntrack 模块会为其创建一个新的连接记录,并根据数据包的类型更新连接状态,如 NEW、ESTABLISHED 等。 4 | 5 | 以 TCP 三次握手为例,说明 conntrack 模块的工作原理 : 6 | 7 | 1. 客户端向服务器发送一个 TCP SYN 包,发起连接请求。 8 | 2. Linux 系统收到 SYN 包后,conntrack 模块为其创建新的连接记录,并将状态标记为 NEW。 9 | 3. 服务器回复 SYN-ACK 包,等待客户端的 ACK。一旦握手完成,连接状态变为 ESTABLISHED。 10 | 11 | 通过命令 cat /proc/net/nf_conntrack 查看连接记录,如下所示,输出了一个状态为 ESTABLISHED 的 TCP 连接。 12 | ```bash 13 | $ cat /proc/net/nf_conntrack 14 | ipv4 2 tcp 6 88 ESTABLISHED src=10.0.12.12 dst=10.0.12.14 sport=48318 dport=27017 src=10.0.12.14 dst=10.0.12.12 sport=27017 dport=48318 [ASSURED] mark=0 zone=0 use=2 15 | ``` 16 | 17 | conntrack 连接记录是 iptables 连接状态匹配的基础,也是实现 SNAT 和 DNAT 的前提。我们知道 Kubernetes 的核心组件 kube-proxy,它作用是负责处理集群中的服务(Service)网络流量。它本质上是一个反向代理(即 NAT),当外部请求访问 Service 时,流量会被 DNAT 转发到 PodIP:Port,响应则经过 SNAT 处理。 18 | 19 | 举一个具体的例子说明。假设客户端向 my-service(IP 10.0.0.10,端口 80)发送 HTTP 请求,流程如下: 20 | - 节点中的 kube-proxy 收到请求后,执行 DNAT 操作,将目标地址从 10.0.0.10:80 转换为某个 Pod 的 IP 和端口(如 192.168.1.2:8080)。 21 | - Pod 处理请求并返回响应,kube-proxy 执行 SNAT 操作,将响应包的源地址从 192.168.1.2:8080 转换为 Service IP 10.0.0.10:80。 22 | 23 | conntrack 模块维护的连接记录包含了从客户端到 Pod 的 DNAT 映射、从 Pod 到客户端的 SNAT 映射。这样有来有回,是一条完整的 NAT 映射关系。但是,如果客户端与 Pod 在同一主机上(如图 3-5),则会出现以下问题: 24 | - 客户端发起请求时,数据包经过网络层,conntrack 模块根据 iptables 规则判断是否需要进行 DNAT; 25 | - 返回响应时,Linux 网桥发现目标 IP 位于同一网桥上,会直接通过链路层转发数据包,而不会触发网络层的 conntrack 模块,导致 SNAT 操作没有执行。 26 | 27 | 如图 3-5 所示,通信双方不在同一“频道”上,NAT 映射关系不完整,进而影响容器间通信,产生各种异常。 28 | 29 | :::center 30 | ![](../assets/bridge-call-iptables.svg)
31 | 图 3-5 请求和响应不在一个“频道”上,双方通信失败 32 | ::: 33 | 34 | 为了解决上述问题,Linux 内核引入了 bridge-nf-call-iptables 配置,决定是否在网桥中触发 iptables 匹配规则,从而保证 NAT 处理时 conntrack 连接记录的完整性。这也解释了为什么在部署 Kubernetes 集群时,必须将该配置设置为 1。 35 | 36 | -------------------------------------------------------------------------------- /network/kernel-bypass.md: -------------------------------------------------------------------------------- 1 | # 3.4 内核旁路技术 2 | 3 | 4 | 前文介绍了“Linux系统收包流程”和内核网络框架,相信你已经理解:对于网络密集型应用,内核态与用户态的频繁切换、复杂的网络协议栈处理,常常使 Linux 内核成为性能瓶颈。 5 | 6 | 在人们想办法提升 Linux 内核性能的同时,另外一批人抱着它不行就绕开它想法,提出了一种“内核旁路“(Kernel bypass)思想的技术方案。其中,DPDK 和 XDP 是主机内的“内核旁路”技术代表,而 RDMA 则是主机之间的“内核旁路”技术代表。 -------------------------------------------------------------------------------- /network/linux-bridge.md: -------------------------------------------------------------------------------- 1 | # 3.5.4 虚拟交换机 Linux Bridge 2 | 3 | 在物理网络中,交换机用于连接多台主机,组成局域网。在 Linux 网络虚拟化技术中,同样提供了物理交换机的虚拟实现,即 Linux Bridge(Linux 网桥,也称虚拟交换机)。 4 | 5 | Linux Bridge 作为虚拟交换机,其功能与物理交换机类似。将多个网络接口(如物理网卡 eth0、虚拟接口 veth、tap 等)桥接后,它们的通信方式与物理交换机的转发行为一致。当数据帧进入 Linux Bridge 时,系统根据数据帧的类型和目的地 MAC 地址执行以下处理: 6 | - **广播帧**:转发到所有桥接到该 Linux Bridge 的设备。 7 | - **单播帧**:查找 FDB(Forwarding Database,地址转发表)中 MAC 地址与设备网络接口的映射记录: 8 | - 若未找到记录,执行“洪泛”(Flooding),将数据帧发送到所有接口,并根据响应将设备的网络接口与 MAC 地址记录到 FDB 表中; 9 | - 若找到记录,则直接将数据帧转发到对应设备的网络接口。 10 | 11 | 以下是一个具体例子,展示如何使用 Linux Bridge 将两个网络命名空间连接到同一二层网络。网络拓扑如图 3-15 所示。 12 | 13 | :::center 14 | ![](../assets/linux-bridge.svg)
15 | 图 3-15 veth 网卡与 Linux Bridge 16 | ::: 17 | 18 | 1. 首先,创建一个 Linux Bridge 设备。如下命令所示,创建一个名为 br0 的虚拟交换机,并将其激活。 19 | 20 | ```bash 21 | $ ip link add name br0 type bridge 22 | $ ip link set br0 up 23 | ``` 24 | 25 | 2. 接着,创建一对 Veth 设备,并将它们分别分配给两个命名空间。 26 | 27 | ```bash 28 | # 创建 veth1 和 veth2 29 | $ ip link add veth1 type veth peer name veth2 30 | 31 | # 将 veth1 分配到 ns1 32 | $ ip link set veth1 netns ns1 33 | # 将 veth2 分配到 ns2 34 | $ ip link set veth2 netns ns2 35 | ``` 36 | 37 | 3. 将 veth1 和 veth2 接入到 br0 桥接设备,从而让它们成为同一二层网络的一部分。 38 | 39 | ```bash 40 | # 将 veth1 添加到 br0 桥接 41 | $ ip link set dev veth1 up 42 | $ brctl addif br0 veth1 43 | 44 | # 将 veth2 添加到 br0 桥接 45 | $ ip link set dev veth2 up 46 | $ brctl addif br0 veth2 47 | ``` 48 | 49 | 4. 为每个命名空间中的 Veth 设备配置 IP 地址。 50 | 51 | ```bash 52 | # 配置命名空间1中的 veth1 53 | $ ip netns exec ns1 ip addr add 172.16.0.1/24 dev veth1 54 | $ ip netns exec ns1 ip link set veth1 up 55 | 56 | # 配置命名空间2中的 veth2 57 | $ ip netns exec ns2 ip addr add 172.16.0.2/24 dev veth2 58 | $ ip netns exec ns2 ip link set veth2 up 59 | ``` 60 | 61 | 4. 最后,在 ns1 命名空间中测试与 ns2 命名空间的通信。 62 | 63 | ```bash 64 | $ ip netns exec ns1 ping 172.16.0.2 65 | PING 172.16.0.2 (172.16.0.2) 56(84) bytes of data. 66 | 64 bytes from 172.16.0.1: icmp_seq=1 ttl=64 time=0.153 ms 67 | 64 bytes from 172.16.0.1: icmp_seq=2 ttl=64 time=0.148 ms 68 | 64 bytes from 172.16.0.1: icmp_seq=3 ttl=64 time=0.116 ms 69 | ``` 70 | 71 | 通过上述步骤,我们创建了一个 Linux Bridge,将两个命名空间 ns1 和 ns2 通过虚拟以太网设备连接在同一个二层网络中。这样,两个命名空间之间可以通过桥接设备直接通信,实现在同一局域网内的网络互通。 72 | 73 | 需要补充的是,Linux Bridge 本质上是 Linux 系统中的虚拟网络设备,具备网卡特性,能够配置 MAC 和 IP 地址。从主机的角度来看,配置了 IP 地址的 Linux Bridge 设备就相当于一块“网卡”,能够参与数据包的 IP 路由。因此,当网络命名空间的默认网关设置为 Linux Bridge 的 IP 地址时,原本隔离的网络命名空间便能够与主机进行通信。 74 | 75 | 实现容器与主机之间的互通,是容器间通信的关键环节。笔者将在第七章的 7.6 节中详细阐述这方面的内容。 76 | 77 | 78 | -------------------------------------------------------------------------------- /network/linux-kernel-networking.md: -------------------------------------------------------------------------------- 1 | # 3.3 Linux 内核网络框架 2 | 3 | Linux 系统处理网络数据包(见图 3-1)看似是一套固定封闭的机制,实际情况并非如此。 4 | 从 Linux 内核 2.4 版本开始,内核引入了一套通用的过滤框架 —— Netfilter,使得“外界”可以在数据包流经内核协议栈时进行干预。 5 | 6 | Linux 系统中的各类网络功能,如地址转换、封包处理、地址伪装、协议连接跟踪、数据包过滤、透明代理、带宽限速和访问控制等,都是基于 Netfilter 提供的代码拦截机制实现的。可以说,Netfilter 是整个 Linux 网络系统最重要(没有之一)的基石。 -------------------------------------------------------------------------------- /network/linux-vritual-net.md: -------------------------------------------------------------------------------- 1 | # 3.5 Linux 网络虚拟化 2 | 3 | Linux 网络虚拟化的核心技术主要是网络命名空间和各种虚拟网络设备,如稍后介绍的 Veth、Linux Bridge、TUN/TAP 等。这些虚拟设备由代码实现,完全模拟物理设备的功能。 4 | 5 | 近年来广泛应用的容器技术,正是基于这些虚拟网络设备,模拟物理设备之间协作方式,将各个独立的网络命名空间连接起来,构建出不受物理环境限制的网络架构,实现容器之间、容器与宿主机之间,甚至跨数据中心的动态网络拓扑。 6 | -------------------------------------------------------------------------------- /network/netfilter.md: -------------------------------------------------------------------------------- 1 | # 3.3.1 Netfilter 的 5 个钩子 2 | 3 | Netfilter 围绕网络协议栈(主要在网络层)“埋下”了 5 个钩子(也称 hook)[^1],用来干预 Linux 网络通信。Linux 内核中的其他模块(如 iptables、IPVS 等)向这些钩子注册回调函数。当数据包进入内核协议栈并经过钩子时,回调函数会自动触发,从而对数据包进行处理。 4 | 5 | 这 5 个钩子的名称与含义如下: 6 | 7 | - **PREROUTING**:只要数据包从设备(如网卡)进入协议栈,就会触发该钩子。当我们需要修改数据包的 “Destination IP” 时,会使用到该钩子,即 PREROUTING 钩子主要用于目标网络地址转换(DNAT,Destination NAT)。 8 | - **FORWARD**:顾名思义,指转发数据包。前面的 PREROUTING 钩子并未经过 IP 路由,不管数据包是不是发往本机的,全部照单全收。如果发现数据包不是发往本机,则会触发 FORWARD 钩子进行处理。此时,本机就相当于一个路由器,作为网络数据包的中转站,FORWARD 钩子的作用就是处理这些被转发的数据包,以此来保护其背后真正的“后端”机器。 9 | - **INPUT**:如果发现数据包是发往本机的,则会触发本钩子。INPUT 钩子一般用来加工发往本机的数据包,当然也可以做数据过滤,保护本机的安全。 10 | - **OUTPUT**:数据包送达到应用层处理后,会把结果送回请求端,在经过 IP 路由之前,会触发该钩子。OUTPUT 钩子 一般用于加工本地进程输出的数据包,同时也可以限制本机的访问权限。比如,将发往 www.example.org 的数据包都丢弃掉。 11 | - **POSTROUTING**:数据包出协议栈之前,都会触发该钩子,无论这个数据包是转发的,还是经过本机进程处理过的。POSTROUTING 钩子 一般用于源网络地址转换(SNAT,Source NAT)。 12 | 13 | 这 5 个钩子在网络协议栈的位置如图 3-2 所示。 14 | 15 | :::center 16 | ![](../assets/netfilter-hook.svg)
17 | 图 3-2 Netfilter 的 5 个钩子 18 | ::: 19 | 20 | 21 | Netfilter 允许在同一钩子上注册多个回调函数,每个回调函数都有明确的优先级,以确保按预定顺序触发。这些回调函数串联起来形成了一个“回调链”(Chained Callbacks)。这种设计使得基于 Netfilter 构建的上层应用大多带有“链”的概念,如稍后将介绍的 iptables。 22 | 23 | [^1]: Hook 设计模式在许多软件系统中广泛应用。例如,本书后续将介绍的 eBPF 和 Kubernetes。Kubernetes 通过暴露各种接口(hook),使用户能够根据需求插入自定义代码或逻辑,从而扩展其在编排调度、网络和资源定义等方面的功能。。 -------------------------------------------------------------------------------- /network/network-layer.md: -------------------------------------------------------------------------------- 1 | # 3.1 OSI 网络分层模型 2 | 3 | 本章及后续章节中,会多次出现“L7”、“L4”、“二层”和“三层”类似的术语,因此有必要提前解释。 4 | 5 | 这些术语源自广为人知的 OSI 七层模型,该模型由 ISO(国际标准化组织)于 20 世纪 80 年代提出,目的是为网络通信提供通用参考标准,使相同规范的网络能够互联。 6 | 7 | 如表 3-1 所示:OSI 模型通过“分层”思想,将网络通信拆解为七个独立的层次,每个层次解决特定的局部问题。笔者按照从上到下的顺序,介绍各个网络分层的含义,供读者参考。 8 | 9 | :::center 10 | 表 3-1 OSI 网络七层模型 11 | ::: 12 | |层级|名称|含义| 13 | |:--|:--|:--| 14 | |7|应用层(Application Layer)|应用层是 OSI 模型的顶层,直接与用户的应用程序交互。该层的协议有 HTTP、FTP、SMTP 等。| 15 | |6|表示层(Presentation Layer)|负责数据的格式转换、加密和解密,确保发送方和接收方之间的数据格式一致。该层的协议有 SSL/TLS、JPEG、MIME 等。| 16 | |5|会话层(Session Layer)|管理应用程序之间的会话,负责建立、维护和终止会话。| 17 | |4|传输层(Transport Layer)|提供端到端的数据传输服务,负责数据分段、传输可靠性以及错误恢复。该层的协议有 TCP 和 UDP。| 18 | |3|网络层(Network Layer)|提供逻辑地址(如 IP 地址),负责数据的路由选择和传输,解决不同网络之间的通信。该层的协议有 IPv4、IPv6、ICMP、ARP 等。| 19 | |2|数据链路层(Data Link Layer)|负责局域网(LAN)内的数据传输,对传输的单元(数据帧)提供错误检测和纠正功能。该层的协议有 Ethernet、PPP、HDLC 等。| 20 | |1|物理层(Physical Layer)|物理层是 OSI 模型的第一层,负责比特流在物理介质上的传输。| 21 | 22 | 通常情况下,数据链路层的数据单元称为“帧”(Frame),网络层的数据单元称为“数据包”(Packet),传输层的数据单元称为“数据段”(Segment),而应用层的数据单元则称为“数据”(Data)。为了简化表述,本书大部分内容不会严格区分这些术语,统一使用“数据包”泛指各层数据单元。 23 | 24 | -------------------------------------------------------------------------------- /network/network-namespace.md: -------------------------------------------------------------------------------- 1 | # 3.5.1 网络命名空间 2 | 3 | 从 Linux 内核 2.4.19 版本开始,逐步集成了多种命名空间技术,以实现对各类资源的隔离。其中,网络命名空间(Network Namespace)是最为关键的一种,也是容器技术的核心。 4 | 5 | 网络命名空间允许 Linux 系统内创建多个独立的网络环境,每个环境拥有独立的网络资源,如防火墙规则、网络接口、路由表、ARP 邻居表及完整的网络协议栈。当进程运行在某个网络命名空间内时,就像独享一台物理主机。 6 | 7 | :::center 8 | ![](../assets/linux-namespace.svg)
9 | 图 3-12 不同网络命名空间内的网络资源都是隔离的 10 | ::: 11 | 12 | 在 Linux 系统 中,ip 工具的子命令 netns 集成了网络命名空间的增、删、查、改等功能。接下来,笔者将使用 ip 命令演示如何操作网络命名空间,帮助你加深理解。 13 | 14 | 首先,创建一个名为 ns1 的网络命名空间。命令如下所示: 15 | 16 | ```bash 17 | $ ip netns add ns1 18 | ``` 19 | 20 | 查询 ns1 网络命名空间内的网络设备信息。可以看到,由于没有进行任何配置,该网络命名空间内只有一个名为 lo 的本地回环设备,且设备状态为 DOWN。 21 | 22 | ```bash 23 | $ ip netns exec ns1 ip link list 24 | 1: lo: mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 25 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 26 | ``` 27 | 28 | 查看 ns1 网络命名空间下的 iptables 规则配置。可以看到,由于这是一个初始化的网络命名空间,因此 iptables 规则为空,并没有任何配置。 29 | 30 | ```bash 31 | $ ip netns exec ns1 iptables -L -n 32 | Chain INPUT (policy ACCEPT) 33 | target prot opt source destination 34 | 35 | Chain FORWARD (policy ACCEPT) 36 | target prot opt source destination 37 | 38 | Chain OUTPUT (policy ACCEPT) 39 | target prot opt source destination 40 | ``` 41 | 42 | 不难看出,不同的网络命名空间默认相互隔离,也无法直接通信。如果它们需要与外界(其他网络命名空间或宿主机)建立连接,该如何实现呢? 43 | 44 | 我们先看看物理机是怎么操作的,一台物理机如果要想与外界进行通信,那得插入一块网卡,通过网线连接到以太网交换机,加入一个局域网内。被隔离的网络命名空间如果想与外界进行通信,就需要利用到稍后介绍的各类虚拟网络设备。也就是,在网络命名空间里面插入“虚拟网卡”,然后把“网线”的另一头桥接到“虚拟交换机”中。 45 | 46 | 没错,这些操作完全和物理环境中的配置局域网一样,只不过全部是虚拟的、用代码实现的而已。 -------------------------------------------------------------------------------- /network/networking.md: -------------------------------------------------------------------------------- 1 | # 3.2 Linux 系统收包流程 2 | 3 | 本节,我们了解数据包进入网卡(eth0)后,Linux 内核中各个模块是如何协作,对 Linux 系统的数据包处理机制有个系统的认识。 4 | 5 | 总结 Linux 系统收包流程,如图 3-1 所示。 6 | :::center 7 | ![](../assets/networking.svg)
8 | 图 3-1 Linux 系统收包流程 9 | ::: 10 | 11 | 1. 外部数据包到达主机时,首先由网卡 eth0 接收。 12 | 2. 网卡通过 DMA(Direct Memory Access,直接内存访问)技术,将数据包拷贝到内核中的 RingBuffer(环形缓冲区)等待 CPU 处理。RingBuffer 是一种首尾相接的环形数据结构,它作为缓冲区,缓解网卡接收数据的速度快于 CPU 处理数据的速度问题。 13 | 3. 接着,网卡产生 IRQ(Interrupt Request,硬件中断),通知内核有新的数据包到达。 14 | 4. 内核调用中断处理函数,标记新数据到达。接着,唤醒 ksoftirqd 内核线程,执行软中断(SoftIRQ)处理。 15 | 5. 软中断处理中,内核调用网卡驱动的 NAPI(New API)poll 接口,从 RingBuffer 中提取数据包,并转换为 skb(Socket Buffer)格式。skb 是描述网络数据包的核心数据结构,无论是数据包的发送、接收还是转发,Linux 内核都会以 skb 的形式来处理。 16 | 6. skb 被传递到内核协议栈,在多个网络层次间处理: 17 | - 网络层(L3 Network layer):根据主机中的路由表,判断数据包路由到哪一个网络接口(Network Interface)。这里的网络接口可能是稍后介绍的虚拟设备,也可能是物理网卡 eth0 接口。 18 | - 传输层(L4 Transport layer):处理网络地址转换(NAT)、连接跟踪(conntrack)等。 19 | 7. 内核协议栈处理完成后,数据包被传递到 socket 接收缓冲区。应用程序利用系统调用(如 Socket API)从缓冲区读取数据。至此,整个收包过程结束。 20 | 21 | 从上述流程可见,Linux 系统的数据包处理涉及多个网络层协议栈(如数据链路层、网络层、传输层和应用层),需要进行封包/解包操作,并频繁发生上下文切换(Context Switch)。在设计网络密集型系统时,Linux 内核瓶颈不可忽视,优化内核参数是不可或缺的环节。除了优化内核参数,业界还提出了“绕过内核”的解决方案,如图 3-1 所示的 XDP 和 DPDK 技术。笔者将在 3.4 节中详细介绍它们的原理与区别。 22 | 23 | 接下来,我们将继续深入 Linux 内核网络模块,研究 Linux 内核是如何过滤、修改和转发数据的。 -------------------------------------------------------------------------------- /network/summary.md: -------------------------------------------------------------------------------- 1 | # 第三章:深入 Linux 内核网络技术 2 | :::tip
3 | 4 | 创造操作系统,就是去创造一个所有应用程序赖以运行的基础环境。从根本上来说,就是在制定规则:什么可以接受、什么可以做、什么不可以做。事实上,所有的程序都是在制定规则,只不过操作系统是在制定最根本的规则。 5 | 6 | :::right 7 | 8 | —— 摘自《Linus Torvalds 自传》[^1] 9 | ::: 10 | 11 | 在第二章,我们讨论了请求如何到达后端系统。本章将进一步探讨请求到达 Linux 系统后的处理过程。 12 | 13 | 本章内容将深入分析 Linux 内核网络技术,根据数据包的处理过程层层推进,首先解析 Linux 内核中关键模块(将介绍 netfilter、iptables 以及 conntrack)如何密切协作、如何影响应用软件的设计。接着,针对 Linux 内核在密集网络系统下的瓶颈问题,探索业内一些“跨内核”思想的解决方案(将介绍 DPDK、RDMA 和 eBPF 技术)。最后,我们将学习虚拟化网络技术,为后续介绍的高级应用(如负载均衡、容器编排、服务网格)储备必要的基础知识。 14 | 15 | 本章内容安排如图 3-0 所示。 16 | :::center 17 | ![](../assets/network-summary.png)
18 | 图 3-0 本章内容导读 19 | ::: 20 | 21 | [^1]: Linus Torvalds,业内知名度最高的程序员之一。Linus Torvalds 是 Linux 内核的最早作者,被称为“Linux 之父”。他还开发了代码版本管理工具 Git,因此也被戏称为程序员的祖师爷。 -------------------------------------------------------------------------------- /network/tuntap.md: -------------------------------------------------------------------------------- 1 | # 3.5.2 虚拟网络设备 TUN 和 TAP 2 | 3 | TUN 和 TAP 是 Linux 内核自 2.4.x 版本引入的虚拟网卡设备,专为用户空间(user space)与内核空间(kernel space)之间的数据传输而设计。两者的主要区别如下: 4 | - **TUN 设备**:工作在网络层(Layer 3),用于处理 IP 数据包。它模拟一个网络层接口,使用户空间程序能够直接收发 IP 数据包; 5 | - **TAP 设备**:工作在数据链路层(Layer 2),用于处理以太网帧。与 TUN 设备不同,TAP 设备传输完整的以太网帧(包括数据链路层头部),使用户空间程序可以处理原始以太网帧。 6 | 7 | Linux 系统中,内核空间和用户空间之间数据传输有多种方式,字符设备文件是其中一种。 8 | 9 | TUN/TAP 设备对应的字符设备文件为 /dev/net/tun。当用户空间的程序打开(open)字符设备文件时,同时,TUN/TAP 的字符设备驱动会创建并注册相应的虚拟网卡,默认命名为 tunX 或 tapX。随后,用户空间程序读写(read/write)该文件描述符,就可以和内核网络栈进行数据交互了。 10 | 11 | 如图 3-13 所示,下面以 TUN 设备构建 VPN 隧道为例,说明其工作原理。 12 | 13 | 1. 首先,一个普通的用户程序发起一个网络请求; 14 | 2. 接着,数据包进入内核协议栈,并路由至 tun0 设备。路由规则如下: 15 | ```bash 16 | $ ip route show 17 | default via 172.12.0.1 dev tun0 // 默认流量经过 tun0 设备 18 | 192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.3 19 | ``` 20 | 3. tun0 设备的字符设备文件 /dev/net/tun 由 VPN 程序打开。所以,用户程序发送的数据包不会直接进入网络,而是被 VPN 程序读取并处理。 21 | 4. VPN 程序对数据包进行封装操作,封装(Encapsulation)是指在原始数据包外部包裹新的数据头部,就像将一个盒子放在另一个盒子中一样。 22 | 5. 最后,处理后的数据包再次写入内核网络栈,并通过 eth0(即物理网卡)发送到目标网络。 23 | 24 | :::center 25 | ![](../assets/tun.svg)
26 | 图 3-13 VPN 中数据流动示意图 27 | ::: 28 | 29 | 封装数据包以构建网络隧道,是实现虚拟网络的常见方式。例如,在本书第七章介绍的容器网络插件 Flannel 早期版本中,曾使用 TUN 设备来实现容器间的虚拟网络通信。但是,TUN 设备的数据传输需经过两次协议栈,并涉及多次封包与解包操作,导致了很大的性能损耗。这也是 Flannel 后来弃用 TUN 设备的主要原因。 30 | -------------------------------------------------------------------------------- /network/virtual-nic.md: -------------------------------------------------------------------------------- 1 | # 3.5.3 虚拟网卡 Veth 2 | 3 | Linux 内核 2.6 版本支持网络命名空间的同时,也提供了专门的虚拟网卡 Veth(Virtual Ethernet,虚拟以太网网卡)。 4 | 5 | Veth 的核心原理是“反转数据传输方向”,即在内核中,将发送端的数据包转换为接收端的新数据包,并重新交由内核网络协议栈处理。通俗的解释,Veth 就是一根带着两个“水晶头”的“网线”,从网线的一头发送数据,另一头就会收到数据。因此,Veth 也被说成是“一对设备”(Veth-Pair)。 6 | 7 | Veth 设备的典型应用场景是连接相互隔离的网络命名空间,使它们能够进行通信。假设存在两个网络命名空间 ns1 和 ns2,其网络拓扑结构如图 3-14 所示。接下来,笔者将通过实际操作演示 Veth 设备如何在网络命名空间之间建立通信,帮助你加深理解。 8 | 9 | :::center 10 | ![](../assets/linux-veth.svg)
11 | 图 3-14 Veth 设备对 12 | ::: 13 | 14 | 首先,使用以下命令创建一对 Veth 设备,命名为 veth1 和 veth2。该命令会生成一对虚拟以太网设备,它们之间形成点对点连接,即数据从 veth1 发送后,会直接出现在 veth2 上,反之亦然。 15 | 16 | ```bash 17 | $ ip link add veth1 type veth peer name veth2 18 | ``` 19 | 20 | 接下来,我们将分别将它们分配到不同的网络命名空间。 21 | 22 | ```bash 23 | $ ip link set veth1 netns ns1 24 | $ ip link set veth2 netns ns2 25 | ``` 26 | 27 | Veth 作为虚拟网络设备,具备与物理网卡相同的特性,因此可以配置 IP 和 MAC 地址。接下来,我们为 Veth 设备分配 IP 地址,使其处于同一子网 172.16.0.0/24,然后激活设备。 28 | 29 | ```bash 30 | # 配置命名空间1 31 | $ ip netns exec ns1 ip link set veth1 up 32 | $ ip netns exec ns1 ip addr add 172.16.0.1/24 dev veth1 33 | # 配置命名空间2 34 | $ ip netns exec ns2 ip link set veth2 up 35 | $ ip netns exec ns2 ip addr add 172.16.0.2/24 dev veth2 36 | ``` 37 | Veth 设备配置 IP 后,每个网络命名空间都会自动生成相应的路由信息。如下所示: 38 | 39 | ```bash 40 | $ ip netns exec ns1 ip route 41 | 172.16.0.0/24 dev veth1 proto kernel scope link src 172.16.0.1 42 | ``` 43 | 44 | 上述路由配置表明,所有属于 172.16.0.0/24 网段的数据包都会经由 veth1 发送,并在另一端由 veth2 接收。在 ns1 中执行 ping 测试,可以验证两个网络命名空间已经成功互通了。 45 | 46 | ```bash 47 | $ ip netns exec ns1 ping -c10 172.16.0.2 48 | PING 172.16.0.2 (172.16.0.2) 56(84) bytes of data. 49 | 64 bytes from 172.16.0.2: icmp_seq=1 ttl=64 time=0.121 ms 50 | 64 bytes from 172.16.0.2: icmp_seq=2 ttl=64 time=0.063 ms 51 | ``` 52 | 53 | 最后,虽然 Veth 设备模拟网卡直连的方式解决了两个容器之间的通信问题,但面对多个容器间通信需求,如果只用 Veth 设备的话,事情就会变得非常麻烦。让每个容器都为与它通信的其他容器建立一对专用的 Veth 设备,根本不切实际。此时,就迫切需要一台虚拟化交换机来解决多容器之间的通信问题,这正是笔者前面多次提到的 Linux bridge。 54 | 55 | -------------------------------------------------------------------------------- /noun.md: -------------------------------------------------------------------------------- 1 | # 术语缩写释义 2 | 3 | 本书各个篇章出现了较多的术语缩写,初次引用时会注明释义。但为了查阅方便,笔者按分类整理成以下表格。 4 | 5 | :::center 6 | 表 1 网络类 7 | ::: 8 | |术语|名词全称|释义| 9 | |:--|:--|:--| 10 | | AS | Autonomous System | 网络自治系统 | 11 | | CIDR | Classless Inter-Domain Routing | 无类域间路由 | 12 | | VPC | Virtual Private Cloud | 私有网络 | 13 | | VIP | Virtual IP address | 虚拟 IP 地址 | 14 | | SDN | Software Defined Networking | 软件定义网络 | 15 | | (S)LB | (Server) Load Balancer | 负载均衡 | 16 | | NIC | Network Interface Card | 网卡 | 17 | | RTT | Round-Trip Time | 往返时延 | 18 | | NAT | Network Address Translation | 网络地址转换 | 19 | | TTFB | Time To First Byte | 首字节时间 | 20 | | BBR | Bottleneck Bandwidth and RTT | Google 推出的拥塞控制算法 | 21 | |PPS|Packet Per Second | 包 / 秒,表示以网络包为单位的传输速率 | 22 | | BDP | Bandwidth-Delay Product | 带宽时延积 | 23 | |RDMA| Remote Direct Memeory Access | 远程内容直接读取| 24 | | 南北流量 | NORTH-SOUTH traffic | 用户访问服务器的流量 | 25 | | 东西流量 | EAST-WEST traffic | 集群中服务与服务之间的流量 | 26 | 27 | :::center 28 | 表 2 云技术类 29 | ::: 30 | |术语|名词全称|释义| 31 | |:--|:--|:--| 32 | | IaaS | Infrastructure as a Service | 基础设施即服务 | 33 | | PaaS | Platform as a Service | 平台即服务 | 34 | | SaaS | Software as a Service | 软件即服务 | 35 | | FaaS | Function as a Service | 功能即服务 | 36 | | CaaS | Container as a Service | 容器即服务 | 37 | | IaC | Infrastructure as Code | 基础设施即代码 | 38 | | KVM | Kernel-based Virtual Machine | 基于内核的虚拟机 | 39 | | AZ | Availability Zone | 可用区 | 40 | | SRE| Site Reliability Engineering | 站点可靠性工程 | 41 | | CE | Chaos Engineering(混沌工程)| 故障演练及解决。研究大规模分布式系统瓶颈、缺陷,提升整体服务稳定的方法学| 42 | | DevOps| Development + Operations | 开发运维 | 43 | | AIDevOps| AI + Development + Operations | 智能开发运维 | 44 | | DevSecOps | Development + Security + Operations | 开发、安全和运维,应用安全 (AppSec) 领域术语 | 45 | | CI/CD| Continuous Integration + Continuous Deployment | 持续集成 + 持续交付 | 46 | 47 | :::center 48 | 表 3 Kubernetes 相关类 49 | ::: 50 | |术语|名词全称|释义| 51 | |:--|:--|:--| 52 | | CNCF | Cloud Native Computing Foundation | 云原生计算基金会 | 53 | | OCI | Open Container Initiative | Linux 基金主导的开放容器标准 | 54 | | CRI | Container Runtime Interface | Kubernetes 定义的容器运行时接口 | 55 | | CNI | Container Network Interface | Kubernetes 定义的容器网络接口 | 56 | | CRD | Custom Resource Definition | 自定义资源的定义,用来扩展 Kubernetes 资源 | 57 | | Operator | CRD + AdmissionWebhook + Controller | 用来解决某个应用场景的 Kubernetes 扩展 | 58 | 59 | :::center 60 | 表 4 业务类 61 | ::: 62 | |术语|名词全称|释义| 63 | |:--|:--|:--| 64 | | QPS | Queries Per Second | 每秒请求数 | 65 | | QoS | Quality of Service | 服务质量 | 66 | | TPS | Transactions Per Second | 每秒事务数 | 67 | | MTBF | Mean Time Between Failure | 平均故障间隔时长 | 68 | | P90 | percentile 90 | 数据聚合统计方式,用来衡量业务指标 | 69 | | QA | Quality Assurance | 品质保证| 70 | | SLA | Service Level Agreement | 服务等级协议,用于向客户承诺提供的服务等级 | 71 | | APM | Application Performance Monitoring | 应用程序性能监控| 72 | 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "thebyte", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "author": "isno", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "vuepress dev .", 9 | "build": "vuepress build ." 10 | }, 11 | "devDependencies": { 12 | "katex": "^0.16.11", 13 | "vuepress": "2.0.0-rc.0", 14 | "vuepress-plugin-comment2": "2.0.0-rc.4", 15 | "vuepress-plugin-md-enhance": "2.0.0-rc.4", 16 | "vuepress-plugin-reading-time2": "2.0.0-rc.4" 17 | }, 18 | "dependencies": { 19 | "vue-github-button": "3.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /review.md: -------------------------------------------------------------------------------- 1 | # 推荐序 2 | 3 | ## 推荐序1 4 | 5 | 和伟峰共事10多年,他对技术始终充满激情,精通前后端多种语言,且在网络技术、云原生、架构设计等领域均有较高的认知。正是因其广泛的知识面和深厚的技术根底,很多项目上他都有独特的见解和创新的观点,能高效的做到技术和业务的融合。凭借其专业能力在爱奇艺国际站建站初期主导了技术和业务架构设计与落地,智能化的业务体系、高可用的服务框架为爱奇艺海外业务的快速迭代与发展奠定了基础。 6 | 7 | 《深入架构原理与实践》作者深入探讨了从传统的软件开发到云计算、微服务、容器技术、服务网格等现代架构理念的演变过程。不仅展示了具体的技术实现,还深入探讨了技术背后的原理和设计思想。理解问题的本质和解決方案的权衡取舍,才是架构师应具备的核心能力。通过对比不同的技术方案和实际案例,读者可以更好地理解各种架构设计选择的优缺点,从而在实际工作中做出更好的决策。同时,本书写作风格通俗易懂,即便是对于没有深厚技术背景的读者,也能够轻松入门,逐步深入。而对于经验丰富的专业人士,书中的深入分析和丰富案例也足以提供新的视角和思考。 8 | 9 | 陆华梅 10 | 爱奇艺海外事业部-高级总监 11 | 2024年6月于上海 12 | 13 | 14 | ## 推荐序2 15 | 16 | 伟峰是位兼具前后端能力的全栈技术人,在过去15年实战中所得的技术精髓,从云计算应用工程师的角度,解读在大型互联网公司中,如何构建以超高可用性为核心的技术体系。此外,全书吸收了与国际社区技术专家互动中的诸多真知灼见,进一步提升了前瞻性和准确度。 17 | 18 | 陈绪 博士 阿里云基础设施资深总监 19 | 20 | ## 推荐序3 21 | 22 | 王老师通过多年的积累,终于推出了这本高质量的作品——《深入架构原理与实践》。本书是针对软件工程师、架构师和技术负责人的权威指南,帮助读者在系统架构中做出明智的决策,并加深对各种技术优缺点的理解。无论是了解基础软件构建还是设计高可用系统,本书都是不可或缺的参考。 23 | 24 | 谢孟军 --------------------------------------------------------------------------------