<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts | Liao Lile</title>
    <link>https://liaolile.com/post/</link>
      <atom:link href="https://liaolile.com/post/index.xml" rel="self" type="application/rss+xml" />
    <description>Posts</description>
    <generator>Wowchemy (https://wowchemy.com)</generator><language>zh-Hans</language><lastBuildDate>Wed, 10 Aug 2022 12:23:10 +0000</lastBuildDate>
    <image>
      <url>https://liaolile.com/media/icon_hu0b7a4cb9992c9ac0e91bd28ffd38dd00_9727_512x512_fill_lanczos_center_3.png</url>
      <title>Posts</title>
      <link>https://liaolile.com/post/</link>
    </image>
    
    <item>
      <title>备忘录</title>
      <link>https://liaolile.com/post/tech/base/0/%E5%A4%87%E5%BF%98%E5%BD%95/</link>
      <pubDate>Wed, 10 Aug 2022 12:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/base/0/%E5%A4%87%E5%BF%98%E5%BD%95/</guid>
      <description>&lt;p&gt;&lt;strong&gt;好记性不如烂笔头。&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;hugo-encryptor-container&#34;&gt;
  &lt;div class=&#34;hugo-encryptor-prompt&#34;&gt;
    
      &lt;p&gt;文章的部分内容被密码保护：&lt;/p&gt;
    
  &lt;/div&gt;
  &lt;div class=&#34;hugo-encryptor-form&#34;&gt;
    &lt;input
      class=&#34;hugo-encryptor-input&#34;
      placeholder=&#39;请输入密码&#39;
    /&gt;
    &lt;input
      class=&#34;hugo-encryptor-button&#34;
      type=&#34;button&#34;
      value=&#39;点击验证&#39;
      onclick=&#34;_click_handler(this)&#34;
    /&gt;
  &lt;/div&gt;
  &lt;div
    class=&#34;hugo-encryptor-cipher-text&#34;
    data-password=&#34;leland&#34;
    style=&#34;display: none;&#34;
  &gt;
    &lt;span style=&#34;display: none;&#34;&gt;--- DON&#39;T MODIFY THIS LINE ---&lt;/span&gt;
    &lt;p&gt;1、再多申请一个台式机电脑，专用于代码应用相关&lt;/p&gt;
&lt;p&gt;2、参考相关内容进行gitlog生成changeme.log&lt;/p&gt;
&lt;p&gt;gitlog.sh &lt;a href=&#34;https://www.cnblogs.com/linkstar/p/10274943.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;利用shell脚本生成CHANGELOG.md（包含git提交规范） - LinkinStar - 博客园 (cnblogs.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/LinkinStars/springBootTemplate&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;LinkinStars/springBootTemplate: SpringBoot项目模版 (github.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Grid Router架构约束&lt;/p&gt;
&lt;p&gt;1、关于迁移涉及：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;GridRouter集群扩节点后怎么把nginx节点挂载到lvs，同时GridRouter扩集群的时候如何把新的域名注册到lvs上；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关于Grid节点扩容，GridRouter提供变更能力到对应的nginx upstream的node节点；扩Grid的时候类似与新增一个Grid upstream和新增Route；&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2、关于测试效率的提升&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于验证可以通过脚本进行，脚本中就是检索日志，然后针对关键字进行识别判断，避免记忆；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3、关于Route去压缩，需要写代码开关主干配置（1-进行升级，2-进行数据清理，default 0-什么都不做），进行mds数据的升级（验证），避免手动操作写数据；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;写数据前做检查，确保id无重复；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据升级，复制一份新的数据；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据验证，打印对应的日志；&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;​	key：/r/servie_name/id&lt;/p&gt;
&lt;p&gt;​	value: gxxx1|tdomain&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新版本数据按照已有的格式进行入库存储；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;4、关于cellid映射解耦&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;upstream名字怎么配置进入到数据库存储（提供界面）长期，短期基于数据库入库变更；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;新的upstream名字设计使用简短的id信息唯一信息，nginx.conf文件无需人看；upstream的唯一的displayName要带入到对应的boltdb，仅用于需要做日志记录的场景，从id -&amp;gt; upstream name&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;复制变更一份：regionLb的upstream变更（手动）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;删除废弃的upstream信息（手动）；&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;api设计需要细分Http返回码&lt;/p&gt;
&lt;p&gt;-201 Created&lt;/p&gt;
&lt;p&gt;验证的过程&lt;/p&gt;
&lt;p&gt;1、reload过程中nginx是否有请求丢失&lt;/p&gt;

  &lt;/div&gt;
&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>技术能力</title>
      <link>https://liaolile.com/post/tech/base/%E6%8A%80%E6%9C%AF%E8%83%BD%E5%8A%9B/</link>
      <pubDate>Fri, 17 Jun 2022 21:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/base/%E6%8A%80%E6%9C%AF%E8%83%BD%E5%8A%9B/</guid>
      <description>&lt;p&gt;技术能力，什么才是技术能力？具有什么样的技术能力才能不丧失竞争力，这需要理解清楚技术能力的本质。&lt;/p&gt;
&lt;p&gt;解决一个技术问题的方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;就事论事，问题解决就万事大吉；当前只是解决了一个具体的问题，面临这同一个问题不同的人可能来问很多次。&lt;/li&gt;
&lt;li&gt;问题解决后立即整理成文档，并把排查方法及根因清晰的梳理，提升了后续自己和组内其他人的效率；&lt;/li&gt;
&lt;li&gt;将此排查问题的方法和逻辑固化为小工具给到具体求助的同学，以后其它人也可以自助使用该工具；解决了别人的问题，重新定义了效能问题并找到更好提效的办法；&lt;/li&gt;
&lt;li&gt;针对问题深挖，最后从业务原理以及产品功能上找到解决方案。同时技术工具抽象为功能完善了当前的业务。问题解决到当前的阶段，已经从某个具体问题看到了架构合理性的问题，并且彻底根治；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;上述都在一定程度上体现了技术能力，即便是一件繁琐的工作，也可以从扩大受益面的角度去提炼价值，并且寻求多个层次的解决方案，解决大多数利益相关者的关注点。同时，自己也锻炼了多层次的思考和抽象能力。往往很多事情也是如此递进的深入，解决具体问题-&amp;gt;总结深究-&amp;gt;工具提效-&amp;gt;融入产品，产品竞争力提升-&amp;gt;人人满意的结果。&lt;/p&gt;
&lt;p&gt;解决一个系统性/管理性等抽象问题的方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;面临着团队协作效率低下，发现抱怨的同学，然后问一问具体的问题，然后针对性解决；&lt;/li&gt;
&lt;li&gt;思考可能是一个普遍的问题，然后收集更广泛的问题，然后理出表格，归类分析并安排对应的人跟进和解决，最后定期跟踪进度；&lt;/li&gt;
&lt;li&gt;对于表格中的问题深入分析并且抽象，从架构调优、流程、产品功能角度寻找对应的原因，并寻求到最本质的原因，并确定解决这些问题带来的业务价值，然后按照目标进行拆解路径，向前向后补齐端到端，最后按照任务推进和跟踪进展；&lt;/li&gt;
&lt;li&gt;更全局角度思考此目标于年度目标的关系，团队组织的关系，思考如何扩大此事的效益，思考如何通过这些事情的解决锻炼和培养团队成员。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如何把问题解决到如何把事情做好，大多是时候是有迹可循的，按照自己的想法深入思考，按照特定的路径就已经在做好的道路上快步前进的。通过问题现象看到最终的本质，并能够通过对问题的抽象归纳进行技术架构层调优以解决同类的问题。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;技术能力&lt;/strong&gt;，就是一种以解决某种问题为目的的思路、方法与执行手段，其本质就是不论问题，解决问题的能力。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在编程领域，就是对遇到的业务问题进行抽象、提炼以及逻辑的构建，通过研发工具以提升解决问题的效能，减低人工低效的重复工作。&lt;/p&gt;
&lt;p&gt;技术能力模型的三个阶段体现：技术力、协作力（连接能力）和领导力。不管在哪个阶段，都要坚持长期主义，充分积累并利用时间的复利；总结的东西分类归类，越多，在时间上的复利就越能促进个人的成长。写下来你所想，讲出来你所想，验证出你所想。这就是提升技术能力的不二法则。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;技术力&lt;/strong&gt;，需要有扎实的技术基础（分布式技术、云原生技术、安全、质量等），对于自己的技能非常的娴熟。对于任务的使命必达、对于技艺的精益求精，对于新事物的好奇行，对于问题的攻坚克难。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;协作力&lt;/strong&gt;，更多的是技术架构能力，能够通过表层的问题现象深入到本质，通过模型的定义，原则的遵循来解决抽象复杂类的问题。需要通过问题发现，归纳定义问题，分析问题和问题本质解决的能力。体现在认知深度的能力，把难的事情做简单的能力，大白话清晰的思路讲清复杂的事情，从而对于这种简化的思维方式抽象为方法论。最终能够干成事，能够攻下城。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;领导力&lt;/strong&gt;，通过技术影响力去寻找团队的愿景和目标，带领组织占领战略高地，使用技术的思维解决超越技术领域的问题。需要对自身底层素质能力的提升，去从一些人与事之间最基本的内容中去领悟价值，从而赢得整个团队的向前的战斗力，力出一孔的必胜信念。&lt;/p&gt;
&lt;p&gt;任何人都是需要成长，才会逐步的提升。而自驱动力过程中要享受练习、思考、总结和感悟，而不是渴望得到别人的认可、反馈和评价。内心的强大才是真正的强大，而不是他人赞扬鼓励你牛逼你就牛逼。&lt;/p&gt;
&lt;p&gt;技术能力之&lt;strong&gt;讲清楚&lt;/strong&gt;，讲清楚是承接了你所想，和你想做的关键部分。&lt;/p&gt;
&lt;p&gt;方法论很多，5W2Y就是如此，但有时候还不够。&lt;/p&gt;
&lt;ol&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;把你要讲的内容现在全局中找个位置，这个全局是什么意思呢，就是对于全局大家都会有一定的认知。比如说GridRouter架构，就应该先介绍华为云，然后阐明GridRouter在华为云中承担的业务具体是干嘛的，或者在架构图中凸显出我们要讲的对象。这样听众的理解也来得快。&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;讲的任何事情必然是多面的，有上有下，有左有右，而往往听众也是多层的。所以一般需要从多个维度讲多个层次，多维度就是一个问题看了哪几个面，多层次就是问题够不够深入，简单的就是多问几个why直到弄懂所有的内容。&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;/ol&gt;
&lt;p&gt;这也是技术能力中关键技术。&lt;/p&gt;
&lt;p&gt;接着再讨论下纯技术思维的不足，单纯只用技术思维来考量的话，就是考虑的维度过于单一，往往考虑的事情只是在how范围内。很多时候，更加重要的是what和why。what和why（0-1）是做一件事情how（0-100）的意义。&lt;/p&gt;
&lt;p&gt;技术思维往往是直线的，因为xx所以xx结果。而实际往往需要的是以&lt;code&gt;结果&lt;/code&gt;来看，影响结果的所有要素都考虑，建立关联后自然而言会思考更广的要素。避免在分析过程丢失结果的。&lt;/p&gt;
</description>
    </item>
    
    <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/base/%E7%90%86%E8%A7%A3%E6%9E%B6%E6%9E%84/</link>
      <pubDate>Mon, 04 Apr 2022 21:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/base/%E7%90%86%E8%A7%A3%E6%9E%B6%E6%9E%84/</guid>
      <description>&lt;p&gt;维基百科:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;软件架构是有关软件整体结构与组件的抽象描述，用于指导大型软件系统各个方面的设计。软件架构会包括软件组件、组件之间的关系，组件特性以及组件间关系的特性。软件架构可以和建筑物的架构相比拟。软件架构是构建计算机软件，开发系统以及计划进行的基础，可以列出开发团队需要完成的任务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;架构是这样定义的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个系统都由一个架构&lt;/li&gt;
&lt;li&gt;架构由架构元素以及相互之间的关系构成&lt;/li&gt;
&lt;li&gt;系统是为了满足利益相关者（Stackholder）的需求而构建的&lt;/li&gt;
&lt;li&gt;利益相关者都有自己的关注点（Concerns）&lt;/li&gt;
&lt;li&gt;架构由架构文档描述&lt;/li&gt;
&lt;li&gt;架构文档描述了一系列的架构视角&lt;/li&gt;
&lt;li&gt;每个视角都解决并且对应到利益相关者的关注点。&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/07/02/rt8cLN25C9mOTkW.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;架构中的利益相关者：业务方、产品经理、客户、开发经理、工程师、项目经理、测试人员、运维人员、运营人员；理解各方的关注点和通电，并出架构解决这些关注点；&lt;/p&gt;
&lt;p&gt;业务驱动与基础设施的进化推动架构的发展。架构需要解决需求的问题，业务需求的变化驱动着架构的进化。&lt;/p&gt;
&lt;p&gt;基础设施的创新和开源价值的推动，一直在演进，到现在云原生时代，业务架构就需要基于云原生进行改造，如何基于云组件做适配，如何合理使用云的弹性、计算存储分离等功能也变得至关重要。而架构中最关键的是应该做到以不变应万变，这是以最终目标来看的：加速软件发布，减少整个软件生命周期中的资源投入（包括人力和最后软硬件资源等），通过管理复杂性、易变形和不确定性，为了简单高效的实现业务需求，确保在长期系统演进过程中，部分架构的变化不会对架构其它部分产生不必要的负面影响，让应用的易变部分能够频繁的变化。&lt;/p&gt;
&lt;p&gt;为了处理好业务复杂性的业务领域建模，实现系统非功能性需求的架构领域的设计模式/风格至今也同样还是架构师的必备技能，只是应用在不同的基础设施上。不管什么时候，我们都强调架构在软件方面的可维护性、可扩展性、高可伸缩性，在组织架构方面的人员组织结构。我们的产品（软件）也必然是其（人员）组织沟通结构的缩影。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The hardest part of design is deciding what to design.             &amp;ndash; the design of design&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;架构需要设计，但是架构更是一个根据业务长期演化才能落地生根的。而最终架构不仅要服务于技术，更要服务于人。&lt;/p&gt;
&lt;p&gt;非功能性需求的架构，xxx-abilities。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/07/02/n5sPD7JHIMQkEXj.png&#34; style=&#34;zoom:80%;&#34; /&gt;
&lt;h4 id=&#34;成为优秀的架构师&#34;&gt;成为优秀的架构师&lt;/h4&gt;
&lt;p&gt;来自蔡超的三点建议：&lt;/p&gt;
&lt;p&gt;1、坚持编码。架构师也是程序员，代码是软件的最终实现形态，停止编程会逐渐让你忘记作为程序员的感受，更重要的是忘记其中的“痛”，从而容易产生一些不切实际的设计。应该尽可能写代码，做测试，然后才是设计架构。&lt;/p&gt;
&lt;p&gt;2、坚持学习。对于IT人而言忙碌已成为习惯，996也讽刺的变成了公司高效的标志。而实时上过度忙碌会导致你没有事件学习和更新自己的知识，进而逐渐落后。&lt;/p&gt;
&lt;p&gt;3、用于关注技术上新的变化，同时更多思考的角度，重点是靠那些经历多年真正不变的技术和理念。&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/07/02/ifVvjWOdkGHQIUn.png&#34; style=&#34;zoom: 50%;&#34; /&gt;
</description>
    </item>
    
    <item>
      <title>编程原则</title>
      <link>https://liaolile.com/post/tech/base/%E7%BC%96%E7%A8%8B%E5%8E%9F%E5%88%99/</link>
      <pubDate>Fri, 18 Mar 2022 22:15:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/base/%E7%BC%96%E7%A8%8B%E5%8E%9F%E5%88%99/</guid>
      <description>&lt;p&gt;[toc]&lt;/p&gt;
&lt;p&gt;有目的的努力方向，才是正确的方向。而编程原则就是抽象于各种编程语言而来的思想，为的就是写下那隽永留千年的代码，因为最经典、最基础的一些思想总是源远流长的！&lt;/p&gt;
&lt;blockquote&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;/blockquote&gt;
&lt;p&gt;系统最本质的内容，我们往往理解的不够，所以出现了很多矛盾和纠结。为啥不深入研究下软件中最基本的内容并且沉淀呢，面对这个最复杂的东西探析清楚，知其所以然。这就是本篇的内容。&lt;/p&gt;
&lt;h3 id=&#34;0-准确定义&#34;&gt;0 准确定义&lt;/h3&gt;
&lt;h4 id=&#34;01-软件&#34;&gt;0.1 软件&lt;/h4&gt;
&lt;p&gt;编程的产物也就是“软件”。我们常说的系统、工具、应用、平台等均是编程的产物，均归类为软件。&lt;/p&gt;
&lt;h4 id=&#34;02-代码&#34;&gt;0.2 代码&lt;/h4&gt;
&lt;p&gt;编程中编写的东西统称为“代码”，包括源代码、程序、源程序等均为代码。&lt;/p&gt;
&lt;h4 id=&#34;03-编程&#34;&gt;0.3 编程&lt;/h4&gt;
&lt;p&gt;编写代码这件事或行为，我们就叫“编程”；也有叫编码、Coding、开发、实现等，均用编程指代。&lt;/p&gt;
&lt;h4 id=&#34;04-程序员&#34;&gt;0.4 程序员&lt;/h4&gt;
&lt;p&gt;负责编程的人统一称作“程序员”，根据不同的场景也区分为开发者、开发人员、软件工程师、程序猿。&lt;/p&gt;
&lt;h4 id=&#34;05-函数&#34;&gt;0.5 函数&lt;/h4&gt;
&lt;p&gt;可供调用的代码块也就是“函数”，还能细化为功能、过程、方法、成员函数等；往往词语指代东西并不一致，功能是有返回值，而过程是无返回值。&lt;/p&gt;
&lt;h4 id=&#34;06-模块&#34;&gt;0.6 模块&lt;/h4&gt;
&lt;p&gt;函数和变量的组合单元可以称为“模块”。包括更多的概念都可以提供如此的组合概念，如类、文件、库、组件、部件等，代表的是关联性较强的代码集合。&lt;/p&gt;
&lt;h4 id=&#34;07-软件架构&#34;&gt;0.7 软件架构&lt;/h4&gt;
&lt;p&gt;软件的整体结构就是“软件架构”，高于模块一层来看整个软件的整体内容，聚焦模块间的交互。&lt;/p&gt;
&lt;h3 id=&#34;1-永恒的真理&#34;&gt;1 永恒的真理&lt;/h3&gt;
&lt;h4 id=&#34;11-no-silver-bullet&#34;&gt;1.1 No Silver Bullet&lt;/h4&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;p&gt;非本质部分的自动化可以大幅改善工作效率和工作质量，而目前对于软件本质来说，需要通过自动化非本质部分而腾出更多的时间给到软件本质，软件真正的价值上。这个和当前的云原生的理念是不谋而合！&lt;/p&gt;
&lt;h4 id=&#34;12-代码即设计文档&#34;&gt;1.2 代码即设计文档&lt;/h4&gt;
&lt;p&gt;软件最终交付的有价值的内容除了代码，别无其它。而编程就是一个设计过程，只不过设计的是代码，而不是文档。产品的性能无法在制造和生产环境得到提升，能够得到提升的过程就是设计过程。不管是哪个环节，最终设计必须使用编程语言来表现，这个过程中编程语言才是最核心的设计要素。&lt;/p&gt;
&lt;p&gt;基本设计、详细设计等上游不应该偏离编程语言，因为编程、调测、测试等下游均是基于编程语言。所以如何端到端的打通整个过程，才是设计的初衷。设计需要创造力，编程就是一种创造行为，与其把不依赖编程语言的设计图翻译为代码，倒不如一开始让设计者编写代码来的省心。代码就是属于设计范畴，应该尽早的开始编写代码。&lt;/p&gt;
&lt;p&gt;代码是设计文档，并不代表代码是唯一文档。代码表达了“怎么做”和“是什么”，代码不能表达为什么这么做。而设计理由需要有地方承载。对于代码中的注释可以承担部分，注释需要弥补代码表达不出来的东西。另一方面，对代码进行说明的注释就是重复，应该避免这点。&lt;/p&gt;
&lt;p&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;h4 id=&#34;13-一定会被修改的代码&#34;&gt;1.3 一定会被修改的代码&lt;/h4&gt;
&lt;p&gt;代码如果不被修改，那软件的生命周期已经趋于死亡。“代码会被修改”是既定事实标准，我们做选择和判断时候优先考虑的事情。软件产生故障，需要修复；软件的新需求，需要新增；不管是修复还是新增，都是对软件的修改，软件必须迎合变化，没有一开始就能满足所有诉求的软件。&lt;/p&gt;
&lt;p&gt;需要编写经得起修改的代码，这个过程中代码的“可读”尤为重要。不管写代码需要耗费多少时间，只要读代码的时间能够缩短，那么我们就能够把消耗在写代码上的时间赚回来。要相信这点！&lt;/p&gt;
&lt;h3 id=&#34;2-正确的指导方针&#34;&gt;2 正确的指导方针&lt;/h3&gt;
&lt;h4 id=&#34;21-kiss-keep-it-short--simple&#34;&gt;2.1 KISS (Keep it short &amp;amp; simple)&lt;/h4&gt;
&lt;p&gt;保持简洁，容易理解，易于修改和使用。必不可少的最小集是什么，还能否做减法？功能简洁，接口简洁。奥卡姆剃刀，当一个事物存在多种解释时，最简单的哪个解释时正确的，减轻思考的负担、增强可读可理解，最后可敏捷修改。&lt;/p&gt;
&lt;h4 id=&#34;22-dry-dont-repeat-yourself&#34;&gt;2.2 DRY (Don&amp;rsquo;t repeat yourself)&lt;/h4&gt;
&lt;p&gt;禁止重复的拷贝。发现重复应该立即予以消除，避免重复这点没有商量余地。重复的代码可读性下降、难以修改且分散多处测试困难。一定程度上的代码抽象化操作可以消除重复。逻辑执行抽象，就是给整个处理过程命名，将其函数化、模块化。对于数据的重复，需要定义常量来替换；对应的重复内容有了名称，提升了可读性。&lt;/p&gt;
&lt;p&gt;对于自动化作业对软件进行测试、构建和发布的持续集成也是消除重复，消除重复的手动作业，提升自动化水平。对于设计模式是一种防止重复思考的手法。&lt;/p&gt;
&lt;p&gt;WET, Write every time， Write everything twice重复同样的事情，正好也是DRY的反义词。&lt;/p&gt;
&lt;p&gt;对于数据库而言，不应该存储重复的数据，one fact only in one place；&lt;/p&gt;
&lt;h4 id=&#34;23-yagni-you-arent-going-to-need-it&#34;&gt;2.3 YAGNI (You aren&amp;rsquo;t going to need it)&lt;/h4&gt;
&lt;p&gt;不用想太多，坚持只写当前需要的代码。比追求通用性，而复杂设计更应该重视单纯性，能用是第一位的，聚焦具体需求为基础的简单方案。&lt;/p&gt;
&lt;p&gt;想的太远只会增加代码的复杂度，提高修改的成本。所以编码的时候，要思考回到原点，保持纯粹的单纯简单，以代码阅读者的角度做些思考。&lt;/p&gt;
&lt;h4 id=&#34;24-pie-program-intently--expressively&#34;&gt;2.4 PIE (Program intently &amp;amp; expressively)&lt;/h4&gt;
&lt;p&gt;编码更多要在表达上花心思，将软件运行方式直观地传达给阅读代码的人。代码是我们正确、完整地理解软件运行方式的唯一线索。代码是动态变更的，任何的文档都是跟不上的，因而编写可读性高的代码，用代码表达意图是唯一可取的方法。&lt;/p&gt;
&lt;p&gt;读代码的次数远多于写代码的次数，所以追求的是代码可读性而不是代码的易写性。代码只写一次，但是多次阅读，读代码的效率应优先于写代码的效率和执行代码的效率。&lt;/p&gt;
&lt;p&gt;表达意图的终极形态是&lt;code&gt;文学编程&lt;/code&gt;，将代码本身当作文档的编程方法，用于描述文档的语言和编程语言结合在一起。代码即文档，文档即代码。代码要表达作品的意图，并且要有自我说明的能力。&lt;/p&gt;
&lt;h4 id=&#34;25-slap-single-level-of-abstraction-principle&#34;&gt;2.5 SLAP (Single level of abstraction principle)&lt;/h4&gt;
&lt;p&gt;抽象是分等级的，根据功能的复杂程度对象化概念进行分离，然后统一各层的抽象级别。统一各抽象级别之后，代码就可以像图书一样供人阅读。&lt;/p&gt;
&lt;p&gt;将代码分成级别统一的函数，能使代码具有概括性和可读性。函数一览起到目录作用，使代码拥有概括性。分割后的函数时小块代码，提升了代码的可读性。抽象度相同的处理在同一个地方，代码更加顺畅更加可读。函数结构化之后，各函数处理以调用比自己低一个级别的函数为中心。这种由其他函数调用组成的函数称为复合函数，符合函数要尽量小，如果想通过名称来表达意图，即使处理只有一行，也可以写成函数。&lt;/p&gt;
&lt;p&gt;面向对象中，容器时抽象类及其继承类。抽象类存放抽象级别较高的概念，继承类存放级别较低的概念。设计结构和编写内容时两件事情，需要独立的模式去实现。&lt;/p&gt;
&lt;h4 id=&#34;26-ocp-open--closed-principle&#34;&gt;2.6 OCP (Open &amp;amp; closed principle)&lt;/h4&gt;
&lt;p&gt;代码需要满足对扩展开发，对修改关闭的属性。扩展开放表示代码的行为可以扩展，修改关闭表示对代码进行行为扩展时，其他代码完成不会受到影响。&lt;/p&gt;
&lt;p&gt;面向对象的多态是实现OCP的代表技术，领域模型是稳定的，识别系统中的稳定成分和不稳定部分，在这两部分之间通过稳定的接口将交界点包裹起来。受保护变化则使用这层接口防护墙将变更带来的影响抵御在外。&lt;/p&gt;
&lt;h4 id=&#34;27-naming-naming-is-important&#34;&gt;2.7 Naming (Naming is important)&lt;/h4&gt;
&lt;p&gt;命名，一个合适的名字意味着元素被正确理解并正确地设计了出来。一个合适的名字表示设计已经完成了一大半。意图传达地核心概念就是命名，让人充分理解某个东西是怎么样做出来的，所以需要最大限度地在名字上下功夫。&lt;/p&gt;
&lt;p&gt;编码的时候并不是向读代码才去读的，在充分理解代码之后的修改或添加功能才是我们真正的目的。在读代码时，混乱的名字会占用所有的脑部资源，让编码困难。&lt;/p&gt;
&lt;p&gt;名字要能够搜索出来，不能是单个字母或数字，要避免常见的搜索在代码中产生无数个结果。名字要能够念出来，需要在团队中统一概念，传播给各个角色这些概念，大家在理解上是一致的。名字应该是基于标准术语来命名，避免大家心里映射才能理解元素表达的意思。&lt;/p&gt;
&lt;h3 id=&#34;3-unix思想&#34;&gt;3 UNIX思想&lt;/h3&gt;
&lt;p&gt;UNIX是被认为是大量经验的结晶，是编写优秀代码的实用性技术集合。所以在这会讲明白其蕴涵的思想是什么，以及怎么做，而不去分析为什么，因为这就是历史的沉淀，一些约定俗成的规定，被证明是正确的，得到全世界开发者的赞同，并不断的完善。&lt;/p&gt;
&lt;p&gt;对我有些触发内容的点是，3.9 表达性原则和3.17 可扩展性原则。&lt;/p&gt;
&lt;h4 id=&#34;31-模块化原则&#34;&gt;3.1 模块化原则&lt;/h4&gt;
&lt;p&gt;代码中关联性较强的元素聚集在一起就是模块，模块接口要简单明了，而不要冗余繁杂，最少和最小的接口提供最简练的功能。&lt;/p&gt;
&lt;p&gt;多个简单模块组装成软件，而每次修改都把影响控制在模块内。&lt;/p&gt;
&lt;h4 id=&#34;32-清晰原则&#34;&gt;3.2 清晰原则&lt;/h4&gt;
&lt;p&gt;代码不应该复杂，应该清晰，便于理解。在读代码时，不要对难以读懂的部分再三解读。第一次需要解读可能那个时因为碰巧没看懂，如果第二次还需要解读，那就需要小重构了。此时可以添加注释解释为什么，或者把代码修改的更加容易理解。&lt;/p&gt;
&lt;h4 id=&#34;33-组合原则&#34;&gt;3.3 组合原则&lt;/h4&gt;
&lt;p&gt;软件应该尽量做成一个简单的过滤器，接受某种数据流后，加工输出另一种数据流的软件。这种输入输出应该是简单明了的。通过不同的软件组合方式，就能够完成多种多样的任务。&lt;/p&gt;
&lt;h4 id=&#34;34-分离原则&#34;&gt;3.4 分离原则&lt;/h4&gt;
&lt;p&gt;是常说的领域模型，因为每个领域内沉淀的内容是稳定的。同时为机制编写有效的测试代码，机制的寿命比较长，同时独立的机制是可以被其他软件重复使用的。&lt;/p&gt;
&lt;h4 id=&#34;35-简单原则&#34;&gt;3.5 简单原则&lt;/h4&gt;
&lt;p&gt;代码设计的足够简单，只能规定只在必要的情况下添加复杂代码。团队间应该营造简单即美丽的文化氛围。&lt;/p&gt;
&lt;h4 id=&#34;36-简约原则&#34;&gt;3.6 简约原则&lt;/h4&gt;
&lt;p&gt;简约和简单不同在于不写大代码，一方面指代码量大，也指代码复杂指数大。要吝啬，尽量少写，让代码维持小的状态。随着代码的添加而变大，就要尽快对代码进行分割。&lt;/p&gt;
&lt;h4 id=&#34;37-透明性原则&#34;&gt;3.7 透明性原则&lt;/h4&gt;
&lt;p&gt;设计软件时，要从外部清楚看到软件的运行状态，不仅让软件正确运行，还要让人能够看到它是在正确地运行。软件需要一眼就能理解软件正在做什么和软件是怎么做地，同时要呈现并监控其内部状态。正式地代码中加入能够简化调试地机制是一件好事，需要认真对待。这是对于系统可观测能力地提升。&lt;/p&gt;
&lt;h4 id=&#34;38-健壮性原则&#34;&gt;3.8 健壮性原则&lt;/h4&gt;
&lt;p&gt;软件不仅能在一般条件下正常运行，还能再预想之外地条件下提供适当地服务。要想代码具有健壮性，需要保证人们能轻松识别其内部结构。&lt;/p&gt;
&lt;h4 id=&#34;39-表达性原则&#34;&gt;3.9 表达性原则&lt;/h4&gt;
&lt;p&gt;代码中地信息要尽量用数据而非逻辑来表达。将信息固定在数据一侧，可以提高逻辑地可读性和健壮性。数据不论多么复杂都能轻松地模型化，用数据来表达信息也更加简单。使用换算表地数组初始化语句与switch语句相比，数据结构一方面更容易理解。&lt;/p&gt;
&lt;p&gt;我们应当把代码中无法避免的复杂部分交给数据表示。当遇到数据和逻辑必须要有一个复杂化的情况时，毫不犹豫选择的是让数据复杂化。这也就是我们的领域模型，通过模型上的数据来承担过程逻辑。&lt;/p&gt;
&lt;h4 id=&#34;310-最小意外原则&#34;&gt;3.10 最小意外原则&lt;/h4&gt;
&lt;p&gt;接口的设计尽量不要让使用者感到意外，让接口运行符合用户的预期。对于一些约定俗成的东西，我们去遵循就好了，我们往往希望看到熟悉的东西就是自己熟知的东西，而不是还需要一层映射才能理解。当然有时候场景的区分需要通过不同来显示区分，比如get从一个模块获取数据，而fetch用以表示获取远程模块的数据。这个fetch和git中的概念就是保持一致的。&lt;/p&gt;
&lt;h4 id=&#34;311-沉默原则&#34;&gt;3.11 沉默原则&lt;/h4&gt;
&lt;p&gt;软件应该将希纳是的内容控制在最少的程度，除非遇到必须提醒的情况。只输出重要的信息，内部运行的信息不要参杂其中。对于错误发生时只将真正错误的部分作为标准错误输出，不输出所需范围之外的任何数据。对于调试而需要的信息，可以通过一个冗余模式的开关，默认让其处于关闭状态。&lt;/p&gt;
&lt;h4 id=&#34;312-修复原则&#34;&gt;3.12 修复原则&lt;/h4&gt;
&lt;p&gt;软件运行过程中，出现错误且修复失败，就应该立即停止处理，同时还应该有明显的提示。对修复失败情况下继续处理，就会出现最坏的结果，故障可能在不知不觉中破坏所有的数据。&lt;/p&gt;
&lt;p&gt;软件在发生错误时应尽早让人立刻知晓，软件在无法自行修复的时候，需要把控制权交给用户进行判断，这点很重要。&lt;/p&gt;
&lt;h4 id=&#34;313-经济原则&#34;&gt;3.13 经济原则&lt;/h4&gt;
&lt;p&gt;程序员的时间时宝贵资源，值得珍惜。任何浪费程序员的时间都是不经济的。&lt;/p&gt;
&lt;h4 id=&#34;314-生成原则&#34;&gt;3.14 生成原则&lt;/h4&gt;
&lt;p&gt;生成原则指编写用于生成代码的代码，减少手动操作，编写用于生成代码地代码。只在优先的范围内生成代码也是很有效果的，重复的、形式固定的代码尤其适合由代码生成器生成。&lt;/p&gt;
&lt;h4 id=&#34;315-优化原则&#34;&gt;3.15 优化原则&lt;/h4&gt;
&lt;p&gt;在代码优化之前，先要保证代码能够正常运行。代码尚且不能充分运行阶段，对细节进行打磨是一种吃力不讨好的做法。先要确保代码正确运行，再去追求所谓的运行速度，确保足够的简单。代码越简单，可优化的地方就越容易被找到。&lt;/p&gt;
&lt;h4 id=&#34;316-多样性原则&#34;&gt;3.16 多样性原则&lt;/h4&gt;
&lt;p&gt;容许存在多种方法，在软件中没有唯一正确的方法。我们不能相信任何宣传软件开发存在唯一正确方法的言论。应该认可多样性，调动思维，不断寻找更好的方案。&lt;/p&gt;
&lt;h4 id=&#34;317-可扩展性原则&#34;&gt;3.17 可扩展性原则&lt;/h4&gt;
&lt;p&gt;通过代码可扩展，代码能满足多样的需求。可以采用可插拔的设计，对于扩展可插拔接口部分，要采用灵活的设计，并且在代码一旁加上“如果需要xxx”的注释。另外，可扩展性并不是添加非必要的功能，而是要编写能在需要的时候轻松添加相应功能的代码。&lt;/p&gt;
&lt;p&gt;可扩展性同样适用于数据格式，要让数据格式具有自我描述和可扩展性。让数据格式由几个独立的自我描述部分组成能够取得更好的效果，而不依赖顺序，甚至依赖其他数据。这样做的好处，可以在不搞混所读取的代码的前提下添加新的部分和删除旧的部分。&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://baike.baidu.com/item/%e7%bd%97%e5%a1%9e%e5%a1%94%e7%9f%b3%e7%a2%91/34799?fr=aladdin&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;罗塞塔石碑（古埃及托勒密王朝著名石碑）_百度百科 (baidu.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>
    
    <item>
      <title>说说缓存</title>
      <link>https://liaolile.com/post/tech/distributesystem/%E8%AF%B4%E8%AF%B4%E7%BC%93%E5%AD%98/</link>
      <pubDate>Mon, 04 Oct 2021 23:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/distributesystem/%E8%AF%B4%E8%AF%B4%E7%BC%93%E5%AD%98/</guid>
      <description>&lt;p&gt;&lt;strong&gt;缓存使用场景：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;从&lt;strong&gt;硬件的角度&lt;/strong&gt;来说，缓存就是可以进行高速数据交换的存储器。最经典例子就是&lt;code&gt;CPU&lt;/code&gt;层面的多级缓存：性能最高的寄存器、多级缓存L1/L2/L3、主存，外部的机械硬盘。计算机总是优先从读写性能最好的存储器中来读写数据。&lt;/p&gt;
&lt;p&gt;从&lt;strong&gt;中间件的角度&lt;/strong&gt;来看，缓存在&lt;code&gt;数据库&lt;/code&gt;中应用，如Mysql拿到一个查询请求后，先会查询缓存是否命中（key为查询语句，value为查询的结果），如果命中则返回；实际中不建议，对于业务表查询缓存失效的概率极高；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RocketMQ&lt;/code&gt;中的缓存，是在Page Cache机制的预读作用下使得Consumer queue文件的读性能几乎接近内存。Page Cache是操作系统对文件的缓存，使用一部分内存用作Page Cache。对于数据的写入，操作系统会先写入至Cache中，随后异步的方式由&lt;code&gt;pdflush&lt;/code&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;内核线程将Cache内的数据刷盘。对于数据读取，如果未出现命中Page Cache，操作系统从屋里磁盘上访问读取文件同时，会顺序对其相邻块数据文件进行预读取Read Ahead。Page Cache利用的是&lt;em&gt;时间局部性&lt;/em&gt;原理，最近访问的数据接下来再次访问当。预读取数据放入Page Cache利用的是&lt;em&gt;空间局部性&lt;/em&gt;原理，依据数据往往是连续访问。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Elastic Search&lt;/code&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;包括Query Cache/Filter Cache、Request Cache、Field Data Cache。Query Cache就是对一个查询中包含的过滤器执行结果进行缓存；Request Cache模块就是为了缓存这些“分片级”的本地结果集，一个面向请求的缓存，缓存的key是查询DSL字符串。Fielddata是专门针对分词的字段在query-time（查询期间）的数据结构的缓存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;常见主流的缓存算法&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LRU(Least-Recently-Used): 替换掉最近请求最少的对象，实际中使用最广。cpu缓存淘汰和虚拟内存效果好，web应用欠佳&lt;/li&gt;
&lt;li&gt;LFU(Least-Frequently-Used): 缓存污染问题(一个先前流行的缓存对象会在缓存中驻留很长时间)&lt;/li&gt;
&lt;li&gt;LRU2(Least Recently Used 2): 为什么LRU2优于LRU：当一次访问过来的时候，在缓存系统中找出最少最近使用的对象是一项时间复杂度非常高的运算，这就是为什么LRU2是最好的选择。&lt;/li&gt;
&lt;li&gt;2Q(two queues)。多级缓存&lt;/li&gt;
&lt;li&gt;SIZE：替换占用空间最大的。也会有缓存污染&lt;/li&gt;
&lt;li&gt;LRU-Threashold：不超过某一个size 的，其他与 LRU 相同&lt;/li&gt;
&lt;li&gt;Log(Size) + LRU: 替换 size 最大的对象，当size相同按 LRU 替换&lt;/li&gt;
&lt;li&gt;Hyper-G: LFU 改进版，同时考虑上次访问时间和对象 size&lt;/li&gt;
&lt;li&gt;Pitkow/Recker: 替换最近最少使用对象，除非所有对象都是今天访问过的。如果是，替换调最大的对象&lt;/li&gt;
&lt;li&gt;Lowest-Latency-First: 替换下载时间最少的，最小化平均延迟&lt;/li&gt;
&lt;li&gt;Hybrid Hybrid: 保留效用最低的会被替换掉&lt;/li&gt;
&lt;li&gt;Lowest Relative Value(LRV): 替换保留效用最低的&lt;/li&gt;
&lt;li&gt;Adaptive Replacement Cache(ARC)&lt;/li&gt;
&lt;li&gt;Most Recently Used(MRU)&lt;/li&gt;
&lt;li&gt;First in First out(FIFO)&lt;/li&gt;
&lt;li&gt;Random Cache&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;缓存的应用&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;以web应用为例说明，用户请求到后台，会先从缓存中取数据，如果在缓存中取到数据，就直接返回结果，如果取不到数据就需要查询数据库，从数据库中取数据，从数据库中取到数据后会同步更新到缓存，并返回结果。下一个用户就可以直接从缓存中取值了。那如果在数据库也没有取到，就只能直接返回空结果。在该场景下，缓存主要是为了缓解数据库访问压力，提升请求响应；&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;flowchart LR
id1[用户请求]
id2{Redis中请求特征Key是否存在}
id3[获取redis中数据]
id4{数据库中请求特征key是否存在}
id5[更新Redis数据]
id6[返回空]
id7[返回Redis数据]
E[结束]

id1[用户请求] --&gt;id2
id2 --&gt;|Yes|id3
id2 --&gt;|No| id4
id3 --&gt; id7
id7 --&gt; E
id4 --&gt; |Yes|id5
id4 --&gt; |No| id6
id5--&gt; id7
id6--&gt; E
 
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;缓存失效或者异常&lt;/strong&gt;，导致访问压力流转到数据库，使得数据库负载过高；归于提升缓存命中率，同时数据库需要限流；&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;缓存穿透:&lt;/p&gt;
&lt;p&gt;外部可以非法请求一个缓存和数据库中必定不存在的数据，让其击穿缓存直接打到数据库，不断的大流量攻击就可以让数据库瘫痪。应对这种情况的发生，使用布隆过滤器进行过滤避免击穿，布隆过滤器存储空间小，可以存储大量的key。但是存在误判：布隆过滤器中没有的元素一定没有，但是布隆过滤器提示有的元素不一定有。&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;缓存中数据大批量到过期时间，而查询数据量大落在数据库上，引起数据库压力大而宕机。缓存击穿是并发查询同一条数据，缓存雪崩是不同数据都过期了，很多数据查不到而查数据库。需要结合业务分析进行缓存预热，针对热key的失效点均衡分布。&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;/ol&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://zhuanlan.zhihu.com/p/71217136&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Linux中的Page Cache  - 知乎 (zhihu.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;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.csdn.net/chennanymy/article/details/52504386&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Elasticsearch2.x 三种缓存介绍：Query Cache、Request Cache、Fielddata Cache_飞奔的代码的博客-CSDN博客_es 缓存&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>安全架构设计</title>
      <link>https://liaolile.com/post/tech/base/%E5%AE%89%E5%85%A8%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Thu, 29 Apr 2021 12:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/base/%E5%AE%89%E5%85%A8%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/</guid>
      <description>&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;下述包括8个维度的安全动作内容和8个基本安全设计原则！&lt;/p&gt;
&lt;p&gt;如果把任何我们要开发的软件系统比做一场必须要赢得的战争，那安全架构就是战略级的威慑，而安全设计就是战术内容，而安全分析就是软件工程师面对的一场场的战斗，成熟的安全威胁库参考就是历史中发生的一场场的战役，而来自不同方面的安全需求就是我们面临每场战斗的具体战法，解决实际问题最需要的实践。&lt;/p&gt;
&lt;p&gt;下面&lt;code&gt;PPT&lt;/code&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/05/22/johXAiPY3DczU5s.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;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/05/22/IE9Dt7lc4CoV82s.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;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/05/22/HblfVQmwjXRyzNO.png&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>hey- a tiny program that sends some load to a web application</title>
      <link>https://liaolile.com/post/tech/sourcecode/hey-a-tiny-program-that-sends-some-load-to-a-web-application/</link>
      <pubDate>Mon, 26 Apr 2021 12:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/sourcecode/hey-a-tiny-program-that-sends-some-load-to-a-web-application/</guid>
      <description>&lt;p&gt;&lt;strong&gt;源码地址&lt;/strong&gt;： &lt;a href=&#34;https://github.com/rakyll/hey&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;rakyll/hey: HTTP load generator, ApacheBench (ab) replacement (github.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;源码语言&lt;/strong&gt;：GO&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;源码出品&lt;/strong&gt;：Google&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;源码关联分析&lt;/strong&gt;： &lt;a href=&#34;https://blog.csdn.net/chenchen5152/article/details/116378028&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;(3条消息) fasthttp性能真的比标准库http包好很多吗？一文告诉你真相！_不想秃头的晨晨的博客-CSDN博客_fasthttp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/bigwhite/experiments/blob/master/http-benchmark/client/http_client_load.sh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;experiments/http_client_load.sh at master · bigwhite/experiments (github.com)&lt;/a&gt; hey的使用封装脚本&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;源码分析&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;hey主要借助go原生的net/http包构造测试请求，可以充当压测小工具。对于请求的响应会做详细的分析，包括：请求摘要信息（平均时延/Qps/最快时延/最慢时延等），响应时延（histogram、tp99等），以及请求时间的具体耗时分析。&lt;/li&gt;
&lt;/ol&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/05/22/LPQcf2Koid5YztX.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;ol start=&#34;2&#34;&gt;
&lt;li&gt;
&lt;p&gt;使用hey工具，hey直接linux使用运行，其结果可以输出到文件中，后续对文件内数据进行提取统计分析；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;其中的Makefile文件对于不同环境的构建进行描述，如下，并且使用&lt;strong&gt;make release&lt;/strong&gt;即可在linux进行编译构建;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&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/05/22/GQ8cHMxAhi6jsKX.png&#34; alt=&#34;image-202205220940343103&#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;ul&gt;
&lt;li&gt;
&lt;p&gt;cmd的命令行参数解析，flag.string的使用，以及cmd help场景，做一个命令行工具的标准参考；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于需要做服务端的请求metrics信息统计，可以参考，快速实现直方图/TP时延等信息的收集；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;相关的并发协程的高级用法参考使用；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Test测试用例的写法，t.Errorf即可输出测试用例失败场景；&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;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;TestBody&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;testing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;T&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&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int64&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;handler&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Request&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&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;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ioutil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ReadAll&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Body&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;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;body&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;s&#34;&gt;&amp;#34;Body&amp;#34;&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;atomic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;AddInt64&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;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&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;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;server&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;httptest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NewServer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;HandlerFunc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;handler&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;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Close&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&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&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;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NewRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;URL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bytes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NewBuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Body&amp;#34;&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;w&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Work&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;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;     &lt;span class=&#34;nx&#34;&gt;req&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;RequestBody&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;nb&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Body&amp;#34;&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;N&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;           &lt;span class=&#34;mi&#34;&gt;10&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;C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;           &lt;span class=&#34;mi&#34;&gt;1&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;nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Run&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;count&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&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;t&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;Expected to work 10 times, found %v&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&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;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>easy-try一种存储介质可扩展的持久化重试方案</title>
      <link>https://liaolile.com/post/tech/sourcecode/easy-retry-%E4%B8%80%E7%A7%8D%E5%AD%98%E5%82%A8%E4%BB%8B%E8%B4%A8%E5%8F%AF%E6%89%A9%E5%B1%95%E7%9A%84%E6%8C%81%E4%B9%85%E5%8C%96%E9%87%8D%E8%AF%95%E6%96%B9%E6%A1%88/</link>
      <pubDate>Sat, 24 Apr 2021 12:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/sourcecode/easy-retry-%E4%B8%80%E7%A7%8D%E5%AD%98%E5%82%A8%E4%BB%8B%E8%B4%A8%E5%8F%AF%E6%89%A9%E5%B1%95%E7%9A%84%E6%8C%81%E4%B9%85%E5%8C%96%E9%87%8D%E8%AF%95%E6%96%B9%E6%A1%88/</guid>
      <description>&lt;p&gt;&lt;strong&gt;源码地址&lt;/strong&gt;：&lt;a href=&#34;https://github.com/alibaba/easy-retry&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;alibaba/easy-retry: easy-retry (github.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;源码语言&lt;/strong&gt;：Java&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;源码出品&lt;/strong&gt;：Alibaba&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;源码关联分析&lt;/strong&gt;： &lt;a href=&#34;https://github.com/houbb/sisyphus&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;houbb/sisyphus: The java retry framework.(支持注解的 java 重试框架) (github.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;源码分析&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;其目录树结构为：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---easy-retry-common
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---easy-retry-core
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---easy-retry-extensions
&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;   ---easy-retry-mybatis-extension
&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;   ---easy-retry-spring-extension
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---easy-retry-starters
&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;   ---easy-retry-memory-starter
&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;   ---easy-retry-mybatis-starter
&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;   ---easy-retry-starter-common
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;目前支持两种模式的重试，包括持久化到mysql依赖mybatis和内存数据版本，分别需要以来easy-retry-mybatis-starter和easy-retry-memoery-starter模块。&lt;/p&gt;
&lt;p&gt;重试的最基本的interface以及model定义在easy-retry-common中，retry逻辑的具体默认实现在easy-retry-core模块中；&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;该重试的模块中定义的核心概念有：&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;Retryable&lt;/code&gt;支持重试的注解，支持定义是否重新抛出异常，以及SpelExpression来驱动重试判定&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryInfo&lt;/code&gt; 通过@Retryable注解绑定获取执行的executor和executorMethod信息绑定到RetryInfo上；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryTask&lt;/code&gt; 对于重试任务的定义，重要的领域模型。其在框架中的convert关系：retryInfo-&amp;gt;retryTask-&amp;gt;retryTaskPo&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryConfiguration&lt;/code&gt; 重试的配置，如果没有自定义的则框架默认的重试机制。支持灵活的自定义内容，包含有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;获取重试任务&lt;/li&gt;
&lt;li&gt;重试信息序列化器获取，默认是 Hessian&lt;/li&gt;
&lt;li&gt;重试机制的定义&lt;/li&gt;
&lt;li&gt;重试执行器，执行驱动业务&lt;/li&gt;
&lt;li&gt;重试最大次数&lt;/li&gt;
&lt;li&gt;重试事件监听&lt;/li&gt;
&lt;li&gt;任务结果序列化器，配合SPEL表达式决策是否需要重试，默认是 Hessian&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Retryer&lt;/code&gt; 重试的基本Call定义，@FunctionalInterface 函数式接口声明&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryContext&lt;/code&gt;，重试的上下文内容，上下文内容来自于RetryConfiguration，目前只有一种实现，即MaxAttemptsPersistenceRetryContext；绑定具体的task和task executor method&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryContainer&lt;/code&gt; 重试的容器承载，目前一种实现，即SimpleRetryContainer。其通过一个生产-消费者设计模式，实现了retryTask的生产和消费，用于对retryTask的管理；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryContext&lt;/code&gt;和&lt;code&gt;RetryContainer&lt;/code&gt;目前都托管在RetryLifeCycle中管理，在启动和关闭时候做相关资源的处理；RetryContainer中是一个优先队列装的是RetryContext，RetryContex中承载了RetryTask，而RetryTask的优先级最终反应到RetryContext上。而任务的优先级通过任务重试的背压机制设置，避免失败的任务频繁的重试；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryFilter&lt;/code&gt;，重试的过滤器，在过滤器中可以针对RetryContext进行相关的拦截统一处理；其中有一个确保线程安全的过滤器；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryInterceptor&lt;/code&gt; 切面的切入，该切入点做了BeforeRetryProcess和OnRetryProcess切入动作，两个process针对正常场景和异常场景定义了相关处理方法，来决策是否需要进行重试；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryProcessor&lt;/code&gt;，拦截面切入的动作定义&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryStrategy&lt;/code&gt;，具体的重试策略，包括等待策略以及结束策略&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryEvent&lt;/code&gt;，重试的事件，包括重试前的重试对象获取前后事件，以及重试中的失败、成功、等待事件等；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryListener&lt;/code&gt;，事件的监听者；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RetryExecutor&lt;/code&gt;，重试的执行器，在上下文中依赖于RetryConfiguration和RetryTask关联，确定task的执行器；当前的executor实现了PersistencRetryExecutor。其处理逻辑是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;RetryContainer从当前优先队列中获取最优先的任务对应的RetryContext上下文信息，送入executor中执行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;executor判断当前任务是否需要立即执行还是继续等待，决定于背压模式下的时间设定。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果可以执行，则更新当前的retryTask状态为handling&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;执行器执行对应的filter逻辑，filter逻辑返回对应的信息，filter链中最后一个处理逻辑为冲RetryContext取出Invocation信息并且invoke对应的method。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;依据filter chain的返回结果后者会抛出异常，针对这两个结果进行判定，决策当前的执行是否需要重试，如果需要重试再决策是否已经达到最大重试次数或者进入背压逻辑，返回该次的结果；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;依据上述的状态结果，进行事件广播，相关的Retrylisterner即会被调用；&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/05/22/tZPD2LrR5ezgySf.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;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;源码借鉴&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;概念定义清楚，从领域建模的角度，区分开来各种概念的含义，面向对象，对象定义清楚，准确定义。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于各个Bean的AutoConfiguration，集中进行管理，且当用户无自定义时候，需要提供默认的注入实现；—这是开发框架和非框架的本质区别；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;按模块做成各个模块之间的独立，模块的边界定义清晰；&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    
    <item>
      <title>markdown命令语法</title>
      <link>https://liaolile.com/post/tools/markdown%E5%91%BD%E4%BB%A4/</link>
      <pubDate>Fri, 04 Dec 2020 21:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tools/markdown%E5%91%BD%E4%BB%A4/</guid>
      <description>&lt;p&gt;&lt;strong&gt;记录在此处，主要避免每次都要互联网中搜索，而是选择在本地就搜索，缩小这个知识的范围；&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;微信公众号排版工具。问题或建议，请公众号留言。&lt;strong&gt;&lt;a href=&#34;#jump_8&#34;&gt;程序员翻身&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;建议使用 &lt;strong&gt;Chrome&lt;/strong&gt; 浏览器，体验最佳效果。&lt;/p&gt;
&lt;p&gt;使用微信公众号编辑器有一个十分头疼的问题：粘贴出来的代码，格式错乱，空间小还带行号，而且特别丑。Markdown.com.cn编辑器能够解决这个问题。&lt;/p&gt;
&lt;p&gt;Markdown是一种轻量级的「标记语言」。&lt;/p&gt;
&lt;p&gt;请阅读下方文本熟悉工具使用方法，本文可直接拷贝到微信中预览。&lt;/p&gt;
&lt;h2 id=&#34;1-markdowncomcn-简介&#34;&gt;1 Markdown.com.cn 简介&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;支持自定义样式的 Markdown 编辑器&lt;/li&gt;
&lt;li&gt;支持微信公众号、知乎和稀土掘金&lt;/li&gt;
&lt;li&gt;点击右上方对应图标，一键复制到各平台&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;2-markdown语法教程&#34;&gt;2 Markdown语法教程&lt;/h2&gt;
&lt;h3 id=&#34;21-标题&#34;&gt;2.1 标题&lt;/h3&gt;
&lt;p&gt;不同数量的&lt;code&gt;#&lt;/code&gt;可以完成不同的标题，如下：&lt;/p&gt;
&lt;h1 id=&#34;一级标题&#34;&gt;一级标题&lt;/h1&gt;
&lt;h2 id=&#34;二级标题&#34;&gt;二级标题&lt;/h2&gt;
&lt;h3 id=&#34;三级标题&#34;&gt;三级标题&lt;/h3&gt;
&lt;h3 id=&#34;22-字体&#34;&gt;2.2 字体&lt;/h3&gt;
&lt;p&gt;粗体、斜体、粗体和斜体，删除线，需要在文字前后加不同的标记符号。如下：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这个是粗体&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;这个是斜体&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;这个是粗体加斜体&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;~这里想用删除线~~&lt;/p&gt;
&lt;p&gt;注：如果想给字体换颜色、字体或者居中显示，需要使用内嵌HTML来实现。&lt;/p&gt;
&lt;h3 id=&#34;23-无序列表&#34;&gt;2.3 无序列表&lt;/h3&gt;
&lt;p&gt;无序列表的使用，在符号&lt;code&gt;-&lt;/code&gt;后加空格使用。如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无序列表 1&lt;/li&gt;
&lt;li&gt;无序列表 2&lt;/li&gt;
&lt;li&gt;无序列表 3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果要控制列表的层级，则需要在符号&lt;code&gt;-&lt;/code&gt;前使用空格。如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无序列表 1&lt;/li&gt;
&lt;li&gt;无序列表 2
&lt;ul&gt;
&lt;li&gt;无序列表 2.1&lt;/li&gt;
&lt;li&gt;无序列表 2.2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;由于微信原因，最多支持到二级列表&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;24-有序列表&#34;&gt;2.4 有序列表&lt;/h3&gt;
&lt;p&gt;有序列表的使用，在数字及符号&lt;code&gt;.&lt;/code&gt;后加空格后输入内容，如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;有序列表 1&lt;/li&gt;
&lt;li&gt;有序列表 2&lt;/li&gt;
&lt;li&gt;有序列表 3&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;25-引用&#34;&gt;2.5 引用&lt;/h3&gt;
&lt;p&gt;引用的格式是在符号&lt;code&gt;&amp;gt;&lt;/code&gt;后面书写文字。如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;读一本好书，就是在和高尚的人谈话。 ——歌德&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;雇用制度对工人不利，但工人根本无力摆脱这个制度。 ——阮一峰&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;27-链接&#34;&gt;2.7 链接&lt;/h3&gt;
&lt;p&gt;微信公众号仅支持公众号文章链接，即域名为&lt;code&gt;https://mp.weixin.qq.com/&lt;/code&gt;的合法链接。使用方法如下所示：&lt;/p&gt;
&lt;p&gt;对于该论述，欢迎读者查阅之前发过的文章，&lt;a href=&#34;https://mp.weixin.qq.com/s/s5IhxV2ooX3JN_X416nidA&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;你是《未来世界的幸存者》么？&lt;/a&gt;
&lt;a id=&#34;jump_8&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;28-图片&#34;&gt;2.8 图片&lt;/h3&gt;
&lt;p&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://www.nginx.cn/wp-content/uploads/2020/03/qrcode_for_gh_82cf87d482f0_258.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;支持 jpg、png、gif、svg 等图片格式，&lt;strong&gt;其中 svg 文件仅可在微信公众平台中使用&lt;/strong&gt;，svg 文件示例如下：&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://markdown.com.cn/images/i-am-svg.svg&#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;em&gt;&lt;strong&gt;拖拽和截图粘贴&lt;/strong&gt;&lt;/em&gt; 到编辑器中，仅支持 https 的图片，图片粘贴到微信时会自动上传微信服务器。&lt;/p&gt;
&lt;h3 id=&#34;29-分割线&#34;&gt;2.9 分割线&lt;/h3&gt;
&lt;p&gt;可以在一行中用三个以上的减号来建立一个分隔线，同时需要在分隔线的上面空一行。如下：&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;210-表格&#34;&gt;2.10 表格&lt;/h3&gt;
&lt;p&gt;可以使用冒号来定义表格的对齐方式，如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:left&#34;&gt;姓名&lt;/th&gt;
&lt;th style=&#34;text-align:center&#34;&gt;年龄&lt;/th&gt;
&lt;th style=&#34;text-align:right&#34;&gt;工作&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;小可爱&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;18&lt;/td&gt;
&lt;td style=&#34;text-align:right&#34;&gt;吃可爱多&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;小小勇敢&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;20&lt;/td&gt;
&lt;td style=&#34;text-align:right&#34;&gt;爬棵勇敢树&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;小小小机智&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;22&lt;/td&gt;
&lt;td style=&#34;text-align:right&#34;&gt;看一本机智书&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;3-特殊语法&#34;&gt;3. 特殊语法&lt;/h2&gt;
&lt;h3 id=&#34;31-脚注&#34;&gt;3.1 脚注&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;支持平台：微信公众号、知乎。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;脚注与链接的区别如下所示：&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-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;链接：[文字](链接)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;脚注：[文字](脚注解释 &amp;#34;脚注名字&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;有人认为在&lt;a href=&#34;https://en.wikipedia.org/wiki/Front-end_web_development&#34; title=&#34;Front-end web development&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;大前端时代&lt;/a&gt;的背景下，移动端开发（Android、IOS）将逐步退出历史舞台。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;%e6%98%af%e6%8c%87%e6%8e%8c%e6%8f%a1%e5%a4%9a%e7%a7%8d%e6%8a%80%e8%83%bd%ef%bc%8c%e5%b9%b6%e8%83%bd%e5%88%a9%e7%94%a8%e5%a4%9a%e7%a7%8d%e6%8a%80%e8%83%bd%e7%8b%ac%e7%ab%8b%e5%ae%8c%e6%88%90%e4%ba%a7%e5%93%81%e7%9a%84%e4%ba%ba%e3%80%82&#34; title=&#34;什么是全栈工程师&#34;&gt;全栈工程师&lt;/a&gt;在业务开发流程中起到了至关重要的作用。&lt;/p&gt;
&lt;p&gt;脚注内容请拉到最下面观看。&lt;/p&gt;
&lt;h3 id=&#34;32-代码块&#34;&gt;3.2 代码块&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;支持平台：微信代码主题仅支持微信公众号！其他主题无限制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果在一个行内需要引用代码，只要用反引号引起来就好，如下：&lt;/p&gt;
&lt;p&gt;Use the &lt;code&gt;printf()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;在需要高亮的代码块的前一行及后一行使用三个反引号，同时&lt;strong&gt;第一行反引号后面表示代码块所使用的语言&lt;/strong&gt;，如下：&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-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// FileName: HelloWorld.java
&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;public&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;HelloWorld&lt;/span&gt; &lt;span class=&#34;o&#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;// Java 入口程序，程序从此入口
&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;public&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#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;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Hello,World!&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#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;&lt;/span&gt;  &lt;span class=&#34;o&#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;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;支持以下语言种类：&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-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bash
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;clojure，cpp，cs，css
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dart，dockerfile, diff
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;erlang
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go，gradle，groovy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;haskell
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;java，javascript，json，julia
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kotlin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lisp，lua
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;makefile，markdown，matlab
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;objectivec
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;perl，php，python
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;r，ruby，rust
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;scala，shell，sql，swift
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tex，typescript
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;verilog，vhdl
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xml
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果想要更换代码高亮样式，可在上方&lt;strong&gt;代码主题&lt;/strong&gt;中挑选。&lt;/p&gt;
&lt;p&gt;其中&lt;strong&gt;微信代码主题与微信官方一致&lt;/strong&gt;，有以下注意事项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;带行号且不换行，代码大小与官方一致&lt;/li&gt;
&lt;li&gt;需要在代码块处标志语言，否则无法高亮&lt;/li&gt;
&lt;li&gt;粘贴到公众号后，用鼠标点代码块内外一次，完成高亮&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;diff 不能同时和其他语言的高亮同时显示，且需要调整代码主题为微信代码主题以外的代码主题才能看到 diff 效果，使用效果如下:&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-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gi&#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;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;- 删除项
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;其他主题不带行号，可自定义是否换行，代码大小与当前编辑器一致&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;33-数学公式&#34;&gt;3.3 数学公式&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;支持平台：微信公众号、知乎。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;行内公式使用方法，比如这个化学公式：$\ce{Hg^2+ -&amp;gt;[I-] HgI2 -&amp;gt;[I-] [Hg^{II}I4]^2-}$&lt;/p&gt;
&lt;p&gt;块公式使用方法如下：&lt;/p&gt;
&lt;p&gt;$$H(D_2) = -\left(\frac{2}{4}\log_2 \frac{2}{4} + \frac{2}{4}\log_2 \frac{2}{4}\right) = 1$$&lt;/p&gt;
&lt;p&gt;矩阵：&lt;/p&gt;
&lt;p&gt;$$
\begin{pmatrix}
1 &amp;amp; a_1 &amp;amp; a_1^2 &amp;amp; \cdots &amp;amp; a_1^n \
1 &amp;amp; a_2 &amp;amp; a_2^2 &amp;amp; \cdots &amp;amp; a_2^n \
\vdots &amp;amp; \vdots &amp;amp; \vdots &amp;amp; \ddots &amp;amp; \vdots \
1 &amp;amp; a_m &amp;amp; a_m^2 &amp;amp; \cdots &amp;amp; a_m^n \
\end{pmatrix}
$$&lt;/p&gt;
&lt;p&gt;公式由于微信不支持，目前的解决方案是转成 svg 放到微信中，无需调整，矢量不失真。&lt;/p&gt;
&lt;p&gt;目前测试如果公式量过大，在 Chrome 下会存在粘贴后无响应，但是在 Firefox 中始终能够成功。&lt;/p&gt;
&lt;h3 id=&#34;34-toc&#34;&gt;3.4 TOC&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;支持平台：微信公众号、知乎。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;TOC 全称为 Table of Content，列出全部标题。&lt;/p&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;由于微信只支持到二级列表，本工具仅支持二级标题和三级标题的显示。&lt;/p&gt;
&lt;h3 id=&#34;35-注音符号&#34;&gt;3.5 注音符号&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;支持平台：微信公众号。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;支持注音符号，用法如下：&lt;/p&gt;
&lt;p&gt;Markdown Nice 这么好用，简直是{喜大普奔|hē hē hē hē}呀！&lt;/p&gt;
&lt;h3 id=&#34;36-横屏滑动幻灯片&#34;&gt;3.6 横屏滑动幻灯片&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;支持平台：微信公众号。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;通过&lt;code&gt;&amp;lt;![](url),![](url)&amp;gt;&lt;/code&gt;这种语法设置横屏滑动滑动片，具体用法如下：&lt;/p&gt;
&lt;p&gt;&amp;lt;















&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://markdown.com.cn/images/blue.jpg&#34; alt=&#34;蓝1&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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://markdown.com.cn/images/green.jpg&#34; alt=&#34;绿2&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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://markdown.com.cn.jpg&#34; alt=&#34;红3&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&amp;gt;&lt;/p&gt;
&lt;h2 id=&#34;4-其他语法&#34;&gt;4 其他语法&lt;/h2&gt;
&lt;h3 id=&#34;41-html&#34;&gt;4.1 HTML&lt;/h3&gt;
&lt;p&gt;支持原生 HTML 语法，请写内联样式，如下：&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;display:block;text-align:right;color:orangered;&#34;&gt;橙色居右&lt;/span&gt;
&lt;span style=&#34;display:block;text-align:center;color:orangered;&#34;&gt;橙色居中&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&#34;42-uml&#34;&gt;4.2 UML&lt;/h3&gt;
&lt;p&gt;不支持，推荐使用开源工具&lt;code&gt;https://draw.io/&lt;/code&gt;制作后再导入图片&lt;/p&gt;
&lt;h2 id=&#34;5-致谢&#34;&gt;5 致谢&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;歌词经理 &lt;a href=&#34;https://github.com/lyricat/wechat-format&#34; title=&#34;灵感来源&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;wechat-fromat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;颜家大少 &lt;a href=&#34;http://md.aclickall.com/&#34; title=&#34;MdA2All&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;MD2All&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;10&#34;&gt;&lt;/h3&gt;
&lt;p&gt;REF:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://markdown.com.cn/basic-syntax/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Markdown 基本语法 | Markdown 官方教程&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>markdown工具绘图</title>
      <link>https://liaolile.com/post/tools/markdown%E7%BB%98%E5%9B%BE/</link>
      <pubDate>Fri, 04 Dec 2020 21:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tools/markdown%E7%BB%98%E5%9B%BE/</guid>
      <description>&lt;p&gt;[toc]&lt;/p&gt;
&lt;p&gt;千言万语不如一张图 &lt;code&gt;Express yourself by Pic&lt;/code&gt;&lt;/p&gt;
&lt;p&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/06/03/7qibJsPXy9ZdaW3.png&#34; alt=&#34;image-20220603155904263&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Markdown可以绘制各种不同的图，依赖于&lt;code&gt;mermaid&lt;/code&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;h4 id=&#34;flowchart&#34;&gt;Flowchart&lt;/h4&gt;
&lt;p&gt;Flowchart 都由&lt;strong&gt;节点&lt;/strong&gt;、几何形状和&lt;strong&gt;边缘&lt;/strong&gt;、箭头或线条组成。mermaid代码定义了这些&lt;strong&gt;节点&lt;/strong&gt;和&lt;strong&gt;边&lt;/strong&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;ol&gt;
&lt;li&gt;
&lt;p&gt;可能的flowchart 方向是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TB - 从上到下&lt;/li&gt;
&lt;li&gt;TD - 自上而下/与自上而下相同&lt;/li&gt;
&lt;li&gt;BT - 自下而上&lt;/li&gt;
&lt;li&gt;RL - 从右到左&lt;/li&gt;
&lt;li&gt;LR——从左到右&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;实例：&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;flowchart  LR  
	id1([start]) --&gt; id2[需求基线确定] --&gt; id3[内部需求变更]--&gt;id4{是否对实际业务产生影响}
	id4--&gt;|no|id5{是否接受当前版本变更} --&gt;|no|id6[下一个版本]
	id4--&gt;|yes|id7[与客户协商需求变更]--&gt;id8[客户需求变更流程]
	id5--&gt;|yes|id9[更新需求文档]--&gt;id10[通知项目组开发测试]--&gt;id11([需求变更备案])
&lt;/div&gt;
&lt;h4 id=&#34;sequence&#34;&gt;Sequence&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;-&amp;raquo; 代表实线箭头，&amp;ndash;&amp;raquo; 则代表虚线箭头&lt;/li&gt;
&lt;li&gt;-&amp;gt;直线，&amp;ndash;&amp;gt;虚线&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;mermaid&#34;&gt;sequenceDiagram
李雷 -&gt; 韩梅梅: Hello 梅梅, How are you?
Note right of 韩梅梅: 韩梅梅心想
韩梅梅 --&gt; 李雷: I&#39;m fine, thanks, and you?
&lt;/div&gt;
&lt;h4 id=&#34;gantt&#34;&gt;Gantt&lt;/h4&gt;
&lt;div class=&#34;mermaid&#34;&gt;gantt
        dateFormat  YYYY-MM-DD
        title 快乐的生活
        section 吃一把鸡就学习
        学习            :done,    des1, 2014-01-06,2014-01-09
        疯狂学习               :active,  des2, 2014-01-09, 3d
        继续疯狂学习               :         des3, after des2, 5d
        吃鸡！               :         des4, after des3, 4d
        section 具体内容
        学习Python :crit, done, 2014-01-06,72h
        学习C++          :crit, done, after des1, 2d
        学习Lisp             :crit, active, 3d
        学习图形学        :crit, 4d
        跳伞           :2d
        打枪                      :2d
&lt;/div&gt;
&lt;h4 id=&#34;classdiagram&#34;&gt;ClassDiagram&lt;/h4&gt;
&lt;div class=&#34;mermaid&#34;&gt;
classDiagram

  Class01 &lt;|-- AveryLongClass: Cool
  &lt;&lt;interface&gt;&gt; Class01
  Class09--&gt;C2: Where am i?
  Class09 --* C3
  Class09 --|&gt; Class07
  Class07: equals()
  Class07: Object[] elementData
  Class01: size()
  Class01: int chimp
  Class01: int gorilla
  class Class10 {
  &lt;&lt;service&gt;&gt;
  int id
  size()
 }
&lt;/div&gt;
&lt;h4 id=&#34;statediagram&#34;&gt;StateDiagram&lt;/h4&gt;
&lt;div class=&#34;mermaid&#34;&gt;stateDiagram

  [*]--&gt;Active
  state Active {
    [*]--&gt;NumLockOff
    NumLockOff--&gt;NumLockOn : EvNumLockPressed
    NumLockOn--&gt;NumLockOff : EvNumLockPressed
    --
    [*]--&gt;CapsLockOff
    CapsLockOff--&gt;CapsLockOn : EvCapsLockPressed
    CapsLockOn--&gt;CapsLockOff : EvCapsLockPressed
    --
    [*]--&gt;ScrollLockOff
    ScrollLockOff--&gt;ScrollLockOn : EvCapsLockPressed
    ScrollLockOn--&gt;ScrollLockOff : EvCapsLockPressed
       }
&lt;/div&gt;
&lt;h4 id=&#34;erdiagram&#34;&gt;ErDiagram&lt;/h4&gt;
&lt;div class=&#34;mermaid&#34;&gt;erDiagram
  CUSTOMER ||--o{ORDER : places
  ORDER ||--|{LINE-ITEM : contains
  CUSTOMER}|..|{DELIVERY-ADDRESS : uses
&lt;/div&gt;
&lt;h4 id=&#34;gitgraph&#34;&gt;GitGraph&lt;/h4&gt;
&lt;div class=&#34;mermaid&#34;&gt;gitGraph:
options
{
&#34;nodeSpacing&#34;: 150,
&#34;nodeRadius&#34;: 15
}
end
commit
branch lelandBranch
checkout lelandBranch
commit
commit
checkout master
commit
commit
commit
merge lelandBranch
&lt;/div&gt;
&lt;h4 id=&#34;pie&#34;&gt;Pie&lt;/h4&gt;
&lt;div class=&#34;mermaid&#34;&gt;pie

title Key elements in Product X
&#34;Calcium&#34; : 42.96
&#34;Potassium&#34; : 50.05
&#34;Magnesium&#34; : 10.01
&#34;Iron&#34; : 5
&lt;/div&gt;
&lt;h4 id=&#34;journey&#34;&gt;Journey&lt;/h4&gt;
&lt;p&gt;展示了不同用户要做的步骤信息，可以展示当前的工作流&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Task name: &lt;score&gt;: &lt;comma separated list of actors&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;mermaid&#34;&gt;journey

title My working day
    section Go to work
        Make tea: 5: Me
        Go upstairs: 3: Me
        Do work: 1 : Me, Cat

    section Go home
        Go downstairs: 5: Me
        Sit down: 3: Me
&lt;/div&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://blog.csdn.net/qq_36075612/article/details/118161100?spm=1001.2101.3001.6661.1&amp;amp;utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-118161100-blog-121381426.pc_relevant_scanpaymentv1&amp;amp;depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-118161100-blog-121381426.pc_relevant_scanpaymentv1&amp;amp;utm_relevant_index=1&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;使用Typora画 流程图、时序图、顺序图、甘特图、等图详解_Ch_champion的博客-CSDN博客_typora 时序图&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://blog.csdn.net/acktomas/article/details/124644100&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;mermaid流程图语法教程_acktomas的博客-CSDN博客_mermaid 流程图&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>测试的概念</title>
      <link>https://liaolile.com/post/tech/test/%E6%B5%8B%E8%AF%95%E7%9A%84%E6%A6%82%E5%BF%B5/</link>
      <pubDate>Fri, 04 Dec 2020 21:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/test/%E6%B5%8B%E8%AF%95%E7%9A%84%E6%A6%82%E5%BF%B5/</guid>
      <description>&lt;p&gt;&lt;code&gt;Test Double&lt;/code&gt; [^1]is a generic term for any case where you replace a production object for testing purposes.&lt;/p&gt;
&lt;p&gt;我们使用&lt;code&gt;Test Double&lt;/code&gt;替代真实的依赖组件去和待测系统进行交互，&lt;code&gt;Test Double&lt;/code&gt;不必和真实的依赖组件的实现一模一样，比如不用去实现依赖组件复杂的内部逻辑等，我们只需要在满足测试需求范围内，确保对于待测系统来说&lt;code&gt;Test Double&lt;/code&gt;提供的API是和依赖组件提供的一样的，API是怎么实现的在这个上下文就显得不重要了。多用于自动化测试比如单元测试和集成测试。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Test Stub, you can define answers to me, I will respond the same&lt;/p&gt;
&lt;p&gt;Stubs会按照我们设计的输出与待测系统进行交互， 这个桩既不会与测试用例(代码)交互，也不会在待测系统内部进行验证。&lt;code&gt;Test Stub&lt;/code&gt;常用于响应待测系统的请求，然后返回特定的值。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hard Coded Test Stub&lt;/li&gt;
&lt;li&gt;Configurable Test Stub&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;UserCase：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;依赖组件无法使用，影响测试结果&lt;/li&gt;
&lt;li&gt;依赖组件响应太慢，影响测试速度&lt;/li&gt;
&lt;li&gt;成为响应者，需要给系统注入特定的数据，从而影响被测试系统&lt;/li&gt;
&lt;li&gt;成为破坏者，需要给系统注入无效的数据，从而对系统产生异常响应&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mock Object，you can set expectation on me and pre-programmed with expectations which form a specification of the calls they are expected to receive.&lt;/p&gt;
&lt;p&gt;Mocks是一个完全代替待测系统的组件，并且应用于验证待测系统输出的对象。这个对象接受待测系统的输入，同时返回输出给到待测系统，然后进行验证。其一个重要特点是可以对无法在待测系统上直接被观察到的行为或输出进行验证。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fake Object，you can have me with limited capabilities and working implements, but usually take some shortcut and have simplified version of production code, make it not suit for production (InMemeoryTestDatabase for example)&lt;/p&gt;
&lt;p&gt;Fakes是指一个轻量级的完全代替待测系统依赖组件的对象，采用更加简洁的方法实现组件的功能。轻量级是指仅仅提供和依赖组件一样的功能接口保证待测系统正常工作，不需要具有真实依赖组件的很多特性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Test Spy，are stubs, monitor real ones，you can change my behavior. Record some information based on how they called.&lt;/p&gt;
&lt;p&gt;Spies是指一个待测系统依赖组件的替身，并且捕捉和保存待测试对象对依赖系统的输出，这个输出是会用于测试代码中的验证。主要用于记录和验证待测试对象对依赖系统的输出。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dummy Object，pass around but never actually used，usually used to fill parameter lists&lt;/p&gt;
&lt;p&gt;Dummies是指为了调用被测试方法而传入的假参数，实际上传入的参数不会对测试有任何作用，仅仅是为了成功调用被测试方法，又被称为Placeholder。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;REF&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;[^1]： &lt;a href=&#34;https://martinfowler.com/bliki/TestDouble.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;TestDouble (martinfowler.com)&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>高效率系统办公</title>
      <link>https://liaolile.com/post/tools/%E9%AB%98%E6%95%88%E7%8E%87%E5%8D%8F%E5%90%8C%E5%8A%9E%E5%85%AC/</link>
      <pubDate>Fri, 04 Dec 2020 21:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tools/%E9%AB%98%E6%95%88%E7%8E%87%E5%8D%8F%E5%90%8C%E5%8A%9E%E5%85%AC/</guid>
      <description>&lt;p&gt;在Windows下工作的效率问题，对于公司和家里都有物理PC机器，也有笔记本，希望在某些时候笔记本具有移动特性的也能够方便的获取到对应应用和数据；在这块的切换，由于各个电脑上安装的内容均不同，且有所变化，导致存在切换的时候要找到的东西内容比较少；&lt;/p&gt;
&lt;p&gt;当前的系统使用的是win10，对于远程桌面这种只能说体验很差，毕竟是两个隔离的环境，而目的是两个环境的一致；同时由于公司是内网，家里是外网，也就是有4台机器数据涉及同步；&lt;/p&gt;
&lt;p&gt;不同的环境保持相同的操作习惯，对于效率的提升无非是有益的。PC和笔记本是瘦客户端，而仅仅是账号、配置等的管理；&lt;/p&gt;
&lt;p&gt;主要的矛盾：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个机器上的应用不同；&lt;/li&gt;
&lt;li&gt;每个机器上对应的数据也不同；&lt;/li&gt;
&lt;li&gt;缺少自动化的手段维持一致性；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;主要解决的问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;实现应用（版本）和数据的一致性，包括安装路径、数据文件路径等、定义规范；&lt;/li&gt;
&lt;li&gt;应用的配置（比如ssl证书等）和安装自动化；&lt;/li&gt;
&lt;li&gt;在自动化手段不够的时候，能够迅速的通过指引找到维持一致性；&lt;/li&gt;
&lt;li&gt;各个&lt;strong&gt;环境账号密码的统一管理&lt;/strong&gt;，不要每个环境都输入密码，以及验证码统一手机；&lt;/li&gt;
&lt;li&gt;在某些场景下找到第三方，实现数据的直接访问，而不需要在多个设备上同步；&lt;/li&gt;
&lt;li&gt;能够快速恢复想要的环境，环境可以在新机上一键拉起；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;场景化：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;办公，办公主要是设计文档、代码调测等需要，以及公司ilearning资源的学习；&lt;/li&gt;
&lt;li&gt;日常，主要是写作博客，积累日常生活中最本质的一些内容；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;公共&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;git，主要用于实现代码和数据的同步能力，在公司依赖codehub，在家依赖gitee；这个都是小数据量的场景；
&lt;ul&gt;
&lt;li&gt;私仓管理，对于个人数据的备份；&lt;/li&gt;
&lt;li&gt;云端管理，对于应用的部署、代码的管理，同时能够往第三方私仓备份；&lt;/li&gt;
&lt;li&gt;备份管理遵循：云服务-&amp;gt;本地备份-&amp;gt;云端备份（自动化，集中化）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;浏览器，Edge数据；&lt;/li&gt;
&lt;li&gt;写作，Typora，基于Markdown的写作；
&lt;ul&gt;
&lt;li&gt;PicGo&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;效率工具utools，everything，beyondCompare&lt;/li&gt;
&lt;li&gt;Idea系列
&lt;ul&gt;
&lt;li&gt;maven/jdk/go-sdk&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;截图软件，snipaste&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;办公&lt;/strong&gt;（更多的是公司）&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数据库连接，navicat&lt;/li&gt;
&lt;li&gt;远程连接，xshell和tabby，xshell主要是现网问题登录问题，tabby主要是日常命令行工具&lt;/li&gt;
&lt;li&gt;onebox，大文件备份同步（关于应用软件，同一版本）&lt;/li&gt;
&lt;li&gt;wenote，云笔记&lt;/li&gt;
&lt;li&gt;Edraw，绘图工具；&lt;/li&gt;
&lt;li&gt;关于测试工具；关于文本工具；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;日常&lt;/strong&gt;（更多的是家庭）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;翻墙Latern，用于github经常访问失败的问题；&lt;/li&gt;
&lt;li&gt;weizhiNote，云笔记；&lt;/li&gt;
&lt;li&gt;本地命令行工具，tabby，通过这个使一切自动化；&lt;/li&gt;
&lt;li&gt;坚果云平台&lt;/li&gt;
&lt;li&gt;fastgithub_win-x64，快速访问github的能力&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于手动数据的合并，怎么通过git管理其差异；比如Edge的书签内容，如何定时的自动化同步；&lt;/p&gt;
&lt;p&gt;本地文件夹设计&lt;/p&gt;
&lt;p&gt;原则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数字前缀，多个单词间下划线分割，全小写；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;p&gt;0_leland  个人重要的数据文件，需要往第三方定时备份的内容（非大文件）；&lt;/p&gt;
&lt;p&gt;1_config  应用的配置以及环境的配置；&lt;/p&gt;
&lt;p&gt;99_backup 云端重要内容，需要往云服务器定时拉取到本地，然后定时备份到第三方的内容；&lt;/p&gt;
&lt;p&gt;apps 应用程序&lt;/p&gt;
&lt;p&gt;software 应用程序安装位置；&lt;/p&gt;
&lt;p&gt;download 所有下载文件的路径；&lt;/p&gt;
&lt;p&gt;Ref:&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%E4%B8%AD%E6%A6%82%E5%BF%B5/</link>
      <pubDate>Sat, 18 Jul 2020 13: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%E4%B8%AD%E6%A6%82%E5%BF%B5/</guid>
      <description>&lt;p&gt;[toc]&lt;/p&gt;
&lt;p&gt;分布式技术理论涉及范围广，包括系统开发、架构设计、网络通信等，本篇聚焦介绍在分布式系统中大家需要理解的一些概念。&lt;/p&gt;
&lt;p&gt;该篇文章会持续的更新，以期覆盖更全的内容概念。&lt;/p&gt;
&lt;h4 id=&#34;1系统开发&#34;&gt;1、系统开发&lt;/h4&gt;
&lt;ul&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;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;具体指应用对于请求的处理，同步时在收到请求/调用时候在没有得到结果之前，就不会返回结果。而异步调用会瞬间返回，但是异步返回的内容并不代表任务处理完成了，往往需要回调或者其他方式在任务完成后通知调用防。如WebFlux框架支持的异步；&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;2架构设计&#34;&gt;2、架构设计&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;高并发&lt;/p&gt;
&lt;p&gt;通过设计保证系统能够同时并行处理很多请求。也就是同时间点，很多用户同时访问系统的能力。常用的指标如TPS/QPS来衡量。&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;冷备为一台运行，另一台不运行作为备份，应对其中一台宕机后使用。冷备需要主动切换服务。而热备是active/standby，当active服务出现故障，通过检测手段发现后激活standby，确保短时间内服务完全恢复正常使用。&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;web服务器架构中，静态页面和动态页面，静态内容接口和动态内容接口分开不同系统访问的架构设计方法，进而提升整个服务访问性能和可维护性。&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;CAP理论&lt;/p&gt;
&lt;p&gt;在分布式系统中，Consistency、Availability、Partition Tolerance不能同时成立。一致性要求同一时刻点，分布式系统的所有的数据备份都相同或处于同一状态；可用性要求系统集群一部分节点宕机后，系统依然能够正确的响应用户的请求。分区容错性是需要系统能够容忍节点之间网络通信的故障。由于分布式系统分区是存在的，往往在一致性和可用性之间做出选择；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BASE理论&lt;/p&gt;
&lt;p&gt;Basically Available/Soft State/Eventually consisitence，对于CAP理论的扩充，对一致性和可用性进行权衡的结果。我们无法做到强一致，但每个应用都可以根据自身的业务特点，采用适当的方式使系统达到最终一致性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;水平扩展/垂直扩展/Z轴扩展&lt;/p&gt;
&lt;p&gt;水平扩展就是scale out更多的实例来分散负载，提升存储能力和计算能力。垂直扩展scale up通过提升单机硬件性能或者软件/架构性能来达到；Z轴扩展时依据sharding对于数据进行分片，让其路由到对应的sharding上进行数据的获取。或者说时Cell架构的扩容；&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;3网络通信&#34;&gt;3、网络通信&lt;/h4&gt;
&lt;ul&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;均值TCP连接，长连接就是建立TCP连接后，一直保持这个连接，在此期间通过发送心跳来确认双方的存在，中间会做多次业务数据传输，一般不会主动断开连接。短连接一般就指连接建立后，执行一次事务后，然后关掉这个连接。&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;NAT&lt;/p&gt;
&lt;p&gt;网络地址转换，替换IP报文头部的地址信息。NAT通常部署在网络出口位置，通过内部IP地址替换为出口IP地址提供公网可达性和上层协议的连接能力。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;4故障异常&#34;&gt;4、故障异常&lt;/h4&gt;
&lt;ul&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;coredump&lt;/p&gt;
&lt;p&gt;程序出现异常而中断的时，OS会把程序的当前工作状态存储为一个coredump文件，通常情况下，该文件包含了程序运行时的内存、寄存器状态、堆栈指针，内存管理信息等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缓存穿透/击穿/雪崩&lt;/p&gt;
&lt;p&gt;穿透指查询一个一定不存在的数据，而导致流量积压到数据库上上旬；击穿指某个热点key过期时候，而这个时候大量该key的并发请求而导致流量也聚集到数据库上；雪崩指缓存中大批量到过期时间，而查询数据量大导致数据库压力过大的情况；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内存溢出/内存泄漏&lt;/p&gt;
&lt;p&gt;内存溢出指程序申请内存时，没有足够的内存供申请者使用，此时回报OOM的失败；内存泄露指的时动态分配的堆内存由于某种原因程序未释放或无法释放，造成系统内存的浪费，导致程序运行速度减慢甚至崩溃。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;句柄泄露&lt;/p&gt;
&lt;p&gt;进程在调用系统文件后，没有释放已经发开的文件句柄。操作系统的交互是通过获取文件句柄来实现的，一般泄露后，机器变慢，CPU飙升；&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;短暂某一时刻，服务器性能的指标比如IO/CPU远大于该时刻前后时间段。毛刺的出现代表服务器资源利用不均匀，不充分容易诱发其他更严重的问题。&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;5监控告警&#34;&gt;5、监控告警&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;服务监控&lt;/p&gt;
&lt;p&gt;主要目的是服务出现故障或问题时候能够准确快速的发现，避免产生更大范围的影响。可以分为系统层包括主机的一些CPU\磁盘等指标，应用层包括进程状态、吞吐量，业务层包括业务自定义的指标，服务响应类等，用户层关注在用户行为、舆情监控等；&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;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;6服务治理&#34;&gt;6、服务治理&lt;/h4&gt;
&lt;ul&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;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;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;
</description>
    </item>
    
    <item>
      <title>未来, 你好</title>
      <link>https://liaolile.com/post/life/%E6%9C%AA%E6%9D%A5%E4%BD%A0%E5%A5%BD/</link>
      <pubDate>Tue, 31 Mar 2020 23:13:00 +0000</pubDate>
      <guid>https://liaolile.com/post/life/%E6%9C%AA%E6%9D%A5%E4%BD%A0%E5%A5%BD/</guid>
      <description>&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/05/15/yVtwJRAK5x1ujNs.jpg&#34; alt=&#34;Snipaste_2022-03-12_15-08-50&#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;如果我用右脑用得多一点，我会相信爱是一切的基础。但礼物只有打开了才算是礼物，所以未来怎样，我也不清楚。&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;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;</description>
    </item>
    
    <item>
      <title>Hugo Todo</title>
      <link>https://liaolile.com/post/tools/hugo-todo/</link>
      <pubDate>Tue, 04 Jun 2019 12:35:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tools/hugo-todo/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;友链&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.tencent.com/developer/article/1944132&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hugo博客添加友链 - 云+社区 - 腾讯云 (tencent.com)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hutusi.com/links/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;友链 | 胡涂说 (hutusi.com)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://iamgodot.com/about/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Godot&amp;rsquo;s Blog (iamgodot.com)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.sulvblog.cn/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Sulv&amp;rsquo;s Blog (sulvblog.cn)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;支持&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://nodogmablog.bryanhogan.net/support/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Support this site | no dogma blog (bryanhogan.net)&lt;/a&gt;&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/05/22/Mzav2DrgPqfmeoE.png&#34; alt=&#34;image-20220522075405309&#34; style=&#34;zoom:67%;&#34; /&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://huhuaping.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Academic (huhuaping.com)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;分发&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/crawlab-team/artipub&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;crawlab-team/artipub: Article publishing platform that automatically distributes your articles to various media channels (github.com)&lt;/a&gt; ArtiPub (Article Publisher 的简称，意为 &amp;ldquo;文章发布者&amp;rdquo;) 是一款开源的一文多发平台，可以帮助文章作者将编写好的文章自动发布到掘金、SegmentFault、CSDN、知乎、开源中国等技术媒体平台，传播优质知识，获取最大的曝光度。ArtiPub 安装简单，提供了多种安装方式，可以一键安装使用，安装一般只要 5 分钟。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;持续集成&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://app.netlify.com/sites/dapper-kringle-21e9eb/settings/domain&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Domain management | Site settings (netlify.com)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(统计分析) &lt;a href=&#34;https://github.com/electerious/Ackee&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/electerious/Ackee&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&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;/li&gt;
&lt;/ul&gt;
&lt;p&gt;云原生领域大神，赵化冰&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/zhaohuabing/hugo-theme-cleanwhite&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;zhaohuabing/hugo-theme-cleanwhite: A clean, elegant blog theme for hugo (github.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.zhaohuabing.com/post/2021-09-26-hugo-theme-clean-white/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hugo Theme: CleanWhite-赵化冰的博客 | Zhaohuabing Blog&lt;/a&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;云原生社区官方网站源码参考学习，基于Hugo：&lt;a href=&#34;https://github.com/cloudnativeto/cloudnative.to&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;cloudnativeto/cloudnative.to: Source code of cloudnative.to (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>Linux的命令学习</title>
      <link>https://liaolile.com/post/tools/linux%E5%91%BD%E4%BB%A4/</link>
      <pubDate>Tue, 04 Jun 2019 12:35:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tools/linux%E5%91%BD%E4%BB%A4/</guid>
      <description>&lt;ol&gt;
&lt;li&gt;关于关键字在对应的目录中查找出对应的文件&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find . -type f &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;xargs grep &lt;span class=&#34;s2&#34;&gt;&amp;#34;Liao lile work&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;查询某个时间以后修改的文件列表&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find ./ -newermt &lt;span class=&#34;s1&#34;&gt;&amp;#39;2022-05-18 23:46:43&amp;#39;&lt;/span&gt; -type f &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;xargs ls -ltr  --full-time
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;
&lt;p&gt;关于linux的控制台颜色定制&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;在~/.bashrc文件中保存下述的内容；&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git_branch&lt;span class=&#34;o&#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;nv&#34;&gt;branch&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;git rev-parse --abbrev-ref HEAD 2&amp;gt;/dev/null&lt;span class=&#34;sb&#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;o&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;branch&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; !&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#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;then&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;o&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;branch&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(no branch)&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#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;then&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;nv&#34;&gt;branch&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;(`git rev-parse --short HEAD`...)&amp;#34;&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;fi&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;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$branch&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;)&amp;#34;&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;fi&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;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PS1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;debian_chroot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:+(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$debian_chroot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\[\033[00;34;1m\]\u\[\033[00;34;1m\]@\[\033[00;34;1m\]\h\[\e[37;1m\]:\[\033[00;34;1m\]\w\[\033[01;36;1m\] \$(git_branch)\[\e[35;1m\] \$\[\e[35;1m\] &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&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://blog.csdn.net/qq_41009742/article/details/85009432&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Linux下使用git设置显示分支名称和改变颜色_犹有傲霜枝的博客-CSDN博客_git分支颜色&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>Hugo环境搭建</title>
      <link>https://liaolile.com/post/tools/hugo%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</link>
      <pubDate>Sat, 04 May 2019 11:35:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tools/hugo%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</guid>
      <description>&lt;p&gt;[toc]&lt;/p&gt;
&lt;h3 id=&#34;hugo是什么&#34;&gt;Hugo是什么？&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Hugo以速度快著称，号称是世界上最快的网站生成框架。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当前放弃了WordPress作为博客的选择！😂😂 体验不够优雅顺滑！其技术栈复杂，用到了mysql, php-fpm, openresty以及wordpress本身，而且wordpress本身一大堆的插件，2U2G的机器不足以容纳如此重的内容；&lt;/p&gt;
&lt;p&gt;下述文档仅记录Hugo环境搭建过程需要注意的内容，以备后续查阅需要。&lt;/p&gt;
&lt;!---more--&gt;
&lt;h3 id=&#34;faq&#34;&gt;FAQ&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;关于nginx ssl 证书的获取&lt;/p&gt;
&lt;p&gt;当前的方案是参考在阿里云申请的免费ssl证书&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;为了避免繁琐的证书到期而切换，希望有一种方法能够自动化实现证书的定期更新，因而找到了另外在skyao的博客中提及的内容&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;/li&gt;
&lt;li&gt;
&lt;p&gt;对于nginx的80端口和443端口&lt;/p&gt;
&lt;p&gt;对于服务能够对外提供既能够提供https, 也能够提供http服务；默认https走的443端口，而http走的80端口,可以按照如下的配置使http的请求都会跳转到对应的https&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-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&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;kn&#34;&gt;listen&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;80&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;kn&#34;&gt;server_name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;liaolile.com&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;www.liaolile.com&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;kn&#34;&gt;rewrite&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;^(.*)&lt;/span&gt;$  &lt;span class=&#34;s&#34;&gt;https://&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$host$1&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;permanent&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关于当前Hugo国际化i18n配置&lt;/p&gt;
&lt;p&gt;需要在hugo的根目录下进行&lt;strong&gt;i18n&lt;/strong&gt;目录的创建，并且在其中加上对应的zh.toml配置文件，用于国际化内容替换&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/05/14/k8NHChwJgrUB4Xp.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;/li&gt;
&lt;li&gt;
&lt;p&gt;关于高效的写作环境
使用的是Typora + PicGo + SM.MS 三个配合进行使用&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;，其中Typora为Markdown写作编辑器，体验不错；PicGo主要用于处理当前Markdown文档中图片自动落床的问题，其会把Markdown文档中插入的图片自动上传到SM.MS图床服务账号中，为啥不选gitee作为图床呢，当前遇到了一些坑，服务端一直报403。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关于hugo academic主题&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;acadmic主题的地址是：&lt;a href=&#34;https://github.com/wowchemy/starter-hugo-academic&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;start-hugo-academic&lt;/a&gt;，类似于springboot的一键式集成，其对应的主题实际是在go.mod中指定的github.com/wowchemy/wowchemy-hugo-modules/wowchemy/v5 ，主题会下载到本地，因而主题的定制需要在对应的本地文件中。&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/05/21/q7wh9jFylQ8GeP3.png&#34; alt=&#34;image-20220521094822726&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;该wowchemy/v5主题中很多资源引用的cdn.jsdelivr.net的资源，但是目前其资源由于dns污染，在中国加载有问题&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;，所以需要切换对静态资源加载的地址，主要的资源地址配置在&lt;code&gt;/opt/blog/hugo-theme&lt;/code&gt;/wowchemy/wowchemy-hugo-modules/wowchemy/data/assets.toml文件中，其中上述加粗/opt/blog/hugo-theme是对应的主题的本地路径。该文件中主要有两种资源：cdn.jsdelivr.net/npm和cdn.jsdelivr.net/gh资源（github静态资源托管），其中https://cdn.jsdelivr.net/npm资源替换为https://unpkg.com/, cdn.jsdelivr.net/gh暂时找不到对应的替换cdn地址，只能去github上下载对应的源码文件并且托管到自身的服务器上，如下是参考：&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/05/21/feibZHkVYhjpBJM.png&#34; alt=&#34;image-20220521100110619&#34; style=&#34;zoom:50%;&#34; /&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于出现替换本地文件后出现Failed to find a valid digest in the &lt;strong&gt;&amp;lsquo;integrity&amp;rsquo;&lt;/strong&gt; attribute for resource &amp;lsquo;&lt;a href=&#34;https://liaolile.com/js/local/cdn.jsdelivr.net/gh/krisk/Fuse@v3.2.1/dist/fuse.min.js%27&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://liaolile.com/js/local/cdn.jsdelivr.net/gh/krisk/Fuse@v3.2.1/dist/fuse.min.js&#39;&lt;/a&gt; with computed SHA-512 integrity &amp;lsquo;&lt;strong&gt;tm9sNooEMtnClt+Dyrr0YPWwlOdUSm9/y97x0WjXHahG7QyPXs334pApMrY2cxitrW5zZIDCHveVvvgHfJS9uQ==&lt;/strong&gt;&amp;rsquo;. The resource has been blocked.问题，直接找到对应的文件的sri值，替换为对应的SHA-512值即可。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关于分享集成&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对于share.js的集成，参考相关的帖子&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;，同时对应share.js的github地址可供相关的定制使用参考：&lt;a href=&#34;https://github.com/overtrue/share.js&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;overtrue/share.js: 一键分享到微博、微信&lt;/a&gt;。界面相关的一些其他的定制，均可参考该帖子，方法类似；当前微信的分享标签在手机端是不显示的，因为手机端的app一般都有分享的控件直接进行控制；网页版效果如下：&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/05/22/djfWxKlQOzBi9aI.png&#34; alt=&#34;image-20220522213142045&#34; style=&#34;zoom:50%;&#34; /&gt;
&lt;p&gt;修改/opt/blog/hugo-theme/wowchemy/wowchemy-hugo-modules/wowchemy/layouts/partials/page_footer.html，放上自己定义的share.html嵌入；&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/05/29/qOAcLinBmCTyatl.png&#34; alt=&#34;image-20220527230558677&#34; style=&#34;zoom:67%;&#34; /&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关于author微信二维码的图片，当前尚无现有的方法进行集成，需要自行写js以及插入到对应的html界面中。获取当前微信头像的悬浮事件，然后绑定图像呈现在对应的下方；当前所有的社交icon均在&lt;strong&gt;network-icon&lt;/strong&gt; class中定义的（当前有两个地方引用，一个是author的个人简介部分，一个是每篇文章的末尾介绍），需要把相关的js加载的，并且把二维码渲染绑定到.fa-weixin上。如下图：&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/05/22/Hrw7ZJqUFynOmLV.png&#34; alt=&#34;文章后面的社交媒体账号信息&#34; style=&#34;zoom:50%;&#34; /&gt;
&lt;p&gt;对应的需要修改的html对应的文件是：&lt;code&gt;/opt/blog/hugo-theme/wowchemy/wowchemy-hugo-modules/wowchemy/layouts/partials/social_link.html&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;新增下述红色内容：&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-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/js/jquery.js&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;/script&amp;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;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/js/self.js&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;img src=&#34;https://s2.loli.net/2022/05/29/59oYdxThEilVJPZ.png&#34; alt=&#34;image-20220527225350013&#34; style=&#34;zoom: 67%;&#34; /&gt;
&lt;img src=&#34;https://s2.loli.net/2022/05/22/FVM2hxTvB3ntDrW.png&#34; alt=&#34;个人简介的社交媒体账号信息&#34; style=&#34;zoom:50%;&#34; /&gt;
&lt;p&gt;对应的需要修改的html对应的文件是：&lt;code&gt;/opt/blog/hugo-theme/wowchemy/wowchemy-hugo-modules/wowchemy/layouts/partials/widgets/about.html&lt;/code&gt;，也是新增自定的js脚本&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/05/29/eCBpTSyaVGrjqf3.png&#34; alt=&#34;image-20220527230303178&#34; style=&#34;zoom:67%;&#34; /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关于文章内容加密&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hugo-Encryptor&lt;/strong&gt;&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; 是一款能够帮助作者保护文章内容的工具。它使用 AES-256 来对文章的内容进行加密，并且通过在文章中嵌入内联 &lt;code&gt;JavaScript&lt;/code&gt; 代码来验证读者输入的密码是否正确。没有正确的文章密码，读者将无法看到文章的加密内容&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;遇到如下的问题：&lt;/p&gt;
&lt;img src=&#34;https://s2.loli.net/2022/08/12/FhzjOD3KpPXbRGU.png&#34; alt=&#34;image-20220812001935062&#34; style=&#34;zoom:67%;&#34; /&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;参考&#34;&gt;参考&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://blog.csdn.net/m0_37969197/article/details/106330622&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;阿里云免费SSL证书配置（图文详解）_老吉丶的博客-CSDN博客_阿里云免费ssl证书&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://skyao.io/learning-hugo/docs/installation/https.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;开启HTTPS | Hugo学习笔记 (skyao.io)&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://blog.csdn.net/sxf1061700625/article/details/107948323&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;使用Gitee作为Markdown的图床_小锋学长生活大爆炸的博客&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;li id=&#34;fn:4&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.csdn.net/u013014254/article/details/122045331&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;jsdelivr炸了如何解决|用这些免费cdn_地域男孩的博客-CSDN博客_jsdelivr&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#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:5&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://huangzhongde.cn/post/2020-02-22-hugo-blog-using-sharejs/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hugo集成Share.js一键分享插件 | 黄忠德的博客 (huangzhongde.cn)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#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:6&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/Li4n0/hugo_encryptor/blob/master/README-zh_CN.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;hugo_encryptor/README-zh_CN.md at master · Li4n0/hugo_encryptor (github.com)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#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:7&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://0n0.fun/post/2019/03/this-is-hugo-encryptor/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;这是一个Hugo文章加密工具 (0n0.fun)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#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/base/%E8%AE%A1%E7%AE%97%E6%9C%BA%E9%A2%86%E5%9F%9F%E7%9A%84%E5%AE%9A%E7%90%86/</link>
      <pubDate>Sun, 08 Apr 2018 21:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/base/%E8%AE%A1%E7%AE%97%E6%9C%BA%E9%A2%86%E5%9F%9F%E7%9A%84%E5%AE%9A%E7%90%86/</guid>
      <description>&lt;p&gt;&lt;code&gt;定律&lt;/code&gt;是为实践和事实所证明，反映事物在一定条件下发展变化的客观规律的论断。定律的特点，是可证，而且已经被不断证明。定律是一种理论模型，它用以描述特定情况、特定尺度下的现实世界，在其它尺度下可能会失效或者不准确。&lt;/p&gt;
&lt;p&gt;计算机领域存在很多经典的理论，由于之前没有系统的去梳理，所以大多是听过，然后后续再听的时候，嗯，是有这么一回事。但是要自己能够在对应的场景下去引用，去讲出来，就有些不够丰满。因而这篇主要关注怎么把这些计算机领域的定律，像故事一样的简单，总结起来。&lt;/p&gt;
&lt;p&gt;tl;dr&lt;/p&gt;
&lt;p&gt;康威定律可谓是软件架构设计中的第一定律，在《人月神话》这本软件圣经引用后被广泛推广。摩尔定律也是人们耳熟能详的，是计算机第一定律。&lt;/p&gt;
&lt;p&gt;另外还包括阿姆达尔Amdahl定律，奥卡姆剃刀原理。&lt;/p&gt;
&lt;p&gt;[toc]&lt;/p&gt;
&lt;h3 id=&#34;康威定律&#34;&gt;康威定律&lt;/h3&gt;
&lt;p&gt;1967年，马尔文·康威：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;设计系统的架构受制于生产这些设计的组织的沟通结构。&lt;/p&gt;
&lt;p&gt;Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;康威定律可以总结为4个定律：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;组织沟通方式会通过系统设计表达出来；&lt;/li&gt;
&lt;li&gt;时间再多一件事情也不可能做的完美，但总有时间做完一件事情；&lt;/li&gt;
&lt;li&gt;线型系统和线型组织架构间由潜在的异质同态特性；&lt;/li&gt;
&lt;li&gt;大的系统组织总是比小系统更倾向于分解；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;组织的沟通和系统的设计之间紧密相连，特别是复杂系统，解决好人与人的沟通才能由一个更好的系统设计。人员增加沟通成本呈指数增长的规律：沟通成本=n*(n-1)/2， n表示人的个数，n-1表示每个人据需要同剩下的n-&lt;/p&gt;
&lt;p&gt;1个人由交流，而沟通交流是双向的，所以会在此基础上除以2。&lt;/p&gt;
&lt;p&gt;对于团队我们应该追求小团队，为了整个系统的开发效率和最终产品结果。使用一切手段提升沟通效率，每个人每个系统有明确的分工。&lt;/p&gt;
&lt;p&gt;在软件开发中人手永远是不够的，事情也是永远做不完的，不可能做完没。面对这样的情况，敏捷开发可以做到不断迭代、持续交付、快速验证和反馈并持续的改进。再牛的开发也会写出bug，在全面的测试覆盖率也无法测出所有的问题，解决方案不是消灭这些问题，而是容忍一些问题的存在，然后通过适当的设计（冗余、监控、高可用）允许接受出错，当问题发生时能够快速解决。&lt;/p&gt;
&lt;p&gt;我们想要什么系统就搭建什么样的团队，反过来有什么样的团队就搭建什么样的系统。对于大的公司，架构不仅仅需要技术，还需要政治。这种政治说的是和他人协作将事情搞定的艺术，架构是一种社交活动，在技术世界里，个人主义很容易被打败即便目的是好的技术也是最有的技术。技术决策是也是政治决策，一个产品任何一个团队都可以做，但是对于选择任何一个都意味着局限。&lt;/p&gt;
&lt;h3 id=&#34;摩尔定律&#34;&gt;摩尔定律&lt;/h3&gt;
&lt;p&gt;1965年，戈登·摩尔：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;每个新芯片大体上包含其前任2倍的容量，每个芯片的生产都是在前一个芯片产生后的18-24个月内。计算能力相对于时间周期将呈指数式的上升。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;衍生出三个版本：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;集成电路芯片上所集成的电路的数目，每隔18个月就翻一番；&lt;/li&gt;
&lt;li&gt;微处理器的性能每隔18个月提高1倍，而价格下降1倍；&lt;/li&gt;
&lt;li&gt;用1个美元所能买大的电脑性能，每隔18个月翻两番；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更有一个安迪比尔定律。安迪给你的，比尔都会拿走。安迪是Intel创始人，比尔是微软的创始人，intel不断提高CPU的计算能力，微软就用新的操作系统来吃掉它，就是硬件性能的提高总会迅速的被新的软件消耗掉。&lt;/p&gt;
&lt;p&gt;相近的一个使维尔斯定律，其认为软件变慢的速度比硬件编码的速度更慢。&lt;/p&gt;
&lt;p&gt;同时有一个反摩尔定律，就是IT公司如果18个月后卖掉同样多的同样的产品，其营业额却要减少1半，需要所有的硬件和设备生产厂商都要追赶上摩尔定律的发展速度。&lt;/p&gt;
&lt;p&gt;目前GPU就是摩尔定律进入失效区间的一个创新，计算不仅仅依赖CPU。图形渲染单元和计算单元放在一个芯片上，因为它们不会同时被使用，所以发热问题得到缓解。GPU简化了控制单元和缓存，把有限的芯片上的空间让个了计算单元，通过牺牲延时换取了吞吐量。&lt;/p&gt;
&lt;h3 id=&#34;阿姆达尔定律--古斯塔夫森定律&#34;&gt;阿姆达尔定律 &amp;amp; 古斯塔夫森定律&lt;/h3&gt;
&lt;p&gt;阿姆达尔定律用于计算优化某一部分能够对整体产生的最大优化效果。在并行计算中，阿姆达尔定律主要用于预测使用多处理器的程序理论上所能达到的最大提速。
$$
{S}&lt;em&gt;{latency}(s)=1/(1-p+p/s)
$$
其中${S}&lt;/em&gt;{latency}$是任务整体执行过程的理论速度，s是任务中受益于系统性能提升的那一部分的加速，p是获益部分占用执行时间的比例。&lt;/p&gt;
&lt;p&gt;古斯塔夫森定律给出了任务执行时间固定时，通过提升系统性能所能达到的理论潜在加速。
$$
{S}&lt;em&gt;{latency}(s)=1-p+sp
$$
其中${S}&lt;/em&gt;{latency}$是整个任务执行过程的理论潜在加速，s是任务中受益于系统资源改进部分的潜在加速，p是系统资源改善之前收益部分占整个任务的执行工作量的比例。&lt;/p&gt;
&lt;p&gt;阿姆达尔定律假设问题大小固定，即执行的工作量不会随着资源的改善而改变。古斯塔夫森定律提出，程序员倾向于调整问题的大小以充分利用通过改善资源释放出的计算能力，更快的设备可以使用相同的时间解决更大的问题。&lt;/p&gt;
&lt;p&gt;阿姆达尔定律优化的目标是使程序在相同的工作负载下更快运行，古斯塔夫森定律意义在于改变了研究目的，选择或重构问题从而使用相同时间解决更大的问题，在相同的运行时间内实现更大的工作负载量。&lt;/p&gt;
&lt;h3 id=&#34;奥卡姆剃刀原理&#34;&gt;奥卡姆剃刀原理&lt;/h3&gt;
&lt;p&gt;14 世纪，逻辑学家奥卡姆的威廉：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如无必要，勿增实体&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不要浪费更多的东西去做，你可以用更少的东西做同样的事情。人们做的大部分事情可能没有意义，而隐藏在复杂事务中的一小部分是有意义的。复杂事情往往可以通过简单的方法解决，应该化繁为简，抓住重点，把我关键。&lt;/p&gt;
&lt;h3 id=&#34;扬尼斯定律&#34;&gt;扬尼斯定律&lt;/h3&gt;
&lt;p&gt;程序员的开发效率每6年会提高一倍。平均年提高16.6%，如果没有达标，则我们的价值其实是在下降16.6%。对于公司来说，6年内员工数量保持不变，如果营业额没有翻一倍，那么公司的利润其实是在下降。但是并不是所有的公司全员都是程序员。&lt;/p&gt;
&lt;h3 id=&#34;梅特卡夫定律&#34;&gt;梅特卡夫定律&lt;/h3&gt;
&lt;p&gt;一家网络的价值与它的用户数量的平方成正比。正式这一预言可以解释看似不可理解的信息现象，并帮助网络拥有者和价值投资者进行正确估值。&lt;/p&gt;
&lt;h3 id=&#34;尤尔互补性定律&#34;&gt;尤尔互补性定律&lt;/h3&gt;
&lt;p&gt;其指出如果两种属性或两种产品是互补品，其中一种互补品的价值/需求将与另一种互补品的价格成反比。也就是说，如果一种补品的价格降低，那另一种补品的需求就会增加。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The Consensus Algorithm - Raft</title>
      <link>https://liaolile.com/post/tech/distributesystem/consensus-protocol/</link>
      <pubDate>Wed, 04 Apr 2018 23:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/distributesystem/consensus-protocol/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;There is only one consensus protocol, and that&amp;rsquo;s Paxos - all other approaches are just broken versions of Paxos.
Ironic, hard enough to understand compared to the Raft.
There are significant gaps between the description of the Paxos algorithm and the needs of a real-world system. . . . the final system will be based on an un-proven protocol.
&lt;code&gt;--Chubby Implementer&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;tl;dr: &lt;a href=&#34;http://thesecretlivesofdata.com/raft/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Raft (thesecretlivesofdata.com)&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;what-is-raft&#34;&gt;What is Raft&lt;/h2&gt;
&lt;p&gt;Raft is a &lt;strong&gt;consensus algorithm&lt;/strong&gt; that is designed to be easy to understand. It&amp;rsquo;s equivalent to Paxos in fault-tolerance and performance. The difference is that it&amp;rsquo;s decomposed into relatively independent sub-problems, and it cleanly addresses all major pieces needed for practical systems. We hope Raft will make consensus available to a wider audience, and that this wider audience will be able to develop a variety of higher quality consensus-based systems than are available today.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Raft decomposes the consensus problem into &lt;em&gt;three relatively&lt;/em&gt; independent sub-problems:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Leader election&lt;/strong&gt;: a new leader must be chosen when starting the cluster and when an exsiting leader fails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Log replication&lt;/strong&gt;: the leader must accept log entries from clients and replicate them across the cluster, forcing the other logs to agree with its own.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Safety&lt;/strong&gt;: if any server has applied a particular log entry to its state machine,  then no other server may apply a different command for the same log index. (the State Machine Safety Property)&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;The basic elements of Raft show as belows:&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/05/15/X7gC2eyUYzaSQMi.png&#34; alt=&#34;raft_basic_elements&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;The main procedure of Raft depicted as follows:&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/05/15/vqhaDMj6EbcGoWe.png&#34; alt=&#34;raft_main&#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;Five things&lt;/strong&gt; to be determinately implemented:&lt;code&gt;&amp;lt;br/&amp;gt;&lt;/code&gt;
&lt;code&gt;Election safety&lt;/code&gt;, at most one leader can be elected in a given term.
&lt;code&gt;Leader append-only&lt;/code&gt;, never delete or overwrites entries, only append entries.
&lt;code&gt;Log matching&lt;/code&gt;, to be perfect
&lt;code&gt;Leader completeness&lt;/code&gt;, to be complete
&lt;code&gt;State machine safety&lt;/code&gt;, the only entry for the a given index.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ensure above the five properties  are correctly executed, then the Raft is achieved.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A Raft cluster contains several servers, five is a typical number and tolerates two failures at the same time.&lt;/p&gt;
&lt;p&gt;At a given time, each server is one of three states: leader, follower, or candidate.
In normal operation, only one leader and the others followers. Followers only respond to leader and candidates.
Leader handles all the client requests.
If a client contacts a follower, the follower will redirects it to the leader.
Candidates work when electing a new leader.&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/05/15/XErM9Dc1IsmZxBJ.png&#34; alt=&#34;raft_roles&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Time is divided into terms, and each term begins with election.
After election, the leader works for the rest of the term.
A new election will begin shortly after a split vote.
Raft ensures at most one leader in a  given term.&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/05/15/sTmRaKArpgyjq2L.png&#34; alt=&#34;raft_time_stream&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Different severs may observer the transitions between terms at different time, and in some situations a server may not observe an election or entire terms.
Terms act a logical clock, which allows servers to detect obsolete information such as stale leaders.
Each server stores a current-term number, which increases monotonically.&lt;/p&gt;
&lt;p&gt;Raft servers communicate use remote procedure calls (RPCs), two type of RPCs is need for the consensus algorithm: &lt;strong&gt;RequestVote RPCs and AppendEntries RPCs&lt;/strong&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The Consensus Algorithm - Raft</title>
      <link>https://liaolile.com/post/tech/distributesystem/%E5%88%86%E5%B8%83%E5%BC%8F%E5%85%B1%E8%AF%86%E7%AE%97%E6%B3%95/</link>
      <pubDate>Wed, 04 Apr 2018 23:23:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/distributesystem/%E5%88%86%E5%B8%83%E5%BC%8F%E5%85%B1%E8%AF%86%E7%AE%97%E6%B3%95/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;There is only one consensus protocol, and that&amp;rsquo;s Paxos - all other approaches are just broken versions of Paxos.
Ironic, hard enough to understand compared to the Raft.
There are significant gaps between the description of the Paxos algorithm and the needs of a real-world system. . . . the final system will be based on an un-proven protocol.
&lt;code&gt;--Chubby Implementer&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;拜占庭帝国想要进攻一个强大的敌人，为此派出了10支军队去包围这个敌人。这个敌人虽不比拜占庭帝国，但也足以抵御5支常规拜占庭军队的同时袭击。这10支军队在分开的包围状态下同时攻击。他们任一支军队单独进攻都毫无胜算，除非有至少6支军队（一半以上）同时袭击才能攻下敌国。他们分散在敌国的四周，依靠通信兵骑马相互通信来协商进攻意向及进攻时间。困扰这些将军的问题是，他们不确定他们中是否有叛徒，叛徒可能擅自变更进攻意向或者进攻时间。在这种状态下，拜占庭将军们才能保证有多于6支军队在同一时间一起发起进攻，从而赢取战斗？&lt;/p&gt;
&lt;p&gt;拜占庭将军问题中并不去考虑通信兵是否会被截获或无法传达信息等问题，即消息传递的信道绝无问题。Lamport已经证明了在消息可能丢失的不可靠信道上试图通过消息传递的方式达到一致性是不可能的。所以，在研究拜占庭将军问题的时候，已经假定了信道是没有问题的。&lt;/p&gt;
&lt;p&gt;共识算法分为两类：Crash Fault Tolerance（CFT）和Byzantine Fault Tolerance（BFT）；&lt;/p&gt;
&lt;p&gt;对于大部分分布式集群来说，集群节点和网络消息一般是可控的，只会出现节点故障而不会出现拜占庭错误那样的伪造和欺骗的网络消息。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;并发控制&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;服务器节点对于资源的管理需要满足并发控制的机制，事务T对某一个服务器节点的资源对象S的并发访问在事务U之前， 需要保证所有服务器节点上对S和其他资源对下那个的冲突访问，T始终在U之前。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;锁并发控制&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;事务T锁住了服务器节点X上的资源A，进行写操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;事务U锁住了服务器节点Y上的资源B，进行写操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;事务T尝试读取服务器节点Y上的资源B，此时B被事务U锁住，因而事务T等待锁释放；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;事务U尝试读取服务器节点X上的资源A，此时A被事务T锁住，因而事务U等待锁释放；&lt;/p&gt;
&lt;p&gt;上述出现分布式事务之间的循环依赖导致死锁的场景，需要有机制检测死锁，然后通知协调者，放弃某个事务；&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;时间戳并发控制&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;协调者在每个事务启动的时候会分配一个全局唯一的时间戳，所有的事物均在统一的时间轴上运行，通过按照访问对象的事务时间戳顺序提交资源对象的版本来强保证事务执行的串行等价性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;乐观并发控制&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;各个并发事务在执行完成之后执行检测是否冲突，如果确实冲突就放弃一些事务，然后让客户端重新启动这些事务进行重试。每个事务在提交前检测验证&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;多版本并发控制&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多版本是MVCC实现的基础。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;what-is-raft&#34;&gt;What is Raft&lt;/h2&gt;
&lt;p&gt;Raft is a &lt;strong&gt;consensus algorithm&lt;/strong&gt; that is designed to be easy to understand. It&amp;rsquo;s equivalent to Paxos in fault-tolerance and performance. The difference is that it&amp;rsquo;s decomposed into relatively independent sub-problems, and it cleanly addresses all major pieces needed for practical systems. We hope Raft will make consensus available to a wider audience, and that this wider audience will be able to develop a variety of higher quality consensus-based systems than are available today.&lt;/p&gt;
&lt;p&gt;tl;dr: &lt;a href=&#34;http://thesecretlivesofdata.com/raft/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Raft (thesecretlivesofdata.com)&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Raft decomposes the consensus problem into &lt;em&gt;three relatively&lt;/em&gt; independent sub-problems:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Leader election&lt;/strong&gt;: a new leader must be chosen when starting the cluster and when an exsiting leader fails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Log replication&lt;/strong&gt;: the leader must accept log entries from clients and replicate them across the cluster, forcing the other logs to agree with its own.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Safety&lt;/strong&gt;: if any server has applied a particular log entry to its state machine,  then no other server may apply a different command for the same log index. (the State Machine Safety Property)&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;The basic elements of Raft show as belows:&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/05/15/X7gC2eyUYzaSQMi.png&#34; alt=&#34;raft_basic_elements&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;The main procedure of Raft depicted as follows:&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/05/15/vqhaDMj6EbcGoWe.png&#34; alt=&#34;raft_main&#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;Five things&lt;/strong&gt; to be determinately implemented:&lt;code&gt;&amp;lt;br/&amp;gt;&lt;/code&gt;
&lt;code&gt;Election safety&lt;/code&gt;, at most one leader can be elected in a given term.
&lt;code&gt;Leader append-only&lt;/code&gt;, never delete or overwrites entries, only append entries.
&lt;code&gt;Log matching&lt;/code&gt;, to be perfect
&lt;code&gt;Leader completeness&lt;/code&gt;, to be complete
&lt;code&gt;State machine safety&lt;/code&gt;, the only entry for the a given index.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ensure above the five properties  are correctly executed, then the Raft is achieved.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A Raft cluster contains several servers, five is a typical number and tolerates two failures at the same time.&lt;/p&gt;
&lt;p&gt;At a given time, each server is one of three states: leader, follower, or candidate.
In normal operation, only one leader and the others followers. Followers only respond to leader and candidates.
Leader handles all the client requests.
If a client contacts a follower, the follower will redirects it to the leader.
Candidates work when electing a new leader.&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/05/15/XErM9Dc1IsmZxBJ.png&#34; alt=&#34;raft_roles&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Time is divided into terms, and each term begins with election.
After election, the leader works for the rest of the term.
A new election will begin shortly after a split vote.
Raft ensures at most one leader in a  given term.&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/05/15/sTmRaKArpgyjq2L.png&#34; alt=&#34;raft_time_stream&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Different severs may observer the transitions between terms at different time, and in some situations a server may not observe an election or entire terms.
Terms act a logical clock, which allows servers to detect obsolete information such as stale leaders.
Each server stores a current-term number, which increases monotonically.&lt;/p&gt;
&lt;p&gt;Raft servers communicate use remote procedure calls (RPCs), two type of RPCs is need for the consensus algorithm: &lt;strong&gt;RequestVote RPCs and AppendEntries RPCs&lt;/strong&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The Basic Elements of Kafka</title>
      <link>https://liaolile.com/post/tech/distributesystem/the_basic_elements_of_kafka/</link>
      <pubDate>Sat, 31 Mar 2018 23:13:00 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/distributesystem/the_basic_elements_of_kafka/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Kafka是一种高吞吐量的分布式&lt;em&gt;发布订阅&lt;/em&gt;消息系统，它可以处理消费者规模的网站中的所有动作流数据。由LinkedIn开发的一个分布式的消息系统，使用Scala编写。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- more --&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/05/15/6RCijK5npvfzyLM.png&#34; alt=&#34;kafka1&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;h2 id=&#34;特点&#34;&gt;特点：&lt;/h2&gt;
&lt;/blockquote&gt;
&lt;p&gt;1、通过O(1)的磁盘数据结构提供消息的持久化，这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。保证常数时间复杂度的访问性能。
2、高吞吐量  ：即使是非常普通的硬件Kafka也可以支持每秒数百万的消息。
3、支持通过Kafka服务器和消费机集群来分区消息。支持Kafka Server间的消息分区，及分布式消费，同时保证每个Partition内的消息顺序传输。
4、同时支持离线数据处理和实时数据处理。
5、支持Hadoop并行数据加载。支持在线水平扩展。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;kafka术语&#34;&gt;Kafka术语&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Broker&lt;/code&gt;
Kafka集群包含一个或多个服务器，这种服务器被称为broker。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Topic&lt;/code&gt;
每条发布到Kafka集群的消息都有一个类别，这个类别被称为Topic。（物理上不同Topic的消息分开存储，逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处）Topic在逻辑上可以被认为是一个queue，每条消费都必须指定它的Topic，可以简单理解为必须指明把这条消息放进哪个queue里。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Partition&lt;/code&gt;
Partition是物理上的概念，每个Topic包含一个或多个Partition，注意消费者数量超过分区数量，多余消费者会闲置。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Producer&lt;/code&gt;
负责发布消息到Kafka broker&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Consumer&lt;/code&gt;
消息消费者，向Kafka broker读取消息的客户端。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Consumer Group&lt;/code&gt;
每个Consumer属于一个特定的Consumer Group（可为每个Consumer指定group name，若不指定group name则属于默认的group）。&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/05/15/iADIMN9EfX3Gbea.png&#34; alt=&#34;kafka2&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Kafka通过Zookeeper管理集群配置，选举leader，以及在Consumer Group发生变化时进行rebalance。
kafka集群有多个kafka实例组成，每个实例(server)成为broker。无论是kafka集群，还是producer和consumer都依赖于zookeeper来保证系统可用性集群保存一些meta信息。
kafka 在 zookeeper 中的存储结构如下图所示：&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/05/15/Wj8ClScpEUVR4rF.png&#34; alt=&#34;kafka3&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;物理上把Topic分成一个或多个Partition，每个Partition在物理上对应一个文件夹，该文件夹下存储这个Partition的所有消息和索引文件。&lt;/p&gt;
&lt;p&gt;每个日志文件都是一个log entry序列，每个log entry包含一个4字节整型数值（值为N+5），1个字节的&amp;quot;magic value&amp;quot;，4个字节的CRC校验码，其后跟N个字节的消息体。每条消息都有一个当前Partition下唯一的64字节的offset，它指明了这条消息的起始位置。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;message length ： 4 bytes (value: 1+4+n)
&amp;ldquo;magic&amp;rdquo; value ： 1 byte
crc ： 4 bytes
payload ： n bytes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个log entries并非由一个文件构成，而是分成多个segment，每个segment以该segment第一条消息的offset命名并以“.kafka”为后缀。另外会有一个索引文件，它标明了每个segment下包含的log entry的offset范围，如下图所示。&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/05/15/2As8knHywVGP9M1.png&#34; alt=&#34;kafka4&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因为每条消息都被append到该Partition中，属于顺序写磁盘，因此效率非常高（经验证，顺序写磁盘效率比随机写内存还要高，这是Kafka高吞吐率的一个很重要的保证）。&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/05/15/LboJe1sWxpSYd4I.png&#34; alt=&#34;kafka5&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;em&gt;多个Partition属于同一个topic，但是如何保证topic消息的顺序呢&lt;/em&gt;？&lt;/p&gt;
&lt;p&gt;对于传统的message queue而言，一般会删除已经被消费的消息，而Kafka集群会保留所有的消息，无论其被消费与否。当然，因为磁盘限制，不可能永久保留所有数据（实际上也没必要），因此Kafka提供两种策略删除旧数据。一是基于时间，二是基于Partition文件大小。例如可以通过配置$KAFKA_HOME/config/server.properties，让Kafka删除一周前的数据，也可在Partition文件超过1GB时删除旧数据。&lt;/p&gt;
&lt;p&gt;Kafka会为每一个Consumer Group保留一些metadata信息——当前消费的消息的position，也即offset。这个offset由Consumer控制。正常情况下Consumer会在消费完一条消息后递增该offset。当然，Consumer也可将offset设成一个较小的值，重新消费一些消息。因为offet由Consumer控制，所以Kafka broker是无状态的，它不需要标记哪些消息被哪些消费过，也不需要通过broker去保证同一个Consumer Group只有一个Consumer能消费某一条消息，因此也就不需要锁机制，这也为Kafka的高吞吐率提供了有力保障。&lt;/p&gt;
&lt;p&gt;在发送一条消息时，可以指定这条消息的key，Producer根据这个key和Partition机制来判断应该将这条消息发送到哪个Partition。Partition机制可以通过指定Producer的partition. class这一参数来指定，该class必须实现kafka.producer.Partitioner接口。
回答了上述的疑问！！&lt;/p&gt;
&lt;p&gt;使用Consumer high level API时，同一Topic的一条消息只能被同一个Consumer Group内的一个Consumer消费（可以多次消费），但多个Consumer Group可同时消费这一消息。&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/05/15/MTEejwBDgJfy6rA.png&#34; alt=&#34;kafka6&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Kafka的设计理念之一就是同时提供离线处理和实时处理。根据这一特性，可以使用Storm这种实时流处理系统对消息进行实时在线处理，同时使用Hadoop这种批处理系统进行离线处理，还可以同时将数据实时备份到另一个数据中心，只需要保证这三个操作所使用的Consumer属于不同的Consumer Group即可。&lt;/p&gt;
&lt;p&gt;push模式很难适应消费速率不同的消费者，因为消息发送速率是由broker决定的。push模式的目标是尽可能以最快速度传递消息，但是这样很容易造成Consumer来不及处理消息，典型的表现就是拒绝服务以及网络拥塞。而pull模式则可以根据Consumer的消费能力以适当的速率消费消息。&lt;/p&gt;
&lt;p&gt;对于Kafka而言，pull模式更合适。pull模式可简化broker的设计，Consumer可自主控制消费消息的速率，同时Consumer可以自己控制消费方式——即可批量消费也可逐条消费，同时还能选择不同的提交方式从而实现不同的传输语义。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可靠的数据传递&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;保证：指的是确保系统在各种不同环境下能够发生一致的行为。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kafka 可以保证分区消息的顺序。同一个分区&lt;/li&gt;
&lt;li&gt;只有当消息被写入分区的所有同步副本（但不一定要写入磁盘），他才被认为是已提交的。&lt;/li&gt;
&lt;li&gt;只要还有一个副本是活跃的，那么已经提交的消息就不会丢失&lt;/li&gt;
&lt;li&gt;消费者只能读取已经提交的信息&lt;/li&gt;
&lt;/ul&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%E4%BA%8B%E5%8A%A1/</link>
      <pubDate>Thu, 29 Mar 2018 23:13:00 +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%E4%BA%8B%E5%8A%A1/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;事务，一组操作构成的可靠的独立执行的单元，事务具备原子性、一致性、隔离性和持久性。&lt;/p&gt;
&lt;p&gt;分布式事务系统， Distributed Transaction System, 指&lt;strong&gt;事务的参与者&lt;/strong&gt;、&lt;strong&gt;支持事务的服务器&lt;/strong&gt;、&lt;strong&gt;资源服务器&lt;/strong&gt;以及&lt;strong&gt;事务管理器&lt;/strong&gt;分别位于不同的分布式的不同节点之上。&lt;/p&gt;
&lt;p&gt;分布式事务，由不同的服务之间通过&lt;strong&gt;网络远程&lt;/strong&gt;协作完成事务，是一次大活动有多个动作，由不同的小活动组成，这些活动要么全部成功，要么全部失败。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;事务理论和概念&#34;&gt;事务理论和概念&lt;/h2&gt;
&lt;h3 id=&#34;1-数据库事务本地事务分布式事务&#34;&gt;1. 数据库事务（本地事务）|分布式事务&lt;/h3&gt;
&lt;p&gt;​	数据库事务在实现时会将一次事务的所有操作全部纳入到一个&lt;strong&gt;不可分割的执行单元&lt;/strong&gt;，该执行单元的所有&lt;strong&gt;操作&lt;/strong&gt;要么都成功，要么都失败，只要其中任一操作执行失败，都将导致整个事务的回滚。支持严格的ACID，高效且可靠，隔离的最小单位受限于资源管理器。&lt;/p&gt;
&lt;p&gt;​	分布式事务是由网络远程协作完成的一系列动作，各个服务是网络分区的；场景覆盖：跨多个进程远程调用，跨数据库实例操作。&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-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;数据库事务
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;begin transaction:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	本地数据库操作：张三-100元
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	本地数据库操作：李四+100元
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;end transaction
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;分布式事务
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;begin transaction：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	本地数据库操作：张三-100元
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	远程调用操作:李四+100元
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;end transaction
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;​	由于远程调用的李四+100成功，但是网络问题导致远程调用失败，则出现本地事务回滚，导致系统的数据不一致。&lt;/p&gt;
&lt;h3 id=&#34;2-分布式事务cap理论&#34;&gt;2. 分布式事务CAP理论&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;一致性 Consistency，多个节点数据是否强一致；
&lt;ul&gt;
&lt;li&gt;数据需要在各个节点同步，所以写操作是有一定的时延。对于一致性会要求对资源暂时锁定，待同步完成后释放锁定资源；如果请求数据同步失败的节点，应当返回失败而不是旧数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可用性 Availability， 分布式系统活跃的节点都能够处理所有操作且能响应查询，不会出现超时或失败；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确保从节点的数据可用性，不应将资源锁定，需要返回数据，即使是返回旧数据，不能返回错误或者响应超时；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分区容忍性 Partition tolerance， 出现网络故障，节点通信失败，但是系统仍能正常工作；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据同步失败不影响当前系统的读写操作，系统部分节点故障不影响整个系统对外的响应，分区容忍性是分布式系统具备的基本能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;只能同时满足上述两个要素，不可三者兼得；&lt;/p&gt;
&lt;p&gt;当前大部分分布式系统选择的是AP（&lt;strong&gt;柔性事务&lt;/strong&gt;）,而对于一致性选择的是最终一致性，而不是强一致性，能够接受查询数据在一定时间内不是最新的；延伸出后续的BASE理论。&lt;/p&gt;
&lt;p&gt;CP是放弃了可用性（&lt;strong&gt;刚性事务&lt;/strong&gt;），zookeeper即使用该策略追求强一致性，同时跨行转账需要双方银行均响应后才完成整个事务。&lt;/p&gt;
&lt;p&gt;CA是放弃了分区容忍性，不考虑网络不通或者节点挂掉的场景，&lt;strong&gt;系统将不是一个标准的分布式系统&lt;/strong&gt;；&lt;/p&gt;
&lt;h3 id=&#34;3-分布式事务base理论&#34;&gt;3. 分布式事务BASE理论&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;B&lt;/strong&gt;asically &lt;strong&gt;A&lt;/strong&gt;vailable，&lt;strong&gt;S&lt;/strong&gt;oft state，&lt;strong&gt;E&lt;/strong&gt;ventually consistent，牺牲强一致性获得可用性，出现故障允许部分不可用但要保证核心功能可用，允许数据在一段时间是不一致的，这段时间不影响系统可用性，但最终达到一致性状态。通过放宽一致性要求，借助本地事务来实现最终分布式事务一致性的同时也保证了系统的吞吐量。&lt;/p&gt;
&lt;p&gt;基于Base的柔性事务往往分为两类：通知型事务（依赖于消息中间件），补偿型事务（TCC）。&lt;/p&gt;
&lt;h3 id=&#34;4-本地事务的acid特性&#34;&gt;4. 本地事务的ACID特性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Atomic 原子性，整个事务过程中的所有操作，要么全部完成，要么全部不做，无中间状态，无部分成功。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于单个事务，原子性就能保证一致性；但是对于多个并发执行的事务，由于执行顺序，最终效果可能不同；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consistency 一致性，保证多个节点中数据的一致性，所有的节点在任何时间数据都是一致的；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;业务操作支持重试，不会产生不利影响，需要满足幂等性；&lt;/li&gt;
&lt;li&gt;强一致性，当更新操作完成后，任何多个线程访问都会返回最新的更新过后的数据；&lt;/li&gt;
&lt;li&gt;弱一致性，系统并不保证线程访问返回最新的更新过后的值；不承诺立即，也不承诺具体多长时间；&lt;/li&gt;
&lt;li&gt;最终一致性，弱一致性的特定形式，系统保证没有后续更新值前提下，系统最终返回上一次更新操作的值；期间不一致的主要因素主要有：&lt;strong&gt;通信延迟、系统负载、副本个数&lt;/strong&gt;等；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Isolation 隔离性，多个事务之间往往是并发的，多个事务之间互相不干扰，一个事务不能看到其他事务的运行过程的中间状态；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;每个事务都是有起止时间，每个事务的执行过程就是实现维度上的一个时间片段，多个时间片段上的并发交错，出现了不同的隔离性问题。数据库事务的隔离isolation级别：Read uncommitted，Read committed，Repeatable read，Serializable&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/27/ONbcMJS4ie6aUKA.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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Durability 持久性，事务完成之后，该事务对数据的更改会被持久化到数据库，且不会被回滚。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;分布式事务解决方案&#34;&gt;分布式事务解决方案&lt;/h2&gt;
&lt;h3 id=&#34;1-刚性事务-数据库事务&#34;&gt;1. 刚性事务-数据库事务&lt;/h3&gt;
&lt;p&gt;数据库一般由两个文件组成，&lt;strong&gt;数据文件及日志文件&lt;/strong&gt;，往往日志文件比数据文件更大。对于任何数据库的写操作都是先写操作日志。
对于事务操作，数据库会先记录这个事务的redo日志，把日志文件写入磁盘，之后再开始操作数据库数据。即便在断电后操作尚未完成，重新启动时候会读取日志文件进行redo前滚或者是undo回滚，以保证数据的一致性；&lt;/p&gt;
&lt;h3 id=&#34;2-缓存最终一致性&#34;&gt;2. 缓存最终一致性&lt;/h3&gt;
&lt;p&gt;现象：缓存用在数据库前面，作为数据读取缓存，使得I/O操作不直接落在数据库上。存在缓存数据与数据库数据不一致现象。&lt;/p&gt;
&lt;p&gt;解决方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;设置缓存过期时间，该时间即系统可以达到最终一致性的容忍时间；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据在数据库更新成功后，同时刷新缓存中的数据；&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;3-两阶段提交-强一致性-2pc-2-phase-commit&#34;&gt;3. 两阶段提交-强一致性 （2PC, 2 Phase Commit）&lt;/h3&gt;
&lt;p&gt;具有强一致性，是&lt;strong&gt;CP系统&lt;/strong&gt;的典型实现；通常两个角色，&lt;strong&gt;协调器&lt;/strong&gt;（事务管理器）及&lt;strong&gt;事务执行者&lt;/strong&gt;，协调器负责整个分布式系统的提交和回滚，事务执行者负责本地事务的提交和回滚。&lt;/p&gt;
&lt;p&gt;高并发场景涉及到性能问题，C系统需要等待多个资源，耗时较长。&lt;strong&gt;同步阻塞&lt;/strong&gt;，执行者在事务未提交之前会一直锁定其占有的本地资源对象。&lt;strong&gt;单点故障&lt;/strong&gt;，如果协调者出现故障后，所有的执行着会进入阻塞状态，导致本地被锁的资源无法被其他进程使用。&lt;strong&gt;数据不一致&lt;/strong&gt;，当doCommit消息发送后由于网路抖动导致部分事务执行者没有搜到消息而不提交事务，导致最终不一致。&lt;/p&gt;
&lt;p&gt;协调器的状态包括：init，preparing，committed，aborted&lt;/p&gt;
&lt;p&gt;事务执行者的状态包括：working，prepared，committed&lt;/p&gt;
&lt;p&gt;两个步骤：prepare极端、commit提交或rollback回滚阶段
















&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/05/15/c962xoZInlCDR5r.png&#34; alt=&#34;2PC&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;统一标准组织定义了分布式事务处理模型DTP（Distributed Transaction Processing Reference Model）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AP (Application Process) 应用程序，使用DTP分布式系统的程序&lt;/li&gt;
&lt;li&gt;RM (Resource Manager) 资源管理器，事务的参与者，资源管理器控制着&lt;strong&gt;分支事务&lt;/strong&gt;，负责本地事务的提交；&lt;/li&gt;
&lt;li&gt;TM (Transaction Manager) 事务管理器，负责协调和管理事务，控制着&lt;strong&gt;全局事务&lt;/strong&gt;，管理事务的生命周期，同时协调各个资源管理器。&lt;/li&gt;
&lt;li&gt;CRM (Communication Resource Manager) 通信资源管理器，控制一个TM域内或者跨TM域的分布式应用之间的通信。&lt;/li&gt;
&lt;li&gt;CP (Communication Protocol)，通信协议，提供分布式应用之间的底层通信服务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个分布式事务即包含若干分支事务的全局事务，全局事务协调分支事务要么全部提交，要么全部回滚。&lt;/p&gt;
&lt;p&gt;DTP模型定义了TM和RM直接通讯接口的规范（叫XA），TM向AP提供应用程序编程接口，AP通过TM进行事务提交和回滚事务；TM通过XA接口来通知RM事务的开始、结束以及提交和回滚。&lt;/p&gt;
&lt;p&gt;对于2PC使用DTP来描述为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;准备阶段&lt;/strong&gt;，RM执行实际的业务操作，但不提交事务，并且同时锁定资源。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;提交阶段&lt;/strong&gt;，TM接受RM在准备阶段的回复，任何一个RM失败，TM通知所有的RM执行回滚操作；否则，TM通知RM进行分支事务的提交。提交阶段结束后释放锁定资源。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;4-补偿模式-最终一致性tcc-try-confirm-cancel&#34;&gt;4. 补偿模式-最终一致性（TCC, Try-Confirm-Cancel）&lt;/h3&gt;
&lt;p&gt;服务化的二阶段提交协议，要求分支事务实现三个操作：预处理Try，确认Confirm，撤销Cancel。预处理做业务检查和资源预留，确认做业务确认操作，撤销实现一个和确认完全相反的操作，回滚。TCC任务只要Confirm阶段或者Cancel阶段不会出错，只要Try成功，Confirm一定成功。若真出现失败，需要支持重试机制和人工处理介入。在事务链中的任何一个正向事务Confirm操作, 都必须存在一个完全符合回滚Cancel规则的可逆事务。&lt;/p&gt;
&lt;p&gt;如果涉及重试，则需要实现为幂等，对于同一个操作无论执行多少次结果均相同。&lt;/p&gt;
&lt;p&gt;TCC需要区分异常的处理机制，支持不同场景的异常处理：空回滚、幂等、悬挂。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;空回滚&lt;/strong&gt;：往往服务宕机和网络故障的时候，对于Try阶段就故障的时候，在故障恢复后，需要识别出是空回滚。依赖与全局事务的ID在分布式事务调用链的持久化。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;幂等&lt;/strong&gt;：确认/撤销操作的幂等性，确保不会重复使用或者重复释放资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;悬挂&lt;/strong&gt;：由于网络时延导致，第一阶段TM认为Try网络拥堵超时了，直接执行了第二阶段Cancel，但是第二阶段执行结束后，第一阶段Try才达到真正的执行者。&lt;/p&gt;
&lt;p&gt;解决方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务调用链关系需要记载；&lt;/li&gt;
&lt;li&gt;每个服务提供则需要额外提供一组业务逻辑相反操作，互为补偿；&lt;/li&gt;
&lt;li&gt;按失败的不同原因执行不同的回滚策略；&lt;/li&gt;
&lt;li&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/05/15/VHhoZcXJe4BDGU7.png&#34; alt=&#34;tryconfirmcancel&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实例（账户扣钱转账30，账户总额100）：&lt;/p&gt;
&lt;p&gt;Try准备阶段，做资源的检查和预留。当前总额是100，但是30已经被冻结，不能用于其他的事务；&lt;/p&gt;
&lt;p&gt;Confirm确认阶段，执行真正的扣钱。冻结的30扣除，账号余额为70；&lt;/p&gt;
&lt;p&gt;Cancel撤销阶段，释放冻结的30，使账号回到最初状态，余额100；&lt;/p&gt;
&lt;p&gt;2PC通常是在跨库的DB层面，TCC则在应用层面，需要通过业务逻辑来实现，对业务有侵入性。可以自行定义数据操作的粒度以降低锁冲突，提高吞吐量，但是侵入性强，每个分支事务均需要实现3个操作。按照网络状态、系统故障等不同的失败场景实现不同的回滚策略。&lt;/p&gt;
&lt;h3 id=&#34;5-三阶段提交-3pc&#34;&gt;5. 三阶段提交 (3PC)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CanCommit（事务询问）&lt;/p&gt;
&lt;p&gt;询问所有参与者是否可以执行事务的操作；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PreCommit（事务执行）&lt;/p&gt;
&lt;p&gt;在事务询问都是okay的前提条件下，执行事务的操作；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DoCommit（事务提交）&lt;/p&gt;
&lt;p&gt;真正的事务提交；&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;针对二阶段的缺陷，解决单点故障问题，减少阻塞；一旦参与者无法及时收到来自协调者的信息之后，会默认执行commit，而不会一直处于阻塞状态。这样会造成最终数据不一致。&lt;/p&gt;
&lt;p&gt;上述解决方案依据具体使用场景而灵活变化，需要适应业务需求。&lt;/p&gt;
&lt;h3 id=&#34;6-消息事务-最终一致性&#34;&gt;6. 消息事务-最终一致性&lt;/h3&gt;
&lt;p&gt;基于消息中间件的二阶段提交，将本地事务以及发放消息放在一个分布式事务中。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;系统向消息系统中间发送预备消息；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;消息中间件保存预备消息并返回成功；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;执行本地事务；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;发送提交消息给消息中间件；&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1和2失败时候事务未执行；&lt;/p&gt;
&lt;p&gt;3失败时候，回滚预备消息；系统实现消息中间件的回调接口，失败则回滚。&lt;/p&gt;
&lt;p&gt;4失败时候，3步骤为成功，消息中间件能够检查到系统已经成功执行，消息中间件自行提交完成整个事务。&lt;/p&gt;
&lt;p&gt;对消息中间件要求较高，&lt;strong&gt;保障消息不丢失，消息不重复不乱序&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;针对投递Commit消息，接收订阅方存在三个问题：&lt;strong&gt;消息可能重复消费，消费者消费超时，消费失败&lt;/strong&gt;；&lt;/p&gt;
&lt;p&gt;针对第一个问题需要在消息消费方进行唯一标识识别，消费方对消息的状态进行保存，识别重复消息；&lt;/p&gt;
&lt;p&gt;针对第二个问题即重试即可，直至消息消费成功；&lt;/p&gt;
&lt;p&gt;针对第三个问题，消费失败如果由于系统bug导致，重试多次一样失败，如果此时需要回滚则有复杂的业务逻辑，最好的办法就是通过报警系统及时发现失败情况然后再人工处理。&lt;/p&gt;
&lt;p&gt;往往第三个问题都是致命异常，要&lt;strong&gt;打印详细的错误日志，并设计一个报警系统在后台实时扫描和分析此类日志&lt;/strong&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/05/15/JRSlC5YoI3HefEU.png&#34; alt=&#34;messageTransaction&#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;ul&gt;
&lt;li&gt;
&lt;p&gt;本地事务与消息的发送的原子性问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;事务参与方接受消息的可靠性。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可靠消息最终一致性适合执行周期长实时性要求低的系统，解耦了服务之间的依赖，同时基于消息的异步操作，避免了分布式事务中的同步阻塞问题。&lt;/p&gt;
&lt;h3 id=&#34;7-重要结论&#34;&gt;7. 重要结论&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;如果业务场景需要强一致性, 那么尽量避免将它们放在不同服务中, 也就是尽量使用本地事务, 避免使用强一致性的分布式事务.&lt;/li&gt;
&lt;li&gt;如果业务场景能够接受最终一致性, 那么最好是使用基于消息的最终一致性的方案(异步确保型)来解决.&lt;/li&gt;
&lt;li&gt;如果业务场景需要强一致性, 并且只能够进行分布式服务部署, 那么最好是使用TCC（try-confirm-cancel）方案而不是2PC方案来解决.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;刚性事务：严格遵循&lt;strong&gt;ACID原则&lt;/strong&gt;的事务，如单机数据库事务；&lt;/p&gt;
&lt;p&gt;柔性事务：遵循&lt;strong&gt;BASE理论&lt;/strong&gt;的事务，实现方式：两阶段提交、TCC补偿提交、消息异步确保、最大努力通知型&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可见性，各个服务需要提供查询接口，来判断操作的处理情况。&lt;/li&gt;
&lt;li&gt;幂等性，可重复操作，调用多次返回的业务结果相同。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本地事务采用刚性事务，分布式事务采用柔性事务。&lt;/p&gt;
&lt;h2 id=&#34;mysql的事务&#34;&gt;MySQL的事务&lt;/h2&gt;
&lt;p&gt;隐式事务和显示事务，mysql默认就是隐式事务模式，当insert，update，delete时，数据库自动开启事务、提交或回滚事务。由autocommit控制，可以由下述命令进行查询；&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;show&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;variables&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;like&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;autocommit&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;1-事务的实现&#34;&gt;1. 事务的实现&lt;/h3&gt;
&lt;p&gt;Mysql的Innodb存储引擎基于日志和锁来实现ACID，默认的事务隔离级别是Repeatable Read。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;通过数据库锁机制和MVCC，确保事务的隔离性；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过Redo Log重做日志，来保障事务的持久性；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Redo Log是记录新数据的备份，事务提交前，将Redo Log持久化而不是数据持久化，当系统崩溃时，虽然数据没有持久化，但是Redo Log持久化，系统恢复后通过Redo Log恢复到崩溃之前的状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过Undo Log撤销日志，来保障事务的原子性和一致性；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;操作任何数据之前，先将数据备份到Undo Log，然后进行数据的修改。对于数据的每行数据，可能会存在多个版本的数据。如果出现Rollback，利用Undo Log中的备份数据恢复到事务开始的状态；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;2-事务的隔离&#34;&gt;2. 事务的隔离&lt;/h3&gt;
&lt;p&gt;事务隔离级别主要是为了解决多个事务之间&lt;strong&gt;数据可见性及数据正确性&lt;/strong&gt;的问题。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;读未提交，Read Uncommitted&lt;/p&gt;
&lt;p&gt;可以读取到其他事务还未提交的数据，多次读取的结果不一致。出现脏读，不可重复读，幻读；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;读已提交，Read Committed&lt;/p&gt;
&lt;p&gt;无法读取到其他事务还未提交的数据，可以读取到其他事务已经提交的数据，多次读取结果不一致，不可重复读和幻读；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可重复读，Repeatable Read&lt;/p&gt;
&lt;p&gt;无法读取到其他事务已经提交的数据，多次读取的结果一致，可重复读；会出现幻读；当两个事务，数据库唯一索引，基于事务中查询后插入的场景。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;串行，Serializable&lt;/p&gt;
&lt;p&gt;让并发的事务串行化，多个事务之间读写，写读，写写会产生互斥，多个事务间读读不会产生互斥。不会出现脏读，不可重复读、读已提交和幻读。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;3-并发控制&#34;&gt;3. 并发控制&lt;/h3&gt;
&lt;p&gt;mysql并发控制主要通过&lt;strong&gt;加锁&lt;/strong&gt;来实现。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;读锁 read lock，也叫共享锁share lock，多个读请求可以同时共享一把锁来读取数据而不会阻塞；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;写锁 write lock，也叫排他锁exclusive lock，写锁会排斥其他的所有获取锁的请求，一直阻塞直到数据写入；&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;锁的粒度分为表锁和行锁&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表锁 table lock，锁定整张表，维护锁的开销最小但是降低了表的读写效率。一般alter table会进行表锁；&lt;/li&gt;
&lt;li&gt;行锁 row lock，最大程度的支持并发，数据库锁的维护开销大。行锁一般由各个引擎实现，而非mysql服务器层面实现；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MVCC版本管理，多版本并发控制，借此做到的读写分离，实现不加锁实现读写并行。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mysql innodb引擎通过在每行记录后保存两个列（创建时间和过期时间，逻辑时间的版本号），每开启一个新的事务，系统版本号会增长，事务开始的版本号会作为事务号，用来和查询的每行记录的版本号进行比较。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;spring事务管理&#34;&gt;Spring事务管理&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;编程式事务管理&lt;/strong&gt;，通过TransactionTemplate或者TransactionManager手动管理事务；相关代码逻辑&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-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nd&#34;&gt;@Autowired&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;kd&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PlatformTransactionManager&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;transactionManager&lt;/span&gt;&lt;span class=&#34;o&#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&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;testTransaction&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#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&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;TransactionStatus&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;transactionManager&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;getTransaction&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DefaultTransactionDefinition&lt;/span&gt;&lt;span class=&#34;o&#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;try&lt;/span&gt; &lt;span class=&#34;o&#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;// ....  业务代码
&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;n&#34;&gt;transactionManager&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;commit&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;o&#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;o&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Exception&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#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;n&#34;&gt;transactionManager&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;rollback&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;o&#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;o&#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;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;声明式事务管理&lt;/strong&gt;，通过AOP实现，基于@Transaction注解实现。如果@Transaction使用在类上，表明该注解对该类中的所有public方法均生效。如果同一个内中的方法调用了@Transanction标记的方法，则事务会失效，因为其依赖的AOP实现机制底层是动态代理，对于外部类调用时候才生效。&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-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nd&#34;&gt;@Transactional&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;propagation&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Propagation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;REQUIRED&lt;/span&gt;&lt;span class=&#34;o&#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;kd&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;aMethod&lt;/span&gt; &lt;span class=&#34;o&#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;//do something
&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;n&#34;&gt;B&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;B&lt;/span&gt;&lt;span class=&#34;o&#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;n&#34;&gt;C&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;o&#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;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;bMethod&lt;/span&gt;&lt;span class=&#34;o&#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;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;cMethod&lt;/span&gt;&lt;span class=&#34;o&#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;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;spring事务框架在于接口的定义&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;PlatformTransactionManager：平台事务管理器，事务策略的核心，事务的管理接口；&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-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;org.springframework.transaction&lt;/span&gt;&lt;span class=&#34;o&#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&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;org.springframework.lang.Nullable&lt;/span&gt;&lt;span class=&#34;o&#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&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;PlatformTransactionManager&lt;/span&gt; &lt;span class=&#34;o&#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;//获得事务
&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;n&#34;&gt;TransactionStatus&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;getTransaction&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;@Nullable&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TransactionDefinition&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;throws&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TransactionException&lt;/span&gt;&lt;span class=&#34;o&#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;//提交事务
&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;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;commit&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TransactionStatus&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;throws&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TransactionException&lt;/span&gt;&lt;span class=&#34;o&#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;//回滚事务
&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;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;rollback&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TransactionStatus&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;throws&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TransactionException&lt;/span&gt;&lt;span class=&#34;o&#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;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;TransactionDefinition：事务定义信息，包括&lt;strong&gt;事务的传播、隔离级别、超时、只读、回滚规则&lt;/strong&gt;等；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;TransactionStatus：事务运行状态，定义了一组方法用于获取事务相应状态信息；&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;事务传播行为&lt;/strong&gt;，为了解决业务层方法之间互相调用的事务问题；当事务方法被另一个事务方法调用的时候，必须指定事务应该如何传播。&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-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nd&#34;&gt;@Service&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;n&#34;&gt;Class&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;A&lt;/span&gt; &lt;span class=&#34;o&#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;nd&#34;&gt;@Autowired&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;n&#34;&gt;B&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#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;nd&#34;&gt;@Transactional&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;propagation&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;X&lt;/span&gt;&lt;span class=&#34;o&#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;kd&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;aMethod&lt;/span&gt; &lt;span class=&#34;o&#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;//do something
&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;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;bMethod&lt;/span&gt;&lt;span class=&#34;o&#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;o&#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;o&#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;nd&#34;&gt;@Service&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;n&#34;&gt;Class&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;B&lt;/span&gt; &lt;span class=&#34;o&#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;nd&#34;&gt;@Transactional&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;propagation&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Y&lt;/span&gt;&lt;span class=&#34;o&#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;kd&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bMethod&lt;/span&gt; &lt;span class=&#34;o&#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;//do something
&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;o&#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;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TransactionDefinition.PROPAGATION_REQUIRED&lt;/code&gt;&lt;/strong&gt;，如果当前存在事务，则加入该事务；如果没有事务，则创建一个新的事务。
&lt;ul&gt;
&lt;li&gt;对于上述代码X和Y均为PROPAGATION_REQUIRED，只要aMethod或者bMethod任何方法回滚，整个事务就回滚；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TransactionDefinition.PROPAGATION_REQUIRES_NEW&lt;/code&gt;&lt;/strong&gt;，创建一个新的事务，如果当前事务存在则挂起。不管外部是否有事务，当前方法均会开始新的事物，且开启的事务相互独立，互不干扰。
&lt;ul&gt;
&lt;li&gt;对于上述代码，X为PROPAGATION_REQUIRED，Y为PROPAGATION_REQUIRED_NEW，aMethod的回滚不会导致bMethod的回滚，如果bMethod的方法回滚，&lt;strong&gt;且抛出了未被捕获的异常满足&lt;/strong&gt;aMethod回滚的规则，则aMethod也会回滚。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TransactionDefinition.PROPAGATION_NESTED&lt;/code&gt;&lt;/strong&gt;，外部开启事务的条件是，内部开启开启新的事务，作为嵌套事务存在。如果外部不存在，则单独开启一个事务，效果同PROPAGATION_REQUIRED。
&lt;ul&gt;
&lt;li&gt;对于上述代码，X为PROPAGATION_REQUIRED，Y为PROPAGATION_NESTED，如果bMethod回滚后，aMethod也会跟着回滚。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TransactionDefinition.PROPAGATION_MANDATORY&lt;/code&gt;&lt;/strong&gt;，如果当前存在事务，则加入该事务；如果没有事务，则直接抛出异常；使用场景较少；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TransactionDefinition.PROPAGATION_SUPPORTS&lt;/code&gt;&lt;/strong&gt;，如果当前存在事务，则加入事务；如果没有事务，则按照非事务的方式继续运行；使用场景较少；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TransactionDefinition.PROPAGATION_NOT_SUPPORTED&lt;/code&gt;&lt;/strong&gt;，以非事务的方式执行，如果当前存在事务，则把当前事务挂起；使用场景较少；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TransactionDefinition.PROPAGATION_NEVER&lt;/code&gt;&lt;/strong&gt;，以非实物的方式执行，如果当前存在事务，则直接抛出异常；使用场景较少；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;事务超时行为&lt;/strong&gt;，一个事务所允许执行的最长时间，如果超过该时间限制但事务还没有完成，则自动回滚事务。默认值为-1，表示没有超时时间或者取决于底层事务系统；&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;事务只读属性&lt;/strong&gt;，对于只有数据查询的事务，可以指定事务类型为read only，只读事务不涉及数据的修改，数据库会提供一些优化手段，适用于有多条数据查询的操作的方法中。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mysql默认对每个新建的连接使用autocommit模式，该模式下，每个发送到Mysql的服务器的sql都会在一个独立的事务中进行处理，事务处理后自动提交，然后开启一个新的事务。给方法加上@Transaction注解，该方法执行的sql会被放在一个事务中，如果是只读事务，mysql会去优化它的执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;事务回滚机制&lt;/strong&gt;，规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下，事务遇到运行时异常和Error时才会回滚，对于受检异常时不会回滚。&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
