<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Cloud Native | Liao Lile</title>
    <link>https://liaolile.com/tag/cloud-native/</link>
      <atom:link href="https://liaolile.com/tag/cloud-native/index.xml" rel="self" type="application/rss+xml" />
    <description>Cloud Native</description>
    <generator>Wowchemy (https://wowchemy.com)</generator><language>zh-Hans</language><lastBuildDate>Sun, 29 May 2022 12:23:10 +0000</lastBuildDate>
    <image>
      <url>https://liaolile.com/media/icon_hu0b7a4cb9992c9ac0e91bd28ffd38dd00_9727_512x512_fill_lanczos_center_3.png</url>
      <title>Cloud Native</title>
      <link>https://liaolile.com/tag/cloud-native/</link>
    </image>
    
    <item>
      <title>Kubernetes</title>
      <link>https://liaolile.com/post/tech/cloudnative/kubernetes/</link>
      <pubDate>Sun, 29 May 2022 12:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/cloudnative/kubernetes/</guid>
      <description>&lt;h3 id=&#34;0-kubernetes是什么&#34;&gt;0. Kubernetes是什么&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Kubernetes(K8s)&lt;/strong&gt; is a portable, extensible, open source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Kubernetes为云原生应用提供了定义规范。&lt;/p&gt;
&lt;p&gt;Kubernetes 已经成为云时代的操作系统。我们可以对比一下经典的 Linux 和 Kubernetes 的概念模型，他们都是定义了开放的、标准化的访问接口；该通用API接口在类Unix下称为POSIX&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;Portable Operating System Interface&lt;/strong&gt; (&lt;strong&gt;POSIX&lt;/strong&gt;) is a family of &lt;a href=&#34;https://en.wikipedia.org/wiki/Standardization&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;standards&lt;/a&gt; specified by the &lt;a href=&#34;https://en.wikipedia.org/wiki/IEEE_Computer_Society&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;IEEE Computer Society&lt;/a&gt; for maintaining compatibility between &lt;a href=&#34;https://en.wikipedia.org/wiki/Operating_system&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;operating systems&lt;/a&gt;.  POSIX defines both the system- and user-level &lt;a href=&#34;https://en.wikipedia.org/wiki/Application_programming_interface&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;application programming interfaces&lt;/a&gt; (API), along with command line &lt;a href=&#34;https://en.wikipedia.org/wiki/Unix_shell&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;shells&lt;/a&gt; and utility interfaces, for software compatibility (portability) with variants of &lt;a href=&#34;https://en.wikipedia.org/wiki/Unix&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Unix&lt;/a&gt; and other operating systems.POSIX is also a &lt;a href=&#34;https://en.wikipedia.org/wiki/Trademark&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;trademark&lt;/a&gt; of the IEEE. POSIX is intended to be used by both application and system developers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Kubernetes定义了云的分布式系统的API。如下是linux同kubernetes之间的类比：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;th&gt;Linux&lt;/th&gt;
&lt;th&gt;Kubernetes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;隔离单元&lt;/td&gt;
&lt;td&gt;进程&lt;/td&gt;
&lt;td&gt;Pod&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;硬件&lt;/td&gt;
&lt;td&gt;虚拟机/物理机&lt;/td&gt;
&lt;td&gt;数据中心&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;并发单元&lt;/td&gt;
&lt;td&gt;线程&lt;/td&gt;
&lt;td&gt;容器进程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;资源管理&lt;/td&gt;
&lt;td&gt;进程内存及CPU&lt;/td&gt;
&lt;td&gt;内存、CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;存储&lt;/td&gt;
&lt;td&gt;文件&lt;/td&gt;
&lt;td&gt;ConfigMap，Secrete，Volumn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;网络&lt;/td&gt;
&lt;td&gt;访问端口&lt;/td&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;终端控制台&lt;/td&gt;
&lt;td&gt;shell，bash&lt;/td&gt;
&lt;td&gt;kubectl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;网络安全&lt;/td&gt;
&lt;td&gt;Iptables&lt;/td&gt;
&lt;td&gt;NetworkPolicy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;权限管理&lt;/td&gt;
&lt;td&gt;用户、文件权限&lt;/td&gt;
&lt;td&gt;UserAccount，ServiceAccount，RBAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Linux和kubernetes作为操作系统，体现在向下封装资源，向上支撑应用。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/06/04/s6pCo18ZjVHDt2Y.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;它们都提供了对底层计算、存储、网络、异构计算设备的资源抽象和安全访问模型。可以根据应用需求进行资源调度和编排。Linux 的计算调度单元是进程，调度范围限制在一台计算节点。而 Kubernetes 的调度单位是 Pod，可以在分布式集群中进行资源调度，甚至跨越不同的云环境。其主要业务是调度和管理容器服务。&lt;/p&gt;
&lt;h3 id=&#34;1-kubernetes架构&#34;&gt;1. Kubernetes架构&lt;/h3&gt;
&lt;p&gt;一个高层级的Kubernetes架构图如下：分为控制面Master和数据面Node节点池；集群上可以是一主多从和多主多从的架构；&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/04/2tZKCeJ491qjN5y.jpg&#34; style=&#34;zoom: 33%;&#34; /&gt;
&lt;p&gt;Kubernetes 的控制平面包含四个主要的组件：API Server、Controller、Scheduler 以及 etcd。如下是其与数据面的交互图，均通过API server同kubelet交互实现的。同时数据面提供loadbalancer给到终端用户请求。K8s 可以在 IDC、云端、边缘等不同场景进行统一部署和交付。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/06/04/JTma7KdVspOqSFW.png&#34; alt=&#34;img&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 id=&#34;11-容器相关概念&#34;&gt;1.1 容器相关概念&lt;/h4&gt;
&lt;p&gt;如下图介绍了Kubernetes以及docker中最核心的一些概念。&lt;/p&gt;
&lt;p&gt;CRI是kubernetes定义的容器运行时接口，具体的实现由两个，一个是来自于docker的containerd，另一个是来自于RedHat的CRI-O。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Docker，Kubernetes 等工具来运行一个容器时会调用容器运行时（CRI）比如 containerd，CRI-O&lt;/li&gt;
&lt;li&gt;通过容器运行时来完成容器的创建、运行、销毁等实际工作&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Docker 使用的是 containerd 作为其运行时；Kubernetes 支持 containerd，CRI-O 等多种容器运行时&lt;/li&gt;
&lt;li&gt;这些容器运行时都遵循了 OCI 规范，并通过 runc 来实现与操作系统内核交互来完成容器的创建和运行&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;CRI（容器运行时接口）是 Kubernetes 用来控制创建和管理容器的不同运行时的 API，它使 Kubernetes 更容易使用不同的容器运行时。它一个插件接口，这意味着任何符合该标准实现的容器运行时都可以被 Kubernetes 所使用。&lt;/li&gt;
&lt;li&gt;OCI 开放容器倡议，是一个由科技公司组成的团体，其目的是围绕容器镜像和运行时创建开放的行业标准。他们维护容器镜像格式的规范，以及容器应该如何运行。&lt;/li&gt;
&lt;li&gt;runc 是轻量级的通用运行时容器，它遵守 OCI 规范，是实现 OCI 接口的最低级别的组件，它与内核交互创建并运行容器。runc 为容器提供了所有的低级功能，与现有的低级 Linux 功能交互，如命名空间和控制组，它使用这些功能来创建和运行容器进程。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;具体详细内容参考下述图表&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/04/fNnYTSmP4OhJr7U.jpg&#34; alt=&#34;img&#34; style=&#34;zoom:67%;&#34; /&gt;
&lt;h4 id=&#34;12-kubernetes设计理念&#34;&gt;1.2 Kubernetes设计理念&lt;/h4&gt;
&lt;p&gt;Kubernetes 在容器编排中有几个关键设计理念：&lt;/p&gt;
&lt;p&gt;**容错性：**容错性是保证K8s集群系统稳定性和安全性的基础，确保系统不崩溃，不出现业务错误，不做坏事。&lt;/p&gt;
&lt;p&gt;**易扩展性：**易扩展性是保证K8s友好，后续快速迭代增加新功能的基础，让系统可以在用户看到的时间内做好事。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;声明式 API&lt;/strong&gt;：开发者可以关注于应用自身，而非系统执行细节。比如 Deployment（无状态应用）、 StatefulSet（有状态应用）、Job（任务类应用）等不同资源类型，提供了对不同类型工作负载的抽象；对 Kubernetes 实现而言，基于声明式 API 的 “level-triggered” 实现比 “edge-triggered” 方式可以提 供更加健壮的分布式系统实现。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可扩展性架构：&lt;strong&gt;所有 K8s 组件都是基于一致的、开放的 API 实现和交互；三方开发者也可通过 CRD（Custom Resource Definition）/Operator 等方法提供领域相关的扩展实现，极大提升了 K8s 的能力。Operator 是 Kubernetes 里面的一个核心思想，它代表着我的任何一个应用和它所需要的能力都可以定义成为一个 Kubernetes 的 API 对象，通过一个叫做 Controller 的机制让你去使用云的能力，再让你接入到各种各样的基础设施里面。这个 Operator 化带来的一个直接结果就是，我的应用本身是高度自动化的，包括&lt;/strong&gt;自愈、健壮性、可靠性、运行的确定性&lt;/strong&gt;，这些在今天都可以交给 Kubernetes去解决。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可移植性&lt;/strong&gt;：K8s 通过一系列抽象如 Loadbalance Service（负载均衡服务）、CNI（容器网络接口）、CSI（容器存储接口）、CRI（容器运行时接口），帮助业务应用可以屏蔽底层基础设施的实现差异，实现容器灵活迁移的设计目标。&lt;/p&gt;
&lt;h4 id=&#34;13-kubernetes核心概念&#34;&gt;1.3 Kubernetes核心概念&lt;/h4&gt;
&lt;p&gt;Kubernetes中核心对象类型包括：资源对象、配置对象、存储对象、策略对象，详细的对象类别中包含一些核心概念。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/04/LypNOxkQGh9tC4H.jpg&#34; style=&#34;zoom: 50%;&#34; /&gt;
&lt;p&gt;上述对象均可理解为Kubernetes API Objects，每个对象包含三大类属性：&lt;strong&gt;元数据metadata，规范spec和状态status&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;元数据&lt;/code&gt;用来标识对象，至少包含三个元数据：namespace，name，uid；除此一般还有label，可以用来标识和匹配不同的对象；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;规范&lt;/code&gt;描述了用户期望kubernetes集群中分布式系统达到的理想状态；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;状态&lt;/code&gt;描述了当前系统实际达到的状态&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kubernetes中所有的配置都是通过API对象的spec去设置的，也就是用户通过配置系统的理想状态来改变系统，所有的API均是声明式的。&lt;/p&gt;
&lt;h5 id=&#34;131-资源对象&#34;&gt;1.3.1 资源对象&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pod&lt;/strong&gt;，Kubernetes中最小的部署应用或服务单元，可以支持部署多容器；同一个Pod中共享网络地址和共享文件，可以通过进程间通信组合完成服务。目前Kubernetes业务主要包括：long-running、batch、node-deamon、stateful application，分别对应的控制器为Deployment，Job，DeamonSet，StatufulSet。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**Deployment **，表示对集群的Kubernetes的一次更新操作，比RS应用模式更广的API对象，可以是创建一个新的服务，更新一个新的服务，也可以是滚动升级一个服务。滚动升级实际是创建一个新的RS，逐步增加到理想的副本个数，旧的RS逐步减小到0的符合操作；以 Kubernetes 的发展方向，未来对所有长期伺服型的的业务的管理，都会通过 Deployment 来管理。Master 节点的中有一个子系统叫做 Deployment Controller，负责实际执行并使当前状态不断趋向于所需状态。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Replication Controller&lt;/strong&gt;， 副本控制器RC, 用来保证Pod高可用的API对象，通过监控运行中的Pod个数来保证集群中运行指定数目的Pod副本。RC是Kubernetes早期技术概念，只适用于long-running业务类型，目前已经使用RS替代。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Replica Set&lt;/strong&gt;， 副本集 RS，RS是新一代RC，提供同样高可用能力，支持更多种类的匹配模式，副本集对象一般不单独使用，而是作为Deployment的理想状态参数使用。ReplicaSet 是管理 pod 生命周期的组件，监控活动副本，当收到指令时或 pod 离线或意外停止时启动 pod，也会在收到指示时杀死 pod，也许是因为用户负载减少。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Job&lt;/strong&gt;, Job是K8s中用来控制批任务的API对象。Job管理Pod根据用户的设置把任务成功完成就自动退出了。成功完成的标志根据不同的spec.completions策略而不同；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deamon Set&lt;/strong&gt;，后台服务集，重点关注K8s中的节点，确保每个节点上均有此类Pod（包括存储、日志、监控等）运行。节点可能是所有集群节点，也可能是通过NodeSelector选定的一些特定节点。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;StatefulSet&lt;/strong&gt;，有状态服务集，RC和RS主要控制的是无状态服务集，其所控制的Pod名字是随机设置的，1个Pod出故障了就被丢弃了，而另个地方重启的Pod名字就变了。对于无状态服务集重要的是数量，而不是名字和在哪。StatefulSet中每个Pod的名字都是事先确定的，不能改变的，用于后续关联Pod的状态。StatefulSet中的Pod每个独立挂载自己的独立存储，Pod出现故障后，还得挂载上原来的存储继续提供有状态服务；StatefuleSet做的事情是将确定的Pod和确定的存储关联起来保证状态的连续性。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&#34;132-配置对象&#34;&gt;1.3.2 配置对象&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Node节点&lt;/strong&gt;, K8s中的计算能力，是所有Pod运行所在的工作主机，可以是物理机也可以是虚拟机，均需要基于kubelet管理节点上的容器。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service服务&lt;/strong&gt;， RC/RS/Deployment只是保证了Pod的数量，没有解决如何访问这些服务的问题。由于Pod的调度机制决定了服务实例不能以确定的IP和端口来提供服务，需要依赖服务端的服务发现和负载均衡能力。在K8s内部，客户端需要访问的服务就是Service对象，每个Service对象都会有一个集群内部的虚拟IP，集群内部通过虚拟IP访问服务；Kube-proxy是K8s中的负载均衡器，在K8s的每个节点上都有一个，这是一个分布式的代理服务，需要访问的节点服务越多，提供负载均衡能力的kube-proxy就越多，高可用节点也越多。 另外，Service 是一组逻辑上的 pod分组，对提供同一个服务的多个Pod进行聚合；它提供了一个单一的虚拟的Cluster IP 地址和 DNS 名称，后端对应1个或多个提供服务的Pod，你可以通过它访问服务内的所有 pod。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secrete 密钥对象&lt;/strong&gt;， 用来保存和传递密码、密钥、认证凭据等敏感信息。在对应的配置文件中通过Secrete对象应用敏感信息。这种方式的好处是：意图明确，避免重复，减少暴露机会。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UserAccount用户账户 &amp;amp; ServiceAccount服务庄户&lt;/strong&gt;, 用户账户为个人提供账户标识，服务账户为计算机进程和K8s集群中运行的Pod提供账户标识。用户账户与下述的服务命名空间无关，而服务账号的是运行绑定在某个命名空间下的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Namespace命名空间&lt;/strong&gt;，提供集群虚拟的集群隔离作用，K8s初始由两个命名空间，1个是默认命名空间default，1个是系统命名空间kube-system。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ingress/Egress&lt;/strong&gt;，Kubernetes pod 的流量称为 Ingress，而从 pod 到集群外的出站流量称为 Egress。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom Resource Definition&lt;/strong&gt;, CRD自定义的资源对象，需要满足K8s API定义规范；
&lt;ul&gt;
&lt;li&gt;apiVersion，自定义资源对象的版本号&lt;/li&gt;
&lt;li&gt;Kind，自定义资源对象的名称，用户可以通过kubectl get ${kind_name}来获取对应的资源对象&lt;/li&gt;
&lt;li&gt;Metadata，继承了原生的K8s的metadata，用于添加lable/annotation等元数据&lt;/li&gt;
&lt;li&gt;Spec，可自定义设计的服务配置参数，如镜像版本号，节点数据量等&lt;/li&gt;
&lt;li&gt;Status，定义资源的相关状态&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&#34;133-存储对象&#34;&gt;1.3.3 存储对象&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Volumn存储卷&lt;/strong&gt;, Docker存储卷作用范围为一个容器，而K8s的存储卷作用范围为一个Pod，每个Pod申请的卷由Pod中所有容器共享。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PersistentVolumn&lt;/strong&gt;持久存储卷 &amp;amp; &lt;strong&gt;PersistentVolumnClaim&lt;/strong&gt;持久存储卷声明， PV和PVC使K8s具有存储的逻辑抽象能力，使得配置Pod的存储卷时候可以忽略对应的存储技术配置。PV和PVC的关系类比于计算的Node和Pod，PV和Node是资源提供者，PVC和Pod是资源使用者。&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&#34;134-策略对象&#34;&gt;1.3.4 策略对象&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Federation集群联邦&lt;/strong&gt;， K8s最初的设计是单一集群在同一个地域内，同一个地区的网络性能才能满足K8s调度和计算存储连接要求。Federation就是让K8s有跨Region和跨服务商的能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RBAC访问授权&lt;/strong&gt;，RBAC中引入角色Role和角色绑定RoleBinding，访问策略是可以和某个角色绑定，具体的用户再和1个或多个角色绑定；&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;14-kubernetes和服务网格servicemesh&#34;&gt;1.4 Kubernetes和服务网格ServiceMesh&lt;/h4&gt;
&lt;p&gt;将应用程序的功能划分为单独的进程运行在同一个最小调度单元中（例如 Kubernetes 中的 Pod）可以被视为 &lt;strong&gt;sidecar 模式&lt;/strong&gt;。如下图所示，sidecar 模式允许您在应用程序旁边添加更多功能，而无需额外第三方组件配置或修改应用程序代码。而通过sidecar模式的组网即为服务网格架构形态。Sidecar 应用与主应用程序松散耦合。它可以屏蔽不同编程语言的差异，统一实现微服务的可观测性、监控、日志记录、配置、断路器等功能。&lt;/p&gt;
&lt;p&gt;中间件实际上是大量的通过 Sidecar 方式去被使用到的，所以我的应用本身不需要再去引入一个库，或者引入一个特定的框架来去做很多事情，我甚至都不需要感知。应用跟云的交互，就通过一个叫 Sidecar 的一个旁路容器，让这个容器去代理应用本身所需要的进出流量，所以云就可以非常容易地通过这样一个代理，调节流量、做流量切分、网络管控，这就是非常简单的 Service Mesh 的原理。如下是两种形态的Sidecar模式。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/06/04/izHEBdmqC3rNkZ8.png&#34; alt=&#34;img&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;使用容器作为Service和Sidecar进程的承载；&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/06/04/uHVP5LsACQvYktd.png&#34; alt=&#34;img&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;使用Function作为Servcie和Sidecar逻辑的承载；&lt;/p&gt;
&lt;h3 id=&#34;2-kubernetes原理机制&#34;&gt;2. Kubernetes原理机制&lt;/h3&gt;
&lt;h4 id=&#34;21-kubernetes服务之间通信&#34;&gt;2.1 Kubernetes服务之间通信&lt;/h4&gt;
&lt;h5 id=&#34;211-clusterip&#34;&gt;2.1.1 ClusterIp&lt;/h5&gt;
&lt;p&gt;在K8s中，Service对应提供一个虚拟的ClusterIp，通过ClusterIp即可访问到服务对应的Pod。而负责这一转发的模块是Kube-proxy。在该场景下，ClusterIp和PodId都是K8s集群内部的访问地址；&lt;/p&gt;
&lt;p&gt;Kube-proxy是一个运行在K8s每个节点上的Go应用程序，支持三种工作模式：userspace、iptables、ipvs。后端选择pod进行转发的时候依赖Label Selector。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;userspace&lt;/p&gt;
&lt;p&gt;该模式下kubep-proxy为每个service创建一个监听端口，发向ClusterIp的请求被iptables规则重定向到Kuber-proxy监听的端口上，Kube-proxy依据LB算法选择一个服务的Pod进行请求转发。该模式下，Kube-proxy是4层loadbalancer。但是由于在用户空间，数据拷贝效率较低。后端Pod不可用时，kube-proxy会重试其他的pod。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;​		&lt;img src=&#34;https://s2.loli.net/2022/06/13/b9uRs8KvqFeIPUH.jpg&#34; style=&#34;zoom: 50%;&#34; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;iptables&lt;/p&gt;
&lt;p&gt;kube-proxy为service后端的每个pod创建对应的iptables规则，直接将发向ClusterIp的请求重定向到一个Pod Ip。该场景下，避免了数据的用户空间和内核空间的拷贝，kube-proxy不充当4层负载均衡，而只负责创建iptables规则。但是当后端pod故障后，无法进行重试；&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/13/XoxSaHyWi4UgmkQ.jpg&#34; style=&#34;zoom: 50%;&#34; /&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ipvs&lt;/p&gt;
&lt;p&gt;kube-proxy监控pod的变化并且创建对应的ipvs rules。ipvs是在kernel模式下通过netfilter实现，采用hash table存储规则，支持更多的loadbalance的算法，依赖在操作系统中安装ipvs内核模块。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/13/RdfguQyJe6DEFnz.jpg&#34; style=&#34;zoom: 50%;&#34; /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;212-nodeport&#34;&gt;2.1.2 NodePort&lt;/h5&gt;
&lt;p&gt;NodePort在集群中的主机节点上为Servcie提供一个代理端口，允许从主机网络对Service进行访问。&lt;/p&gt;
&lt;p&gt;在创建NodePort时，kube-proxy也会同时为Service创建Cluster Ip相关的iptables规则，kube-proxy并不不会直接接受主机的端口进入的流量，而是创建相应的iptables规则，通过从该带瘤端口收到的流量直接转发到后端的Pod中。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/13/OQMLzIygXrJE7da.jpg&#34; style=&#34;zoom: 50%;&#34; /&gt;
&lt;h5 id=&#34;213-loadbalancer&#34;&gt;2.1.3 LoadBalancer&lt;/h5&gt;
&lt;p&gt;K8s支持将Service定义为LoadBalancer类型；LoadBalancer类型的Service创建后，Cloud Provider Controller会将配置下发到Cloud Provider网络中的&lt;strong&gt;四层负载均衡器&lt;/strong&gt;，该负载均衡器负责将外部的流量分发到后面多个节点的NodePort端口上。也就是说外部流量需要依赖NodePort端口才能把流量转发到K8s内部。而LoadBalancer需要依赖各个云服务商提供支持。&lt;/p&gt;
&lt;h5 id=&#34;214-ingress&#34;&gt;2.1.4 Ingress&lt;/h5&gt;
&lt;p&gt;当一个应用需要对外提供多个服务时，需要借用Kubernetes Ingress来统一网络入口。其声明了一个应用层的负载均衡器，可以根据HTTP请求的内容将来自同一个TCP端口的请求分发到不同的Kubernetes Service。支持按Http URL进行路由，同时也支持按照请求的Host进行路由。&lt;/p&gt;
&lt;p&gt;Kubernetes使用Ingress Controller来监控Ingress规则，并通过一个七层网关来实现这些要求，一般可以使用Nginx，HAProxy等；由于Ingress是不是在K8s集群中，对外部流量来说，需要配合NodePort和LoadBalancer才能提供对外的流量入口。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/13/tPm73usSKd21DUp.jpg&#34; style=&#34;zoom:33%;&#34; /&gt;
&lt;p&gt;在NodePort，Ingress，Pod等不同的接入层面都可以对系统进行水平扩展，以应对不同的外部流量要求。详细的局部细节图如下：&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/13/oAVIRh3PYZHWxpy.jpg&#34; style=&#34;zoom: 50%;&#34; /&gt;
&lt;p&gt;&lt;strong&gt;REFERENCE&lt;/strong&gt;:&lt;/p&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/POSIX&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;POSIX - Wikipedia&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/490585683&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Docker，containerd，CRI，CRI-O，OCI，runc 分不清？看这一篇就够了 - 知乎 (zhihu.com)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>Kubernetes上的分布式系统</title>
      <link>https://liaolile.com/post/tech/distributesystem/kubernetes%E4%B8%8A%E7%9A%84%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/</link>
      <pubDate>Sat, 28 May 2022 16:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/distributesystem/kubernetes%E4%B8%8A%E7%9A%84%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/</guid>
      <description>&lt;p&gt;分布式系统不仅仅是运行时，还是&lt;strong&gt;开发时、构建时、运维时&lt;/strong&gt;；分布式系统需要4个方面的能力，包括生命周期的管理、网络通讯能力、资源绑定能力以及有状态逻辑的处理。&lt;/p&gt;
&lt;p&gt;系统的生命周期能力，我们需要一个可靠且&lt;strong&gt;全自动化的打包和部署、回滚、健康检查&lt;/strong&gt;。能够实现应用在不同节点的分发，且资源隔离、扩展、配置可管理。这些能力就是第一位的基础。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/09/12/RQO89TrqgJL2C4B.png&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;网络的连接能力&lt;/strong&gt;是分布式系统的第二要素。可靠韧性的连接到其他的服务，无论集群内还是集群外，分布式系统预期有服务发现、负载均衡等能力。同时由于不同的流量策略，需要具备流量转移的能力。服务的韧性在网络方面体现在超时重试、断路器等。围绕网络还要有安全保障，足够的监控、追踪和可观察性。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/08/03/rDEnmNFXhZcy3Kz.png&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;分布式系统的有能力与不同的API和端点交互，即&lt;strong&gt;资源绑定与其协议不同的数据格式交互&lt;/strong&gt;，甚至从一种数据格式到另外一种数据格式的转换。对于消息数据的点对点pub/sub交互，以及数据的过滤，数据的路由；&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/08/03/CHJf8shcnWpGUIk.png&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;关于&lt;strong&gt;依赖状态&lt;/strong&gt;的开发人员抽象，分布式系统需要有工作流的管理能力，管理长进程以及短周期的调度任务，依赖分布式缓存，需要具有幂等性和支持回滚。这些均需要考虑系的同内部的已有状态的处理，依赖于开发人员的抽象。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/09/12/noBu75Wh3dNAxOY.png&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;技术架构的演进从单体到微服务再到云原生架构；&lt;/p&gt;
&lt;p&gt;按照业务领域进行划分出现了微服务，容器和Kubernetes是管理这些微服务的优秀平台。Readiness和Liveness探测在kubernetes对于容器的生命周期管理至关重要，一个是确定应用在启动期间何时可以接受外部流量，一个是检查服务的健康状况；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LivenessProbe，判断容器是否存活running状态，如果不健康会kill后重启处理；&lt;/li&gt;
&lt;li&gt;ReadinessProbe，判断容器服务是否可用ready状态，ready后的pod才接受来自外部的数据。Service同Pod Endpoint之间的关联关系基于该Pod的Ready状态进行设置；&lt;/li&gt;
&lt;/ul&gt;
&lt;img src=&#34;D:\0_leland\blog\blog-image\distributed\distributedSystem-architectrue-history.png&#34; style=&#34;zoom:80%;&#34; /&gt;
&lt;p&gt;Kubernetes 可以启动你的应用；它可以将其关闭，然后在不同的节点上移动它。为此，你必须正确执行平台在应用启动和关闭期间告诉你的事件。围绕声明式部署，声明资源需求，部署策略，应用程序同时需要执行来自环境的事件（健康检查、应用就绪度等）；实现整个部署的资源隔离、配置管理、故障隔离；&lt;/p&gt;
&lt;p&gt;Kubernetes中的Pod有两个约束：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod的部署会确保所有的容器均在同一个节点；各个容器间可以通过localhost进行通信，也可以通过其他的类似文件共享/IPC机制等；&lt;/li&gt;
&lt;li&gt;Pod中的容器生命周期可以不同，分为Init容器和应用容器，Pod启动时，Init容器按顺序一个一个运行，仅前一个成功后一个才运行；应用容器是并行运行的，在整个Pod生命周期中运行；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;K8s内部依赖调谐循环来确保状态和声明一致，将期望的状态驱动到与实际状态。&lt;/p&gt;
&lt;h4 id=&#34;ref&#34;&gt;REF&lt;/h4&gt;
</description>
    </item>
    
    <item>
      <title>云原生可观测性理解</title>
      <link>https://liaolile.com/post/tech/cloudnative/%E4%BA%91%E5%8E%9F%E7%94%9F%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E7%90%86%E8%A7%A3/</link>
      <pubDate>Tue, 24 May 2022 21:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/cloudnative/%E4%BA%91%E5%8E%9F%E7%94%9F%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E7%90%86%E8%A7%A3/</guid>
      <description>&lt;h3 id=&#34;0-可观测性&#34;&gt;0 可观测性&lt;/h3&gt;
&lt;p&gt;复杂度以及数据处理量不断增长，为了了解系统的负载状态，我们需要系统有更好的可观测性。出现故障的时候必须要更快的找到问题根本原因并且解决，以满足更严格的服务水平要求。&lt;/p&gt;
&lt;p&gt;越来越多的新应用基于云原生的方式而构建，提高了韧性、性能和安全性，但是同时失去了对于运行这些软件基础设施的控制的风险成本。作为系统owner必须要同时理解应用程序以及基础设施的运行状态。对于系统自身来说，其它均是外部实体，而系统在开发的时候就应该考虑给外部实体的可观测提供便利。这往往意味着编写更多的代码、自动化基础设施的操作并且监控关键的指标。&lt;/p&gt;
&lt;p&gt;一旦系统的可观测能力能够达到一个令人满意的水平，这带来的益处是显而易见的。做到知其然，知其所以然，一切的信息都在掌控之中。这些观测能力的建设，依赖工作理念的改变、工具、目标、工作方法的变化。&lt;/p&gt;
&lt;p&gt;对于可观测系统，其设计和开发中需要依赖遥感数据并且从这些数据中提取加工出有意义的信息。当前&lt;strong&gt;遥感数据&lt;/strong&gt;主要包括：&lt;strong&gt;metrics，logs，traces，events，profiles和crash dumps&lt;/strong&gt;，我们也把这些内容叫做&lt;strong&gt;观测信号&lt;/strong&gt;。每种数据都有它自己的意义和最佳处理方式，如果处理不当就会产生各种新的问题，比如监控的频繁误报、故障扩容等。&lt;/p&gt;
&lt;p&gt;控制论中的Controllability和Observability表示的是&lt;code&gt;可控性&lt;/code&gt;，控制量对状态变量的控制能力，&lt;code&gt;可观测性&lt;/code&gt;，输出量对状态变量的反应能力。可观测性是衡量一个系统仅凭其外部输出来判断其内部运行状态的精确度的指标，给外部实体往往是人，用来观察理解系统状态并且做出反应的功能。&lt;/p&gt;
&lt;p&gt;可观测性是可以用在系统生命周期内的所有阶段，测试新功能、监测环境的韧性，了解你的用户，以及后续产品的路线图。对于观测信号都有不同的收集和测量方法，花费不同的资源来获取、存储和分析，同时提供不同的方法来观测相同的系统，以提供不同的视角来观察同一个技术，它们之间是互补的。&lt;/p&gt;
&lt;p&gt;Metrics以实时、可靠、廉价的监控为中心，是支持快速、可靠告警的基础。Logs是为了更加深入了解系统运行细节，以便获取更多上下文的内容。更多时候的细节来自于请求书，也就是distributed tracing，支持了跨进程的context传播效应和串联效应。同时，也可能通过profiles来检查哪些代码效率低下并且使用了超出预期的资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Metrics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;metrics是数据的数值表现，主要分为已经是数值的数据和被转化为数值的数据。前者比较典型的就是温度、高度等。后者转化为数值的数据，在转化的时候旧丢失了细节，比如计数，其统计的是某个周期的，对于特定的增量发生时间是丢失的。领域专家需要明确选择提取什么，如何提取，这对于数据的如何保留、转化、传输、存储和处理数据的负担大大减少，人们可以借由该metrics指标了解当前的状况。&lt;/p&gt;
&lt;p&gt;metrics最常见的是构建概览和各项细节指标的图表集，每个指标都是一个逻辑计量单元，体现了一段时间之内相关指标的状态。&lt;/p&gt;
&lt;p&gt;进而发出告警或自动化通知到人员或者其他自动化系统。另外也可用于长期的趋势分析和长期计划，同时也能够在时候提供解决和监控潜在问题的建议。&lt;/p&gt;
&lt;p&gt;metrics更多的时候告诉我们“发生了什么”，衡量了关于系统的整体行为和健康状态。但是metrics往往不能告诉我们“为什么”，而是提供了相关问题定位的思路信息，并作为深入排查问题产生原因的出发点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Logs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;logs是在操作系统、应用程序中执行的过程、活动和操作的一系列文本类的对象流，是离散事件，具备结构化，人类可读的细节数据。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;应用logs，可以帮助开发者理解和衡量应用程序在开发中及后续发布后的行为方式；&lt;/li&gt;
&lt;li&gt;系统logs，可以记录操作系统本身的事件，可用于相关系统资源类的状态查看；&lt;/li&gt;
&lt;li&gt;安全logs，是为了响应系统上发生的安全事件而创建的。对于系统中关键的内容均可以把其记录进入到安全logs中，往往系统管理员可以配置安全logs中包含哪些类型的事件；&lt;/li&gt;
&lt;li&gt;审计logs，本质上是事件和变化的记录，代表着过程中的谁在什么事件进行了哪些动作，并且响应结果的记录。通常系统管理员会根据业务的需要而决定审计logs搜集什么。&lt;/li&gt;
&lt;li&gt;基础设施logs，在本地或者云上，涉及管理影响组织IT基础的物理设备和逻辑设备，并且可以通过API、系统logs或者其他使用基于主机之上的代理收集的方式。比如往往很多主机上会安装有agent，做大量的数据搜集并且分析。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;logs里的数据也可以转化成其他的可观测信号，包括metrics和traces，同时也可以使用logs分析技术来进行可视化和分析。logs级别是用来表示每条logs数据的重要性，一般常见的ERROR, WARNING, INFO和DEBUG。&lt;/p&gt;
&lt;p&gt;ERROR往往报告的是故障的发生及其原因细节；WARNING是一个需要注意的消息，虽然可能这并不是一个故障；INFO适用于帮助理解系统是怎么运行的；DEBUG是用于每个操作非常详细信息的，其数据量较大，往往仅在故障排查时使用，避免影响存储空间和性能；&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Traces通常是一组“tracing数据点”或者是一组可以用甘特来表示被称作为span。spans间是高度上下文相关的，并且包含 了初始化它的span信息。这使得分布式系统中不同的参与者（服务、队列、数据库）之间能够建立因果关系。各个参与者之间往往会定义一套标准的trace context进行信息的透传，W3C trace context定义了包含标准HTTP Header和值的格式来传播context信息，context信息唯一标识了分布式系统内的各个请求，还定义了通过添加和传播provider-specific的context信息。&lt;/p&gt;
&lt;p&gt;组件埋点在分布式追踪系统中扮演中扮演重要的角色，负责创建数据点本身以及将context在服务间进行传递。没有context的传播，就无法将传入的HTTP请求与它下游HTTP请求或消息的生产者及消费者关联起来。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Profiles&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;随着云原生应用程序的不断优化，对于细粒度上理解性能指标也愈发重要，一些工具通常会帮我们发现存在的性能问题，而持续收集profiles使我们可以更深入理解某个特定系统遇到某个问题的原因，这些profiles聚焦在理解资源是如何在系统中被分配的，包括CPU Profilers，Heap Profilers，IO Profilers等。Profiling由于消耗太大，之前被认为是不适合在生产系统中添加。随着采样profiling技术的普及，在云环境中变得越来越普遍，而仅仅只是消耗很少的性能。&lt;/p&gt;
&lt;p&gt;tracing是应用于理解应用程序的哪个部分导致延迟问题发生，profiling可以更加深入挖掘并理解那些导致延迟问题存在的原因，另外还可以知道哪些代码使用了最多的服务器资源。运行期生成的profiling数据通常包括精确到行号的统计，是回答从“是什么”到“为什么”的重要数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dumps&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;软件开发中，当应用进程异常挂掉后会产生dump文件用于排除程序故障。通常，操作系统会根据一些配置，把进程崩溃时的内存镜像写入dump文件，以便后续分析。Linux内核2.6后，dump文件的收集工作不是操作系统完成，而是 崩溃的进程输出推送到负责写入文件的应用程序的标准输入流中，这个应用程序就是核心dump处理程序，在ubuntu下可以在systemd支持下完成。&lt;/p&gt;
&lt;p&gt;云原生环境下，应用和基础设施的所有者角色不是那么明确，有特权的去访问系统全局配置的权限较低。另外一方面需要给崩溃的应用在pod重启之前就收集核心dump文件并写入持久卷时提供帮助。&lt;/p&gt;
&lt;p&gt;往往系统中的一个事件会产生多个信号，产生metrics增量、出发logs日志记录和开启一个新的span追踪。这意味着与当前特定事件有关的元数据和context在整个系统中都是重复的。对于多信号，我们希望理想的结果是一个整体的互补的可观测系统，希望使用来自另外一个信号的额外信息来补充，而不仅仅是增加了整个系统的数据量和数据的处理难度。&lt;/p&gt;
&lt;h3 id=&#34;1-构建可观测系统&#34;&gt;1 构建可观测系统&lt;/h3&gt;
&lt;p&gt;前提条件是：一致的目标元数据被附加到所有的信号内。&lt;/p&gt;
&lt;p&gt;不一致的元数据对于可观测系统是灾难的，即使label之间最微小的差别也会造成很大的麻烦。重新标记或默认是用pull模式会对这有所帮助。&lt;/p&gt;
&lt;p&gt;建立可观测的目的是确保系统的高可用。对于高可用的衡量一般使用如下几个概念：&lt;/p&gt;
&lt;p&gt;SLI 服务水平指标：服务水平精确的量化定义的指标；&lt;/p&gt;
&lt;p&gt;SLO 服务水平目标：能够承受的系统故障频率目标，由SLI服务数据平指标的目标值或者目标区间组成；&lt;/p&gt;
&lt;p&gt;SLA 服务水平协议：规定由SLO不达标造成的后果的商业协议。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>可观测性系统建立</title>
      <link>https://liaolile.com/post/tech/cloudnative/%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E7%B3%BB%E7%BB%9F%E5%BB%BA%E7%AB%8B/</link>
      <pubDate>Tue, 24 May 2022 21:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/cloudnative/%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E7%B3%BB%E7%BB%9F%E5%BB%BA%E7%AB%8B/</guid>
      <description>&lt;p&gt;Prometheus&lt;/p&gt;
&lt;p&gt;Zipkin&lt;/p&gt;
&lt;p&gt;Skywalking&lt;/p&gt;
&lt;p&gt;OpenResty xray&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>分布式系统的设计</title>
      <link>https://liaolile.com/post/tech/distributesystem/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E7%9A%84%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Tue, 24 May 2022 12:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/distributesystem/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E7%9A%84%E8%AE%BE%E8%AE%A1/</guid>
      <description>&lt;p&gt;分布式系统应该具有的架构特性（设计方向）：高并发、可扩展性、高可用性、高性能。同时分布式系统中存在的一致性问题，也需要有对应的解决方案。&lt;/p&gt;
&lt;p&gt;高并发并不是一种技术，而是系统要面临的技术技术场景。在这个场景下，确保高并发时的用户体验，系统不应该出现错误且以极快的速度给用户响应。可用性、可扩展性、高性能就是用于定量分析高并发系统的3个视角。&lt;/p&gt;
&lt;h4 id=&#34;分布式系统的高可用性&#34;&gt;分布式系统的高可用性&lt;/h4&gt;
&lt;p&gt;目标是为了让系统尽可能不发生错误，或者发生错误后的损失降到最低。系统运行时间是定量，不可用时间是变量。&lt;/p&gt;
&lt;p&gt;发布/故障/压力/外部依赖导致可用性问题&lt;/p&gt;
&lt;p&gt;变化数量*变化产生故障的比例*故障的影响*故障持续的时间&lt;/p&gt;
&lt;p&gt;初始设计按照20/10/5来分别设计、开发、发布，这里说的数字是实际流量的倍数。&lt;/p&gt;
&lt;p&gt;容错设计，单点故障、特性开关、服务分级、降级设计、超时重试&lt;/p&gt;
&lt;p&gt;隔离策略：进程、用户、集群、租户、物理、逻辑&lt;/p&gt;
&lt;p&gt;熔断：失败时候主动切断避免灾难发生&lt;/p&gt;
&lt;p&gt;流控：流控算法/流控策略（在什么地方做流控）&lt;/p&gt;
&lt;p&gt;容量预估：全链路压测明白系统的当前能力现状，而不是单接口、单业务，生产环境直接压；&lt;/p&gt;
&lt;p&gt;故障演练：故障模式梳理以及实践验证容灾方案&lt;/p&gt;
&lt;p&gt;数据迁移：逻辑分离/物理分离&lt;/p&gt;
&lt;h4 id=&#34;分布式系统的高性能&#34;&gt;分布式系统的&lt;strong&gt;高性能&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;目标是为了让尽可能多的用户，用尽可能少的时间得到系统的响应。任务目标是定量，任务完成耗时是变量。&lt;/p&gt;
&lt;p&gt;内存IO时间+网络IO时间+CPU时间+磁盘IP时间+等待时间&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;响应时间/吞吐量/负载敏感度/可伸缩性&lt;/p&gt;
&lt;p&gt;附在敏感度为系统响应是随时间变化的程度，需要可量化。用户请求过多的时候，系统响应时间是如何的一个衰减速度。&lt;/p&gt;
&lt;p&gt;可伸缩性为系统扩容增加资源对于性能的影响，可量化衡量，即吞吐量扩1倍，需要多少服务资源的衡量；&lt;/p&gt;
&lt;h4 id=&#34;分布式系统的可扩展性&#34;&gt;分布式系统的&lt;strong&gt;可扩展性&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;目标是为了支撑可用性和高性能，在一些特殊情况下，不得不对系统系统进行调整时，能够以低成本的方式完成的能力。&lt;/p&gt;
&lt;p&gt;AKF扩展立方体&lt;/p&gt;
&lt;p&gt;可以沿着X/Y/Z轴三个方向进行扩展。&lt;/p&gt;
&lt;p&gt;X轴扩展也叫水平扩展/横向扩展，通过复制实例（往往无状态），前端对流量进行负载均衡，分摊整体压力为目的进行扩展。&lt;/p&gt;
&lt;p&gt;Y轴扩展依据服务或者资源扩展，依据服务拆分，各个微服务依据当前能力独立进行横向扩展，降低当前系统的复杂度&lt;/p&gt;
&lt;p&gt;Z轴扩展依据当前的业务查询或计算结果进行拆分，即分片的思想。基于分区扩展，扩展性更强，突破单张表的数据规模上限，但是对于数据迁移复杂；&lt;/p&gt;
&lt;p&gt;数据库的X/Y/Z轴扩展：主从复制、分库/分表、分片sharding&lt;/p&gt;
&lt;h4 id=&#34;分布式系统的一致性设计&#34;&gt;分布式系统的&lt;strong&gt;一致性设计&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;事务：原子性、一致性、隔离性、持久性&lt;/p&gt;
&lt;p&gt;CAP定理：一致性/可用性/分区容错性，三选二&lt;/p&gt;
&lt;p&gt;BASE理论：强一致性、弱一致性、最终一致性；依据业务的考量来决策，不一致性场景下时候是基本可用、不可用、可接受；&lt;/p&gt;
&lt;p&gt;Quorum机制：强一致性的保障在写入数据的时候，所有节点成功后才算成功，此时写性能较差；转变思路为在读的阶段再决策，确保每次均能读到最新的数据。Quorum机制满足公式：备份个数N&amp;lt;成功写入W个+读取R个备份&lt;/p&gt;
&lt;p&gt;租约机制Lease：为了实现一致性，确保节点中有一个leader，leader负责数据写入、follower负责数据读取，管理节点M通过心跳判断各个节点，指定Leader，Leader故障后重新选取Leader。&lt;/p&gt;
&lt;p&gt;脑裂：Paxos、Raft、Lease算法确保&lt;/p&gt;
&lt;p&gt;分布式系统最终体现在&lt;em&gt;数据的一致性&lt;/em&gt;（严格一致性、顺序一致性、因果一致性）：&lt;/p&gt;
&lt;p&gt;X轴扩展数据可以是多个副本，多个副本不同的物理存储，故障时可以访问正常的副本数据；需要解决数据写入性能问题&lt;/p&gt;
&lt;p&gt;Z轴扩展对数据进行分区，即Sharding；&lt;/p&gt;
&lt;p&gt;分布式系统的用户（泛化）一致性模型（需要有标识，且唯一）：&lt;/p&gt;
&lt;p&gt;单调读一致性，单调写一致性、写后读一致性、读后写一致性&lt;/p&gt;
&lt;p&gt;弱一致性：写入一个数据成功后，在数据副本上可能读出来，也可能读不出来，不保证每个副本的数据一定一致；&lt;/p&gt;
&lt;p&gt;最终一致性：写入一个数据后，在其他副本有可能读不到最新值，单在某个时间窗口之后保证能最终读到；（重试机制、本地日志复制如binglog、可靠事件模式、Saga事务模型，TCC事务模型）&lt;/p&gt;
&lt;p&gt;强一致性：数据一旦写入成功，任何副本上在写入后的任意时刻都能读到最新值；实现模型：两阶段提交/三阶段提交&lt;/p&gt;
&lt;h4 id=&#34;分布式系统中的八大谬误&#34;&gt;分布式系统中的八大谬误&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;网络是可靠的&lt;/p&gt;
&lt;p&gt;实际不是可靠的，应用系统中需要做的事情可能有：retry，acknowledge import messages, identify/ignore duplicates, record messages, verifiy message integrity。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传输是无延迟&lt;/p&gt;
&lt;p&gt;延迟指数据从一个地方传递到另一个地方需要的时间，这中间带宽决定了同时可以传输多少数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;带宽是无限的&lt;/p&gt;
&lt;p&gt;其实不是，随着带宽的增长，我们传输的数据量也在增加，同时传输就存在丢包的问题。在信息的传递和延迟之间是要trade-off。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网络是安全的&lt;/p&gt;
&lt;p&gt;通往网络的安全是多层的，包括基础设施、网络传输和应用层等；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;拓扑是不变的&lt;/p&gt;
&lt;p&gt;系统中不应该依赖特定的路由或节点，需要同时提供位置透明性和发现服务&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传输是无成本的&lt;/p&gt;
&lt;p&gt;我们从应用层到传输层的数据传递，需要对数据进行编码，这需要消耗时间和计算资源。而设置和运行网络都是需要代价，需要金钱购买。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网络是同构的&lt;/p&gt;
&lt;p&gt;不应该在应用层去依赖一些自营的协议，而是通用的协议。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;只有一个管理员&lt;/p&gt;
&lt;p&gt;当没有出现问题的时候，我们不需要管理员。但是一旦问题发生，就会抓狂的需要。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;ref&#34;&gt;REF&lt;/h4&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://gist.github.com/jboner/2841832&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Latency Numbers Every Programmer Should Know (github.com)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>云原生开篇</title>
      <link>https://liaolile.com/post/tech/cloudnative/%E4%BA%91%E5%8E%9F%E7%94%9F/</link>
      <pubDate>Thu, 10 Feb 2022 09:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/cloudnative/%E4%BA%91%E5%8E%9F%E7%94%9F/</guid>
      <description>&lt;p&gt;[toc]&lt;/p&gt;
&lt;h4 id=&#34;0-云原生&#34;&gt;0. 云原生&lt;/h4&gt;
&lt;p&gt;云原生是一种思想，是一种解决方案，是一种抽象。云原生是从云的原生应用角度出发，是一种构建和运行应用程序的方法，是一套技术体系和方法论&lt;code&gt;Cloud Native Stack&lt;/code&gt;，一整套设计、开发、部署、运行、维护的流程、技术栈以及背后文化理念的统称。&lt;strong&gt;云原生&lt;/strong&gt;是一个用来描述应用、架构、平台/ 基础架构和流程的形容词，包括研发流程规范，软件架构，基础设施和工具集，是一套不断自我演进的理论体系提供指导思想和最佳实践的组合。谈云原生的本质，不如我们将它理解为一套愿景，一种文化，而不具象为哪些技术体系&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;您是否能&lt;strong&gt;赢得、服务和留住&lt;/strong&gt;&lt;code&gt;客户&lt;/code&gt;，很大程度上取决于能否通过&lt;strong&gt;软件应用持续、快速地交付新功能&lt;/strong&gt;，提供备受认可的业务价值。而云原生就是为了这个价值而努力的手段；&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CNCF（云原生计算基金会）&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中，构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。&lt;/p&gt;
&lt;p&gt;这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段，云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;VMware Tanzu&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;云原生是一种利用云计算交付模型的优势来构建和运行应用程序的方法论。当企业使用云原生架构开发和运维应用程序时，它们能更快速地响应客户需求将新想法推向市场。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;云原生是关于不需要人类做出决定的自治系统。它仍然使用自动化，但只有在决定了所需的操作之后。只有在系统不能自动确定正确的事情时才应该通知人。具有这些特征的应用程序需要一个能够实际监控，收集度量标准并在发生故障时做出反应的平台。&lt;/p&gt;
&lt;p&gt;云原生系统（pivotal公司2017）一般具有如下的特点，：模块化（Modularity）、可观测性（Observability）、可部署性（Deployability）、可测试性（Testability）、可处理性（Disposability）、可替代性（Replaceability）。&lt;/p&gt;
&lt;h5 id=&#34;01-云原生的范围内容&#34;&gt;0.1 云原生的范围内容&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;云原生范围&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;主要内容&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;方法论与原则&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;12要素，声明式API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;流程规范&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;DevOps，持续交付，自动化测试，Code Review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;软件架构&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;微服务，服务网格，无服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;基础设施&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;敏捷基础设施，如K8S、Docker、云服务器、云数据库、云存储等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;工具集&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;Prometheus，Envoy，Jaeger等&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5 id=&#34;02-云原生中的代表技术&#34;&gt;0.2 云原生中的代表技术&lt;/h5&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/04/73n8N26SJQDCXlq.jpg&#34; style=&#34;zoom: 33%;&#34; /&gt;
&lt;ol&gt;
&lt;li&gt;不可变基础设施&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;基础设施可编程且不可变的，直接通过API可以对外提供服务，通过代码或者配置来定义一组基础设施，并通过版本化的管理能够保证业务的快速变更。其中的应用载体是不可变的，自包含构建方式以及运行环境，简化应用的更新，删除旧实例，上线新实例。&lt;/p&gt;
&lt;p&gt;任何的基础实例（服务器、容器等各种软硬件）一旦创建之后便成为一种只读状态，不对其进行任何更改，如果需要修改或升级实例，唯一方式是创建一批新实例以替换。&lt;/p&gt;
&lt;p&gt;Pets Vs Cattle&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;，宠物和牲口。过去依赖传统的高可靠基础设施，服务的可靠性依赖于高可靠性的服务器，对待服务器就像对待宠物一样，需要实时关注服务的状态并精心维护，系统故障或者升级时候需要通过对服务器进行修复和配置实现。牲口模式下，底层系统故障或者需要升级，直接杀掉后重新创建一个，云原生的架构下底层就是依赖这种模式。&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4 id=&#34;pets&#34;&gt;Pets&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;Servers or server pairs that are treated as indispensable or unique systems that can never be down. Typically they are manually built, managed, and “hand fed”. Examples include mainframes, solitary servers, HA loadbalancers/firewalls (active/active or active/passive), database systems designed as master/slave (active/passive), and so on.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;h4 id=&#34;cattle&#34;&gt;Cattle&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;Arrays of more than two servers, that are built using automated tools, and are designed for failure, where no one, two, or even three servers are irreplaceable. Typically, during failure events no human intervention is required as the array exhibits attributes of “routing around failures” by restarting failed servers or replicating data through strategies like triple replication or erasure coding. Examples include web server arrays, multi-master datastores such as Cassandra clusters, multiple racks of gear put together in clusters, and just about anything that is load-balanced and multi-master.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;相同的类比是：雪花服务器和凤凰服务器，雪花服务器是手工管理的服务器，需要经常更新和调整，从而形成独特的环境。凤凰服务器总时从0开始构建，并且很容易通过自动化过程重新创建（浴火重生）。&lt;/p&gt;
&lt;p&gt;不可变基础设施同不可变变量类似，完成赋值后不能够被修改。运行服务的服务器在完成部署后，就不再进行变更，这一点是通过容器镜像来实现的，是一个自包含、自描述可以完全在不同的环境中迁移的东西。&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;声明式API&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;描述最终的状态和幂等性。&lt;/p&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;
&lt;p&gt;容器&lt;/p&gt;
&lt;p&gt;作为应用包装的载体。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;服务网格&lt;/p&gt;
&lt;p&gt;服务网格（Service Mesh）这个术语通常用于描述构成这些应用程序的微服务网络以及应用之间的交互。随着规模和复杂性的增长，服务网格越来越难以理解和管理。它的需求包括服务发现、负载均衡、故障恢复、指标收集和监控以及通常更加复杂的运维需求，例如 A/B 测试、金丝雀发布、限流、访问控制和端到端认证等，服务于系统的可观测性、安全性和可靠性。通常是由平台层而不是应用层来实现。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;微服务&lt;/p&gt;
&lt;p&gt;微服务是一种分布式架构设计理念，为了推动细粒度服务的使用，这些服务要能协同工作，每个服务都有自己的生命周期。一个微服务就是一个独立的实体，可以独立的部署在 Paas 平台上，也可以作为一个独立的进程在主机中运行。服务之间通过 API 访问，修改一个服务不会影响其它服务。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&#34;03-云原生基础设施&#34;&gt;0.3 云原生基础设施&lt;/h5&gt;
&lt;p&gt;云，它是一种新兴的 IT 基础设施交付方式，通过虚拟化技术，对 IT 硬件资源与软件组件进行了标准化、抽象化和规模化，变成 “产品服务” 和 “账单”（pay as you go）。&lt;/p&gt;
&lt;p&gt;Support for cloud native attribute: modularity, operability, elasticity, resilliency;&lt;/p&gt;
&lt;p&gt;Gartner 将云原生基础设施划分：Iaas(VMs), Caas(Container), Serverless, Faas&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/06/04/zc7SQiZYG8IenPf.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;目前更多的AI出现，衍生的Daas，数据即服务，AI与云服务结合产生很多高价值的服务。&lt;/p&gt;
&lt;h4 id=&#34;1-云原生应用&#34;&gt;1. 云原生应用&lt;/h4&gt;
&lt;p&gt;云原生应用是一个相互关联但又不独立的组件（&lt;strong&gt;service、task、worker&lt;/strong&gt;）的集合，这些组件与配置结合在一起并在适当的运行时实例化后，共同完成统一的功能目的。云原生应用开发是根据众所周知的云计算技巧与技术构建、运行和改进应用的一种方法。云原生应用是独立的小规模松散耦合服务的集合。&lt;/p&gt;
&lt;p&gt;云原生应用程序被设计为在平台上运行，并设计用于&lt;strong&gt;弹性，敏捷性，可操作性和可观测性&lt;/strong&gt;。弹性包含失败而不是试图阻止它们；它利用了在平台上运行的动态特性。敏捷性允许快速部署和快速迭代。可操作性从应用程序内部控制应用程序生命周期，而不是依赖外部进程和监视器。可观测性提供信息来回答有关应用程序状态的问题。&lt;/p&gt;
&lt;p&gt;符合云原生架构的应用程序应该是：采用开源堆栈（K8s+Docker）进行容器化，基于微服务架构提高灵活性和可维护性，借助敏捷方法、DevOps支持持续迭代和运维自动化，利用云平台设施实现弹性伸缩、动态调度、优化资源利用率。通过一组架构原则和设计模式，将应用中的非业务代码部分进行最大化的剥离，从而让云设施接管应用中原有的大量非功能特性（如弹性、韧性、安全、 可观测性、灰度等），借助云原生委托大量应用非功能性特性，使业务不再受非功能性业务中断困扰的同时，具备轻量、敏捷、高度自动化的特点。&lt;/p&gt;
&lt;h5 id=&#34;11-云原生应用模型&#34;&gt;1.1 云原生应用模型&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;OAM &lt;/code&gt;全称是 Open Application Model，旨在定义了云原生应用的标准，阿里巴巴和微软共同开源的云原生应用规范模型[^]。云原生中的大部分概念来自于此，对不同平台和场景的逻辑中DevOps做出更高级别的抽象。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开放（Open）：支持异构的平台，容器运行时、调度系统、云供应商、硬件配置等；与底层无关，与供应商无关；&lt;/li&gt;
&lt;li&gt;应用（Application）：云原生应用&lt;/li&gt;
&lt;li&gt;模型（Model）：应以标准，以使其与底层平台无关；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OAM中定义的术语对象概念：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Workload（工作负载）：应用程序的工作负载类型（如有状态工作负载）对于部署单元的具体描述，由平台提供；&lt;/li&gt;
&lt;li&gt;Component（组件）：定义了Workload的实例，并以基础设施中的术语声明其运维特性；&lt;/li&gt;
&lt;li&gt;Trait（特性）：用于将运维特性（如弹性、回滚、实例个数等）分配给组件实例；&lt;/li&gt;
&lt;li&gt;ApplicationScope（应用作用域）：将组件划分为具有共同特性的松散耦合的应用（如网络/健康）；&lt;/li&gt;
&lt;li&gt;ApplicaitonConfiguration（应用配置）：描述Component的部署、包括Trait和ApplicationScope；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;云原生应用来说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基础设施运维：提供不同的Workload类型供开发者使用；&lt;/li&gt;
&lt;li&gt;应用运维：定义适用于不同Workload的运维属性Trait和管理Component的ApplicaitonScope；&lt;/li&gt;
&lt;li&gt;应用开发者：负责应用组件Component的定义；&lt;/li&gt;
&lt;li&gt;应用开发和运维：应用程序全生命周期管理，绑定Component和Trait；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/06/04/aBAnFwUrSj4RPxX.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;OAM规范原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;关注点分离：根据功能和行为来定义模型，以此划分不同角色的职责，&lt;/li&gt;
&lt;li&gt;平台中立：OAM 的实现不绑定到特定平台；&lt;/li&gt;
&lt;li&gt;优雅：尽量减少设计复杂性；&lt;/li&gt;
&lt;li&gt;复用性：可移植性好，同一个应用程序可以在不同的平台上不加改动地执行；&lt;/li&gt;
&lt;li&gt;非编程模型：OAM 提供的是应用程序模型，描述了应用程序的组成和组件的拓扑结构，而不关注应用程序的具体实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;12-云原生应用12军规&#34;&gt;1.2 云原生应用12军规&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;The Twelve-Factor App&lt;/code&gt;：云原生应用架构的模式集合&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/04/iJdvcAYptLHM8l3.jpg&#34; style=&#34;zoom: 33%;&#34; /&gt;
&lt;p&gt;更多3项&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API声明管理，万物皆服务。你的代码会被一个前端客户端、网关或者其他服务调用；&lt;/li&gt;
&lt;li&gt;认证和授权，从 一开始就需要考虑设计；&lt;/li&gt;
&lt;li&gt;监控与告警，领域相关的监控以及健康数据；&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;13-云原生系统哲学&#34;&gt;1.3 云原生系统哲学&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;面向分布式设计（Distribution）：容器、微服务、API驱动的开发；&lt;/li&gt;
&lt;li&gt;面向配置设计（Configuration）：一个镜像，多个不同环境配置；&lt;/li&gt;
&lt;li&gt;面向韧性设计（Resistancy）：故障容忍和自愈；&lt;/li&gt;
&lt;li&gt;面向弹性设计（Elasticity）：弹性扩展和环境（负载）做出响应；&lt;/li&gt;
&lt;li&gt;面向交付设计（Delivery）：自动拉起，缩短交付时间；&lt;/li&gt;
&lt;li&gt;面向性能设计（Performance）：响应式，并发和资源高效利用；&lt;/li&gt;
&lt;li&gt;面向自动化设计（Automation）：自动化的Devops；&lt;/li&gt;
&lt;li&gt;面向诊断性设计（Diagnosability）：集群级别的日志、metric和追踪；&lt;/li&gt;
&lt;li&gt;面向安全设计（Security）：安全端点、API Gateway、端到端加密&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&#34;14-关于云原生应用的健康报告和遥测数据&#34;&gt;1.4 关于云原生应用的健康报告和遥测数据&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;健康报告&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;停止逆向工程应用程序并开始从内部进行监控。 —— Kelsey Hightower，Monitorama PDX 2016：healthz&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;应用程序应该暴露健康检查以便提高其可操作性和管理自动化；一个常见的手段是提供web服务，返回Http状态码来检查健康状态。对于平台需要更准确的了解应用程序所处的状态，平台需要知道应用程序什么时候开始接受流量，而应用通过该检查来表明自身的健康。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;遥测数据&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;遥测数据是进行决策所需的信息。遥测数据可能与健康报告存在部分重叠，但它们有不同的用途。&lt;code&gt;健康报告&lt;/code&gt;通知我们&lt;strong&gt;应用程序生命周期状态&lt;/strong&gt;，而&lt;code&gt;遥测数据&lt;/code&gt;通知我们&lt;strong&gt;应用程序业务目标&lt;/strong&gt;。更加关注的应用层面SLO内容，而不是某个节点，确保应用程序的性能处于服务级别目标内。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;请求率&lt;/code&gt;: 收到了多少个请求？&lt;code&gt;错误&lt;/code&gt;: 应用程序有多少错误？&lt;code&gt;时间&lt;/code&gt;: 多久才能收到回复？&lt;/p&gt;
&lt;h4 id=&#34;2-云原生实践&#34;&gt;2. 云原生实践&lt;/h4&gt;
&lt;h5 id=&#34;21-cncf-给出的云原生实践路线图&#34;&gt;2.1 CNCF 给出的云原生实践路线图&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;容器化&lt;/p&gt;
&lt;p&gt;一般目前以Docker为主要方式进行容器化。各类应用均可进行容器化，容器化建议服务分割为微服务的方式进行；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CI/CD&lt;/p&gt;
&lt;p&gt;创建持续集成持续部署的环境，敏捷的快体现就是快速集成，快速发布。使得整个Devops可以自动从源码进行容器化构建和测试，并部署到生产环境。同时系统可以自动部署、自动回滚、自动测试。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;应用定义和编排&lt;/p&gt;
&lt;p&gt;Kubernetes作为容器化的应用编排成熟解决方案，目前使首选。Helm Charts能帮助使用者对复杂的Kubernetes应用进行定义、安装和升级&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;监控和分析&lt;/p&gt;
&lt;p&gt;解决方案应该包括监控、日志、和追踪（metrics、logs、tracing），推荐的为Prometheus监控和告警、Fluentd用于日志，而Jaeger用于调用链追踪。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;服务代理、服务发现和服务网格&lt;/p&gt;
&lt;p&gt;提供健康检查、请求路由方向代理以及负载均衡等。服务发现可以使用CoreDNS, 服务网格目前成熟的使Envoy和Linkerd。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网络和策略&lt;/p&gt;
&lt;p&gt;网络需求可以基于CNI兼容的网络解决方案如Flannel或者Weave Net。OPA(Open Police Agent)秉承着“策略即代码”原则，完成通用的策略引擎的基本功能，使用者控制策略和权限确保合规。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分布式数据库与存储&lt;/p&gt;
&lt;p&gt;分布式数据库可以获取更好的弹性和伸缩性能。确保横向扩展中，通过sharding的方式保证mysql的横向扩展性，Vitess是一个不错的选择。作为Kubernetes大脑的，etcd提供了集群中以可靠的方式存储数据的能力；需要使用KV存储时候，可以考虑TiKV，其使用Rust编写的高性能的分布式事务级Key-Value解决方案。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;流与消息处理&lt;/p&gt;
&lt;p&gt;对于json-rest更高性能诉求时候，gRPC或者NATS是一个更好的选择。NATS是一个包含了请求、发布/订阅、复杂均衡队列的多模型消息系统；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;镜像私库和运行环境&lt;/p&gt;
&lt;p&gt;可以使用Harbor作为镜像私库进行存储以及内容扫描，运行环境需要使用具有OCI兼容性的方案。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;软件分发&lt;/p&gt;
&lt;p&gt;TLS能够去确保通信的安全，特别是当服务器出现问题后，使用Notary/TUF可以解决这问题，是，使得在软件的分发和更新更加安全。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&#34;22-helm包管理&#34;&gt;2.2 Helm包管理&lt;/h5&gt;
&lt;p&gt;Helm是K8s生态系统中的软件包管理工具，为了以下的目的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;管理、编辑以及更新分散在各处的kubernetes API 对象描述文件；&lt;/li&gt;
&lt;li&gt;相关配置文件作为一个应用进行管理，管理应用依赖关系、管理应用版本并发布软件仓库；&lt;/li&gt;
&lt;li&gt;分发和重用K8s应用配置；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Helm包中的概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tiller: Helm的服务端，部署在K8s集群中用于处理Helm命令；&lt;/li&gt;
&lt;li&gt;Chart： Helm的打包格式，不好了一组相关K8s的配置；&lt;/li&gt;
&lt;li&gt;Repository：Helm的软件仓库，该软件仓库保存了Chart软件包以供下载，并提供Chart包清单以供查询；&lt;/li&gt;
&lt;li&gt;Release： 使用Helm install命令在K8s集群中安装Chart就成为Release&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过一系列的Helm命令，可以创建、校验、打包、绑定repo，搜索、部署、查看、升级、回滚的对应的应用；Helm总有一个字段Revision记录了Release的被更新次数，同etcd中的Revision（Create Revision/Mod Revision等）概念一致，对应于某个时间点的版本信息；&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reference&lt;/strong&gt;:&lt;/p&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://landscape.cncf.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CNCF Cloud Native Interactive Landscape&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;http://cloudscaling.com/blog/cloud-computing/the-history-of-pets-vs-cattle/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The History of Pets vs Cattle and How to Use the Analogy Properly | Cloudscaling&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://12factor.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Twelve-Factor App (12factor.net)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>理解Boltdb</title>
      <link>https://liaolile.com/post/tech/cloudnative/%E7%90%86%E8%A7%A3boltdb/</link>
      <pubDate>Wed, 13 Oct 2021 12:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/cloudnative/%E7%90%86%E8%A7%A3boltdb/</guid>
      <description>&lt;p&gt;[toc]&lt;/p&gt;
&lt;p&gt;😃&lt;/p&gt;
&lt;p&gt;在不同的场景、不同的组件中。具体采用&lt;strong&gt;自底向上&lt;/strong&gt;还是&lt;strong&gt;自顶向下&lt;/strong&gt;来分析。见仁见智，也具体问题具体分析。在本篇中自底向上分析boltdb，然后到etcd，应为etcd的底层就依赖于boltdb的数据存储。&lt;/p&gt;
&lt;h3 id=&#34;1-boltdb&#34;&gt;1. boltdb&lt;/h3&gt;
&lt;h4 id=&#34;11-boltdb基本理解&#34;&gt;1.1 boltdb基本理解&lt;/h4&gt;
&lt;p&gt;boltdb 是一个纯 go 编写的支持事务的文件型单机 kv嵌入式数据库。目前支持的事务包括：&lt;em&gt;读写事务、只读事务&lt;/em&gt;。事务中的所有操作都在内存中进行，只有commit时候才会写磁盘。boltdb所有数据都存储在磁盘上，数据涉及在内存和磁盘的交换，适用于读多写少的存储场景。其对外暴露的是kv的接口，支持数据类型均是[]byte的key和value。&lt;/p&gt;
&lt;p&gt;boltd的源码大约4000行&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;， 目前已经归档，是目前etcd，InfluxDb依赖的底层存储。boltdb中三大概念名词：DB, Bucket， K/V。如果把boltdb比喻成衣柜，我们把东西整理放入衣柜就是对boltd的操作，Bucket就是柜子分隔后的小柜子或者抽屉，K/V就是放入衣柜的每个东西，其中K就是这个东西的标记，V就是具体的东西。换着说：boltdb是有多个桶Bucket，每个桶存放键值对数据kv。&lt;/p&gt;
&lt;p&gt;boltdb每个db对应一个文件，文件按照page来组织，page id为0和1的两个page是metadata，同时还有freelist的page用来存放空闲的page id， 剩下的page构成一个B+树包括brach page用于存放具体的索引信息以及leaf page存放真实的用户数据。通过Bucket来支持namespace，每个Bucket是一个完整的B+树。&lt;/p&gt;
&lt;p&gt;全局视图如下：&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/26/4oxOWdGKq6gB5IQ.png&#34; alt=&#34;image-20220626174419166&#34; style=&#34;zoom:80%;&#34; /&gt;
&lt;h4 id=&#34;12-boltdb数据结构&#34;&gt;1.2 boltdb数据结构&lt;/h4&gt;
&lt;p&gt;对于文件数据库的性能提升，因为文件是在磁盘上，为了减少读磁盘的时间（寻道时间+旋转时间+传输时间），同时顺序读写比随机更快，因而性能提升主要聚焦在如何最大程度进行顺序读写方式来进行数据的写入和查询。&lt;/p&gt;
&lt;p&gt;如何将用户写进来在内存中的数据尽可能采用顺序写的方式放进磁盘，同时在用户读数据时候，将磁盘中保存的数据尽可能少的IO调用次数加载到内存中，而返回给用户。&lt;/p&gt;
&lt;p&gt;对于boltdb在存储结构上，磁盘上是按照4K的page进行数据结构组织，内存中的数据结构是node，还有一个page和node之间的相互转化。对于boltdb的set操作，本质上对应的就是set-&amp;gt;node&amp;gt;page-&amp;gt;file， 而对于get操作是file-&amp;gt;page-&amp;gt;node-&amp;gt;get的过程。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/26/xjMyzIXcnbClYh6.jpg&#34; style=&#34;zoom:80%;&#34; /&gt;
&lt;p&gt;boltdb没有实现page cache，而是调用mmap将整个文件进行内存映射，并且调用madvise(MADV_RANDOM)由操作系统管理page cache，后续对磁盘上的文件的所有读写操作直接读取db.data即可。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// mmap memory maps a DB&amp;#39;s data file.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;mmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;DB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sz&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// Map the data file to memory.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Mmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sz&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;PROT_READ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MAP_SHARED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MmapFlags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// Advise the kernel that the mmap is accessed randomly.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;madvise&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MADV_RANDOM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Errorf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;madvise: %s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// Save the original byte slice and convert to a byte array pointer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;dataref&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;maxMapSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Pointer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;datasz&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;boltdb中，一个Bucket对象是一颗B+树，它上面存储一批kv键值对，同时一个Bucket下还可以由嵌套的subbucket。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Page&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;数据在磁盘上按照Page页来存储的，以page为单位来读取和写入数据，page大小是保持和操作系统对应的内存页大小一致。page上由两部分数据组成：header+data，即页头数据和真实数据，页头数据占用16字节。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/26/GsQkzCZB5ce1PhT.jpg&#34; style=&#34;zoom:80%;&#34; /&gt;
&lt;p&gt;boltdb在写入数据到磁盘文件时候直接写入的是page结构体的二进制，避免了序列化和反序列化的开销；&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;meta page&lt;/strong&gt;, 其pageId是固定的0和1，该page主要用来保存数据库的基本信息，比如根节点、版本号、空闲列表，当前元数据页的id，最大的事务txid等；其中一个元数据页出问题了，可以使用另外一份进行修复来保证数据库可用。每次读写事务前，都会选取txid最大的那个meta进行事务初始化，同时MVCC时，会拷贝最新的meta。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;leaf page&lt;/strong&gt;，是用户的数据实际存储的结构，相关的对应地址信息可以通过header中的数据获取得到。存在如下的关系:&amp;amp;leafPageElement + pos == &amp;amp;key、&amp;amp;leafPageElement + pos + ksize == &amp;amp;val。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/06/26/xdjmJKuplqWwe8P.jpg&#34; style=&#34;zoom:80%;&#34; /&gt;
&lt;p&gt;对于上述的leafPageElement中的flags取值为0时，表示叶子节点为普通的key/value类型，取值为1时，标识叶子节点为桶类型，其key为桶的key，当桶中的元素很少时，value会填充为桶的pgid以及其内联的kv节点数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;branch page&lt;/strong&gt;, 主要用于构建索引，方便提升查询效率。一个分支页节点页上会存储多个分支页元素即branchPageElement，branch node的value是子节点的pageId，存放在branchPageElement中，而key的存储相同都是通过pos获得。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/06/26/73aPx2do9AcgFz1.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;B+树的存储中单个节点为node，包括branch和leaf节点，访问节点时首先将page的内容转化为内存中的node，每个node对应一个或多个连续的page。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://s2.loli.net/2022/06/26/cNdKYwPZ72zj9hx.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对于branch节点而言，每对key/val指向一个节点，key是子节点的其实range，val存放子节点的pageId。对于leaf节点，每对key/val存放数据，没有指针指向sibiling node；&lt;/p&gt;
&lt;p&gt;对于数据的查询过程如下步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;找到bucket的根节点，也就是B+树的根节点page id；&lt;/li&gt;
&lt;li&gt;读取对应的page，转化为内存中的node；&lt;/li&gt;
&lt;li&gt;若是branch node，则更具key查找合适的子节点的page id;&lt;/li&gt;
&lt;li&gt;重复2/3步骤找打leaf node，返回node中对应的value；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;freelist page&lt;/strong&gt;，空闲列表页中主要包含三个部分：所有已经可以重新利用的空闲页列表ids，将来很快释放掉的事务关联页的列表pending，页的id缓存。&lt;/p&gt;
&lt;h4 id=&#34;13-boltdb事务&#34;&gt;1.3 boltdb事务&lt;/h4&gt;
&lt;p&gt;对于boltdb同一时间有且只能由一个读写事务执行，但是同一时刻允许多个只读事务执行。每个事务都拥有自己的一套一致性视图。&lt;/p&gt;
&lt;p&gt;boltdb所有的数据最终会保存在文件中，当事务结束后，会将数据进行刷盘。由于用户的直接改动数据最终都发生在叶子节点，为了维持B+树的性质，会在commit前进行调整，调整过程中会引起中间节点的级联变化。所有这些节点在&lt;code&gt;spill&lt;/code&gt;阶段通过node.write转化为页，所有变动的页称为脏页，在spill后会对这些脏页进行刷盘，按照下述的步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将脏页按page id排序后逐个遍历；&lt;/li&gt;
&lt;li&gt;将page id转化为offset；&lt;/li&gt;
&lt;li&gt;通过db.ops.writeAt将脏页在offset处刷盘；&lt;/li&gt;
&lt;li&gt;通过page pool服用page size = 1的脏页，以备allocate时复用；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于刷盘有个开关控制db.NoSync，如果配置为true，每次commit后并不会刷盘，而是写入缓冲区，有操作系统决定真正落盘的时机；上述刷盘结束后，会对元信息（freelist和整个db元数据）进行刷盘，只有元信息页落盘成功，才会使得改动对用户可见。元信息页作为全局指针，该指针的写入原子性来保证事务的原子性，如果宕机元数据没有写入完成，所有改动便不会生效，达到了自动回滚的效果。&lt;/p&gt;
&lt;p&gt;boltdb会通过冗余一份元数据来做容错，当事务提交时，如果写入一般机器挂了，此时数据会有问题。当boltdb再次恢复时，会对元数据进行校验和修复。&lt;/p&gt;
&lt;p&gt;boldtb在上层支持多个进程以读写或者只读的方式打开数据库，在内部实现的时候底层是不同的锁，只读模式是共享锁，而读写模式是互斥锁。在数据库内部中支持上述说的读写事务和只读事务，两种类型的事务底层都保留一套完整的视图和元数据，彼此间相互隔离；&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;增量写内存。&lt;/li&gt;
&lt;li&gt;穿透读磁盘。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;读写事务的变动都在内存中，而只读事务通过 mmap 直接读取的磁盘上的内容，因此读写事务的改动不会为只读事务所见。多个读写事务是串行的，也不会互相影响。而每个只读事务期间所看到的状态，就是该只读事务开始执行时的状态。&lt;/p&gt;
&lt;h3 id=&#34;ref&#34;&gt;REF&lt;/h3&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/boltdb/bolt&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;boltdb/bolt: An embedded key/value database for Go. (github.com)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
  </channel>
</rss>
