<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
    <channel>
            <title> 我的知识海洋</title>
            <link></link>
        <generator>Halo 1.5.5</generator>
        <lastBuildDate>Mon, 15 Jul 2024 20:37:47 CST</lastBuildDate>
                <item>
                    <title>
                        <![CDATA[ 互联网简历｜应届生如何书写互联网开发简历]]>
                    </title>
                    <link>/archives/hu-lian-wang-jian-li</link>
                    <description>
                            <![CDATA[<h2 id="引言">引言</h2><p><strong>改简历不是改命，改的是进面概率</strong></p><p>我在网易实习时内推了100多人，在快手实习期间帮组里收简历也收到了400多份实习简历，在我和几位同学一起组织的知识星球内也修改过很多校招/实习简历，也和很多秋招SSP选手/人才计划选手探讨交流过简历的一些细节, 面试时也被不同厂的不同面试官夸过简历写的不错。零零总总看了不下600份校招/实习简历，所以对于写简历有一些自己的看法，又是一年求职季，想总结出来与大家交流一下。</p><p>每个人经历不同，对简历看法自然不同，本文是我个人对于“应届生如何写校招/实习简历”的一些个人看法，请各位读者辩证看待，欢迎友善讨论，如果你觉得不对的地方，是我的想法有误。（防 gang 声明</p><p>本文自然也无法涵盖所有人的所有情况，只能是提供一个思路供大家参考。</p><h2 id="个人信息">个人信息</h2><p>必须有的：</p><ol><li>手机号 （可以加一个微信同号）</li><li>邮箱（可以考虑用163/谷歌邮箱）</li></ol><p>可以写的：</p><p>求职意向： 后端研发实习生、前端研发实习生</p><p>GitHub个人链接</p><p>个人网站链接</p><p>其他能展示个人能力的东西（知乎、B站、小红书、领英、推特........）</p><p>找实习可以写： 一周到岗，实习六个月</p><h3 id="学校教育经历">学校/教育经历</h3><p>985、211（下简称92）、海硕，直接放到最前面，如果是偏远/小众92可以考虑加一个小tag 【985、211】</p><p>如果是保研的同学，可以加一个 保送 的tag，名次高的话可以写一个排名，如 1/29</p><p>双一流，可以加个tag 【双一流高校】</p><p>双非，可以考虑在简历最前面写 2x届 + 专业 ，202 x 年4/7月毕业，然后把教育经历放最后</p><p><strong>在校时间不要写至今，可以直接写 2021.7-2025.7</strong> （直观，一眼就知道是不是应届）</p><h3 id="学校课程">学校课程</h3><p>科班同学写这个感觉没啥用（也可以凑篇幅），非科班同学可以写一些自学的计算机课程</p><h3 id="绩点">绩点</h3><p>高绩点可以写上去，有些面试官喜欢，加印象分。排名类也可以加上去，如 1/123</p><h2 id="实习开源经历">实习/开源经历</h2><h3 id="实习经历">实习经历</h3><p>不需要写很详细的公司名字，写大家知道那个就行。比如 美团，而不是北京三快科技有限公司。</p><p>可以放个logo，在旁边，很明显，很方便。</p><p>实习日期，已经结束的就写具体时间，没有的可以写预计时间。</p><h3 id="实习经历写法">实习经历写法</h3><p>我看过的简历中，实习经历大多数分为两种。第一种是把实习信息还有实习做的事放一起，第二种是在实习经历里简单提一下实习，然后把实习做的事放项目经历里。</p><p>个人觉得第一种更好，是一个完整的叙事过程，地点、时间、经过和实习收获/总结。而第二种需要面试官自己去找上下文，不太友好，故不推荐第二种写法。以下例子为第一种写法，个人喜好，请君自选。</p><hr /><p>某公司    某部门  某业务（可选）  后端开发实习生（前端开发实习生） 地点（可选）    日期（简历中的所有日期格式需统一）</p><p>产品介绍（如果是基础架构的同学可以列一下，比如阿里云的xxx服务）</p><p>涉及技术栈（可选） ：</p><p>实习业务介绍（业务同学推荐写）：（例子）为Google Ads平台提供广告技术支持，业务包括品牌广告和效果广告. 个人负责xxxx平台需求开发, 保证广告业务的正常迭代.</p><p>实习内容：</p><ul><li>重构xxxx鉴权（s）, 利用xxxx设计模式解耦（a）, 将xxxxx（a），解决了xxxxx权限问题（r）.</li><li>为了xxxx（s），分发多机器执行xxxx（a）, 优化xxxx计算时间（r）, xxx从平均300ms-&gt;50ms（r）.</li></ul><p>实习总结（可选）： 学习了xxx的业务，对xxxx有了更深入的理解</p><hr /><p>其中实习内容每一条可以考虑用 satr 法则描述（S—Situation：事情是在什么情况下发生； T—Task：你是如何明确你的任务的； A—Action：针对这样的情况分析，你采用了什么行动方式； R—Result：结果怎样，在这样的情况下你学习到了什么。）</p><p><strong>尽量控制在 1-2 行内，2行以上已经很长了，可能没耐心读完。</strong></p><h3 id="开源经历">开源经历</h3><p>此部分指各种开源相关的经历，比如自己参与的社区、参加的开源活动、通过考核的开源夏令营。</p><p>开源活动汇总： <a href="https://github.com/erdengk/gsoc-analyse">https://github.com/erdengk/gsoc-analyse</a></p><p>这部分可以分为两类，参加开源夏令营/官方活动的，没参加活动自己贡献的。</p><p>一般来说，要贴上自己贡献的社区主页、自己贡献的 feature 链接地址。</p><h3 id="参加开源夏令营官方活动">参加开源夏令营/官方活动</h3><p>受限于开源夏令营还不是那么出名，所以可以在这段经历前可以简单介绍下这个活动，让HR、面试官了解下活动的含金量。</p><p>例子：</p><p>GSoC ： 全球知名开源活动，连续举办 18 年，2022 年全球 4k 人申请，中国区 35 人左右中选(35 / 4000)。申请书在 Apache 基金会内排名 11/121. （可以贴 项目申请书、项目结项报告）</p><p>OSPP ： 入选中科院中科院软件所“开源软件供应链点亮计划”（开源之夏），2023年全球 x 人申请，x人中选。 （可以贴 项目申请书、项目结项报告）</p><p>更多开源活动可以查看  <a href="https://github.com/erdengk/gsoc-analyse">https://github.com/erdengk/gsoc-analyse</a></p><p>github仓库 ：erdengk/gsoc-analyse</p><h3 id="自己进行贡献的">自己进行贡献的</h3><p>PR 地址 、 官方推文、 社区feature设计文档、总结文档，都可以贴链接</p><p>如果是committer 之类的角色，可以在最前面加粗列出来，比如 <strong>Apache Commiter (Dubbo)</strong></p><p>如果没有贡献那么多，也可以写写自己做的东西，书写方式可以参考上一节中实习内容的写法</p><h3 id="3个月实习和6个月实习">3个月实习和6个月实习</h3><p>这部分内容来自于我和一位阿里 P6+ 探讨简历后的总结</p><p>Github 和 博客是推荐放的，博客记得常更新。（起码第一页要最近更新的）</p><p>对于实习，你需要考虑好怎么讲一个完整的故事，前面你把故事讲好了，面试官开心了，他就会问你后面基础知识和算法题问的少，且他给你的面评高。</p><p>不要写线上BUG与漏洞修复。 （ 你的开发没有bug，别人的 bug 不归你管，写这些东西显得你像打杂的）</p><p>开发简历不要提任何测试相关的（包括单元测试），写上去会让 hr 和 面试官觉得你这段实习/项目是测试。</p><p>投递时，最好根据每个岗的 jd ，然后去适当修改简历。</p><p>3个月实习 和 6个月实习的区别<br />看实习生看两个东西，第一是成长，第二才是稳定性，实习了 6 个月及 6 个月以上能保证稳定性好。没有人会对一个三个月的实习生有期望。<br />但如果你实习了半年，那所有面试官或者所有 mentor、leader 的期望其实就是你可以完成一个正式员工的工作。所以你必须按照你是一个正式员工的方式来写你这段 6 个月的实习。<br />同样的，如果是时间比较长的实习，你不仅需要考虑你自己的工作，你还需要去弄清楚部门业务、项目上下游、接口如何设计、模块分层、内部拆分子模块等等这些东西，需要把这个故事想清楚。</p><p>可以多看 mentor 的汇报材料和 mentor 的 OKR 、绩效自评，那是很好的总结材料。</p><p>面试最好找内推/强推，部分公司的部门现在是照常收简历，但不面新候选人的，除非特别优秀或者强推才有机会进面。同时，最好保证每次的面评不要太差，只要不是很差，都有机会被捞起来。</p><h2 id="技术栈技能">技术栈/技能</h2><p>一些不想准备的八股，可以不写或者写了解 （比如Java后端的 Spring ）（ps ：只是说不想准备八股，而不是说它不重要）</p><p>自己比较熟悉的东西，可以加粗试图触发八股</p><p>不熟悉/准备的不多的东西，写了解</p><p>技能可以分为以下几部分进行书写</p><p>计算机基础相关的，语言类相关的，中间件相关的，其他的</p><p>以Java后端为例：</p><p>数据结构、计算机网络和操作系统，Java基础、Java并发和JVM，数据库、消息队列和其他常用中间件，分布式、设计模式之类的。</p><h2 id="项目经历">项目经历</h2><p><strong>先说数量</strong>：最少一个（实习/开源经历多可以不写），最多三个（除非都很厉害，要不然不需要全部都写上，放GitHub就行）</p><p><strong>然后说哪些不往上写</strong>： 未经优化/包装的烂大街项目，怎么定义烂大街，大家都做过的点评外卖秒杀，rpc，以及一些经常看到的项目都算。（不否认其他人直接用这种项目拿offer，但不是每个人都有这种实力/机会的）</p><p><strong>最后说可以写的</strong>：</p><p>包装/优化过的练手项目 、 已经上线在运营的项目（多见于学校内实验室）、自己从0-1实现的业务项目、各种轮子，各种开源的项目（也可以是帮这种项目做了很多工作、新功能）</p><p>氪金类：java3y 的项目（3y哥请结一下广告费😝）、慕课网部分项目还没烂大街（可能也是因为需要氪金所以人更少</p><p><strong>怎么包装/优化</strong>：</p><p>文末列了一些参考链接，感兴趣的同学可以参考参考，在这里我讲一个我个人的例子，仅做参考。</p><p>我第一次份实习简历写了一个微服务的项目，是把慕课网的一个优惠券项目包装了一下写上去的，现在回首来看，项目还是不够成熟、漏洞很多，但这样不妨碍用这种程度的项目去拿到实习。</p><p>这个项目的优点是不烂大街、有难点可以直接问，面试官还是很愿意聊这个的，缺点是这种项目很容易被问穿，所以需要有自己比较熟悉的点来证明自己还是花了些心思做的。</p><p>我自己介绍项目时会讲为什么要做这个项目，以及学到哪些东西，遇到的难点是什么，怎么调研的，怎么解决的，有些面试官会中间提问，有些也会等我讲完再细问他感兴趣的，项目虽然简单，但还是能聊很多东西的。</p><h3 id="项目经历中常见问题">项目经历中常见问题</h3><p>你为什么要做这个项目？</p><p>介绍下你的项目？</p><p>介绍下项目难点？</p><p>你是怎么解决/优化的？</p><p>还有其他方案吗？</p><p>有了解业内的方案吗？</p><p>这里就不回答了，改天可以整理一下列一个和 时错 老师类似的文章, <a href="https://nowcoder.com/discuss/612425745993859072?sourceSSR=users">HR面试面经问题汇总（共计30+问题，2500+字数</a>  （对这个感兴趣的同学欢迎留言</p><h2 id="照片获奖荣誉个人介绍论文">照片/获奖/荣誉/个人介绍/论文</h2><h3 id="照片">照片</h3><p>可以不放，要放照片就放一张正式的证件照，不要随便照一张就放上来，不要放一些卡通头像/虚拟人头像（我真收到过几份）</p><h3 id="获奖荣誉">获奖/荣誉</h3><p>case1 : 如果简历其他部分内容欠缺，可以写点这个填充</p><p>case2 : 如果是一些和实习工作相关的奖项推荐写上，包括但不限于 ACM、蓝桥杯（国家级奖以上）、各类算法比赛（kaggle、天池）的高名次奖项、各种知名公司/组织举办的活动、四六级高分、高绩点</p><p>case3 : 如果其他部分内容比较丰满，这块可写可不写</p><h3 id="个人介绍">个人介绍</h3><p>这两种情况建议写：</p><p>没其他能写的时候</p><p>or</p><p>有比较厉害的东西，但不适合放其他部分 / 或者想详细介绍下的</p><p>比如视频中的这样【[杂谈]校招&amp;实习简历编写建议|简历模板|5min速通版】 【精准空降到 04:38】 <a href="https://www.bilibili.com/video/BV1mx4y1Z7so/?share_source=copy_web&amp;t=278">https://www.bilibili.com/video/BV1mx4y1Z7so/?share_source=copy_web&amp;t=278</a></p><h3 id="论文">论文</h3><p>这块我不熟，请教了几位算法ssp的佬哥，主要是写了发表论文的刊物名字、等级、发表时间，并给出了可以直接访问的链接，以及论文主要是干什么的。</p><h2 id="模版排版">模版/排版</h2><h3 id="模版">模版</h3><p>软件部分，word/latex 都可以，自己喜欢用哪个就哪个。</p><p>我个人的简历是用 word 排出来的，每一行都是自己调整出来的。我的模版在这里，需要的在GitHub自取 <a href="https://github.com/erdengk/erdengk/tree/master/presonal">resume</a></p><p>如果使用了超级简历，需要注意，它的中文排版有些细节不能自己调整，它英文简历的模版不错，推荐使用。</p><h3 id="排版">排版</h3><p>可以参考：<a href="https://erdengk.top/archives/jian-li--mian-shi">https://erdengk.top/archives/jian-li--mian-shi</a></p><p>总结：</p><ol><li>一句话不要写一大段，除非完全无法拆分，尽量分点</li><li>对自己熟悉、想要引起面试官的细节，使用加粗。（也可以用高亮，但受限于模版，新手不推荐使用）</li><li>日期按倒序，除非你很想把某段经历放前面，那无所谓。</li></ol><h3 id="关于页数">关于页数</h3><p>有些人喜欢一页简历，有些人觉得一页两页无所谓。(应届不至于写3页，不管是排版还是内容，大罗金仙级别的同学请忽略此条)</p><p>个人建议是，不要硬往一页排版就行，要不然会很挤很难看，人都是颜值动物，太挤了容易不想看。</p><p>如果你各种经历都很丰富，一页大概率是不够用的，可以按照正常排版排到一页半到两页，没问题的，不会影响你拿offer的。</p><p>也可以针对性的把 与 <strong>现在要投的岗</strong> 相关的东西整理出来，再排一份新的简历使用。</p><hr /><h3 id="小红书暑期实习秋招内推">小红书暑期实习/秋招内推</h3><p>最后的最后，在这里给我司打个广告，我最后选了小红书的商业化后端开发的offer，所以后面可以帮大家内推/直推一下我司的各种岗位。</p><p>【目前小红书还在发展期，进来大概率像其他厂一样不会纯打杂，有很多机会做点东西。在一些很成熟的厂里因为技术和业务都很稳定了，就可能只能打杂了，个人觉得程序员初期还是要有机会来做点东西锻炼自己的】</p><pre><code>qq群 : 165991086</code></pre><h2 id="参考">参考</h2><p>【1】简历、面试  <a href="https://erdengk.top/archives/jian-li--mian-shi">https://erdengk.top/archives/jian-li--mian-shi</a></p><p>【2】【[杂谈]校招&amp;实习简历编写建议|简历模板|5min速通版】 <a href="https://www.bilibili.com/video/BV1mx4y1Z7so/?share_source=copy_web">https://www.bilibili.com/video/BV1mx4y1Z7so/?share_source=copy_web</a></p><p>【3】【面试官教你这样包装项目，进大厂必看！】 <a href="https://www.bilibili.com/video/BV1pA4m1N7UF/?share_source=copy_web&amp;vd_source=4d050090b394b684b27865dbb93eb184">https://www.bilibili.com/video/BV1pA4m1N7UF/?share_source=copy_web&amp;vd_source=4d050090b394b684b27865dbb93eb184</a></p><p>【4】【手写项目亮点！分布式事务如何落地！一起coding吧！】 <a href="https://www.bilibili.com/video/BV1bd4y1A7ad/?share_source=copy_web&amp;vd_source=4d050090b394b684b27865dbb93eb184">https://www.bilibili.com/video/BV1bd4y1A7ad/?share_source=copy_web&amp;vd_source=4d050090b394b684b27865dbb93eb184</a></p><br><br><br><p>写于2024年7月15日，北京大钟寺</p>]]>
                    </description>
                    <pubDate>Mon, 15 Jul 2024 20:13:36 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[弱链接]]>
                    </title>
                    <link>/archives/ruo-lian-ji</link>
                    <description>
                            <![CDATA[<blockquote><p>本文之外的琐事</p><p>近一年一直在忙求职的事，回校后在忙毕业的事</p><p>托各位前辈/朋友们的帮助，秋招顺利完成，毕业相关事宜也在计划进度之中</p><p>近期恢复正常更新</p></blockquote><h1 id="弱链接">弱链接</h1><blockquote><p>一定要成为中心点，在别人的必经之路上</p></blockquote><h3 id="缘起">缘起</h3><p>忘记了是什么时候认识了敢问社区（前mentor社区）的瑞风哥，在23年求职后半阶段一直在听他社区的免费公开分享，有次听他提到了弱链接这个词，这个词听起来不难理解，就是链接没那么强的链接，至于具体定义/如何利用弱链接我也不太懂，直到有次他自己分享+群友讨论我才有了更深的体会。</p><h3 id="150定律与六度分隔理论">150定律与六度分隔理论</h3><p>人的精力总是有限的，没法同时维持很多人际关系，<a href="https://zh.wikipedia.org/wiki/%E9%82%93%E5%B7%B4%E6%95%B0">邓巴数</a>又称150定律就是指这种现象。</p><blockquote><p><strong>邓巴数</strong>（英语：Dunbar's number），也称<strong>150定律</strong>，指能与某个人维持紧密人际关系的人数上限，通常人们认为是150。这里的人际关系是指某个人知道其他人是谁并且了解那些人之间的关系。支持者认为超过这个人数上限的团队，需要更加严格的规则，法律以及强制性规范来维持稳定性和凝聚力。邓巴数并没有精确的数值，它处于100到230之间，而通常人们使用150。</p></blockquote><p><a href="https://zh.wikipedia.org/wiki/%E5%85%AD%E5%BA%A6%E5%88%86%E9%9A%94%E7%90%86%E8%AE%BA">六度分隔理论</a> 告诉我们一个人认识另一个完全陌生的人只需要很少的中间人就能完成。如果我们可以尽可能的多认识人并建立一定的链接，即使是只有一面之缘，那无论是对求职还是求学都会有极大的助力。</p><blockquote><p>六度分隔理论（英语：Six Degrees of Separation）认为世界上任何互不相识的两人，只需要很少的中间人就能够建立起联系。哈佛大学心理学教授斯坦利·米尔格拉姆于1967年根据这个概念做过一次连锁信实验，尝试证明平均只需要6步就可以联系任何两个互不相识的人。</p></blockquote><p>我也在做自媒体，微信+QQ+各种其他社交软件加了联系方式的也有2k+人，但不是所有的人都会经常联系，有的甚至是简单聊过两句就没后续联系了。</p><p>我也在思考如何能够更好的维护这些人际关系的同时并扩展更多的链接，<strong>有没有一种办法能够让我们突破150定律或者在150人之外能够建立更多有效的人际关系呢？</strong></p><p><strong>弱链接应该可以算一种</strong></p><h3 id="什么是弱链接">什么是弱链接？</h3><p>讲个我认为的弱链接的定义：弱链接是指平时不需要太多或者不需要时间精力持续维持，但想使用的时候可以即时建立的链接。</p><p>弱链接一定要让其他人知道你是谁，“我是谁，我在做啥，我有什么”，这样才能在需要用的时候快速想起来进而判断是否需要交流。</p><h3 id="建立弱链接">建立弱链接</h3><p>建立弱链接的前提------双方不是白嫖怪</p><p>我觉得你是个可信任的人，你觉得我是个可信任的人。</p><p>我大概知道你能做什么，你大概知道我能做什么。</p><p>我们之间平时不需要/或者花费很少精力投入来维系我们的关系，但一旦有需要的地方我们也可以给彼此一定的帮助。</p><p>可以理解为一种需要时的资源置换。</p><h3 id="举个">举个🌰</h3><p>有时候信息就是资源，很多事都是因为减少了信息差而获得成功。当下的环境，普通人之间差别没那么大，你能干，别人也能干，怎么能获得更多机会？合理的推销自己是一个很不错的机会。</p><p>我们会在各种场合加到新的人，刚加上之后是建立弱链接最好的时候，可以顺势做个自我介绍，学历/学校/专业/工作方向/.... 都可以讲，选自己突出的方面介绍，这个操作本质上类似于推销自己。</p><p>比如我可以这样介绍我自己</p><p>我是K，24届硕士，自媒体常用名字是尔等同学，之前在百度网易快手实习过，秋招签了小红书后端。</p><h4 id="弱链接-强链接">弱链接-&gt;强链接</h4><p>这里的强链接指的就是上文提到过的150定律中经常联系的，我们所有的强链接也是从不认识到越来越熟悉后发展起来的。</p><p>对于弱链接，假设我们认识了一个陌生人，刚开始可能互相问个好做个自我介绍。</p><p>突然有天我公司有个机会在收人，我觉得他可以胜任，顺手推荐给了他，他可能刚好想换个工作，且由于他本身能胜任这个工作，人也不错，他成功进入我们公司，他获得了涨薪，我获得了内推费，双赢。我们之前的联系就更多了，弱链接也就变成更强的链接。</p><p>本文写于2024年3月3日下午，西安回成都的高铁路上</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img2024202403041455482.png" alt="image-20240304144622909" /></p><h2 id="参考">参考</h2><ol><li>敢问社区主人瑞风的公开分享</li><li>敢问社区公众号：<a href="https://mp.weixin.qq.com/s/5SKomn3lUAIjFFChHVerMQ">https://mp.weixin.qq.com/s/5SKomn3lUAIjFFChHVerMQ</a></li></ol><h2 id="下一篇">下一篇</h2><p>打算写 《我的求职前半生》，关于大一到研三路上求职的一些事～</p>]]>
                    </description>
                    <pubDate>Sun, 03 Mar 2024 16:46:23 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[《见识》吴军]]>
                    </title>
                    <link>/archives/jian-shi-wu-jun</link>
                    <description>
                            <![CDATA[<p>很久没更新博客了，从暑期到入职，再到秋招</p><p>中间很多时间都没能持续阅读和总结，希望现在可以再捡起来吧。</p><p>一直很喜欢吴军博士的书，下面这本是《见识》</p><h2 id="性格决定命运">性格决定命运</h2><blockquote><p>人一辈子被扇巴掌的情况和原因很多，各不相同，但是一个人对待它们的方法却有高度的一致性。习惯于扇回去的人一辈子都在扇别人巴掌。英国著名的女首相撒切尔夫人喜欢讲这样一段话：</p><p>注意你的想法，因为它能决定你的言辞和行动。</p><p>注意你的言辞和行动，因为它能主导你的行为。</p><p>注意你的行为，因为它能变成你的习惯。</p><p>注意你的习惯，因为它能塑造你的性格。</p><p>注意你的性格，因为它能决定你的命远。</p><p>这可能是我们今天所说的“性格决定命运”的由来。其实决定命运的还包括我们的习惯、行为及其背后的思维方式。思维方式出问题的人，命运之神是永远不会眷顾的。前面提到的那些在机动车道上健走的人，就属于思维方式出了问题，用句北京的老话讲，就是凡事浑不凛。</p></blockquote><h3 id="幸福是目的成功是手段">幸福是目的，成功是手段</h3><blockquote><p>当一个人对社会产生了极大的正向影响力后，他不仅可以获得物质（比如金钱）和精神（比如名誉）的财富，而且会有一种由衷的幸福感。</p><p>为什么会有人在意自己的影响力，因为它是人幸福感和满足感的来源之一。人的幸福感有多种来源，而且不同的人还会有所不同，比如男欢女爱、财富、成就和影响力都可以让我们感到幸福。不过，学者们认为，幸福感的本源只有两个—一基因的传承和影响力。</p><p>当我们得知自己的所作所为给世界带来了或多或少的正面影响时，会有一种发自内心的高兴。而人的髟响力则是由其作为的宽度、深度和长度所决定的。2012 年，我又回到离开了两年的谷歌，发现公司在很多地方已经改变了，甚至文化也变得不同了。不过我发现，当初写的一些代码被略作修改和封装后，依然在广泛地使用，其中使用率最高的一组算法已经被用在了上百个项目中。这时的幸福感远不是钱可以换来的。</p></blockquote><p>虽然给开源社区做的贡献很小很小，但想到自己的代码能服务于那么多人，还是很自豪的。</p><p>另外一直在组织的开源分享，也直接或间接的帮助到了一些人，甚感欣慰。</p><h3 id="人生最重要的投资">人生最重要的投资</h3><blockquote><p>我给男生的最后一个建议是，一个人，特别是年轻的时候，可塑性很重要。虽然我们常说喜欢一个人就要包容对方的缺点，但包容一天可以，一年可以，包容一辈子还是很有难度的。幸福的婚姻不应该是一方包容另一方一辈子。具有可塑性的好处在于，虽然一开始有摩擦，甚至在很多方面有所缺陷，但是这样的人进步会很快，磨合起来也很容易，将来日子会越过越容易。我们都知道，今天看似再完美的匹配，时间一长总要遇到矛盾，能够有一定的柔性，彼此妥协解决问题、相互适应，才能一起过得长远。</p></blockquote><p>或许婚姻的本质应该是，过日子？</p><h3 id="先让父母成熟起来">先让父母成熟起来</h3><blockquote><p>今天，中国伏然有很多父母把孩子看成是自己的私产，不这多大都说孩子应该听自己的话、孝顺自己。这种认识其实还停留在衣耕文明时代。那时没有健全的社会保障制度，一个大家族的人要抱团取暖，很多事情才能解决，养老就是最现实的问题。哪个大家族能够做到几代人和睦相处，就能在竞争中取得优势。当然这种家长制不仅让女性没有地位，也大大地限制了个人的发展。</p><p>在今天，很多观念不仅显得不合时宜，而且对孩子的发展也不利。</p><p>今天，如果能让孩子从心里尊重父母，在行动上愿意和父母交流，那么比停留在形式上的孝顺有意义得多。在当下，我倒认为父母和子女之间所缺三的恰恰是彼此的尊重和理解。我的母亲和岳母在几代人间的相互关系上都有两个共识。首先，在我家，我和我妻子是主人，她们都是客人，因此没有发言权。当然，到了她们家，她们便是主人，我们没有发言权。其次，对我的孩子怎么教育由我们自己决定，她们不多发言。很多人都说我们家里的老人</p><p>很开明，但是她们并非一开始就有这样开明的想法，而是氧自己不断地与时俱进，以及我们不断对她们施加影响的结果。我或许应该庆幸，我的父母和岳母都很成熟。</p><p>在我周围有不少来自农村或者底层家庭的子女，通过努力实现了社会阶层的进阶，很多已经成为社会精英。我接触过那些朋友家里的老人，发现他们有三个共同的特点。首先是大气、开明，不斤斤计较，不倚老卖老。其次，虽然他们自己受教育程度不高，但是学习的愿望很强烈，愿意尝试新的东西、接受新鲜事物。有一次，一位过去长期生活在农村、现在到美国看望子女的老人和我讲：“你们（指我和他的孩子）也不比过去那么年轻了，多保重身体，注意饮食，少吃红肉（指猪牛羊肉）。”我听了他最后一向话觉得很奇径，这位老伯一直生活在农村，怎么会知道要少吃红肉这件事，这是一般美国医生给人的建议，很多中国老人觉得冬天吃羊肉是大补的。于是就问他怎么有这个常识的。他讲，来到美国后，医生们给他新的饮食建议，虽然和他过去几十年的经验不同，但是他觉得有道理就接受了。可见，一个人是香愿意接吗</p><p>新的知识在于是否有开放的心态，而非过去的数育程度。</p></blockquote><p>不知道未来的自己是否有勇气去做父母，但现在先把自己修炼好再说吧。</p><h3 id="向死而生">向死而生</h3><blockquote><p>从哲学的层面讲，死亡其实并不可怕。我最早很严肃地思考。</p><p>这个问题，是在父亲病重时，因为第一次感觉到死亡离我非常近。</p><p>我读了爱因斯坦和他 朋友的一段谈话，这位物理学家是一位看穿了时空的智者。他说，我们对死亡的恐惧有点儿莫名其妙，我们站在 “有” 的世界，试图理解“无” 的问题，按照“有” 的逻辑，对“无”产生恐惧。这句话，不是那么容易理解，不过你会慢慢体会出它的含义。</p><p>人如果不想在 “有”的世界对“无”的世界产生恐惧，就要采取一些有意义的行动。梁实秋在晚年感叹：“人一出生，死期己定，这是怎样的悲伤，我问天，天不语。”这未免有点儿伤感，对于宿命，我倒是更喜欢周国平的态度：“这个世界大家其实都在排着队沿着一条路往前走，停不下来，走到尽头就是死亡（到此为止和梁实秋讲得差不多)。这时，有些男人和女人搭上了腔，开始说笑起来，更多的人参与了进来，整个队伍便充满了欢乐。”我想，我们的生活其实就应该是这样的。</p></blockquote><p>是从什么时候开始的呢，大概是某天喝酒时突然想到了父母年过半百，爷爷奶奶这些祖辈也年龄不小了，该来的总会来，不知道是在哪一天就突然到来。</p><p>我为了避免结束，选择了避免开始，因为没有开始，就不会有结束</p><p>没有结婚，没有要孩子，就不会有她走了我没走，我走了她没走这种问题，孩子也得承受新一轮的痛苦，何必呢？</p><p>或许极端，或许自私，亦或许是没有勇气去面对吧</p><h2 id="人生需要做减法">人生需要做减法</h2><blockquote><p>个人在工作中也常常容易检芝麻、丟西瓜。我在前面提到的伪工作者就是捡芝麻的典型例子。那些人习惯于做简单、重复且价值又低的工作，因为那种工作不需要太动脑筋，不会遇到非常大的困难。但是，人一旦习惯于这种工作，真正有创造性的工作就做不来了。我曾经批评过 2016 年在阿里巴巴抢月饼的人，以及为他们开脱的人，他们行为本身的对错倒在其次，这种把心思放在捡芝麻上的人，让我瞧不上，因为他们永远地远离了西瓜。糟糕的思维方式和街量价值的标准，决定了人不幸的命运。</p><p>苹果公司的产品线一个巴掌就能数过来，却是全世界挣钱最多的公司，因为它在捡西瓜。捡西瓜的人在思维方式上和捡芝麻的人完全不同，他们不会为那些蝎头小利动心，而是把目光放得更长远。乔布斯在回到苹果时，发现公司内一大堆的项目和产品都是小芝麻，他在那些项目和产品上一个个画叉，直至剩下个位数的产品，再把它们每—个变成西瓜，这才救活了苹果。</p><p>除了眼光和思维方式的不同，捡西瓜更是要有能力的，它不能靠运气，而是需要长期培养才能获得。我们在职场中的每个人，与其把心思放在赚小钱上，不如把它们都聚焦到一点，练就捡西瓜的能力，让自己从同事中脱颖而出。通常，人有能力晋级一个台阶，贡献、职责、影响力就可能增加一个数量级，至于收入就更不用发愁了。当然，世界上检芝麻的人多、捡西瓜的人少，你如果致力于捡西瓜，就要耐得住寂寞。有人说，我没有遇到西瓜</p><p>啊，其实不是没有遇到，而是因为你满眼都是芝麻，天天为检芝麻而忙碌，就没有机会练就检西瓜的能力了。</p></blockquote><h3 id="生也有涯知也无涯">生也有涯，知也无涯</h3><blockquote><p>庄子在《养生主》一章中开篇讲了这样一句话：“吾生也有涯，而知也无涯，以有涯随无涯，殆矣。已而为知者，殆而已矣。”它的大意是，我的生命是有限的，但是知识是无限的，以有限的生命追求无限的知识，是要失败的。已经知道这个事实还要为之，失败是确定无疑的了。</p><p>罗振宇老师在很多场合把我说成是一个善于利用时间，同时能做很多事情的人，以至很多人也这样看我，手是写信问我做事情的时间是如何挤出来的，怎样才能同时做更多的事情。其实，罗振宇老师是在往我脸上贴金，我虽然时 间管理得还算好，也不能同时做很多事情。我做事的快窍（如果这也算是诀窍的话）恰怡和大家想的相反，就是少做事，甚至不做事。当然，我把这个答家告诉提问者时，很多人会说，每天的事情那么多，这件事情应该做，那件事情也是必须完成的，怎么可能不做呢？我会对他们讲：“这是因为你已经陷入了常人的,思维定式，你说的那些事情如果不做的话，难道天还能塌下来吗？</p><p>​很多时候，我们会路入一种思维定式不能自拔。我们在生活中经常遇到这样的人，他们有习惯性迟到的毛病，而每—次理由都还不一样。比如，今天出门之前，刚好母来打来一个电污，总不好不接，于是耽搁了一点时间；而昨天的迟到则是因为在地铁站遇到一个老同学，对方要寒暄几句，不和人家说几分钟话会显得架子太大，太不给面子了；前天参加聚会迟到则是有别的理由，本来做好的准备提早下了班，但是快到聚会的地点时，一看时间还早，顺道去家乐福买了个化妆品，可不巧赶上收款的队排得很长；大前天下班接孩子也迟到了，因为下班前同事跑来聊了两句，就耽搁了 5 分钟，谁知晚出来这5 分钟就赶上了下班的高峰期，手是堵车了。我发现，这些人迟到的毛病基本上改不掉，因为他们有一个思维定式，临时插进来的事情必须要做，不做就没礼魏、没面子，或者就亏了。其实那些事情如果不做，天根本不会塌下来。</p><p>每当别人问我：“怎么才能每天有更多的时间做事情，或者如何能够抓紧时间？，我总是告诉他们：“你不可能有更多的时同，因为你已经很抓紧时间了。你需要做的事跳出原有的思维方式少做事。如果你想通俄很多事情不做其实也无关大体，就不要去做它们，这样你就不会天天忙忙碌碌了。“</p></blockquote><h2 id="谈谈见识">谈谈见识</h2><blockquote><p>很多时候，成败与否取决于见识的高低，而不是自己简单的努力。今天，由于交通和通信技术的发展，我们增加见识要比过去容易得多。但在我们心中，有时依然有一道围墙，阳碍了我们的见识。</p></blockquote><h2 id="大家智慧">大家智慧</h2><h3 id="论朋友">论朋友</h3><blockquote><p>1.凡事三思而行，不要想到什么就说什么</p><p>这其实是教导我们为人做事要持重，要多动脑筋，不要毛毛燥燥。这其实是现在很多人的通病对人要和气，但不要过分狎呢。</p><p>2.很多时候，礼数有加，但保持距离是朋友之间最好的交往方式。</p><p>相知有素的朋友，应该用钢國箍在你的三观上，可是不要对每一个泛泛的新知滥施你的交情。</p><p>这三条也是我一生交友的准则。人一生总能认识一些朋友，他们是我们一生最大的财富。</p></blockquote><blockquote><p>人一辈子做事情，不可能没有人帮忙，而这个合作伙伴的选择，其实至关重要。有些时候，考家一个人只要看看他（她）的朋友圈就行了。人遇到一个合适的伙伴并不容易，因此要像莎士比亚讲的那样，“用钢圈貓在你的灵魂上”。当然，莎土比亚还说了后半句话，“不要对每一个泛泛的新知滥施你的交情”。一个人</p><p><strong>因为交往的带宽有限，因此不可能和所有人交情都很深，一个表面上对所有盆友一视同仁的人，实际上是很难有至交的。</strong></p><p>面上对所有朋友一视同仁的人，实际上是很难有至交的。</p><p>我过去有一个非常不成功的老板，当年是一个专业能力烦强的新说。因为他做事情无私心，老局长很喜欢他，就提披他。这位老板是二个好好先生，对所有部下一视同仁，他自己觉得这很公平。但是不到两年，所有能干的部下全跑光了，手下剩的都是平庸之辈，他一点业绩也做不出来，于是很早就退休赋闲了。</p><p>人的出生自己无法决定，周围的家人、亲威的圈子基本上是固定的，无法改变，能自己决定和选择的只剩朋友了。好的朋友是巨大的财富，而损友则是巨大的负资产。至于如何避免损友，每个人都应该有自己的方法，当然很多人一辈子没有合适的方法，最后死在所谓朋友的手里都不知道是怎么死的。</p></blockquote><blockquote><p>你如果问我是怎么做的，我用的是曾国落的一个原则，简单地讲就是不要给损友第二次机会，永远不要来往。曾国藩在家书里写过这样一句话：“袁婿荒唐…永远绝之。”非常坚决。这里所说的“袁是指曾国落的四女婿、他的老朋友翰林袁芳瑛的长子，非常不成器。曾国落的这种做法，也给了我很多启发。</p><p>我对任何人，一般都先假设他是正直、善良和诚信的。当然，这样一来我会有很大的机会上别人的当，而在生活中我也确实如此。不过这没有关系，我只会上一次当，因为在上当之后我并不给那些人第二次机会。你可能会问，这样一来，是否会错失很多本来能够成为朋友的机会，因为人是会改变的，他可能会变好。</p><p>**是的，人确实会变好，但是已经与我无关了。要知道，可交往的人很多，而你的时 间和精力只能维持少数的几十个。**这种笨办法能够避免在朋友关系的投资上出现填不满的无底洞。我们都知道，不知道止损的投资者注定是要倾家荡产的，在和朋友的关系上也是如此。</p><p>在我的心目中，莎士比 亚和曾国落都是智者，他们的建议都是金玉良言，我对他们的话也是在身体力行。</p><p>朋友是我们一生的财富。</p></blockquote><p>上当之后，还是别给第二次机会了。</p><p>（如果在职场中遇到这种怎么办呢？（或许，提升自己，早日远离，是一个不错的办法）</p><blockquote><p>谷歌商业模式的本质还有一个要点是，有用的内容并不需要是自己的。我在 《智能时代》中讲，在未来的智能社会，连接比拥有更重要。谷歌和脸谱网这样的公司并不拥有什么内容，但是它们有对用户的连接；爱彼迎没有自己的房子，但它却是全世界最大的房屋租赁公司；优步和滴滴不拥有汽车，却是全球最大的出租车公司。懂得了这一点，就理解了互联网经济的本质。</p><p>世界上是否还有在本质上类似谷歌这种商业模式，但在表面看又完全不同的公司呢？其实很容易找到。比如阿里巴巴，它所销售的商品都不是它自己的，它的作用只是把商品信息送达用户。</p><p>分外，“罗辑恩维” 也很相似，就是将有用的内容（它称之为知识）送达读者。理解谷歌商业模式的精儲，并不需要照猫画虎；相反，那些将垃圾强制推送给用户的公司反而是画虎不成反类犬</p></blockquote><p>连接，比，拥有更重要。</p><p>我不是A公司的员工甲，但我认识A公司的人，当有人问我A公司的事时，我可以通过员工甲来打听，下一次可能是反过来，连接多了之后，我就成了一个中转站，同时也因为各种信息都会经过我，我自身对于整个行业的信息差也在减少，双 win ！</p><blockquote><p>人相处的技巧在于，要让对方感觉对你有所需求。</p><p>最后做个总结：如果我们能够顾及别人的面子，生意就能做好，事情就能做好；如果我们为别人提供价值，而不是一味地推销，我们的产品，甚至我们自己，就会受到欢迎。</p></blockquote><p>能提供相互价值，才能走的更远，不论是朋友，恋人。</p><h2 id="拒绝伪工作者">拒绝伪工作者</h2><blockquote><p>效率高低不取决于开始了多少工作，而在于完成了多少。很多我们看上去非做不可的事情，其实想通了并没有那么重要，因为它们是伪工作。所以，无论是在职场上还是在生活中，提高效率都需要从拒绝伪工作开始。</p><p>IT 工作伪工作</p><ol><li>那些既不能給公司带来较大收益，又不能络用户带来你位的政进和“升级”，很多是份工作。比如，在互联网行业里，如果一个产品中菜些功能或 者设计上线之后生命网期不到三个月，那么当初很多开发的工作都是份工作。按照这个标准衡量，微软在Windows、Offce（基于 Windows 操作系统的办公软件套裝）和正（网页浏览器）上很多工作其实都是伪工作。</li><li>有的人明明能够通过学习一种新技能更有效地工作，却偏偏要守着过去的旧工具工作，甚至手工操作，这种人是典型的伪工作者。</li><li>在做事情前不认真思考，做事时通过简单的试错方法(trial and error）育日寻找答案。</li><li>做产品不讲究质量、不认真测试，上线后不停地修补，总是在花费很多的时问和精力找漏洞和打补丁。</li><li>不注重用有限的资源解决95%的问题，而是把大部分时问和精力用于纠结不重要的5%的问题。</li><li>每次开会找来大量不必要的人员旁听，或者总去参加那些不必要参加的会议。</li></ol></blockquote><p>面向自己老板编程，面向产品老板编程，面向大老板编程。</p><h3 id="三板斧破四困境">三板斧破四困境</h3><blockquote><p>第一板斧确立 “愿景-目标-道路”</p><p>第二板斧：即使听到不中意的话，也要试眷找出其中的合理之处</p><p>这是我的中学校长万帮儒先生在我毕业前对我讲的，他这句话大概有三层意思。</p><p>第一层，相当于我们今天说的换位,思考，当然当时还没有换位思考这个词。</p><p>第二层，凡事要习惯回过头来三思。比如某个人和你讲一件事，你第一感觉可能觉得他完全是胡说八道，但是，一定要想第二遍，是否我错了、他对了。这一遍思考，一定不能假设自己是对的；</p><p>如果又想了第二遍，还是觉得自己对、对方错，要想第三遍，是否我的境界不够，不能理解他。</p><p>为什么要想第三遍呢？因为任何一个想要精进的人，都要和比自己强的人多来往，比如下棋，如果整天和臭棋篓子下，只能越下越臭。既然是和比自己强的人交往，第三种情况就很可能发生，因此这时候不妨进一步交流，深入了解对方那么说的原因。只要经常这么做，就能避免习惯性失败。</p><p>第三层，即使对方真的是胡说八道，也要思考他为什么这么说，找出其中的合理性。举一个极端的例子，你在公司里遇到一个照街的泼妇，你也没有招惹她，她对你路头盖脸就是一通臭骂。对此我们有三种做法：一种是骂回去；一种是装作没听见；</p><p>但是我会采取第三种，就是要思考为什么她没缘由地骂我，或许她就是一个疯子，那么我以后走路躲她远点，也算接受一个教训;或许她真有一个骂我的原因，这个原因就是合理性，<strong>如果我们找到了这个原因，不仅理解了她的问题，而且对人性的理解也有了提升</strong>。</p><p><strong>如果我们总是能从不中听的话中找到合理性，不仅进步快，而且眼界、气度都会比常人高出很多，才不会陷入林黛玉式的困境</strong>。<strong>这一点看似不容易做，但我的做法很简单，就是每次遇到别人和我有不同意见时，就立即开启寻找对方合理性的开关，直到找到对方的合理性为止。我也不知道这样做是否是强迫症，但对自己的进步真的特别有益。相反，当对方看法和我们一致时，反而不需要找合理性让自己沾沾自喜。</strong></p></blockquote><p>重要的是相悖的建议</p><blockquote><p>第三板斧：凡事做记录，这样可以避免狗熊掰棒子</p><p>做任何职业，比如工程师、会计师、律师，都会遇到一些难题，解快了这些难题，我们就进步了。遗憾的是，大部分人过分</p><p>相信自己的记忆力，以为自己能记住，但实际上很快就忘了，等到第二次、第三次遇到同一个问题时，还是束手无策，或者花很多时间去解决。因此，这是凡事做记录的好处之一。做记录的另一个好处是，在记录的过程中又思考了一遍，进步得会更快。相</p><p>比之下，欧美人比较喜欢记录，他们发明一个东西是可以给当时的时代一个定义，比如美国工业崛起的时代等，当时是如何做实验的，今天依然能找到记录，这样经验也容易积累和传承。相反，在中国，失传是个非常常见的词，以至常常在低水平上重复发明。</p></blockquote><blockquote><p>这三板斧对我来讲非常有效，是否对所有人都有用，我不敢打包票。有没有更多、更好的方法呢？或许有。但是，太多太复杂的方法难以实施，效果反而不如那些简单易行的方法。我从不认为自己能够记住那些 “10 个改变你生活的方法”或“20条提高效率的法宝” 等，因为数量太多根本记不住，更不要说照着执行了。对于简易可行的方法，或许灵，或许不灵，但是即使不灵也能很快发现而去寻找更有效的方法。艾萨克 •牛顿讲，自然界喜欢简单性。</p><p><strong>而在工作中，有效的方法也常常是简单的，这也算是我在职场上这么多年的一些感悟吧。</strong></p></blockquote><h3 id="做好最后-1">做好最后 1%</h3><blockquote><p>你可能会发现，在日常生活中，大部分人愿意开头而不愿意收尾，九十九步都走了，就是懒得把最后一步走完。这可能是人的天性，凡事差不多就可以了，总觉得最后一点即使不做也无关大局，但是这样完成事博的质量就要大打折扣。在工作中，这种人平时完成一般的工作或许没有问题，但是对于那些最要紧的事情，领导可能不敢交给他们。这些人实际上可能和走完一百步的人同样辛苦，但是成就却相去甚远。</p></blockquote><p>总是容易懒得做最后一步，久而久之形成习惯就很难改了。。。</p><h2 id="职场的误区和破法">职场的误区和破法</h2><blockquote><p>人的第一份工作很重要，它的性质和成败决定了你此后职业发展的方向和事业起点。对第一份工作，年轻人常常陷入一些误区，尤其是过于看重薪酬而影响了对工作的价值判断。</p></blockquote><h3 id="按照朗道理论划分的行业的五级工程师">按照朗道理论划分的行业的五级工程师</h3><blockquote><p>最高等级：开创一个产业</p><p>能设计和实现别人不能做出的产品，也就是说他的作用很难取代</p><p>高级：能独立设计和实现产品，并且在市场上获得成功</p><p>中级：能指导和带领其他人一同完成更有影响力的工作</p><p>初级：能独立解决问题，完成工程工作</p><p>按照朗道的方法，我也将工行业的工程师分成了 5个等级，对于其他专业人士，也可以依此分类。分类的原则大致如下图所示。</p><p>以计算机行业为例，一个人毕业后，经过一段时间的锻炼，能够熟练应用工程的知识和技能解决问题，独立完成所分配的工作，而不需要他人指导，就算是一个合格的第五级工程师了。再具体一点，比如这个人在京东任职，老板让他开发一个工具，找出那些不断帮助女（男）朋友买书的读;者。他自己知道在公司内找谁去要数据，如何确认两个人可能是男女朋友，而且经常买书；</p><p>也知道自己在京东的环境里，应该使用什么样的开发工具，以及为了方便客户使用，这个工具应该有什么样的基本功能。</p><p>如果做不到这件事情，算不上一个合格的工程师。在过去，工程师和科学家是可以并列的头街，今天在法国和德国依然如此——那里的工程师会有一个特殊的资格证书，就如同医生和律师有特殊的资格证书一样。但是在中国，很多人从工科大学一毕业，公司就在他的名片上印上“工程师”，然后他就似乎已经成为工程师了。但很多人有这个头街，却并不具有工程师所应该有的基本技能。在IT行业，很多人被称为“码农”，虽然名字不大好听，但是仔细想想，似乎也是对天天简单地重复低层次工作的人的一个形象的马照。</p><p>我想，上述对一个第五级工程师的要求，任何一个从工科大学华业的学生，只要自己有心，也往这个方向努力，就不难达到。如果达不到这个层次，不能算合格的工程师。</p><p>对于第四级的工程师，就需要有领导能力和在工程上把大问题化解为小问题的能力。用我之前写的“愿景一目标一道路”的逻辑（见第五章），他们能够寻找出实现比较大的目标的道路。工程师和科学家不同，后者考應的是对和错，前者只是在现有条件下考虑好和坏的解决方案。</p><p>比如在建造一座海湾大桥时，工程师会在现有资金的条件下，根据交通的需求设计一座200 年使用寿命的大桥，但是为了让军队迅速通过一东河，他们追求的目标就变成了在最短时间内建造一座足够让军队安全渡河的浮桥。目标不同，工程师的解決方案就不同，这件事对于士木工程师和桥梁工程师来讲，常常不是问题，但是很多摘工的人，常常会把海湾大桥修成浮桥，也会把浮桥按照海湾大桥来慢慢修。</p><p><strong>因此，能否成为第四级的工程师，要看能否最好地解决一个这样有规模的实际问题。这个能力远不是熟练写程序就足够的。</strong></p><p>很多人抱怨自己的机会不够，其实从管理者的角度看，中国IT公司里非常缺乏这样有头脑的工程师。至于为什么有的人能够得到机会，那是他们和上下级之间较强的沟通能力帮助了他们。</p><p>对于第三級的工程师，就应该能够独立＃领其他人做出一个公司挣得利润的产品。这里面除了上述能力外，还涉及对市场的判断能力和营销能力。很多人讲，我就是做工程的，这个东西是否有用我不清楚，有什么事情你叫我做就好了。这样显然达不到第三级工程师的要求。**第三级的工程师，本身必须是非常好的产品经理。**一个有良好工程素养的人，如果心胸开阔，愿意接受各种意见和建议，经过努力，可以做到这一步。你可能奇怪，我为什么专门强调心胸开阔。因为人有多大的心，就能做多大的事情。有人抱怨自己作为工程师，收入和社会地位太低，我想如果你做到第三级就不低了。当然再往上，就不是很多人能够做到的。</p><p>第二级工程师是能够做出先前没有的东西，世界因为他们多少有点儿不同。举几个例子，比如北极光风投的创始人邓锋，在他（和谢青、柯岩）之前，世界上没有真正意义上的网络防火墙</p><p>设备，他们做出了这个设备，并且成功创立了当时世界上最大的防火墙公司（Netscreen )，这家公司在被收购前市值大约为20亿美元。他可以算得上是第二级工程师。另外，谷歇云计算的发明人杰夫•迪恩也可以算。你如果能成为第二级工程师非常好，但是如果不能也没有关系，不必对自己太苛刻。</p><p>第一级工程师是开创一个产业的人，包括爱迪生、福特、贝尔等人，可能离我们远一点。</p><p>接下来大家应该知道努力的方向了，每提高一级，你的影响力和收入就增加很多，当然对你的综合能力的要求也高很多。</p><p>最后，对这一节的内容做一句话的总结：凡事做到 50分靠常识，从50分做到90分靠技术，从90分做到100 分靠艺术。每一个阶段是不能跳跃的，做到 90 分我们通过努力都能达到，至于是否能做得更好，就因人而定，可遇不可求，所以不必有负担。</p></blockquote><h2 id="商业的本质">商业的本质</h2><blockquote><p>世界上每过一段时间，就会诞生出一些新的商业概念，最后大家发现炒完概念后剩不下什么东西。其实，不论概念如何炒，南业的本质上千年都没有什么改变。</p></blockquote><h2 id="理性的投资观">理性的投资观</h2><blockquote><p>事业成功，挣到了钱，却不会花、不会理财，可能最后白忙活一场；没有挣到钱，空有一腔理想抱负，可能也不过是幻想。因此，金钱观不仅会对人的事业产生影响，也会快定人的幸福。</p><p>钱是上帝存在你那里的，不是给你的，回头你要还给他</p><p>很多人一辈子，尤其是前半辈子非常辛苦地打拼，凭自己的能力、努力挣钱，而且常常为了挣钱放弃了一切，比如白己的健康、亲情、友情和幸福。但是，他们没有想通一件事情，那就是世界上做任何事情都是有代价的，挣钱也是如此。对于那些能够</p><p>留下巨额遗产的人，最终钱只有三个去处：</p><ol><li>﻿﻿在生前都花掉，花不掉就糟蹋掉。</li><li>﻿﻿交给山姆大权（美国的绰号和拟人化形象）这样的国家部门或者慈善机构（中国现在还没有道产税，但不等于将來没有)。</li></ol><p>3.留给他人，包括后代。</p></blockquote><h3 id="钱只有花出去才是你的">钱只有花出去才是你的</h3><blockquote><p>钱的本质是什么？它实际上是对各种资源的所有权和使用权的量化度量，而资源本身又可以分为自然资源和人的资源。这句话怎么理解呢？我们不妨看这样两个例子。</p><p>如果你运气好检到一颗钻石，你就有了钱，因为你拥有了一部分自然资源；如果你买了一块士地盖房子，你花出去的钱就换得了土地这种自然资源。对于人的资源的拥有，也是如此。当你花钱买一辆汽车时，除了换回了一点钢铁、橡胶等少量自然资源外，其实是花钱买生产线上工人的时间；当你请保姆打扫房间时，实就是买他们的时间；</p></blockquote><p>合理的钱买合理的时间</p><p>合理的钱办合理的事</p>]]>
                    </description>
                    <pubDate>Tue, 18 Jul 2023 19:47:17 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[《我的实习前半生》]]>
                    </title>
                    <link>/archives/wo-de-shi-xi-qian-ban-sheng</link>
                    <description>
                            <![CDATA[<h1 id="我的实习前半生">《我的实习前半生》</h1><p>实习，便是借用学生身份去体验实际工作环境，如若合适，可以考虑留下，如若拉垮，提桶跑路。</p><p>实习，便是了解正式工作后的生活，问自己，如果未来的生活是这样，还要选择继续吗？</p><p>实习，或许是与自己和解吧</p><p>从上一段实习到离职，再到入职下一段实习一个半月，经历了很多，有想过偷懒总结了，但还是觉得应该写写，看了几届暑期实习/秋招，只有自己亲身经历过这一遭才知道是什么样的。</p><p>或许这篇文章也可以用另一个标题 《2023 暑期实习 69 投 20 面 0 offer》 ，因为第 21 面后有了offer 🤣</p><p>本文或许对 2024 的应届同学没太大帮助，更适合 25 届的同学做一个参考。</p><p>我会介绍自己的实习与准备暑期实习的经验与收获，也会总结一些 拿个offer 的同学的经历与经验。</p><p>下文中，拿友 = 拿个offer的朋友，mentor = 带实习生的正式员工， leader = 部门主管、老板。</p><h2 id="钻石一月">钻石一月</h2><p>因为是刚开始实习，所以也没给什么正式的需求，帮忙测一些接口和做一些简单的工作。也没有能写入简历的东西，相当于是带薪学习了。</p><p>此时和组里的同事也是点头之交，并没有太多交集。</p><h3 id="mentor-的奇怪举动">mentor 的“奇怪”举动</h3><p>一开始不知道 mentor 的工作经历，通过同学大概知道他职级约等于阿里的P7</p><p>还记得第一次和 mentor 1v1 ，mentor 讲了工作上应该注意些什么、组内业务、项目结构。</p><p>然后推荐了几本书，并建议多写算法和多看优秀的代码，理由是“大公司都很注重这些”</p><p>年前小组聚餐了一次，mentor 又提到了要去大公司工作，不管是技术还是眼界都会有很大的帮助</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172110484.png" alt="在这里插入图片描述" /></p><p>或许 mentor 希望我能去更大的公司，他也把一些正式的需求交给我做，我遇到的问题也会尽心讲解，教导我不要为了解决问题而解决问题，更重要的是为什么会发生这种问题以及如何解决。</p><p>在整个实习期间，mentor 派活也是循序渐进的，不会一上来就写需求，有些杂活也是大家分着做，不会因为我是实习生就把杂活都给我做。</p><p>每念及此，总是庆幸自己能遇到一个这么好的 mentor 。</p><h2 id="铂金二月">铂金二月</h2><p>2月将学校的事情弄完后开始了暑期的投递</p><p>我还记得那天刚弄完学校的报告，就投递阿里云的暑期提前批（拿offer是不太现实的，进面刷经验就好了）。</p><p>2月做了一些需求，换了工位，和组里最厉害的同事是邻桌，经常和他一起下午茶，混熟了之后他经常帮我解决一些问题，整理了一下实习做的事，写了第一版的简历（暑期求职4个月，简历更新了将近20版🤣）</p><h3 id="阿里云暑期提前批">阿里云暑期提前批</h3><p>阿里云提前批是不进系统的，很多员工都在牛客上发贴，只要通过了简历筛选的都可以进行面试，也就是说只要你够厉害，理论上是可以把阿里云所有招人的组都面一遍的，事实上，确实有大佬这样做了（后文会介绍到的），当然，这是对于大佬而言的。</p><p>这个机制也可以用另一种方式去理解，只要投的够多，是可能有机会获得面试机会的。我自问不是 双9 ，亦不是顶会作者，实习也不是在大厂核心部门，只能多投。</p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172110325.png" alt="在这里插入图片描述" style="zoom:50%;" /><p>牛客邮件大约投了20多份，微信加了10个左右，收到了 2 场电话面，但更多的是拒绝 or 没有回应</p><h2 id="金三">金三</h2><h3 id="实习收获">实习收获++</h3><p>实习的组里另一个老哥请假了，只有我和 mentor 两个人干活，一起发布了两个版本，完整的走了几遍开发、上线流程。</p><p>mentor 之前是带过一些实习生的，和他共事就很舒服，他也经常推荐给我一些东西（包括不限于技术、如何学习、思维提升、做人做事）。</p><p>故余虽愚，卒获有所闻</p><h3 id="阿里系正式批">阿里系正式批</h3><p>3 月，阿里开系统了，我知道我是过不了阿里云学历要求的，甚至连阿里边缘部门都很难，于是把阿里的目标定位进面刷经验就可以，从牛客上联系了很多人，从三月到五月，我邮件发了 30-40 封，微信也加了不少。有些员工会直接说不合适，有些会说需要评估一下（然后就没后续了），有些说可以进面直接在系统投递，有些会打电话简单聊聊介绍部门业务。</p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172110611.png" alt="在这里插入图片描述" style="zoom:50%;" /><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172110668.png" alt="在这里插入图片描述" style="zoom:50%;" /><p>一些不合适、被拒的记录：<br /><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172118209.png" alt="image-20230716182535314" style="zoom:33%;" /></p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172114013.png" alt="image-20230716182638737" style="zoom:33%;" /><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172110427.png" alt="在这里插入图片描述" style="zoom:33%;" /><p>对我个人而言，阿里电话面过 3 次，在确认可以进面后，投递了某部门，P7 一面，隔了一周 P8 二面，个人认为表现应该还可以，猜测是排序挂了。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172111454.png" alt="在这里插入图片描述" /><br /><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172118557.png" alt="在这里插入图片描述" /></p><p>蚂蚁也投递了不少，也有一些电话联系。有个确认能进面的部门后就在系统上选了这个部门。当天约面了，可能是比较急着走流程，周末两天也可以约。准备几天后就面了。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172111568.png" alt="在这里插入图片描述" /></p><p>没有二面，从一面学到了很多，也对面试有了更多的理解，还是很感谢面试官的建议的。</p><p>至于挂的原因，太多了，可能没达到面试官预期，可能排序不过，不知道了。</p><h3 id="一些其他公司">一些其他公司</h3><p>简单列一些公司及我知道的后续</p><p>我美团投太晚，三个志愿都结束了 （5月末拿到想去的 offer 后有去美团实习的朋友说组里还有hc，问要不要面一下，当时心气也没了，就没面 （后续猜测可能是之前拿了offer没去，被卡了）</p><p>美团应该是今年暑期的 byd ，发了很多 offer，且不是那么卡学历或学校。当然，后面排序时还是会综合看一看的。</p><p>百度、pdd 海笔，进面的相对比较少。</p><p>米哈游，简历筛了很多人，进笔试和面试的就更少了。</p><h2 id="银四">银四</h2><p>能面的也没多少了，能去的公司也没多少了</p><p>有个拿友可以组内直推我去某东，但那个组转正卡 211，这个机会也相当于就没了。</p><p>某电车厂的学长和我说他们开会说能没有 hc 就没 hc，事实上确实如此，hr面完后的池子深不可测。</p><p>还有个拿友推荐去面腾讯微信的客户端，个人认为因为微信这个平台实在太大了，即使是转客户端也是可以接受的，但阴差阳错之下被后端捞了，但由于自己积累不够（实习经历、算法），止步于面委会四面。</p><h3 id="实习点滴">实习点滴</h3><p>投了 2 个月实习，每天要干实习的活，还要复习、投实习、准备面试，充分体验了一边实习一边准备面试到底多累😭</p><p>晚上回去根本不想学习，索性直接睡觉，强迫自己第二天早起学习。</p><p>有一段时间的作息比较极端，晚上 10 点开始看书睡觉，6 点起床在拿友群里发个红包，然后学到8点去公司吃饭，8点到10点复习八股，中午极速吃完饭睡觉，然后 1 点到 2 点刷一小时算法，工作不忙的话就摸鱼学东西，看公司的文档，和组里大佬请教东西。</p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172111855.png" alt="在这里插入图片描述" style="zoom:50%;" /><h3 id="腾讯-wxg-但止步于四面">腾讯 WXG ，但止步于四面</h3><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172111149.png" alt="在这里插入图片描述" /></p><p>只能说，积累不够，错失良机。</p><p>牛客链接：</p><p><a href="https://www.nowcoder.com/discuss/489416896752652288?sourceSSR=users">WXG后端一面</a><br /><a href="https://www.nowcoder.com/discuss/489728144547565568?sourceSSR=users">WXG后端二面</a></p><h3 id="shein-一个岗一个方向只有一个hc">Shein 一个岗一个方向只有一个HC</h3><p>shein 是一家跨境电商，我朋友在里面，我也一直有关注这家公司，是暑期的目标公司之一。</p><p>我投的南京的，先两轮技术面，技术面过了才是hr面，广州的好像是先一轮技术面，然后 hr 面，过了是总监技术面。</p><p>一面很简单，随便问问，随便聊聊，反问环节问了下简历有没有修改的地方。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172111929.png" alt="在这里插入图片描述" /></p><p>二面和一面差距太大了，全程被拷打。。。面试官一边说着这个没有大型项目经验不懂这个一边继续问。。。整不会了</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172111689.png" alt="在这里插入图片描述" /></p><h3 id="银行类">银行类</h3><p>从三月到五月，所有开了的银行我都投了，现实是没有一个银行给我发过笔试。（ 纵向对比一下认识的双9 同学，投了的基本都给发了）</p><p>总结了下原因，学校很拉垮，机器筛选直接挂，但有些银行可能是随机给机会，比如中行，我有个本科和我一个学校，硕士也是普通双非的同学拿到了笔试，但他的硕士同学（本2调剂双非）也有没笔试的。</p><p>可能银行是随机筛 + 随机发的吧。</p><p>有些银行会卡 gap ，也就是复读、考研二战（据说华为今年要卡这些）</p><h3 id="dubbo-开源是如何助力cong佬的实习的">Dubbo 开源是如何助力cong佬的实习的</h3><p>cong 佬应该是 24 届硕士走互联网赛道里比较厉害的一位同学了，和 cong 佬认识也有一年了，cong 佬今年做了一件很酷的事情，具体可以看这个 ：<a href="https://www.nowcoder.com/discuss/476855105258594304">暑期实习总结：致敬我的阿里云25面</a></p><p>正好有个机会可以请 cong 佬分享一次，和 cong 佬敲定内容后就开始了宣传。</p><p>正式分享中，参会人数达到了80人，半数以上的人参会时间达到了分享时间的60%，总体来说还是很不错的一次分享。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172115151.png" alt="" /></p><p>活动宣传稿 ： <a href="https://docs.qq.com/doc/p/fcf8f90bb87a9b7ea78b2b5b3e37661feaa8dcef">GSoC-CN &amp; Apache Dubbo  开源活动分享</a></p><p>录播 ： <a href="https://www.bilibili.com/video/BV1gT41187u5">Dubbo开源是怎样助力我的校招实习的？</a></p><h3 id="开源收获">开源收获</h3><p>过去的一年里，我和其他几位小伙伴一直在维护 GSoC-CN 的 QQ群，群内不止有参与开源的学生，还有各个社区的贡献者、作者。</p><p>由于各个开源活动的时间基本是错开的，所以大家在群里不只聊 GSoC、也会聊OSPP等其他活动</p><p>由于 QQ 群人数有数量限制，我之前想的是暑期上岸之后充个会员扩一下，没想到在北京大学学生 Linux 俱乐部的赞助下，直接扩容了。</p><p><a href="https://lcpu.club/wiki/index.php?title=LCPU%E5%BC%80%E6%BA%90%E6%94%AF%E6%8C%81%E8%AE%A1%E5%88%92">北京大学学生 Linux 俱乐部 LCPU 开源支持计划</a></p><p>开源活动总结：<a href="https://github.com/erdengk/gsoc-analyse">https://github.com/erdengk/gsoc-analyse</a></p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172111565.png" alt="在这里插入图片描述" style="zoom:50%;" /><h2 id="铜五">铜五</h2><p>接近暑期了，有些同学都提前入职了，我还是没能去的暑期 offer ，说不焦虑是假的，但因为还有实习能兜底一下，只能一边继续投，继续准备。不怕面试过不了，而是很少有面试，这个才是最绝望的。</p><p>实习的组大概率没转正 hc，或者说即使有，我也不敢信。</p><p>现在这个形势，他说有，可能是真的有，但不能保证后面一定能有hc。</p><p>或许，之后应该多考虑秋招拿offer，而不是猜是否有转正。（当然，像美团和阿里这种高转正的还是可以好好卷卷产出拿个转正保底的）</p><h3 id="准备-ospp--和-面试">准备 OSPP  和 面试</h3><p>OSPP 是中科院举办的一个开源活动，又名开源之夏。</p><p>官网介绍：</p><p>开源之夏是由中科院软件所“开源软件供应链点亮计划”发起并长期支持的一项暑期开源活动，旨在鼓励在校学生积极参与开源软件的开发维护，培养和发掘更多优秀的开发者，促进优秀开源软件社区的蓬勃发展，助力开源软件供应链建设。</p><p>我申请的是蚂蚁金服的 SOFAJRAFT 项目，当时因为还在找实习，项目申请书花的时间并不多，加上整个项目也很庞大，害怕中又害怕中了做不了。后面开奖了，不是我，另一位同学申请书写的很详细，心服口服。</p><p>OSPP：<a href="https://erdengk.github.io/gsoc-analyse/cn/ospp/">https://erdengk.github.io/gsoc-analyse/cn/ospp/</a></p><p>其他开源活动介绍：<a href="https://github.com/erdengk/gsoc-analyse">https://github.com/erdengk/gsoc-analyse</a></p><p>面了一下杭州的连连支付，流程挺快的，几天拿了 offer ，如果有人面他家建议简单准备一些支付方面的知识。</p><p>Boss 面了一下小米，由于是数据平台的，全程底层原理拷打，一面过了，二面答的不太行，应该是挂了（面二面时拿了想去的暑期offer，也没心气准备了）</p><h3 id="柳暗花明--铜-5-收获暑期实习offer">柳暗花明--铜 5 收获暑期实习offer</h3><p>在随想录认识的 B 佬因为上一段实习结束，又面了几家大厂，都拿到了 offer，最后选择了一个业务比较好的部门，他进去实习了一段时间后和 Leader 混熟了，得知需要招实习生后强力内推了我。</p><p>他问了组里的 ld 的 ld （也就是整个部门的大老板），确定了能进面。</p><p>然后，一周之内走完了流程，约面，一面，二面，因为提前了解过了情况， hr 面也没免了，二面完隔天 OC 了。</p><h2 id="关于简历">关于简历</h2><p>算上投谷歌的一版，从 1 月到 2 月改了将近 20 版简历，因为找实习的时间很长，中间也在不断的更新、迭代。</p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202307172112954.png" alt="简历" style="zoom:50%;" /><p>对于不同的厂不同的岗也需要做一定的调整，有些岗如果偏基础架构，我会将分布式的技能放到前面，如果是业务部门我会把分布式的东西放后面作为一个补充。</p><p>总体上还是一个原则，突出自己的优势，减弱劣势的存在感。</p><p>应该很难有人的简历能过所有 HR 的筛选，太厉害可能OQ ( over quality 超过招聘要求) 被挂，不匹配可能会被挂，学校不在本地可能被挂，HR 看简历写的不认真、写的太长可能被挂。。。。。</p><p>尽人事，听天命。</p><p>实习期间内推了 120 人左右，然而最后只有 2 人过了面试、入职。这是一个很小的样本，却可以看出很多问题。</p><p>有些确实是简历有很大的问题，如应届简历写 3 页或者 3页+、排版乱、该有的信息没有、项目抄别人的且改都不改的。</p><p>有些是因为投的晚了，hr 说已经有几个合适的同学在流程中了，所以建议再换个岗投。</p><p>有些是因为技术栈不匹配，拿开发简历投测试、测开岗，被直接挂</p><p>有些是因为没有项目、项目烂大街，内推过 2个 ACM银牌，hr 直接挂，都没到用人部门筛选。（现在 ACM 也没以前吃香了）</p><p>很多简历有不同大小的问题，有些同学比较熟，我会和他们讨论下该怎么改。</p><h2 id="关于如何找实习求职机会">关于如何找实习/求职机会</h2><p>boss 上多投，吃饭刷刷，散步刷刷，遇到合适的就投</p><p>牛客上也会有些组内直招的，看运气刷到了</p><p>有些朋友在公司里实习，hr会让帮忙找人，同学内推一个23届的同学6月拿了offer</p><h2 id="关于如何了解组内情况">关于如何了解组内情况</h2><p>无他，广交友，多打听</p><p>如何广交友？</p><p>参与开源（ 效率高、要求高</p><p>聊天水群（效率低、要求低</p><p>实习过的人应该都能体会到组和组的差距到底有多大，一个好的组实在是太重要了，</p><h2 id="总结">总结</h2><p>个人认为，求职第一因素是运气，运气到位基本什么都可以，面试两数之和+聊天都可以。</p><p>第二是信息差/人脉，有个组急招人，可能直接就面上了。有个组可能不卷/很卷，如果不认识里面的人，很难了解具体情况</p><p>第三是技术，这个是最基础的，没这个很难上岸。</p><p>尽人事，听天命</p><p>我不是最厉害的，也不是最菜的，机缘巧合之下认识了一些朋友，求职路上受到了很多的帮助，也越发觉得求职时需要互相帮助。</p><p>因此在牛客也发了些收集贴：<a href="https://www.nowcoder.com/discuss/484086112256802816?sourceSSR=users">收集24届真双非硕/25届同学/类双9</a></p><h2 id="后续预告">后续预告</h2><p>我自己也是一个普通的校招生，对于如何实习转正、实习答辩等话题我并没经验，但在不远的将来，我应该会有这些经验，到时候再与诸位分享。</p><h2 id="最后">最后</h2><p>借用一下罗翔老师的毕业致辞</p><blockquote><p>其实我很想祝大家一帆风顺，但是我觉得这不现实。</p><p><strong>智者说：人这一生至少有三件事是无法避免的：一个是苦难，一个是邪恶，还有一个是人生的终点。</strong></p><p>所以，愿我们每时每刻都在当下储存足够多美好的记忆，去对抗人生不期而至的苦楚；也愿我们在记忆中能够储存足够多的美善，能够与邪恶相对抗而不和它同流合污；更愿我们能够在记忆中有更多的美好，能让我们平静从容的走向人生的终点。</p><p>**这个世界其实有很多所谓的成功人士，他们并不值得信任。**纪伯伦说过：这个世界有两种痛苦,一种是野心还没实现的痛苦，还有一种是野心成就后的无聊。</p><p>**我见过很多成功的和正在追逐成功的人，他们都在这两种痛苦中双向切换。**所以有人说： <strong>真正能够带给我们宁静的是我们内心的原则。</strong></p><p>.......</p><p>我真心祝福各位同学，能够找到内心的宁静，一生平安。</p></blockquote><p>衷心希望各位同学能找到适合自己的归宿，能够找到内心的宁静，一生平安，永远年轻，永远自由。</p><p>祝好</p>]]>
                    </description>
                    <pubDate>Mon, 17 Jul 2023 21:07:27 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[24年暑期阿里云云网络提前批一面]]>
                    </title>
                    <link>/archives/24-nian-shu-qi-a-li-yun-yun-wang-luo-ti-qian-pi-yi-mian</link>
                    <description>
                            <![CDATA[<p>此文首发于拿个offer星球，先行感谢群里大佬对于群垫底的我的提携</p><h2 id="面试回放-复盘">面试回放-复盘</h2><p>简历问题：普罗米修斯你们怎么用的</p><blockquote><p>讲了部门业务和公司内部产品</p></blockquote><p>简历问题：docker拷贝文件命令</p><h3 id="场景题">场景题：</h3><p>我们其实我们现在日志的采集量很大，大概一天可能一个 1 月份有上百个 g 类似的这么大的日志采集，我们从中间通过关键字去查询的时候，你觉得它是怎么样去查询的？能够快速地定位到我们需要的日志？</p><p>其实就是存ES，倒排索引去查</p><p>场景题：假如我们想要去处理一批数据，这一批数据，这么给你说，假如我们想要去处理一批数据，这一批数据是多个用户调性的哪一天，或者就数据 API 的这个 API 是多个用户调进来的API，它会打到登录式的一个系统上面。但是这些 API 可能会去共享一些资源。在 分布式的系统上，你觉得首先共享资源会出现哪些问题？ API 进来请求上会出现哪些问题？我们怎么去解？因为每台信息它可能也是多线程处理的是吧？处理每个API，首先一个共享 PM 怎么去解？第二个是你站在分布式的一个系统设计上来看，你觉得如果我允许你在分布式系统上面在前面再加一台proxy，你怎么去实现能够更好的做到系统性能。</p><blockquote><p>引导着往锁的方向答，我觉得锁不太适合。。。中间提了mq、多级队列、资源池，没想到就是锁，还是不够了解系统设计。</p></blockquote><p>如果我前面允许你放一个proxy，你会怎么去设计，更尽可能地从上面去规避</p><p>假如我的API，我每个 API 是可以带一个用户的UID</p><p>uid 做分流，扯了一致性hash，还有一致性hash虚拟节点减少服务雪崩的问题</p><p>现场问题 ：如何提高 CPU 命中cahche的概率</p><p>不会，扯了 L1 L2 L3 cache，面试官说可以看一下 cpu 亲和性的东西</p><p>普通八股：</p><p>hashmap结构</p><p>数据库索引</p><p>计算机网络拥塞控制 （问了一个 BBR 算法，谷歌的）</p><h3 id="实习">实习：</h3><p>业务</p><p>用的中间件</p><p>实习计划</p><p>对公司感觉怎么样？</p><p>讲了部分代码可能要求低，我觉得代码风格不好，会主动改一下代码（保证没问题的前提下）<br />又讲了一下上次发版的复盘</p><p>阿里压力可能会比较大，要做好准备</p><p>有听过，能接受，想去阿里</p><h3 id="反问">反问：</h3><p>有二面吗？</p><p>我后面主管一起的评估的，根据我们面试。</p>]]>
                    </description>
                    <pubDate>Fri, 03 Mar 2023 20:51:13 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[我的硕士前半生]]>
                    </title>
                    <link>/archives/wo-de-shuo-shi-qian-ban-sheng</link>
                    <description>
                            <![CDATA[<p>本篇文章属于随笔类，它可能无法对你起到直接帮助，它只是我这个普通学生一年半以来的一些足迹与思考。它可能更适合大二，研0研一的同学查看。本文首发于我的个人博客 <a href="http://erdengk.top/">Forever Young</a></p><blockquote><p>我的本科像硕士，有实验室有工位，桌子超级大，有老师带有学长可以问。</p><p>我的硕士像本科，没有实验室，工位真的是公共座位，导师放养，没有直系学长，开题毕业求职差不多纯靠自己</p></blockquote><p>本文约有6k字，阅读大约需要15min，请提前准备好爆米花，感谢你花时间阅读此文，但凡它能对你有丁点帮助都是我的荣幸。（本文图片的图床用的是GitHub，可能需要读者准备个🪜）</p><p>2023年1月28更新：本文冲到了牛客热榜第一，感谢朋友们的关注与点赞支持</p><p><img src="https://img-blog.csdnimg.cn/4e584c57f8bf4d1bad9d28da5410bbd4.png" alt="在这里插入图片描述" /></p><h1 id="我的硕士前半生">我的硕士前半生</h1><p>22年11月底，马上要离开成都了，离开这个自己没什么感觉甚至是有些厌恶的城市（吃不习惯、听四川话听到PTSD），刚好也是读研读了一半，遂写此文当作纪念</p><p>23年1月中旬回家高铁上伴着窗外大雪写了一部分</p><p>除夕当天在个人博客上发布本文</p><h2 id="21年9月-迷茫">21年9月 迷茫</h2><p>研一刚入学还是有些迷茫的，这种迷茫不是那种无头苍蝇式的迷茫，大体方向是准备实习找工作，落实到具体细节却并没有做好</p><p>先是没有吸取大学的经验，都准备去找互联网工作了，竟然还准备去参加班干部选举（幸亏没选上😂，要不然就被学校绑死了</p><p>然后发现了学校政策其实不是那么完善，奖学金和国奖有漏洞，花时间和钱就一定能拿，但这样拿了又有什么意义</p><p>和本科实验室的阿里学长聊了下该学什么，简单规划路线后就开始学了</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202211300022927.png" alt="image-20221130002234746" /></p><h2 id="21年11月-gsoc">21年11月 GSoC</h2><h3 id="缘起">缘起</h3><p>准备过程说起来也很简单，就是正常的学，刷题、八股。</p><p>忘记了是因为什么想起了GSoC，算是为了圆梦吧，第一次认识它也是在知乎，来自那篇广为流传的文章</p><p><a href="https://zhuanlan.zhihu.com/p/27330699">Google 编程之夏(GSoC)：海量优质项目，丰厚报酬，你竟然还不知道？</a></p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202211300025119.png" alt="image-20221130002505050" /></p><p>我还记得再次读到这篇文章还是觉得很酷，是那种不同于其他比赛、竞赛、活动的酷，于是踏上了准备GSoC的路</p><h3 id="查找资料">查找资料</h3><p>确定参加后就开始查找资料，国内国外中文英文资料都在搜。</p><p>也收集了很多前人的经验，认识了各个组织和社区，了解了开源的“玩法”，这些也为后面我编写 《开源小册 》做了良好的铺垫。</p><p><a href="https://github.com/erdengk/gsoc-analyse">开源小册，介绍开源活动</a></p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301150917664.png" alt="image-20230115084608758" /></p><p>因为官网的搜索并不是很好用，我的主要技术栈是 Java，于是想从一些Java社区入手，在官网上搜索 Java，结果会连 Javascript 的社区也一并搜索出来，我觉得这很不方便，于是将官网2021年的项目信息爬下来，存到数据库里。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301150917228.png" alt="image-20230115085238470" /></p><p>然后用 SpringBoot 读取出来做些简单数据处理输出到MD文件中，也就产生了早期的  gsoc-analyse 项目，本意是为了更好的查找符合自己技术栈的项目。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301150919732.png" alt="image-20230115091940709" /></p><p><a href="https://github.com/erdengk/gsoc-analyse">开源小册，介绍开源活动</a></p><p><img src="https://uploadfiles.nowcoder.com/images/20230125/2673318_1674662319350/D2B5CA33BD970F64A6301FA75AE2EB22" alt="alt" /></p><h3 id="casbin-奇遇">Casbin 奇遇</h3><p>gsoc-cn有一个gitter群（一个聊天室，可以查看很久之前的信息），我查找资料的时候，翻看了近2年的所有聊天记录，发现了 Casbin 的罗老师有在收人，也就是 <a href="https://github.com/casbin/Talent2023/tree/92ae5009e5d0285378d216ab36488ff4c1baf3ed">Casbin明日之星预选生计划-Talent for Casbin 2022</a>, 我去加了群，也给罗老师发了简历。</p><p>因为我当时比现在更菜，简历上也没什么能看的，硕士还写了个电子信息，让罗老师误以为是 EE （<em>Electronic Engineering</em> ） 而不是 CS （<em>Computer Science</em> ），这也给我提了个醒，看简历的人不一定和写简历的人有相同的知识背景，只是大致相等，对于部分可能出现误会的地方应该标识/解释清楚。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301150929008.png" alt="image-20230115092924970" /></p><p>然后我又和罗老师围绕着我简历交流了一些其他问题（后来才知道罗老师是两届GSoC学生，北大博士，跪了</p><p>最后罗老师还是友善的给了建议，其实一直知道自己菜，但没能完全找到自己的弱点。如果是想一直靠技术吃饭，但活到老学到老是必然的。即时是想先进个好点的厂打工，知识的深度也是要远比广度重要的。</p><p>后面在开源相关的事上也请教过很多次罗老师，后面GSoC开始申请前还有幸以采访的形式写了一篇文章：<a href="https://mp.weixin.qq.com/s/dKn3zCaVcsrFo9C5LSC0Mw">Google Summer of Code谷歌编程之夏活动流程全解析（上）</a>, 罗老师对问题的回答真的是高屋建瓴，每次阅读都有新的收获。</p><h3 id="21年11月-申请维护gsoc-qq群">21年11月 申请维护GSoC QQ群</h3><p>我感觉gitter上交流没有群聊方便，gsoc-cn之前的QQ群也没人维护了，我建立了新的QQ群，并发到Gitter上，又在GitHup上的GSoC-CN仓库上提交了issue，申请把QQ群加入到他们的readme中，让更多的人加入到群里。<br />仓库的reviewer也同意了我的请求，让我提交pr，然后快速的学习了下pr之类的操作提交了第一个pr。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301150933828.png" alt="image_1637688000050" /></p><p>算是迈出了个人开源的一小步</p><h3 id="22年4月-前期准备及提交申请">22年4月 前期准备及提交申请</h3><p>这部分细说起来要写很多，就不详细写了</p><p>大致就是我先选了一个社区，社区不是很活跃（一个博士课题组的社区，他们都很忙，一个pr得审好久好久），我没有收到正反馈以及不知道能做些什么，也就放弃了这个社区。</p><p>也是运气使然，我后来的mentor 在群里发布了社区的项目，我一开始不知道他是mentor，先加了他微信，看了社区的项目，发现有一个是自己还敢尝试一下的，然后在github上发现了项目导师的联系方式</p><p>巧的是，我已经加了他的微信（在不了解项目时加了联系方式，后面选的项目刚好是他当导师😂</p><p>因为之前看了很多经验贴，建议不要在没了解过项目的前提下和导师交流</p><p>后面也就开始了贡献，在社区里解决了第一个 good first issue 后初步了解了项目，</p><p>后面开始解决其他问题时，也遇到了愿意帮忙解决问题的贡献者（Jooks 、Y哥、福哥 .....</p><p>（算是另一种意义上的组&gt;部门&gt;公司了）</p><p>中间也是提交了一部分pr</p><p>然后花了一周每天2-3点睡，学习了项目中用到的另一个东西</p><p>晚上疯狂用GitHub 的 action 做实验，最后做出了一个demo</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301151017415.png" alt="image-20230115101704361" /></p><p>期间也和项目mentor一直在讨论项目细节，mentor也给了很多建议</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301151021300.png" alt="image-20230115102116268" /></p><p>或许是之前写保研申请书的时候经验起了作用，再加上看了很多前辈的申请书，proposal 中加了一些花里胡哨的图、apache要求的内容，mentor reveiw之后还夸了我的 proposal （开心～</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301151022113.png" alt="image-20230115102226085" /></p><p>gsoc是支持一个人申请三个项目，我一直在这个项目上探索，最后也就申请了这一个项目</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301150954539.png" alt="image-20230115095406511" /></p><h3 id="22年5月-gsoc-cn社群分享会">22年5月 GSoC-CN社群分享会</h3><p>建立QQ群之后，因为有gsoc-cn的引流，也吸引了很多小伙伴</p><p>比如后来我们一起举办分享会的 <a href="https://cheverjohn.me/">cheverjohn</a> , 彼时他还在 Apache Apisix 实习，也认识很多开源大佬，和他交流后也了解到了很多关于Apache 基金会的东西，然后我们就在群里举办了 GSoC-CN的第一个分享会，是由 Skywalking 的 Committer  <a href="https://github.com/fgksgf">江前辈</a> （Apache SkyWalking Committer ｜ Google Summer of Code 2021 Student ｜ pingcap intern ）主讲的 关于OSPP 的 分享会。</p><p>活动视频 ：<a href="https://www.bilibili.com/video/BV1E3411P7d2/">GSoC-CN 社群关于OSPP的开源经验分享</a></p><h3 id="侥幸中选">侥幸中选</h3><p>分享会之后不久，就是 GSoC 开奖了，规则限制导师不能提前透露相关信息，我也没有去问，公布名单的时间是国内时间的晚上两点，我还记得那天晚上我开了个腾讯会议，群里很多人一起在那等待，2点过了一会等到了第一封邮件。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301150953394.png" alt="image-20230115095302365" /></p><h2 id="22年6月-开题与glcc">22年6月 开题与GLCC</h2><p>这里首先要感谢我的导师，没有他的“支持”，我也不能这么自由。</p><p>我导师应该是个反卷达人了，也不加班，平时自己接点项目自己做，学生想做可以做，不想做也没事，工程领域里的他全都会，前后端嵌入式人工智能都会</p><p>在开题这件事上，他允许我自己去探索，即使他自己也不懂我当时想做的云原生领域。</p><p>我一开始不懂为什么不能直接放手学生去做自己想做的，后来和罗老师交流才明白导师能让我做是多么不容易。</p><p>对于研究生来收，一个组通常都是做同一个细分方向的，如果有个学生要做其他领域的东西，对于导师来说，这个东西他也不懂，也就很难给出指导，所以一般不会允许自己的学生去做其他方向。</p><p>后来和导师商量着先自己去探索，如果探索出了些东西，很好。如果没有，那就需要在他指导下做点东西。（毕业还是要毕业的，兴趣不能当饭吃</p><h3 id="学习分布式相关知识">学习分布式相关知识</h3><p>因为对分布式比较感兴趣，之前看谷歌的三驾马车也是囫囵吞枣的阅读完了，没有真正的学懂它们。</p><p>然后从谷歌、知乎、GitHub、各种社区搜寻分布式的资料</p><p>得益于谷歌的搜索及排名算法，我找到了很多不错的资料和博客</p><p>然后就是自己看论文，看项目代码</p><p>花了几周，学了一些基础知识，自己太菜了，没人带没能深入到具体的某个方向</p><p>后续因为在GLCC上看到了感觉合适的项目，和校内导师商量之后觉得可以作为毕设，就去申请，因为自己没申请上，用一个自己感兴趣的东西作为毕设的想法也就泡汤了 😭</p><h3 id="glcc-开始-结束">GLCC-开始-结束</h3><p>彼时，计算机学会的 GLCC 刚开放申请，我也申请了一个项目，分布式相关的，也和导师做了一些交流，可惜，太菜了，没能获得社区导师的认可。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301211820170.png" alt="image-20230121182058059" /></p><p>路漫漫其修远兮，吾将上下而求索</p><h2 id="22年8月-日常实习求职实录">22年8月 日常实习求职实录</h2><h3 id="投递面试">投递&amp;面试</h3><p>花了一个月面试</p><p>小厂、中厂、大厂，除了字节约面拒了以外，其他约面的都面完了</p><p>期间也记录下每天的投递与面试 <a href="https://www.nowcoder.com/discuss/1088711"><strong>24届双非日常实习求职实录</strong></a></p><p>因为之前花时间入门了一下分布式的东西，再加上当时已经写了 <a href=""></a> 这篇博客，所以将一些分布式的东西也写在简历上，我觉得是运气加持，遇到了一些比较match的面试官，他们有的懂分布式，就会问一些问题，这些问题，我有的会，有的以前没思考，借用他们的提问，我完善了我的八股串，后期熟练之后可以不间断输出自己的理解</p><p>有的不懂，那我会从其他方面聊一些入门知识，聊着聊着就耗完了面试时间，做道算法题，这场比试就结束了。</p><p>可能是我唬住了面试官，除了一开始投的某八股厂，剩下的面试都过了（以及一堆面完之后没发感谢信也没发后续流程的公司）</p><h3 id="offer-选择--人生处处cap">Offer 选择--人生处处CAP</h3><p>靠着8分运气，也拿到了一些offer，大厂、中厂、技术厂、小厂外包、传统公司都有，</p><p>选择起来说简单也简单，自己学历不够好，选个大厂学学项目规范，让简历看起来好看一些。</p><p>然后就剩下了几家了，但都是卧龙凤雏，base、部门、公司 每个offer都欠一样，或许人生处处CAP吧</p><h2 id="23年1月-创建-拿个offer">23年1月 创建 拿个Offer</h2><p>找日常实习时，在随想录星球里认识了也在准备日常实习的 <a href="https://www.zhihu.com/people/nevada-44-55">ConquerJ</a> (现在是titok的实习生)，然后在群里一起准备日常实习，群里也收集了一些有实习/准备找实习的同学一起学习 。后续为了更好的“捕捉”大佬，也为了建造一个高质量的交流群我们开始了建立知识星球。</p><p>拿个offer 来源自 “真还传”的罗老师的 交个朋友</p><p>offer 是广义的，公司的offer是offer，申请海外硕，夏令营申请，都会有offer，这个名字的本义也是希望我们能够从一个目标到另一个目标，一直拿offer，一直进步</p><p>无限进步 （ 影视飓风打钱</p><h3 id="给巨佬们跪了">给巨佬们跪了</h3><p>有了第一批人之后，也就更容易收集到新的佬哥，然后事情也就开始变得魔幻了起来</p><p>目前有：</p><p>获得 N个 SSP 算法岗 offer 23届佬哥 ｜ N个 SPP offer 佬哥们 ｜23届 阿里P6 佬哥 ｜top +米哈游 佬哥</p><p>top+顶会+大厂实习佬哥 ｜ 985+NUS 佬哥 ｜ UCLA + 华尔街量化佬哥</p><p>Apache 某社区 Committer 佬哥 | CNCF 某社区 Reviewer 佬哥</p><p>本科发顶会论文佬哥 ｜国内顶尖实验室佬哥 .......</p><p>2023年1月25更新</p><p>邀请到了</p><p>Apache IoTDB committer <a href="https://www.zhihu.com/people/tan-xin-yu-22">谭新宇</a><br /><img src="https://uploadfiles.nowcoder.com/images/20230125/2673318_1674662047417/D2B5CA33BD970F64A6301FA75AE2EB22" alt="alt" /></p><p>以及乾象的 <a href="https://www.nowcoder.com/discuss/438476093755056128">悟空哥</a></p><p><img src="https://uploadfiles.nowcoder.com/images/20230125/2673318_1674662120491/D2B5CA33BD970F64A6301FA75AE2EB22" alt="alt" /></p><p>正式创建星球后，在知乎上收到了一些巨佬的入驻，然后巨佬之间又是互相认识的，也就造成了后面群里能有神奇的梗</p><p><strong>“我经常被他们嘲笑，因为我有一个offer是sp”</strong></p><p><strong>部分佬哥们的自我介绍：</strong></p><p><strong>23届 11 个算法 SSP Offer</strong><img src="https://pic4.zhimg.com/80/v2-c9f8c82bbefde026b93cebf4961d1ebf_1440w.webp" alt="img" style="zoom:50%;" /></p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301211717692.png" alt="image-20230121171703561" style="zoom:50%;" /><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301211718003.png" alt="image-20230121171819947" style="zoom:50%;" /><h3 id="和佬哥们一起交流">和佬哥们一起交流</h3><p>因为群里都是同一届找工作的，大家也会聚一起模拟面试、交流简历。</p><p>星球正式建立的第一周周末</p><p>和两位多段大厂实习佬交流简历✔️</p><p>和源码佬八股佬大厂实习佬交流模拟面试✔️</p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202301151433301.png" alt="image-20230115143336260" style="zoom:20%;" /><p>晚上和IEG佬哥交流简历暑期实习秋招✔️</p><p>随着看过的优秀简历增多，我也对简历有了新的理解，而这都是在交流中获得的，好的交流环境更容易诞生出更好的想法。</p><p><a href="https://zhuanlan.zhihu.com/p/602571244">24届秋招 | 高密度信息交流环境 | 高质量交流群</a></p><h2 id="23年1月-gsoc-cn社群第三次活动">23年1月 GSoC-CN社群第三次活动</h2><p>筹划了两周的活动于2023年1月14日，小年夜，顺利举行，此次人数全程50+，最多有60人在线。</p><p>第三次活动宣传稿：<a href="https://docs.qq.com/doc/DWVR1cVJzWFBkd0Fw">https://docs.qq.com/doc/DWVR1cVJzWFBkd0Fw</a></p><p>活动PPT：<a href="https://blog.aflybird.cn/2023/01/before-good-first-issue">https://blog.aflybird.cn/2023/01/before-good-first-issue</a></p><h2 id="最后">最后</h2><h3 id="回首才发现走出去了很远">回首才发现走出去了很远</h3><p>如同乔帮主在斯坦福演讲中所讲的</p><blockquote><p>当然，当时的我没有办法把这些点点滴滴连接起来，但当我从这回头看时，一切都变的清清楚楚。</p><p>的确如此，没有人可以未卜先知，把自己所学到的东西连接在一起，我们只能在回首的时候，发现这些是如何改变现在的自己的。</p><p>所以，你必须要有这样一种信念，那就是你现在的所有点滴，都会在未来的某一天连接起来，改变你的人生。</p><p>你必须要有一种信念，相信胆识，命运，生活，轮回，无论什么都好。</p><p>因为通过这些信念，会带给你遵从内心的勇气。</p><p>即使你内心的声音让你走一条人迹罕至的路，这些信念也会给你勇气，然后改变一切。</p></blockquote><p>当时因为感兴趣而去准备GSoC，去维护QQ群，去举办活动，才能在后面认识了很多前辈，进入了另一个圈子。</p><p>GSoC的活动，或许并没有让我的编程水平有突飞猛进式的提升，但通过参与它，我有了勇气去尝试新的未知的东西，这是最大的收获。也因为参与GSoC，我认识了社区里的前辈，后期投递实习时拿到了很多内推机会。</p><p>当时因为兴趣去学的分布式基础知识，没能在毕业设计中直接用到，但在后面面试中用到了很多，也获得一些面试机会，获得一些offer。</p><p>当时因为喜欢交流，加入了随想录的星球，才能在后来认识了八股战神&amp;放弃直博复旦的冰冰同学，认识了三个月上岸的titok的凡哥.......</p><p>没有人可以未卜先知，我们只能基于当前时间之前的经验做出选择</p><p>直到回首望去，所有的脚步都会被串联起来，指向你现在的位置</p><h3 id="follow-your-heart">Follow your heart</h3><p>不一定大公司就适合每一个人，可能它要求实习生日报，正式员工okr，双月okr，可能每天要开站会，可能要早上8点上班，也可能支持永久远程。</p><p>公司有很多很多，但我们很难知道自己想要什么。</p><p>我之前没去过字节，对字节有种好奇，后来知道同学进去那么卷，它可能不太合适我，但如果它给我一个机会去实习，我还是想去体验下，然后视情况离职。</p><p>希望大家都能去一个自己觉得合适的公司。</p><blockquote><p>工作将占据你生命中很大的一部分<br />Your work is going to fill a large part of your life</p><p>只有相信自己所做的是伟大的工作，你才能获得快乐<br />and the only way to be truly satisfied is to do what you believe is great work</p><p>而伟大的工作就源自你的爱<br />And the only way to do great work is to love what you do</p><p>如果你还没有找到<br />If you haven't found it yet</p><p>继续寻找，不要止步<br />Keep looking and don't settle</p><p>全心全意地寻找<br />As with all matters of the heart</p><p>当你遇到它时，你就会明白<br />You'll know when you find it</p><p>就像那些美好的爱情<br />And like any great relationship</p><p>随着岁月的流逝，愈加醇美<br />it just gets better and better as the years roll on</p><p><strong>所以，继续寻找，绝不止步！</strong><br /><strong>So keep looking, don't settle</strong></p></blockquote><h3 id="读书好-多读书-读好书">读书好 多读书 读好书</h3><p>大学时人傻，没有好好利用好时间</p><p>读研后，因为睡眠一直不好，控制变量做了些实验后觉得是睡前没有平复心情</p><p>然后开始看书，小说、传记、技术书都看</p><p>学校的图书馆很好，一次可以借很多本，借完放床头，睡前开始看，看个1h再睡，睡眠改善了很多。</p><blockquote><p>在这个信息纷杂的年代，读书可以帮助我们更好的思考，</p></blockquote><p>很多经典技术书也是非常值得一看的，还记得面试某游戏厂时遇到的一个问题，最近有看什么书吗？</p><p>当时在看DDIA，刚读完吴军博士的软能力，对着面试官就是一顿输出😂</p><p>多读一些经典书、好书，总会派上用场的</p><h2 id="鸣谢">鸣谢</h2><p>非常感谢本科实验室的 L 哥、T哥，以及实验室的老师，或许学校不是很好，但学校已经将最好的资源给了我，而我目前“一事无成”，实在是愧对学校😭</p><p>非常感谢硕士学校的导师及舍友小伙伴，是导师的信任才让我有这么多自由，是舍友小伙伴的帮助，使得我能花更少的精力在学校的琐事上</p><p>非常感谢ShenYu社区的小伙伴，让我在初入开源时体会到了良好的社区是怎样的，</p><p>@<a href="https://github.com/JooKS-me">JooKS-me</a>，@ <a href="https://github.com/HessTina-YuI">HessTina-YuI</a>，@ <a href="https://github.com/yu199195">yu199195</a> ........</p><p>非常感谢 gsoc-cn 的小伙伴，一起筹备活动，开源布道，@<a href="https://github.com/Chever-John">John Chever</a>，@<a href="https://github.com/itwaix">Yuang XU</a>， @<a href="https://github.com/aFlyBird0">Bird</a>，</p><p>非常感谢某里巴巴工程师 PS 哥在我准备实习期间的指导（ @<a href="https://www.zhihu.com/people/gan-lan-zhi-31-11">凌云师兄</a></p><p>非常感谢某东后端实习生冰冰同学在我实习期间教导我八股、算法题 ，让我有机会和面试官聊天吹牛拿offer （ @<a href="https://github.com/smartPigL">冰冰</a></p><p>非常感谢 拿个offer星球 的第一批用户，我在群学到了很多很多，每天都有新的收获，有些东西是很难拿钱买来的，比如眼界、比如信息差。</p>]]>
                    </description>
                    <pubDate>Sat, 21 Jan 2023 18:40:35 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[八股文-个人经验]]>
                    </title>
                    <link>/archives/ba-gu-wen</link>
                    <description>
                            <![CDATA[<p>##八股文</p><p>有同学在评论区问如何背八股<br />在这里发表下个人看法</p><p>首先明确一个事，只背八股大概率拿不到一个好的实习<br />需要在八股之外，有自己的东西<br />可以是算法（acm、lc 高分选手）、项目（工作项目、实习项目）、经历（开源、实习、外包）</p><p>至于八股，我并不是那种八股战神，源码大佬，所以只讨论下自己做的准备以及后续修正路线还有实际遇到的情况。<br />因为我并没有参加过应届的暑期实习or秋招，所以对于八股的理解及使用都是从日常实习的经验里总结出来的</p><p>以上是背景铺垫，下面是正文。</p><p>第一步，先完成k-v的基础，也就是一些基础问题，能完成给你一个问题立马回一个答案的任务</p><p>第二步，融汇贯通，上面的数据结构是一个hashmap，这一步要做的是将这些hashmap作为一个个链表元素串起来。</p><p>我们需要自己构建他们之间的连接<br />以及<br />让大脑能够联想起每个元素后面是什么东西。（这个链表个人称为八股串）</p><p>第三步，练习，巩固。</p><p>一图胜千言，例子说话更方便。</p><p><img src="https://img-blog.csdnimg.cn/f9efb302f889486f825cb70088bb26fe.png" alt="在这里插入图片描述" /></p><p>比如面试官问mysql索引，我们就可以自行拓展出下面的东西，从索引数据结构到索引分类到索引失效。</p><p>即使他不问下面的，通过知识之间的联系也可以帮助我们更好的理解与记忆这块知识点。</p><p>如果他问了，那我们就可以开始“吟唱”了。</p><p>这个是最基础的链表，当我们自己使用索引、做过索引优化，也可以把相关知识、经历加到里面，变成一棵树，多叉树。</p><p>再举个例子<br /><img src="https://img-blog.csdnimg.cn/44235a50d6e6490fa1b57769f98cad8b.png" alt="在这里插入图片描述" /></p><p>分布式相关的简单知识可以看笔者拙作：<a href="http://erdengk.top/archives/fen-bu-shi-jian-dan-ru-men-zhi-shi">http://erdengk.top/archives/fen-bu-shi-jian-dan-ru-men-zhi-shi</a></p><p>个人经历</p><p>我在刚开始背八股的时候只做到了 k-v，也就是能回答一些简单的问题，如果面试官连着问，或者跳着问，我并不能够快速的回忆起相关知识or将知识联系到一起</p><p>咨询了几位八股大佬，我模拟面试了一下他们，从他们背八股的方法中总结出了上面背及联想的方式，它可能不适合每个人，但希望它能对你有所帮助。</p><p>总结</p><p>这并不是什么新的东西or个人方法，就是简单的联想及串联，但这其中的工作需要自己去琢磨及学习。</p><p>琢磨是去看其他人面经、面试视频、面试录音</p><p>学习是去学其他人是怎么回答问题的，可以找一个八股背的好同学，你模拟面试他，然后从中学习他是怎么叙述八股的。</p><p>以上</p><p>祝好</p><p>（本文首发于代码随想录知识星球，再次感谢卡哥的创建了此星球）</p>]]>
                    </description>
                    <pubDate>Mon, 02 Jan 2023 20:17:16 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[GSoC-1 ｜ GSoC介绍、活动流程、名额机制]]>
                    </title>
                    <link>/archives/gsoc-1</link>
                    <description>
                            <![CDATA[<h1 id="gsoc介绍活动流程名额机制">GSoC介绍、活动流程、名额机制</h1><br><p>我，尔等同学，Github： <a href="https://github.com/erdengk">erdengk</a>，有幸中选了GSoC2022，在准备阶段，我也花了很多时间来了解GSoC，也接受了很多前辈的帮助，也为开源社区做了一些小小的贡献。</p><p>一个人的力量终究是有限的，我也希望开源新手能通过参与开源活动进入开源世界，持续为开源社区做出贡献，也能持续提升自己，持续双赢。于是编写此系列文章，帮助新手了解、参与GSoC 。</p><p>受个人知识水平影响，本文可能也有部分错误，如您发现错误，欢迎指出（评论区 or 我邮箱：<br /><a href="mailto:wannengdek@gmail.com">wannengdek@gmail.com</a> ）</p><h2 id="gsoc介绍">GSoC介绍</h2><p>具体活动介绍此处就不重复了</p><p>这两篇介绍写的很详细了</p><p><a href="https://zhuanlan.zhihu.com/p/27330699">Google 编程之夏(GSoC)：海量优质项目，丰厚报酬，你竟然还不知道？</a></p><p><a href="https://zhuanlan.zhihu.com/p/27823910">Google Summer of Code 学生申请指南</a></p><p>简单来说</p><p>GSoC是一项开源活动，谷歌负责项目津贴及前期组织，各个开源社区提出适合新手的项目供申请人申请，中选后中选者会同其导师一起完成项目（主要是申请者自己完成），导师负责提供帮助及审核项目是否通过。</p><p>GSoC 是一个入门开源世界的好机会，但由于其特殊的名额规则（下文会有提到），可能会有特殊的落选情况存在，但瑕不掩瑜，这仍然是一个非常不错的活动。</p><h2 id="活动流程">活动流程</h2><p>活动流程我这里贴一个2023年的时间线为大家简单介绍一下，完整时间线<a href="https://developers.google.com/open-source/gsoc/timeline">地址在这</a>，下文有删减。</p><h3 id="2023-年-google-夏季编程时间表">2023 年 Google 夏季编程时间表</h3><table><thead><tr><th>时间</th><th>日程</th></tr></thead><tbody><tr><td>January 23</td><td>Mentoring organizations can begin submitting applications to Google</td></tr><tr><td>February 7</td><td>Mentoring organization application deadline</td></tr><tr><td>February 7 - 21</td><td>Google program administrators review organization applications</td></tr><tr><td>February 22</td><td>List of accepted mentoring organizations published</td></tr><tr><td>February 22 - March 19</td><td>Potential GSoC contributors discuss application ideas with mentoring organizations</td></tr><tr><td>March 20</td><td>GSoC contributor application period begins</td></tr><tr><td>April 4</td><td>GSoC contributor application deadline</td></tr><tr><td>April 27</td><td>GSoC contributor proposal rankings due from Org Admins</td></tr><tr><td>May 4</td><td>Accepted GSoC contributor projects announced</td></tr><tr><td>May 4 - 28</td><td>Community Bonding Period | GSoC contributors get to know mentors, read documentation, get up to speed to begin working on their projects</td></tr><tr><td>May 29</td><td>Coding officially begins!</td></tr><tr><td>July 10</td><td>Mentors and GSoC contributors can begin submitting midterm evaluations</td></tr><tr><td>July 14</td><td>Midterm evaluation deadline (standard coding period)</td></tr><tr><td>July 14 - August 21</td><td>Work Period | GSoC contributors work on their project with guidance from Mentors</td></tr><tr><td>August 21 - 28</td><td>Final week: GSoC contributors submit their final work product and their final mentor evaluation (standard coding period)</td></tr><tr><td>August 28 - September 4</td><td>Mentors submit final GSoC contributor evaluations (standard coding period)</td></tr><tr><td>September 5</td><td>Initial results of Google Summer of Code 2023 announced</td></tr><tr><td>September 4 - November 6</td><td>GSoC contributors with extended timelines continue coding</td></tr><tr><td>November 6</td><td>Final date for all GSoC contributors to submit their final work product and final evaluation</td></tr><tr><td>November 13</td><td>Final date for mentors to submit evaluations for GSoC contributor projects with extended deadlines</td></tr></tbody></table><p>简单总结下：</p><p>2.22，公布组织列表（常年参与的组织一般会继续申请，也会更容易被谷歌通过申请，比如Apache、CNCF、Linux）</p><p>3.20，申请者开始申请（每个人可以提交三份申请）</p><p>4.4，申请截止</p><p>5.4，公布中选名单</p><p>这里需要科普一些名词，供下文理解名额机制使用。</p><h3 id="组织">组织</h3><p>可能是一大个组织（Apache基金会），也可能是一个社区（比如Git社区），本系列文章中的一个组织指的是官网上的一个logo下的社区集合。</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202212311906369.png" alt="image-20221231190654183" /></p><h3 id="社区">社区</h3><p>一般是一个大组织下的社区，比如Apache基金会下有很多社区</p><p>2022 参与的社区有<a href="https://cwiki.apache.org/confluence/display/COMDEV/GSoC+2022+Ideas+list#GSoC2022Ideaslist-ApacheDubbo">Apache Dubbo</a>、<a href="https://cwiki.apache.org/confluence/display/COMDEV/GSoC+2022+Ideas+list#GSoC2022Ideaslist-RocketMQ">RocketMQ</a> 等等</p><h3 id="谷歌官方">谷歌官方</h3><p>负责收集组织申请，公布组织列表</p><p>分配具体名额给组织</p><p>提供项目津贴</p><h3 id="申请者">申请者</h3><p>所有成年人都可以是申请者</p><p>每人可以申请三个项目，但只能中选一个</p><h2 id="gsoc名额机制">GSoC名额机制</h2><p>本文重点，名额机制。</p><p>因为是申请制，所以必然会有落选的可能。</p><p>对于每个提出来的项目，所有人都可以申请，对于申请人A来说，A 先需要获得导师的认可，导师最后选择了A，那么A只成功了一半。</p><p>另外的一半是来自组织内排序的问题。</p><p>假设这个A 同学获得了导师的认可，那么他还需要参加组织/社区内的排名，如果谷歌只给了这个组织/社区 5个名额，而A同学 排名7/10，他就落选了。</p><p>可以理解为要双重筛选，第一重是导师的筛选，第二重是组织/社区的筛选。</p><h3 id="举个">举个🌰</h3><p>上面我们介绍了 谷歌官方、组织、社区、申请者的概念，这里用一个例子来介绍一下GSoC的名额机制。</p><p>拿我很佩服的Apache基金会举个例子</p><p>比如Apache基金会在23年的GSoC活动中有30个社区提交了申请，每个社区平均提出3个项目，那就是90个项目。</p><p>假设一部分项目有人申请，导师也都挑选了自己认可的申请者，假设这个成功双选的数量是50个。</p><p>接下来Apache需要排序这50个项目，具体规则不同的组织应该有自己的一套规则，Apache 的 规则是这个：<a href="https://community.apache.org/mentee-ranking-process.html">mentee-ranking-process</a></p><p>排序完成后，50个同学的顺序也定好了。</p><p>谷歌官方会公布给各个组织的名额，假设给Apache的是30个，那么只有排名在前30的同学会获得谷歌的正式名额，剩下的20位同学虽然他们也获得了导师的认可，但他们可能也无缘此次活动了（可能前面同学主动放弃会顺延名额）。</p><h2 id="下期预告">下期预告</h2><p>下一期，如何选择合适自己的社区（开源小白角度分析）</p><p>我会以我自己选择社区为例子分享我是如何选择社区以及后续是怎样开始贡献的，敬请期待（会在谷歌公布2023中选组织前更新）</p>]]>
                    </description>
                    <pubDate>Sat, 31 Dec 2022 19:37:14 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[本站优秀博客汇总]]>
                    </title>
                    <link>/archives/top</link>
                    <description>
                            <![CDATA[<p>欢迎新朋友快速查看本站优秀博客（自认为的优秀（狗头（逃（bushi</p><h3 id="开源">开源</h3><p><a href="https://erdengk.top/archives/gsoc">GSoC 从开始到中选</a></p><p><a href="https://erdengk.top/archives/gsoc-1">GSoC-1 ｜ GSoC介绍、活动流程、名额机制</a></p><h3 id="个人提升">个人提升</h3><p><a href="https://erdengk.top/archives/zongjie">22年日常实习总结</a></p><p><a href="https://erdengk.top/archives/jian-li--mian-shi">简历、面试</a></p><p><a href="https://erdengk.top/archives/ba-gu-wen">八股文-个人经验</a></p><p><a href="https://erdengk.top/archives/wo-de-shuo-shi-qian-ban-sheng">我的硕士前半生</a></p><p><a href="https://erdengk.top/archives/wo-de-shi-xi-qian-ban-sheng">我的实习前半生</a></p><h3 id="分享">分享</h3><p><a href="https://erdengk.top/archives/meetup">Meetup 活动分享</a></p>]]>
                    </description>
                    <pubDate>Sat, 31 Dec 2022 17:03:51 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[22年日常实习总结]]>
                    </title>
                    <link>/archives/zongjie</link>
                    <description>
                            <![CDATA[<h1 id="22年12月日常实习总结">22年12月日常实习总结</h1><br><p>12月结束了，8月末开始准备的日常实习也算是告一段落了</p><p>准备了2个多月，面试了一个月，也拿了一些offer</p><p>算是小有感触，遂写下此文，供还在准备或者要准备日常实习的同学参考。</p><p>个人背景及投递的日常实录在这篇文章里 <a href="https://www.nowcoder.com/discuss/416905527369707520">24届双非日常实习求职实录</a></p><p>下文中，我说的可能对，也能全不对，还请君自辩</p><p>不定期更新，点赞收藏关注不迷路～</p><p>（更新顺序，先个人博客后牛客（可能懒得更））</p><p>GitHub： <a href="https://github.com/erdengk">https://github.com/erdengk</a></p><p>个人博客 ： <a href="http://erdengk.top/">http://erdengk.top/</a></p><p>牛客主页 ：  <a href="https://www.nowcoder.com/users/2673318">https://www.nowcoder.com/users/2673318</a></p><p>------------------------------------------------------</p><h2 id="本文概览">本文概览</h2><p>本文可能会比较长，建议读者自行选择感兴趣的部分阅读</p><p>简历书写 （如何书写简历（简略版））</p><p>投递</p><p>面试及面试复盘</p><p>offer选择 （个人对于多个offer 选择的看法）</p><p>知识星球及收获问题（个人对于）</p><p>本次日常实习的面经、个人笔记总结、资源分享</p><p>一个信息浓度非常高的群（介绍一个优秀的群）</p><p>------------------------------------------------------</p><h2 id="日常实习收获概况">日常实习收获概况</h2><p>认识到了自己有多菜</p><p>结识了很多优秀的前辈、同辈</p><p>明确了自己想要的是什么样的公司</p><p>某团、某度、某滴、某易、某站日常实习offer</p><p>几个中小厂实习offer</p><p>几个技术厂实习offer</p><p>------------------------------------------------------</p><h2 id="简历书写">简历书写</h2><p>我在B站上看到了一个很好的视频，以及在字节训练营开营视频学到了一部分东西，把它们总结到了这篇博客里</p><p>请君移步：<a href="http://erdengk.top/archives/jian-li--mian-shi">简历、面试</a></p><h3 id="简历篇幅">简历篇幅</h3><p>正常写完要超了1页就不要硬扣回一页，一般两个项目的同学很容易超1页，硬扣回一页页不是不行，但排版会很挤</p><p>没必要硬凹一页，正常排版就行</p><p>当然也可以自行删减为1页，优秀的人可能有太多亮眼的实习，1页是放不下的（比如y总）</p><h3 id="简历内容安排">简历内容安排</h3><p>学历好，学校直接放前面</p><p>学历一般，比如我，我把学校放在了最后面。</p><p>另外有个人感触就是，既然“正常”简历已经过不了面试，为何不另辟蹊径？</p><p>上来先把自己弱势放最前面，然后和其他人去竞争，这并不是一个很好的策略</p><p>将自己觉得最值得说的东西放到最前面，最弱势的东西放到最后</p><p>简历的作用是拿到面试，不是为了写简历而写简历</p><p>我见过一位源码佬（形容此人对源码十分了解）的简历，说实话，有点配不上他的实力</p><p>后面修改后，亮点突出了，也拿到了他想要的offer</p><p>求职人太多了，需要靠自己想办法才行</p><p>------------------------------------------------------</p><h2 id="投递">投递</h2><p>boss优先，实习僧也可以投一下</p><p>官网也可以投，可能有些hr是喜欢捞官网投的简历</p><p>牛客，也可以投，但我总感觉牛客上可能是员工想挣内推积分什么的在搞</p><h3 id="个人经验">个人经验</h3><p>在保证自己能把个人介绍、个人项目讲明白后，开始投递</p><p>如果你认识某个在职员工，最好的找他投递，一方面能跟进，一方面也能了解公司部门情况</p><p>我投某厂时找了大学同学，给了hr，hr给的部门主管，没有走投递流程，4天三面极速走完了流程。</p><p>------------------------------------------------------</p><h2 id="面试及面试复盘">面试及面试复盘</h2><h3 id="面试顺序">面试顺序</h3><p>小厂开始面，然后中厂，最后大厂</p><h3 id="关于面评">关于面评</h3><p>有些厂会记录面评，但这个东西我觉得比较玄乎，面试官不一定看，也不一定不看</p><p>总原则就是不要在状态不好或者没准备好的时候去面大厂</p><h3 id="面试复盘">面试复盘</h3><p>不复盘等于浪费自己时间，还浪费面试官时间</p><p>可以开始面试前就自己开个飞书会议，面试完直接生成文字，非常方便（字节飞书看到能给个offer吗？）</p><p>注意复盘两种东西</p><ul><li>自己没答好的问题及自己本来会但描述不好的问题</li><li>具体的场景题，场景题是最考验人的题，多准备准备</li></ul><p>------------------------------------------------------</p><h2 id="offer选择">Offer选择</h2><p>学历好，随便选，想去哪去哪</p><p>学历一般，优先名气大的厂（同等层次的厂挑组）</p><p>------------------------------------------------------</p><h2 id="知识星球及收获问题">知识星球及收获问题</h2><p>这部分内容本不打算在这写的，但因为此次日常实习也有很多和这个有关的事发生，就写在这里了。</p><h3 id="知识星球有用吗">知识星球有用吗？</h3><p>我认为，除了保底的资料以及星球主人提供的服务外，剩下的看运气</p><p>你可能进去第一天发现了一个内推，然后试着投了下，就进公司了</p><p>你也可能进去发现其他人自己做自己的，你收获的很有限。</p><p>我在代码随想录卡哥的星球，一开始是刷lc时发现了carl哥，然后我觉得随想录很好，也就进星球追寻卡哥的脚步了</p><p>我在星球提问过几次，一次是问时间规划，一次是问简历，还有些零散的问题是在微信问的。</p><p>我个人觉得我在星球里是赚到了的</p><p>有卡哥这种优秀的前辈答疑解惑</p><p>认识了某冰佬，教我背八股，我不会的算法题大佬能给我讲</p><p>进入了冲友群，膜拜群佬，拓展好友圈，认识更多优秀的同辈</p><p>。。。。。。。。还有很多优点，就不一一列举了</p><p>缺点自然也有， 你得自己花一定的时间去发掘这些东西</p><p>如果这个星球价钱合理，以及他有你想要的服务，那么就大胆的加入它吧</p><p>合理的钱换合理的时间，在人生任何阶段都是可以接受的事。</p><p>------------------------------------------------------</p><h2 id="本次日常实习的面经个人笔记总结资源分享">本次日常实习的面经、个人笔记总结、资源分享</h2><p>面经在牛客主页可以找到</p><p>部分面经有二次补充在 github：<a href="https://github.com/erdengk/notes/tree/main/2022日常实习面经（2022.11-12">面经</a></p><p>个人笔记同github：<a href="https://github.com/erdengk/notes">https://github.com/erdengk/notes</a></p><p>收集了一些优秀的面经：<a href="https://github.com/erdengk/excellent-interview">https://github.com/erdengk/excellent-interview</a></p><p>收集了一些轮子类项目：[https://github.com/erdengk/excellent-wheel](</p><p>因为还要准备开题，暂时没时间总结面经复盘</p><p>计划下次准备实习时二次复盘</p><p>还准备截取部分面试实录发到B站上（大约23年11月份，如果秋招提前结束也会提前）</p><p>------------------------------------------------------</p><h2 id="一个信息浓度非常高的群">一个信息浓度非常高的群</h2><p>一个人可以走的很快，一群人可以走的很远</p><p>我个人理解为优秀的人都是优秀的信息源</p><p>无论是他们本身的技术，还是他们认识的人，以及他们经历过的事，都可以抽象成信息，越是优秀的人，信息浓度越高、信息质量越高</p><p>群，是一个聚合信息源的地方，我在卡哥的知识星球认识了冲友群的群主，有幸进群膜拜诸位群佬。</p><p>现在我也把这个优秀的群分享出来，欢迎新的小伙伴加入</p><p>群内有在不同大厂、中厂、独角兽公司实习同学，也有热爱开源几段开源实习的同学，也有海硕+量化实习的同学...............</p><p>如何进群？可以私信我（自我介绍），也可以去小红书那私信群主。</p><p>部分群佬自我介绍：</p><p><a href="https://zhuanlan.zhihu.com/p/602571244">24届秋招 | 高质量学习交流环境</a></p><h1 id="永远在路上">永远在路上</h1><p>准备实习、实习、正式上班都是在磨练自身，愿吾与诸君共勉</p><p>永远是学生，永远年轻</p><p>无限进步、无限热爱</p><p>祝24届的xdm，都有自己想要的offer</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202212311650179.JPG" alt="IMG_5019" /></p>]]>
                    </description>
                    <pubDate>Sat, 31 Dec 2022 16:44:55 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[Meetup 活动分享]]>
                    </title>
                    <link>/archives/meetup</link>
                    <description>
                            <![CDATA[<p>此处会分享一些meetup的活动，主要是开源社区和分布式、云原生、数据库方向的活动。</p><p>不定期更新，关注不迷路～</p><p>（更新顺序，先个人博客后牛客）</p><p>GitHub : <a href="https://github.com/erdengk">https://github.com/erdengk</a></p><p>个人博客 : <a href="http://erdengk.top/">http://erdengk.top/</a></p><p>牛客主页 : <a href="https://www.nowcoder.com/users/2673318">https://www.nowcoder.com/users/2673318</a></p><p>------------------------------------------------------------------------------</p><h3 id="328ict-中国高层论坛---云原生发展论坛">3.28｜ICT 中国·高层论坛 - 云原生发展论坛</h3><p><a href="https://www.huodongxing.com/event/1664224667200?">https://www.huodongxing.com/event/1664224667200?</a></p><p>时间：03月28日全天</p><p>地点：北京国家会议中心C区多功能厅A</p><p>规模：300人</p><p>主题：软件架构的变革、新生产力的飞跃</p><h3 id="12212022全球分布式云大会深圳站">12.21｜2022全球分布式云大会·深圳站</h3><p><a href="https://www.huodongxing.com/event/7674443676600">https://www.huodongxing.com/event/7674443676600</a></p><p>2022全球分布式云大会·深圳站</p><p>2022年12月21日 8:30 ～ 2022年12月22日 18:00</p><h3 id="1217apache-apisix--阿里-edas-联合-meetup深圳站">12.17｜Apache APISIX &amp; 阿里 EDAS 联合 Meetup——深圳站</h3><p><a href="https://www.huodongxing.com/event/1678054775200">https://www.huodongxing.com/event/1678054775200</a></p><p>12 月 17 日（周六）13:30，Apache APISIX 联合 阿里开源项目 EDAS 共同举办线下 Meetup——深圳站。</p><p>本次活动邀请到来自阿里巴巴的技术专家，Apache APISIX PMC Member 等多位大咖分享云原生时代的微服务趋势。更有圆桌讨论，关注开源项目走出国外需要做哪些转变！欢迎各位社区小伙伴，及广大开源爱好者、开发者报名本次活动！</p><h3 id="1216-shardingsphere-meetup-上海站--sphereex-联合喜马拉雅共话云原生数据技术应用创新实践">12.16｜ ShardingSphere Meetup 上海站 | SphereEx 联合喜马拉雅共话云原生数据技术应用创新实践</h3><p><a href="https://www.huodongxing.com/event/1680323350900">https://www.huodongxing.com/event/1680323350900</a></p><p>活动时间</p><p>2022年12月16日 14:00-17:30</p><p>活动地点</p><p>上海市浦东新区丹桂路 799 号 3 号楼 201</p><h3 id="12142022-edgex开发者峰会上海站-暨2022-edgex中国挑战赛闭幕">12.14｜2022 EdgeX开发者峰会上海站 暨2022 EdgeX中国挑战赛闭幕</h3><p><a href="https://www.huodongxing.com/event/7680224712800">https://www.huodongxing.com/event/7680224712800</a></p><p>2022年12月14日 12:00 ～ 2022年12月14日 18:30</p><p><a href="https://www.huodongxing.com/event/map/7680224712800">（上海徐汇）田林路192号J座微软Reactor</a></p><h3 id="1210tidb-workshop-day-serverless-htap-on-tidb-cloud-体验课">12.10｜TiDB Workshop Day-Serverless HTAP on TiDB Cloud 体验课</h3><p><a href="https://www.huodongxing.com/event/5677472167800">https://www.huodongxing.com/event/5677472167800</a></p><p>TiDB Workshop Day 又来了！12 月 10 日，上海见</p><h3 id="129贝斯的圆桌趴-聊聊中国原创的开源项目">12.9｜贝斯的圆桌趴 ｜聊聊中国原创的开源项目</h3><p><a href="https://www.huodongxing.com/event/7679051961300">https://www.huodongxing.com/event/7679051961300</a></p><p>12 月 9 日（本周五）晚 7 点，Bytebase 将举行社区活动「<strong>贝斯的圆桌趴｜聊聊中国原创的开源项目</strong>」，并采取<strong>线上 &amp; 线下</strong>同步进行的方式。</p><ul><li>有兴趣来现场与我们面对面交流的同学，欢迎报名参加，成功报名后 BB 小助手会在一个工作日内拉你进活动交流群，现场签到的同学都可以得到晚餐 🍕 和 Bytebase 布袋！</li><li>不便来现场的伙伴们请关注 Bytebase 公众号预约直播，周五晚间线上见 🤗！</li></ul>]]>
                    </description>
                    <pubDate>Fri, 09 Dec 2022 11:12:09 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[分布式简单入门知识]]>
                    </title>
                    <link>/archives/fen-bu-shi-jian-dan-ru-men-zhi-shi</link>
                    <description>
                            <![CDATA[<h2 id="分布式简单入门知识">分布式简单入门知识</h2><p>学习了这些不一定入门，但不学这些应该不能入门</p><p>因学业繁忙，所以先写一个大致框架，后期补充相关博客</p><p>可以使用小标题直接去 <strong>谷歌</strong> 搜索对应知识，标题下会写一些最近面试遇到的问题</p><p>最后引用部分贴一些之前看到的写的好的博客，暂未分类</p><h2 id="分布式基础理论">分布式基础理论</h2><h3 id="cap理论">CAP理论</h3><p><a href="https://tanxinyu.work/cap-theory/">https://tanxinyu.work/cap-theory/</a></p><h3 id="pacelc理论">PACELC理论</h3><p>这个好好看，说了CAP记得要说这个</p><h3 id="base理论">BASE理论</h3><h3 id="nwr多数派理论">NWR多数派理论</h3><p>说了PACELC可以补充一个这个的例子</p><h3 id="一致性理论">一致性理论</h3><p><a href="https://tanxinyu.work/consistency-and-consensus/">https://tanxinyu.work/consistency-and-consensus/</a></p><h3 id="一致性hash算法">一致性hash算法</h3><p>普通一致性hash算法</p><p>一致性hash算法底层数据结构</p><p>一致性hash算法的具体实现</p><p>虚拟节点</p><h2 id="分布式共识算法">分布式共识算法</h2><h3 id="2pc--3pc">2PC &amp; 3PC</h3><p>说一下2pc、3pc</p><p><a href="https://www.bilibili.com/video/BV1EA411u7gM">https://www.bilibili.com/video/BV1EA411u7gM</a></p><p><a href="https://www.bilibili.com/video/BV1XT4y1B73Y">https://www.bilibili.com/video/BV1XT4y1B73Y</a></p><h3 id="paxos协议">Paxos协议</h3><p>将一下paxos协议</p><p>活锁</p><p><a href="https://www.bilibili.com/video/BV1X54y1d7xU/">https://www.bilibili.com/video/BV1X54y1d7xU/</a></p><h3 id="raft算法">Raft算法</h3><p>raft选举过程</p><p>raft脑裂</p><p><a href="https://www.bilibili.com/video/BV1BZ4y1U774">https://www.bilibili.com/video/BV1BZ4y1U774</a></p><p><a href="https://www.bilibili.com/video/BV1aA4y1R7YH">https://www.bilibili.com/video/BV1aA4y1R7YH</a></p><p><a href="https://tanxinyu.work/raft/#%E8%83%8C%E6%99%AF">https://tanxinyu.work/raft/#%E8%83%8C%E6%99%AF</a></p><h3 id="zab协议">Zab协议</h3><p>zab选举过程</p><p>zab奔溃恢复过程</p><p>脑裂</p><p><a href="https://www.bilibili.com/video/BV14Y411g7ok">https://www.bilibili.com/video/BV14Y411g7ok</a></p><h2 id="reference">Reference</h2><p>分布式理论相关（总）：<a href="https://github.com/erdengk/notes/blob/main/%E7%AC%94%E8%AE%B0/3%20%E5%88%86%E5%B8%83%E5%BC%8F/1%20%E5%88%86%E5%B8%83%E5%BC%8F%E7%90%86%E8%AE%BA%E7%9B%B8%E5%85%B3.md">https://github.com/erdengk/notes/blob/main/%E7%AC%94%E8%AE%B0/3%20%E5%88%86%E5%B8%83%E5%BC%8F/1%20%E5%88%86%E5%B8%83%E5%BC%8F%E7%90%86%E8%AE%BA%E7%9B%B8%E5%85%B3.md</a></p><p>分布式算法相关（总）：<a href="https://github.com/erdengk/notes/blob/main/%E7%AC%94%E8%AE%B0/3%20%E5%88%86%E5%B8%83%E5%BC%8F/2%20%20%E5%88%86%E5%B8%83%E5%BC%8F%E7%AE%97%E6%B3%95%E7%9B%B8%E5%85%B3.md">https://github.com/erdengk/notes/blob/main/%E7%AC%94%E8%AE%B0/3%20%E5%88%86%E5%B8%83%E5%BC%8F/2%20%20%E5%88%86%E5%B8%83%E5%BC%8F%E7%AE%97%E6%B3%95%E7%9B%B8%E5%85%B3.md</a></p><p><a href="https://www.nowcoder.com/discuss/post/362412702839451648">https://www.nowcoder.com/discuss/post/362412702839451648</a></p><p>基础理论：</p><p><a href="http://zhangtielei.com/posts/blog-distributed-strong-weak-consistency.html">http://zhangtielei.com/posts/blog-distributed-strong-weak-consistency.html</a></p><p><a href="https://cn.pingcap.com/blog/linearizability-and-raft">https://cn.pingcap.com/blog/linearizability-and-raft</a></p><p><a href="http://www.choudan.net/2013/08/07/CAP%E7%90%86%E8%AE%BA%E5%92%8CNWR%E7%AD%96%E7%95%A5.html">http://www.choudan.net/2013/08/07/CAP%E7%90%86%E8%AE%BA%E5%92%8CNWR%E7%AD%96%E7%95%A5.html</a></p><p><a href="https://blog.csdn.net/m0_68850571/article/details/126140636">https://blog.csdn.net/m0_68850571/article/details/126140636</a></p><p><a href="https://www.changping.me/2020/04/10/distributed-theory-cap-pacelc/">https://www.changping.me/2020/04/10/distributed-theory-cap-pacelc/</a></p><p><a href="https://pdai.tech/md/dev-spec/spec/dev-microservice-kangwei.html">https://pdai.tech/md/dev-spec/spec/dev-microservice-kangwei.html</a></p><p><a href="https://www.52code.net/a/8xjTPFSabM">https://www.52code.net/a/8xjTPFSabM</a></p><p><a href="https://pdai.tech/md/arch/arch-z-theory.html">https://pdai.tech/md/arch/arch-z-theory.html</a></p><p><a href="https://cloud.tencent.com/developer/article/1752382">https://cloud.tencent.com/developer/article/1752382</a></p><p>分布式算法：</p><p><a href="https://zhuanlan.zhihu.com/p/112651338">https://zhuanlan.zhihu.com/p/112651338</a></p><p><a href="https://pdai.tech/md/algorithm/alg-domain-distribute-x-zab.html">https://pdai.tech/md/algorithm/alg-domain-distribute-x-zab.html</a></p><p><a href="https://cloud.tencent.com/developer/article/1525566">https://cloud.tencent.com/developer/article/1525566</a></p><p><a href="https://pdai.tech/md/algorithm/alg-domain-distribute-x-paxos.html">https://pdai.tech/md/algorithm/alg-domain-distribute-x-paxos.html</a></p><p><a href="https://blog.csdn.net/yzf279533105/article/details/127163022">https://blog.csdn.net/yzf279533105/article/details/127163022</a></p><p><a href="https://blog.openacid.com/algo/paxos">https://blog.openacid.com/algo/paxos</a></p><p><a href="https://blog.csdn.net/Z_Stand/article/details/108547684">https://blog.csdn.net/Z_Stand/article/details/108547684</a></p><p><a href="http://www.xuyasong.com/?p=1970">http://www.xuyasong.com/?p=1970</a></p><p><a href="https://cloud.tencent.com/developer/article/1798049">https://cloud.tencent.com/developer/article/1798049</a></p><p><a href="https://zhuanlan.zhihu.com/p/68743917">https://zhuanlan.zhihu.com/p/68743917</a></p><p><a href="https://draveness.me/consensus/">https://draveness.me/consensus/</a></p><p><a href="https://pdai.tech/md/algorithm/alg-domain-distribute-x-consistency-hash.html">https://pdai.tech/md/algorithm/alg-domain-distribute-x-consistency-hash.html</a></p><p><a href="https://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/24%E8%AE%B2%E5%90%83%E9%80%8F%E5%88%86%E5%B8%83%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%BA%93-%E5%AE%8C/20%20%20%E5%85%B1%E8%AF%86%E7%AE%97%E6%B3%95%EF%BC%9A%E4%B8%80%E6%AC%A1%E6%80%A7%E8%AF%B4%E6%B8%85%E6%A5%9A%20Paxos%E3%80%81Raft%20%E7%AD%89%E7%AE%97%E6%B3%95%E7%9A%84%E5%8C%BA%E5%88%AB.md">https://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/24%E8%AE%B2%E5%90%83%E9%80%8F%E5%88%86%E5%B8%83%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%BA%93-%E5%AE%8C/20%20%20%E5%85%B1%E8%AF%86%E7%AE%97%E6%B3%95%EF%BC%9A%E4%B8%80%E6%AC%A1%E6%80%A7%E8%AF%B4%E6%B8%85%E6%A5%9A%20Paxos%E3%80%81Raft%20%E7%AD%89%E7%AE%97%E6%B3%95%E7%9A%84%E5%8C%BA%E5%88%AB.md</a></p><p><a href="https://here2say.com/44/">https://here2say.com/44/</a></p>]]>
                    </description>
                    <pubDate>Wed, 16 Nov 2022 20:50:05 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[macOS Monterey终端添加App权限]]>
                    </title>
                    <link>/archives/zhong-duan-tian-jia-app-quan-xian</link>
                    <description>
                            <![CDATA[<p>下午面试用钉钉，一直无法给权限。。。搜了下解决方案，最好的方案没排在谷歌搜索的上面。。。遂自己记录一份</p><p><a href="https://juejin.cn/post/7033792167362035749">解决方案1</a></p><p><a href="https://blog.csdn.net/qq_34029469/article/details/107284443">解决方案2</a></p><p><a href="https://iaiti.blog.csdn.net/article/details/119883675?spm=1001.2101.3001.6650.2&amp;utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-119883675-blog-107284443.pc_relevant_3mothn_strategy_and_data_recovery&amp;depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-119883675-blog-107284443.pc_relevant_3mothn_strategy_and_data_recovery&amp;utm_relevant_index=3">mac os 权限表</a></p><p>部分应用的包名字</p><blockquote><p>com.tencent.meeting<br />com.tencent.xinWeChat<br />// 飞书<br />com.electron.lark</p></blockquote>]]>
                    </description>
                    <pubDate>Wed, 09 Nov 2022 19:53:19 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[10.23｜ 你项目里的Redis和DB是如何保持一致性的？]]>
                    </title>
                    <link>/archives/db-cache</link>
                    <description>
                            <![CDATA[<h2 id="你项目里的redis和db是如何保持一致性的">你项目里的Redis和DB是如何保持一致性的？</h2><p>首先，如果要实现两者在同一时间上的完全的一致，完全的同步是不可能的。</p><p>如果业务上对数据不一致零容忍，就使用分布式锁。</p><p>从理论上来说，给缓存设置过期时间，是可以保证最终一致性的解决方案。</p><p>这种方案下，我们可以对存入缓存的数据设置过期时间，所有的写操作以数据库为准，对缓存操作只是尽最大努力即可，也就是说如果数据库写成功，缓存更新失败，那么只要到达过期时间，则后面的读请求自然会从数据库中读取新值然后回填缓存</p><blockquote><p>现有策略总是或多或少都有些缺陷的，能说清楚各种策略哪些地方可能会导致不一致就行了</p></blockquote><p>接下来讨论的思路不依赖于给缓存设置过期时间这个方案，并且尽可能的实现缓存与数据库的一致性。</p><p>我们讨论<strong>三种</strong>更新策略：</p><ol><li>先更新数据库，再更新缓存</li><li>先删除缓存，再更新数据库</li><li>先更新数据库，再删除缓存</li></ol><h3 id="先更新数据库再更新缓存">先更新数据库，再更新缓存</h3><p>结论：不推荐</p><p>如果同时有请求A和请求B进行更新操作，那么会出现<br />（1）线程A更新了数据库<br />（2）线程B更新了数据库<br />（3）线程B更新了缓存<br />（4）线程A更新了缓存<br />这就出现请求A更新缓存应该比请求B更新缓存早才对，但是因为网络等原因，B却比A更早更新了缓存。这就导致了脏数据，因此不考虑。</p><h3 id="先删除缓存再更新数据库">先删除缓存，再更新数据库</h3><p>该方案会导致不一致的原因是。同时有一个请求A进行更新操作，另一个请求B进行查询操作。那么会出现如下情形:<br />（1）请求A进行写操作，删除缓存<br />（2）请求B查询发现缓存不存在<br />（3）请求B去数据库查询得到旧值<br />（4）请求B将旧值写入缓存<br />（5）请求A将新值写入数据库<br />上述情况就会导致不一致的情形出现。而且，如果不采用给缓存设置过期时间策略，该数据永远都是脏数据。</p><h4 id="延时双删策略">延时双删策略</h4><p>先淘汰缓存<br />再写数据库（这两步和原来一样）<br />休眠一段时间，再次淘汰缓存<br />这么做，可以将这一段时间内所造成的缓存脏数据，再次删除。</p><p>下次再有读取请求时，会访问缓存，缓存没有，去数据库拿到最新的，同时更新缓存</p><h4 id="如果dbcache-不是单机而是主从配置怎么办">如果db、cache 不是单机而是主从配置怎么办</h4><p>在这种情况下，造成数据不一致的原因如下，还是两个请求，一个请求A进行更新操作，另一个请求B进行查询操作。</p><pre><code>（1）请求A进行写操作，删除缓存（2）请求A将数据写入数据库了，（3）请求B查询缓存发现，缓存没有值（4）请求B去从库查询，这时，还没有完成主从同步，因此查询到的是旧值（5）请求B将旧值写入缓存（6）数据库完成主从同步，从库变为新值</code></pre><p>还是使用双删延时策略。只是，睡眠时间修改为在主从同步的延时时间基础上，加几百ms。</p><p>多加的时间是为了让db、cache 内部同步。</p><h4 id="采用这种同步淘汰策略吞吐量降低怎么办">采用这种同步淘汰策略，吞吐量降低怎么办？</h4><p>那就将第二次删除作为异步的。自己起一个线程，异步删除。这样，写的请求就不用沉睡一段时间后了，再返回。这么做，加大吞吐量。</p><h4 id="第二次删除如果删除失败怎么办">第二次删除,如果删除失败怎么办？</h4><p>第二次删除失败，就会出现如下情形。还是有两个请求，一个请求A进行更新操作，另一个请求B进行查询操作，为了方便，假设是单库：</p><p>（1）请求A进行写操作，删除缓存<br />（2）请求B查询发现缓存不存在<br />（3）请求B去数据库查询得到旧值<br />（4）请求B将旧值写入缓存<br />（5）请求A将新值写入数据库<br />（6）请求A试图去删除请求B写入对缓存值，结果失败了。</p><p>ok,这也就是说。如果第二次删除缓存失败，会再次出现缓存和数据库不一致的问题。</p><h4 id="如何解决异步删除失败">如何解决异步删除失败</h4><p>先更新db，再删除cache</p><h3 id="先更新数据库再删除缓存">先更新数据库，再删除缓存</h3><h4 id="cache-aside-pattern">Cache-Aside pattern</h4><p>老外提出了一个缓存更新套路，名为<a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside">《Cache-Aside pattern》</a>。其中就指出</p><ul><li><strong>失效</strong>：应用程序先从cache取数据，没有得到，则从数据库中取数据，成功后，放到缓存中。</li><li><strong>命中</strong>：应用程序从cache中取数据，取到后返回。</li><li><strong>更新</strong>：先把数据存到数据库中，成功后，再让缓存失效。</li></ul><p>另外，知名社交网站facebook也在论文<a href="https://www.usenix.org/system/files/conference/nsdi13/nsdi13-final170_update.pdf">《Scaling Memcache at Facebook》</a>中提出，他们用的也是先更新数据库，再删缓存的策略。</p><p>假设这会有两个请求，一个请求A做查询操作，一个请求B做更新操作，那么会有如下情形产生</p><p>（1）缓存刚好失效<br />（2）请求A查询数据库，得一个旧值<br />（3）请求B将新值写入数据库<br />（4）请求B删除缓存<br />（5）请求A将查到的旧值写入缓存</p><p>ok，如果发生上述情况，确实是会发生脏数据。</p><p>==发生上述情况有一个先天性条件==，就是步骤（3）的写数据库操作比步骤（2）的读数据库操作耗时更短，才有可能使得步骤（4）先于步骤（5）。</p><p>可是，大家想想，数据库的读操作的速度远快于写操作的（不然做读写分离干嘛，做读写分离的意义就是因为读操作比较快，耗资源少），因此步骤（3）耗时比步骤（2）更短，这一情形很难出现。</p><p>假设，有人非要抬杠，有强迫症，一定要解决怎么办？</p><p><strong>如何解决上述并发问题？</strong></p><p>首先，给缓存设有效时间是一种方案。其次，采用策略（2）里给出的异步延时删除策略，保证读请求完成以后，再进行删除操作。</p><p><strong>还有其他造成不一致的原因么？</strong></p><p>有的，这也是 <code>先删缓存后更新数据库</code> 和 <code>先更新数据库后删缓存</code>都存在的一个问题，如果删缓存失败了怎么办，那不是会有不一致的情况出现么。</p><p>比如一个写数据请求，然后写入数据库了，删缓存失败了，这会就出现不一致的情况了。</p><p><strong>如何解决最后的问题？</strong></p><p>提供一个保障的重试机制即可，这里给出两套方案。</p><h4 id="方案一消息队列重试"><strong>方案一</strong>：消息队列重试</h4><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202210231709202.png" alt="image" /></p><p>流程如下所示</p><p>（1）更新数据库数据；<br />（2）缓存因为种种问题删除失败<br />（3）将需要删除的key发送至消息队列<br />（4）自己消费消息，获得需要删除的key<br />（5）继续重试删除操作，直到成功</p><p>然而，该方案有一个缺点，对业务线代码造成大量的侵入。于是有了方案二，在方案二中，启动一个订阅程序去订阅数据库的binlog，获得需要操作的数据。在应用程序中，另起一段程序，获得这个订阅程序传来的信息，进行删除缓存操作。</p><h4 id="方案二binlog订阅机制"><strong>方案二</strong>：binlog订阅机制</h4><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202210231710611.png" alt="image" /></p><p>流程如下图所示：</p><p>（1）更新数据库数据<br />（2）数据库会将操作信息写入binlog日志当中<br />（3）订阅程序提取出所需要的数据以及key<br />（4）另起一段非业务代码，获得该信息<br />（5）尝试删除缓存操作，发现删除失败<br />（6）将这些信息发送至消息队列<br />（7）重新从消息队列中获得该数据，重试操作。</p><p>**备注说明：**上述的订阅binlog程序在mysql中有现成的中间件叫canal，可以完成订阅binlog日志的功能。至于oracle中，博主目前不知道有没有现成中间件可以使用。</p><h2 id="解决方案">解决方案</h2><h3 id="分别处理">分别处理</h3><p>​      针对某些对数据一致性要求不是特别高的情况下，可以将这些数据放入Redis，请求来了直接查询Redis，例如近期回复、历史排名这种实时性不强的业务。</p><p>而针对那些强实时性的业务，例如虚拟货币、物品购买件数等等，则直接穿透Redis至MySQL上，等到MySQL上写入成功，再同步更新到Redis上去。这样既可以起到Redis的分流大量查询请求的作用，又保证了关键数据的一致性。</p><h3 id="高并发情况下">高并发情况下</h3><p>此时如果写入请求较多，则直接写入Redis中去，然后间隔一段时间，批量将所有的写入请求，刷新到MySQL中去；如果此时写入请求不多，则可以在每次写入Redis，都立刻将该命令同步至MySQL中去。这两种方法有利有弊，需要根据不同的场景来权衡。</p><h3 id="基于订阅binlog的同步机制">基于订阅binlog的同步机制</h3><p>​       阿里巴巴的一款开源框架canal，提供了一种发布/ 订阅模式的同步机制，通过该框架我们可以对MySQL的binlog进行订阅，这样一旦MySQL中产生了新的写入、更新、删除等操作，就可以把binlog相关的消息推送至Redis，Redis再根据binlog中的记录，对Redis进行更新。值得注意的是，binlog需要手动打开，并且不会记录关于MySQL查询的命令和操作。</p><blockquote><p>分布式系统里要么通过2PC或是Paxos协议保证一致性，要么就是拼命的降低并发时脏数据的概率</p><p>缓存系统适用的场景就是非强一致性的场景，所以它属于CAP中的AP，BASE理论。</p><p>异构数据库本来就没办法强一致，<strong>只是尽可能减少时间窗口，达到最终一致性</strong>。</p><p>还有别忘了设置过期时间，这是个兜底方案</p><p>陈浩《缓存更新的套路》</p></blockquote><h2 id="reference">Reference</h2><p><a href="https://coolshell.cn/articles/17416.html">https://coolshell.cn/articles/17416.html</a></p><p><a href="https://www.cnblogs.com/rjzheng/p/9041659.html">https://www.cnblogs.com/rjzheng/p/9041659.html</a></p><p><a href="https://blog.csdn.net/qq_30683329/article/details/80543178">https://blog.csdn.net/qq_30683329/article/details/80543178</a></p><p><a href="https://juejin.cn/post/6964531365643550751">https://juejin.cn/post/6964531365643550751</a></p><p><a href="https://www.easemob.com/news/7604">https://www.easemob.com/news/7604</a></p><p><a href="https://note.dolyw.com/cache/00-DataBaseConsistency.html">https://note.dolyw.com/cache/00-DataBaseConsistency.html</a></p>]]>
                    </description>
                    <pubDate>Sun, 23 Oct 2022 20:57:35 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[10.13｜讲一下你知道的分布式共识算法]]>
                    </title>
                    <link>/archives/fenbushi-gongshi</link>
                    <description>
                            <![CDATA[<h2 id="共识算法">共识算法</h2><p>paxos、raft准确来说是共识（consensus）算法，而不是一致性（consistency）算法。</p><p>共识指的是一个或多个进程提议了一个值应当是什么后，采用一种大家都认可的方法，使得系统中所有进程对这个值达成一致意见。</p><p>比如说选主（Leader election）问题中所有进程对Leader达成一致；互斥（Mutual exclusion）问题中对于哪个进程进入临界区达成一致；原子组播（Atomic broadcast）中进程对消息传递（delivery）顺序达成一致。对于这些问题有一些特定的算法，但是，<strong>分布式共识问题试图探讨这些问题的一个更一般的形式，如果能够解决分布式共识问题，则以上的问题都可以得以解决。</strong></p><p>一致性指的是对于同一个数据的多个副本之间，保持其对外表现的数据一致性。</p><p>一些常见的误解：使用了 Raft或者 paxos 的系统都是线性一致的（Linearizability 即强一致），其实不然，共识算法只能提供基础，要实现线性一致还需要在算法之上做出更多的努力。</p><h3 id="共识算法属性">共识算法属性</h3><p>它的三个属性。</p><ol><li>正确性（Validity）：诚实节点最终达成共识的值必须是来自诚实节点提议的值。</li><li>一致性（Agreement）：所有的诚实节点都必须就相同的值达成共识。</li><li>终止性（Termination）：诚实的节点必须最终就某个值达成共识。</li></ol><p>共识算法中需要有“诚实”节点，它的概念是节点不能产生失败模型所描述的“任意失败”，或是“拜占庭失败”。</p><h2 id="paxos协议">Paxos协议</h2><p>Paxos 其实是一类协议，Paxos 中包含 Basic Paxos、Multi-Paxos、Cheap Paxos 和其他的变种。Raft 就是 Multi-Paxos 的一个变种，Raft 通过简化 Multi-Paxos 的模型，实现了一种更容易让人理解和工程实现的共识算法，</p><p>Paxos是第一个被证明完备的共识算法，能够让分布式网络中的节点在出现错误时仍然保持一致，当然前提是没有恶意节点，也就是<a href="https://www.infoq.cn/article/the-byzantine-generals-problem-and-blockchain">拜占庭将军问题</a>。在传统的分布式系统领域是不需要担心这种问题的，因为不论是分布式数据库、消息队列、分布式存储，你的机器都不会故意发送错误信息，最常见的问题反而是节点失去响应，所以它们在这种前提下，Paxos是足够用的。</p><p>一些常见的误解：使用了 Raft [0] 或者 paxos 的系统都是线性一致的（Linearizability [1]，即强一致），其实不然，共识算法只能提供基础，要实现线性一致还需要在算法之上做出更多的努力。以 TiKV 为例，它的共识算法是 Raft，在 Raft 的保证下，TiKV 提供了满足线性一致性的服务。</p><h3 id="paxos的直观解释">Paxos的直观解释</h3><p><strong>有时间的话推荐直接看大佬的原文</strong>：<a href="https://blog.openacid.com/algo/paxos">https://blog.openacid.com/algo/paxos</a></p><p>paxos的工作, 就是把一堆运行的机器协同起来, 让多个机器成为一个整体系统. 在这个系统中, 每个机器都必须让系统中的状态达成一致, 例如三副本集群如果一个机器上上传了一张图片, 那么另外2台机器上也必须复制这张图片过来, 整个系统才处于一个<strong>一致</strong>的状态.</p><p>几乎所有的分布式存储都必须用某种冗余的方式在廉价硬件的基础上搭建高可靠的存储. 而冗余的基础就是多副本策略, 一份数据存多份. 多副本保证了可靠性, 而副本之间的一致, 就需要paxos这类分布式一致性算法来保证.</p><h4 id="主从异步复制">主从异步复制</h4><p><img src="https://blog.openacid.com/post-res/paxos/slide-imgs/paxos-07.jpg" alt="img" /></p><p><strong>主从异步复制</strong>是最简单的策略之一, 它很容易实现, 但存在一个问题: 客户端收到一个<strong>数据已经安全</strong>(OK)的信息, 跟<strong>数据真正安全</strong>(数据复制到全部的机器上)在时间上有一个空隙, 这段时间负责接收客户端请求的那个机器(master)如果被闪电击中或被陨石砸到或被打扫卫生的大姐踢断了电源, 那数据就可能会丢失. 因此它不是一个可靠的复制策略(使用主从异步复制要求你必须相信宇宙中不存在闪电陨石和扫地大姐).</p><h4 id="主从同步复制">主从同步复制</h4><p><img src="https://blog.openacid.com/post-res/paxos/slide-imgs/paxos-08.jpg" alt="img" /></p><p>跟主从异步复制相比, <strong>主从同步复制</strong>提供了完整的可靠性: 直到数据真的安全的复制到全部的机器上之后, master才告知客户端<strong>数据已经安全</strong>.</p><p>但主从同步复制有个致命的缺点就是整个系统中有任何一个机器宕机, 写入就进行不下去了. 相当于系统的可用性随着副本数量指数降低.</p><h4 id="主从半同步复制">主从半同步复制</h4><p><img src="https://blog.openacid.com/post-res/paxos/slide-imgs/paxos-09.jpg" alt="img" /></p><p>然鹅, 在同步和异步之间, 做一个折中, 看起来是一个不错的方案. 这就是<strong>半同步复制</strong>. 它要求master在应答客户端之前必须把数据复制到<strong>足够多</strong>的机器上, 但不需要是全部. <strong>这样副本数够多可以提供比较高的可靠性; 1台机器宕机也不会让整个系统停止写入</strong>.</p><p>但是它还是不完美, 例如数据a复制到slave-1, 但没有到达slave-2; 数据b复制达到了slave-2但没有到达slave-1, 这时如果master挂掉了需要从某个slave恢复出数据, 任何一个slave都不能提供完整的数据. 所以在整个系统中, 数据存在某种<strong>不一致</strong>.</p><h4 id="多数派">多数派</h4><p><img src="https://blog.openacid.com/post-res/paxos/slide-imgs/paxos-10.jpg" alt="img" /></p><p>为了解决半同步复制中数据不一致的问题, 可以将这个复制策略再做一改进: <strong>多数派读写</strong>: 每条数据必须写入到<strong>半数以上</strong>的机器上. 每次读取数据都必须检查<strong>半数以上</strong>的机器上是否有这条数据.</p><p>在这种策略下, 数据可靠性足够, 宕机容忍足够, 任一机器故障也能读到全部数据.</p><h4 id="多数派引起的问题1">多数派引起的问题1</h4><p><img src="https://blog.openacid.com/post-res/paxos/slide-imgs/paxos-11.jpg" alt="img" /></p><p>然鹅多数派读写的策略也有个<strong>但是</strong>, 就是对于一条数据的更新时, 会产生不一致的状态. 例如:</p><ul><li>node-1, node-2都写入了a=x,</li><li>下一次更新时node-2, node-3写入了a=y.</li></ul><p>这时, 一个要进行读取a的客户端如果联系到了node-1和node-2, 它将看到2条<strong>不同</strong>的数据.</p><p>为了不产生歧义, 多数派读写还必须给每笔写入增加一个全局递增的<strong>时间戳</strong>. 更大时间戳的记录如果被看见, 就应该忽略小时间戳的记录. 这样在读取过程中, 客户端就会看到a=x₁, a=y₂ 这2条数据, 通过比较时间戳1和2, 发现y是更新的数据, 所以忽略a=x₁. 这样保证多次更新一条数据不产生歧义.</p><h4 id="多数派引起的问题2">多数派引起的问题2</h4><p>是的, <strong>但是</strong>又来了. 这种带时间戳的<strong>多数派读写</strong>依然有问题. 就是在客户端没有完成一次完整的多数派写的时候: 例如, 上面的例子中写入, a=x₁写入了node-1和node-2, a=y₂时只有node-3 写成功了, 然后客户端进程就挂掉了, 留下系统中的状态如下:</p><pre><code>node-1: a=x₁node-2: a=x₁node-3: a=y₂</code></pre><p>这时另一个读取的客户端来了,</p><ul><li>如果它联系到node-1和node-2, 那它得到的结果是a=x₁.</li><li>如果它联系到node-2和node-3, 那它得到的结果是a=y₂.</li></ul><p>整个系统对外部提供的信息仍然是不一致的.</p><p>==paxos可以认为是多数派读写的进一步升级, paxos中通过2次原本并不严谨的多数派读写, 实现了严谨的强一致consensus算法.==</p><h4 id="算法描述">算法描述</h4><p>一句话总结</p><blockquote><p>proposer将发起提案（value）给所有accpetor，超过半数accpetor获得批准后，proposer将提案写入accpetor内，最终所有accpetor获得一致性的确定性取值，且后续不允许再修改。</p></blockquote><ul><li>Proposer 可以理解为客户端.</li><li>Acceptor 可以理解为存储节点.</li><li>Quorum 在99%的场景里都是指多数派, 也就是半数以上的Acceptor.</li><li>Round 用来标识一次paxos算法实例, 每个round是2次多数派读写: 算法描述里分别用phase-1和phase-2标识. 同时为了简单和明确, 算法中也规定了每个Proposer都必须生成全局单调递增的round, 这样round既能用来区分先后也能用来区分不同的Proposer(客户端).</li></ul><p>在存储端(Acceptor)也有几个概念:</p><ul><li>last_rnd 是Acceptor记住的最后一次进行<strong>写前读取</strong>的Proposer(客户端)是谁, 以此来决定谁可以在后面真正把一个值写到存储中.</li><li>v 是最后被写入的值.</li><li>vrnd 跟v是一对, 它记录了在哪个Round中v被写入了.</li></ul><p>首先是paxos的phase-1, 它相当于之前提到的写前读取过程. 它用来在存储节点(Acceptor)上记录一个标识: 我后面要写入; 并从Acceptor上读出是否有之前未完成的paxos运行. 如果有则尝试恢复它; 如果没有则继续做自己想做的事情.</p><p><img src="https://blog.openacid.com/post-res/paxos/slide-imgs/paxos-28.jpg" alt="img" /></p><p>Proposer X收到多数(quorum)个应答, 就认为是可以继续运行的.如果没有联系到多于半数的acceptor, 整个系统就hang住了, 这也是paxos声称的只能运行少于半数的节点失效.</p><p>这时Proposer面临2种情况:</p><ul><li><p>所有应答中都没有任何非空的v, 这表示系统之前是干净的, 没有任何值已经被其他paxos客户端完成了写入(因为一个多数派读一定会看到一个多数派写的结果). 这时Proposer X继续将它要写的值在phase-2中真正写入到多于半数的Acceptor中.</p></li><li><p>如果收到了某个应答包含被写入的v和vrnd, 这时, Proposer X 必须假设有其他客户端(Proposer) 正在运行, 虽然X不知道对方是否已经成功结束, 但任何已经写入的值都不能被修改!, 所以X必须保持原有的值. 于是X将看到的最大vrnd对应的v作为X的phase-2将要写入的值.</p><p>这时实际上可以认为X执行了一次(不知是否已经中断的)其他客户端(Proposer)的修复.</p></li></ul><p><img src="https://blog.openacid.com/post-res/paxos/slide-imgs/paxos-29.jpg" alt="img" /></p><p>在第2阶段phase-2, Proposer X将它选定的值写入到Acceptor中, 这个值可能是它自己要写入的值, 或者是它从某个Acceptor上读到的v(修复).</p><p><img src="https://blog.openacid.com/post-res/paxos/slide-imgs/paxos-30.jpg" alt="img" /></p><p>当然这时(在X收到phase-1应答, 到发送phase-2请求的这段时间), 可能已经有其他Proposer又完成了一个rnd更大的phase-1, 所以这时X不一定能成功运行完phase-2.</p><p>Acceptor通过比较phase-2请求中的rnd, 和自己本地记录的rnd, 来确定X是否还有权写入. 如果请求中的rnd和Acceptor本地记录的rnd一样, 那么这次写入就是被允许的, Acceptor将v写入本地, 并将phase-2请求中的rnd记录到本地的vrnd中.</p><p><img src="https://blog.openacid.com/post-res/paxos/slide-imgs/paxos-31.jpg" alt="img" /></p><h4 id="算法描述2">算法描述2</h4><p><img src="https://img-blog.csdnimg.cn/img_convert/3529e518c84c2dc16eb1b0984fda12e9.png" alt="Paxos算法流程" /></p><p>Paxos算法分为<strong>两个阶段</strong>。具体如下：</p><ul><li><p><strong>阶段一：</strong></p><p>(a) Proposer选择一个<strong>提案编号N</strong>，然后向<strong>半数以上</strong>的Acceptor发送编号为N的<strong>Prepare请求</strong>。</p><p>(b) 如果一个Acceptor收到一个编号为N的Prepare请求，且N<strong>大于</strong>该Acceptor已经<strong>响应过的</strong>所有<strong>Prepare请求</strong>的编号，那么它就会将它已经<strong>接受过的编号最大的提案（如果有的话）<strong>作为响应反馈给Proposer，同时该Acceptor承诺</strong>不再接受</strong>任何<strong>编号小于N的提案</strong>。</p></li><li><p><strong>阶段二：</strong></p><p>(a) 如果Proposer收到<strong>半数以上</strong>Acceptor对其发出的编号为N的Prepare请求的<strong>响应</strong>，那么它就会发送一个针对**[N,V]提案<strong>的</strong>Accept请求<strong>给</strong>半数以上<strong>的Acceptor。注意：V就是收到的</strong>响应<strong>中</strong>编号最大的提案的value**，如果响应中<strong>不包含任何提案</strong>，那么V就由Proposer<strong>自己决定</strong>。</p><p>(b) 如果Acceptor收到一个针对编号为N的提案的Accept请求，只要该Acceptor<strong>没有</strong>对编号<strong>大于N</strong>的<strong>Prepare请求</strong>做出过<strong>响应</strong>，它就<strong>接受该提案</strong>。</p></li></ul><p><a href="https://blog.csdn.net/yzf279533105/article/details/109315877">https://blog.csdn.net/yzf279533105/article/details/109315877</a></p><h4 id="活锁">活锁</h4><p><img src="https://img-blog.csdnimg.cn/20190510215412909.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI0MTQxODk=,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述" /></p><p>为了保持活性，避免上述的问题，就必须选择一个主Proposer，并规定只能由主Proposer才能提出议案，只有主能提出议案，那么就算主被抛弃了，下次也会提出更高议案，而其他非主不能再次提出更高的议案，这样就不会陷入死循环中，从而避免了上述的问题。</p><h3 id="mutil-paxos">Mutil-Paxos</h3><p>原始的Paxos算法(Basic Paxos)只能对一个值形成决议，决议的形成至少需要两次网络来回，在高并发情况下可能需要更多的网络来回，极端情况下甚至可能形成活锁。如果想连续确定多个值，Basic Paxos搞不定了。因此Basic Paxos几乎只是用来做理论研究，并不直接应用在实际工程中。</p><p>实际应用中几乎都需要连续确定多个值，而且希望能有更高的效率。Multi-Paxos正是为解决此问题而提出。Multi-Paxos基于Basic Paxos做了两点改进:</p><ul><li>针对每一个要确定的值，运行一次Paxos算法实例(Instance)，形成决议。每一个Paxos实例使用唯一的Instance ID标识。</li><li>在所有Proposers中选举一个Leader，由Leader唯一地提交Proposal给Acceptors进行表决。这样没有Proposer竞争，解决了活锁问题。在系统中仅有一个Leader进行Value提交的情况下，Prepare阶段就可以跳过，从而将两阶段变为一阶段，提高效率。</li></ul><p>Multi-Paxos首先需要选举Leader，Leader的确定也是一次决议的形成，所以可执行一次Basic Paxos实例来选举出一个Leader。选出Leader之后只能由Leader提交Proposal，在Leader宕机之后服务临时不可用，需要重新选举Leader继续服务。在系统中仅有一个Leader进行Proposal提交的情况下，Prepare阶段可以跳过。</p><p>Multi-Paxos通过改变Prepare阶段的作用范围至后面Leader提交的所有实例，从而使得Leader的连续提交只需要执行一次Prepare阶段，后续只需要执行Accept阶段，将两阶段变为一阶段，提高了效率。为了区分连续提交的多个实例，每个实例使用一个Instance ID标识，Instance ID由Leader本地递增生成即可。</p><p>Multi-Paxos允许有多个自认为是Leader的节点并发提交Proposal而不影响其安全性，这样的场景即退化为Basic Paxos。</p><p>Chubby和Boxwood均使用Multi-Paxos。ZooKeeper使用的Zab也是Multi-Paxos的变形。</p><h2 id="raft算法">Raft算法</h2><h3 id="状态机">状态机</h3><p>简单来说，就是具有相同的初始状态的对象，加上相同的中间操作，最后的状态也必定是一样的。</p><h3 id="基本术语">基本术语</h3><p>Raft集群包含多个服务器，5个服务器是比较典型的，允许系统容忍两个故障。在任何给定时间，每个服务器都处于以下三种状态之一，领导者（Leader），追随者（Follower）或候选人（Candidate）。 这几个状态见可以相互转换。</p><p>Leader：处理所有客户端交互，日志复制等，一般一次只有一个Leader</p><p>Follower：类似选民，完全被动</p><p>Candidate：候选人，类似Proposer，可以被选为一个新的领导人</p><p><img src="https://ask.qcloudimg.com/http-save/yehe-4736527/qpoopk9cal.jpeg?imageView2/2/w/1620" alt="img" /></p><h3 id="raft算法子问题">Raft算法子问题</h3><p>Raft实现了和Paxos相同的功能，它将一致性分解为多个子问题: Leader选举(Leader election)、日志同步(Log replication)、安全性(Safety)、日志压缩(Log compaction)、成员变更(Membership change)等</p><h4 id="leader选举">Leader选举</h4><p>Raft 使用心跳(heartbeat)触发Leader选举。当服务器启动时，初始化为Follower。Leader向所有Followers周期性发送heartbeat。如果Follower在选举超时时间内没有收到Leader的heartbeat，就会等待一段随机的时间后发起一次Leader选举。</p><p>Follower将其当前term加一然后转换为Candidate。它首先给自己投票并且给集群中的其他服务器发送 RequestVote RPC (RPC细节参见八、Raft算法总结)。结果有以下三种情况:</p><ul><li>赢得了多数的选票，成功选举为Leader；</li><li>收到了Leader的消息，表示有其它服务器已经抢先当选了Leader；</li><li>没有服务器赢得多数的选票，Leader选举失败，等待选举时间超时后发起下一次选举。</li></ul><p><img src="https://pdai.tech/_images/alg/alg-dst-raft-4.jpg" alt="img" /></p><p>选举出Leader后，Leader通过定期向所有Followers发送心跳信息维持其统治。若Follower一段时间未收到Leader的心跳则认为Leader可能已经挂了，再次发起Leader选举过程。</p><p>Raft保证选举出的Leader上一定具有最新的已提交的日志。</p><h4 id="日志同步">日志同步</h4><p>Leader选出后，就开始接收客户端的请求。</p><p>Leader把请求作为日志条目(Log entries)加入到它的日志中，然后并行的向其他服务器发起 AppendEntries RPC 复制日志条目。==当这条日志被复制到大多数服务器上，Leader将这条日志应用到它的状态机并向客户端返回执行结果。==</p><p><img src="https://pdai.tech/_images/alg/alg-dst-raft-5.jpg" alt="img" /></p><p>某些Followers可能没有成功的复制日志，Leader会无限的重试 AppendEntries RPC直到所有的Followers最终存储了所有的日志条目。</p><p>Leader通过强制Followers复制它的日志来处理日志的不一致，Followers上的不一致的日志会被Leader的日志覆盖。</p><p>Leader为了使Followers的日志同自己的一致，Leader需要找到Followers同它的日志一致的地方，然后覆盖Followers在该位置之后的条目。</p><p>Leader会从后往前试，每次AppendEntries失败后尝试前一个日志条目，直到成功找到每个Follower的日志一致位点，然后向后逐条覆盖Followers在该位置之后的条目。</p><h4 id="安全性">安全性</h4><p>Raft增加了如下两条限制以保证安全性:</p><ul><li>拥有最新的已提交的log entry的Follower才有资格成为Leader。</li></ul><p>这个保证是在RequestVote RPC中做的，Candidate在发送RequestVote RPC时，要带上自己的最后一条日志的term和log index，其他节点收到消息时，如果发现自己的日志比请求中携带的更新，则拒绝投票。</p><p>日志比较的原则是，如果本地的最后一条log entry的term更大，则term大的更新，如果term一样大，则log index更大的更新。</p><ul><li>Leader只能推进commit index来提交当前term的已经复制到大多数服务器上的日志，旧term日志的提交要等到提交当前term的日志来间接提交(log index 小于 commit index的日志被间接提交)。</li></ul><h4 id="日志压缩与成员变更">日志压缩与成员变更</h4><p><a href="https://pdai.tech/md/algorithm/alg-domain-distribute-x-raft.html">https://pdai.tech/md/algorithm/alg-domain-distribute-x-raft.html</a></p><h3 id="raft与multi-paxos的不同">Raft与Multi-Paxos的不同</h3><p><img src="https://pdai.tech/_images/alg/alg-dst-raft-12.jpg" alt="img" /></p><h3 id="总结">总结</h3><p>Raft算法具备强一致、高可靠、高可用等优点，具体体现在：</p><p>强一致性：虽然所有节点的数据</p><p>并非实时一致，但Raft算法保证Leader节点的数据最全，同时所有请求都由Leader处理，所以在客户端角度看是强一致性的。</p><p>高可靠性：Raft算法保证了Committed的日志不会被修改，State Matchine只应用Committed的日志，所以当客户端收到请求成功即代表数据不再改变。Committed日志在大多数节点上冗余存储，少于一半的磁盘故障数据不会丢失。</p><p>高可用性：从Raft算法原理可以看出，选举和日志同步都只需要大多数的节点正常互联即可，所以少量节点故障或网络异常不会影响系统的可用性。即使Leader故障，在选举超时到期后，集群自发选举新Leader，无需人工干预，不可用时间极小。但Leader故障时存在重复数据问题，需要业务去重或幂等性保证。</p><p>高性能：与必须将数据写到所有节点才能返回客户端成功的算法相比，Raft算法只需要大多数节点成功即可，少量节点处理缓慢不会延缓整体系统运行。</p><h3 id="关于raft的一些面试题">关于Raft的一些面试题</h3><p><a href="https://blog.csdn.net/yzf279533105/article/details/127167605">https://blog.csdn.net/yzf279533105/article/details/127167605</a></p><h2 id="zab协议">ZAB协议</h2><p>基本和raft相同，只是在一些名词的叫法上有一些区别<br />比如ZAB 将某一个leader的周期称为epoch,而raft称为 term。</p><p>实现上的话 raft为了保证日志连续性，心跳方向是从leader到follower，ZAB则是相反的</p><h3 id="原子广播与-zab">原子广播与 ZAB</h3><blockquote><p>ZAB 协议全称：Zookeeper Atomic Broadcast（Zookeeper 原子广播协议）</p></blockquote><p>广播协议是一类将数据从一个节点同步到多个节点的协议。</p><p>以上的广播过程产生了一个问题，那就是这个协调节点是明显的单点，它的可靠性至关重要。要保障其可靠，首先要解决的问题是需要检查这个节点的健康状态。我们可以通过各种健康检查方式去发现其健康情况。</p><p>如果它失败了，会造成消息传播到一部分节点中，而另外一部分节点却没有这一份消息，这就违背了“一致性”。那么应该怎解决这个问题呢？</p><p>一个简单的算法就是使用“漫灌”机制，这种机制是一旦一个消息被广播到一个节点，该节点就有义务把该消息广播到其他未收到数据节点的义务。这就像水田灌溉一样，最终整个系统都收到了这份数据。</p><p>当然以上的模式有个明显的缺点，就是会产生N2的消息。其中 N 是目前系统剩下的未同步消息的节点，所以我们的一个优化目标就是要减少消息的总数量。</p><p>虽然广播可以可靠传递数据，但通过一致性的学习我们知道：需要保证各个节点接收到消息的顺序，才能实现较为严格的一致性。所以我们这里定义一个原子广播协议来满足。</p><ol><li>原子性：所有参与节点都收到并传播该消息；或相反，都不传播该消息。</li><li>顺序性：所有参与节点传播消息的顺序都是一致的。</li></ol><p>满足以上条件的协议我们称为原子广播协议，最为常见的原子广播协议就是ZAB：Zookeeper Atomic Broadcast（ZAB）。</p><h3 id="zab-设计">ZAB 设计</h3><p>ZooKeeper <a href="http://zookeeper.apache.org/doc/r3.4.9/zookeeperProgrammers.html#ch_zkGuarantees">文档</a>中明确写明它的一致性是 Sequential consistency即顺序一致</p><p>ZooKeeper中针对同一个Follower A提交的写请求request1、request2，某些Follower虽然可能不能在请求提交成功后立即看到（也就是强一致性），但经过自身与Leader之间的同步后，这些Follower在看到这两个请求时，一定是先看到request1，然后再看到request2，两个请求之间不会乱序，即顺序一致性</p><p>其实，实现上ZooKeeper 的一致性更复杂一些，ZooKeeper 的读操作是 sequential consistency 的，ZooKeeper 的写操作是 linearizability 的，关于这个说法，ZooKeeper 的官方文档中没有写出来，但是在社区的邮件组有详细的讨论。ZooKeeper 的论文《Modular Composition of Coordination Services》 中也有提到这个观点。</p><p>总结一下，可以这么理解 ZooKeeper：从整体（read 操作 +write 操作）上来说是 sequential consistency，写操作实现了 Linearizability。</p><p>ZAB 协议由于 Zookeeper 的广泛使用变得非常流行。它是一种原子广播协议，可以保证消息顺序的传递，且消息广播时的原子性保障了消息的一致性。</p><p>ZAB 协议中，节点的角色有两种。</p><ol><li>领导节点。==领导是一个临时角色，它是有任期的==。这么做的目的是保证领导角色的活性。领导节点控制着算法执行的过程，广播消息并保证消息是按顺序传播的。读写操作都要经过它，从而保证操作的都是最新的数据。如果一个客户端连接的不是领导节点，它发送的消息也会转发到领导节点中。</li><li>跟随节点。主要作用是接受领导发送的消息，并检测领导的健康状态。</li></ol><p>既然需要有领导节点产生，我们就需要领导选举算法。</p><p>这里我们要明确两个 ID：数据 ID 与节点 ID。</p><p>前者可以看作消息的时间戳，后者是节点的优先级。</p><p>==选举的原则是：==</p><p>在同一任职周期内，节点的数据 ID 越大，表示该节点的数据越新，数据 ID 最大的节点优先被投票。</p><p>所有节点的数据 ID 都相同，则节点 ID 最大的节点优先被投票。当一个节点的得票数超过节点半数，则该节点成为主节点。</p><p>一旦领导节点选举出来，它就需要做两件事。</p><ol><li>声明任期。领导节点通知所有的跟随节点当前的最新任期；而后由跟随节点确认当前任期是最新的任期，从而同步所有节点的状态。通过该过程，老任期的消息就不会被跟随节点所接受了。</li><li>同步状态。这一步很关键，首先领导节点会通知所有跟随节点自己的领导身份，而后跟随节点不会再选举自己为领导了；然后领导节点会同步集群内的消息历史，保证最新的消息在所有节点中同步。因为新选举的领导节点很可能并没有最新被接受的数据，因此同步历史数据操作是很有必要的。</li></ol><p>经过以上的初始化动作后，领导节点就可以正常接受消息，进行消息排序而后广播消息了。在广播消息的时候，需要 Quorum（集群中大多数的节点）的节点返回已经接受的消息才认为消息被正确广播了。同时为了保证顺序，需要前一个消息正常广播，后一个消息才能进行广播。</p><p>领导节点与跟随节点使用心跳算法检测彼此的健康情况。如果领导节点发现自己与 Quorum 节点们失去联系，比如网络分区，此时领导节点会主动下台，开始新一轮选举。同理，当跟随节点检测到领导节点延迟过大，也会触发新一轮选举。</p><p>ZAB 选举的优势是，如果领导节点一直健康，即使当前任期过期，选举后原领导节点还会承担领导角色，而不会触发领导节点切换，这保证了该算法的稳定。</p><p>另外，它的节点恢复比较高效，通过比较各个节点的消息 ID，找到最大的消息 ID，就可以从上面恢复最新的数据了。</p><p>最后，它的消息广播可以理解为没有投票过程的两阶段提交，只需要两轮消息就可以将消息广播出去。</p><h3 id="zab-消息广播">ZAB 消息广播</h3><p>ZAB 协议的消息广播过程使用的是一个原子广播协议，类似一个 二阶段提交过程。对于客户端发送的写请求，全部由 Leader 接收，Leader 将请求封装成一个事务 Proposal，将其发送给所有 Follwer ，然后，根据所有 Follwer 的反馈，如果超过半数成功响应，则执行 commit 操作（先提交自己，再发送 commit 给所有 Follwer）。</p><p>Leader 在收到客户端请求之后，会将这个请求封装成一个事务，并给这个事务分配一个全局递增的唯一 ID，称为事务ID（ZXID），ZAB 兮协议需要保证事务的顺序，因此必须将每一个事务按照 ZXID 进行先后排序然后处理。</p><p>在 Leader 和 Follwer 之间还有一个消息队列，用来解耦他们之间的耦合，解除同步阻塞。</p><p>zookeeper集群中为保证任何所有进程能够有序的顺序执行，只能是 Leader 服务器接受写请求，即使是 Follower 服务器接受到客户端的请求，也会转发到 Leader 服务器进行处理。</p><p>实际上，这是一种简化版本的 2PC，不能解决单点问题。</p><h3 id="zab-奔溃恢复">ZAB 奔溃恢复</h3><p>Leader 崩溃怎么办？还能保证数据一致吗？如果 Leader 先本地提交了，然后 commit 请求没有发送出去，怎么办？</p><p>实际上，当 Leader 崩溃，即进入我们开头所说的崩溃恢复模式（崩溃即：Leader 失去与过半 Follwer 的联系）。下面来详细讲述。</p><ul><li>假设1：Leader 在复制数据给所有 Follwer 之后崩溃，怎么办？</li><li>假设2：Leader 在收到 Ack 并提交了自己，同时发送了部分 commit 出去之后崩溃怎么办？</li></ul><p>针对这些问题，ZAB 定义了 2 个原则：</p><ul><li>ZAB 协议确保那些已经在 Leader 提交的事务最终会被所有服务器提交。</li><li>ZAB 协议确保丢弃那些只在 Leader 提出/复制，但没有提交的事务。</li></ul><p>所以，ZAB 设计了下面这样一个选举算法：<strong>能够确保提交已经被 Leader 提交的事务，同时丢弃已经被跳过的事务</strong>。</p><p>针对这个要求，如果让 Leader 选举算法能够保证新选举出来的 Leader 服务器拥有集群总所有机器编号（即 ZXID 最大）的事务，那么就能够保证这个新选举出来的 Leader 一定具有所有已经提交的提案。</p><p>而且这么做有一个好处是：<strong>可以省去 Leader 服务器检查事务的提交和丢弃工作的这一步操作</strong>。</p><p><img src="https://pdai.tech/_images/alg/alg-zab-5.png" alt="img" /></p><p>这样，我们刚刚假设的两个问题便能够解决。假设 1 最终会丢弃调用没有提交的数据，假设 2 最终会同步所有服务器的数据。这个时候，就引出了一个问题，如何同步？</p><h3 id="zab-数据同步">ZAB 数据同步</h3><p>当崩溃恢复之后，需要在正式工作之前（接收客户端请求），Leader 服务器首先确认事务是否都已经被过半的 Follwer 提交了，即是否完成了数据同步。目的是为了保持数据一致。</p><p>当所有的 Follwer 服务器都成功同步之后，Leader 会将这些服务器加入到可用服务器列表中。</p><p>实际上，Leader 服务器处理或丢弃事务都是依赖着 ZXID 的，那么这个 ZXID 如何生成呢？</p><p>答：在 ZAB 协议的事务编号 ZXID 设计中，ZXID 是一个 64 位的数字，其中低 32 位可以看作是一个简单的递增的计数器，针对客户端的每一个事务请求，Leader 都会产生一个新的事务 Proposal 并对该计数器进行 + 1 操作。</p><p>而高 32 位则代表了 Leader 服务器上取出本地日志中最大事务 Proposal 的 ZXID，并从该 ZXID 中解析出对应的 epoch 值，然后再对这个值加一。</p><p><img src="https://pdai.tech/_images/alg/alg-zab-6.png" alt="img" /></p><p>高 32 位代表了每代 Leader 的唯一性，低 32 代表了每代 Leader 中事务的唯一性。同时，也能让 Follwer 通过高 32 位识别不同的 Leader。简化了数据恢复流程。</p><p>基于这样的策略：当 Follower 链接上 Leader 之后，Leader 服务器会根据自己服务器上最后被提交的 ZXID 和 Follower 上的 ZXID 进行比对，比对结果要么回滚，要么和 Leader 同步。</p><h3 id="总结-1">总结</h3><p>ZAB 协议和我们之前看的 Raft 协议实际上是有相似之处的，比如都有一个 Leader，用来保证一致性（Paxos 并没有使用 Leader 机制保证一致性）。再有采取过半即成功的机制保证服务可用（实际上 Paxos 和 Raft 都是这么做的）。</p><p>ZAB 让整个 Zookeeper 集群在两个模式之间转换，消息广播和崩溃恢复，消息广播可以说是一个简化版本的 2PC，通过崩溃恢复解决了 2PC 的单点问题，通过队列解决了 2PC 的同步阻塞问题。</p><p>而支持崩溃恢复后数据准确性的就是数据同步了，数据同步基于事务的 ZXID 的唯一性来保证。通过 + 1 操作可以辨别事务的先后顺序。</p><h2 id="paxos-raft-redis的raft-一致性算法总结">paxos、 raft 、redis的raft 一致性算法总结</h2><h3 id="basic-paxos算法也就是经典的paxos算法">basic-paxos算法，也就是经典的paxos算法</h3><p>1）    2PC(2 phase commit，也就是2阶段提交），分为 prepare（准备）阶段：proposer产生perposeID，发给各个accepter。accept(接受)阶段：proposer根据准备阶段的结果最终提出commit，accepter决定接受还是不接受。至少三次网络交互的延迟（1. 产生logID；2. prepare阶段；3. accept阶段），所以效率很低</p><p>2）    没有leader概念，各个进程之间是完全平等的</p><p>3）    一个进程可能既是proposer，又是accepter</p><h3 id="multi-paxos算法">multi-paxos算法</h3><p>1）    有leader概念，先根据basic-paxos算法选举一个proposer为leader，其他proposer不再发起提案，这样就进入了一个leader任期，只能由leader发起提案，后续不再需要产生proposeID，也不必执行prepare阶段，直接执行accept阶段，所以冲突的可能性很低，效率比较高。我们可以将leader选举过程中的prepare操作，视为该leader任期内所有日志的一次性prepare操作，实际上acceptor应答选举的prepare成功的消息之前要先将这次prepare请求所携带的proposalID持久化到本地</p><p>2）    后续的日志仍然要经过所有accepter的大多数（超过1/2）同意，即仍然有accept阶段</p><p>3）    confirm日志的优化，之前的basic-paxos读取日志时，仍要执行一轮Paxos过程，效率低下，所以multi-paxos算法引入了confirm日志的优化，对于有confirm日志的日志不再执行paxos过程。对于没有confirm日志的日志，才会重新执行一遍paxos过程，即重确认</p><p>4）    日志可能不连续，所以新leader需要对空洞的日志都进行一轮paxos</p><h3 id="raft算法-1">raft算法</h3><p>1）    有leader概念，且日志条目（log entries）只从 leader 流向其他follower服务器。leader有任期（term）限制，当leader失联时，其各个follower使用随机计时器进行 leader 选举，经过其他follower节点的大多数同意可当选为leader。</p><p>2）分三中角色，Leader，Follower，Candidate 这三种角色相互独立，也就是服务器在同一时间内只可能扮演其中一种角色。Leader：用于对所有用户的请求进行处理以及日志的复制等等；Follower：不会主动发送消息，只响应来自Leader与Candidate的请求；Candidate：用于选举新的Leader</p><p>3）    有任期（term）概念，用一个数字表示，每一个任期的开始都是一次选举，一个或多个Candidate会试图称为Leader，但同一任期内只有获得超过一半的票数才能称为Leader，该机制保证了在给定的一个任期最多只有一个Leader</p><p>4）    日志中包含的内容（任期号，日志包含的命令，索引号），如果 2 个节点日志的相同的索引位置的日志条目的任期号相同，那么 Raft 就认为这个日志从头到这个索引之间的所有日志全部相同。所以当 leader 和 follower 日志冲突的时候，leader 将校验 follower 最后一条日志是否和 leader 匹配，如果不匹配，将递减查询，直到匹配，匹配后，follower删除冲突的日志。这样就实现了主从日志的一致性</p><h3 id="redis的raft">redis的raft</h3><p>redis虽然用的raft算法，但是做了修改，并非原始的raft算法</p><p>在 redis 里 raft 算法主要体现在：<strong>redis 主从数据复制</strong> 和 <strong>sentinel 故障转移</strong></p><p>==不同之处：==raft算法中发生选举时是某个leader的所有follower内部进行选举出一个新leader。但redis中是某个leader的所有follower向其他的所有leader发起选举投票，计票数从而产生新leader</p><p>raft中的follower投票时并不是无脑地投给第一个发来请求的，而是会比较其附带的最后日志索引，只有对方的索引日志比自己大时才会投赞同票，若比自己的日志索引号小，则拒绝。</p><p>redis中因为是其他leader节点投票，他们自己本地没有对应的日志索引号，所以会无脑投票给第一个发来请求的节点</p><p>相同之处：选举时的算法（超过一半即可），日志的复制等</p><h3 id="关联问题raft协议与redis集群中的一致性协议的异同">关联问题：Raft协议与Redis集群中的一致性协议的异同</h3><p><a href="https://blog.csdn.net/bluehawksky/article/details/100747363">https://blog.csdn.net/bluehawksky/article/details/100747363</a></p><p><a href="https://zhuanlan.zhihu.com/p/112651338">https://zhuanlan.zhihu.com/p/112651338</a></p><h2 id="reference">Reference</h2><p><a href="https://zhuanlan.zhihu.com/p/112651338">https://zhuanlan.zhihu.com/p/112651338</a></p><p><a href="https://pdai.tech/md/algorithm/alg-domain-distribute-x-zab.html">https://pdai.tech/md/algorithm/alg-domain-distribute-x-zab.html</a></p><p><a href="https://cloud.tencent.com/developer/article/1525566">https://cloud.tencent.com/developer/article/1525566</a></p><p><a href="https://pdai.tech/md/algorithm/alg-domain-distribute-x-paxos.html">https://pdai.tech/md/algorithm/alg-domain-distribute-x-paxos.html</a></p><p><a href="https://blog.csdn.net/yzf279533105/article/details/127163022">https://blog.csdn.net/yzf279533105/article/details/127163022</a></p><p><a href="https://blog.openacid.com/algo/paxos">https://blog.openacid.com/algo/paxos</a></p><p><a href="https://blog.csdn.net/Z_Stand/article/details/108547684">https://blog.csdn.net/Z_Stand/article/details/108547684</a></p><p><a href="http://www.xuyasong.com/?p=1970">http://www.xuyasong.com/?p=1970</a></p><p><a href="https://cloud.tencent.com/developer/article/1798049">https://cloud.tencent.com/developer/article/1798049</a></p><p><a href="https://zhuanlan.zhihu.com/p/68743917">https://zhuanlan.zhihu.com/p/68743917</a></p><p><a href="https://draveness.me/consensus/">https://draveness.me/consensus/</a></p><p><a href="https://pdai.tech/md/algorithm/alg-domain-distribute-x-consistency-hash.html">https://pdai.tech/md/algorithm/alg-domain-distribute-x-consistency-hash.html</a></p><p><a href="https://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/24%E8%AE%B2%E5%90%83%E9%80%8F%E5%88%86%E5%B8%83%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%BA%93-%E5%AE%8C/20%20%20%E5%85%B1%E8%AF%86%E7%AE%97%E6%B3%95%EF%BC%9A%E4%B8%80%E6%AC%A1%E6%80%A7%E8%AF%B4%E6%B8%85%E6%A5%9A%20Paxos%E3%80%81Raft%20%E7%AD%89%E7%AE%97%E6%B3%95%E7%9A%84%E5%8C%BA%E5%88%AB.md">https://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/24%E8%AE%B2%E5%90%83%E9%80%8F%E5%88%86%E5%B8%83%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%BA%93-%E5%AE%8C/20%20%20%E5%85%B1%E8%AF%86%E7%AE%97%E6%B3%95%EF%BC%9A%E4%B8%80%E6%AC%A1%E6%80%A7%E8%AF%B4%E6%B8%85%E6%A5%9A%20Paxos%E3%80%81Raft%20%E7%AD%89%E7%AE%97%E6%B3%95%E7%9A%84%E5%8C%BA%E5%88%AB.md</a></p>]]>
                    </description>
                    <pubDate>Thu, 13 Oct 2022 19:25:29 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[10.12 ｜ 讲讲你了解的分布式一致性]]>
                    </title>
                    <link>/archives/fenbushi-yizhixing</link>
                    <description>
                            <![CDATA[<p>如果只想背八股，可以直接看最后总结部分</p><h2 id="一致性分类">一致性分类</h2><p>什么是一致性，简单的来说就是评判一个并发系统正确与否的标准。</p><p>分布式系统中的一致性从强到弱可以分为四种：</p><ol><li><a href="https://en.wikipedia.org/wiki/Linearizability">线性一致性 （Linearizability：Strong consistency or Atomic consistency)</a></li><li><a href="https://en.wikipedia.org/wiki/Sequential_consistency">顺序一致性（Sequential consistency）</a></li><li><a href="https://en.wikipedia.org/wiki/Causal_consistency">因果一致性（Causal consistency）</a></li><li><a href="https://en.wikipedia.org/wiki/Eventual_consistency">最终一致性（Eventual consistency）</a></li></ol><p>强一致性包括线性一致性和顺序一致性，其他的如因果一致性、最终一致都是弱一致性。</p><p>强一致性集群中，对任何一个节点发起请求都会得到相同的回复，但将产生相对高的延迟。而弱一致性具有更低的响应延迟，但可能会回复过期的数据，最终一致性即是经过一段时间后终会到达一致的弱一致性。</p><p><a href="http://www.xuyasong.com/?p=1970">http://www.xuyasong.com/?p=1970</a></p><h3 id="顺序一致性">顺序一致性</h3><p>如果可以找到一个所有 CPU 执行指令的排序，该排序中每个 CPU 要执行指令的顺序得以保持，且实际的 CPU 执行结果与该指令排序的执行结果一致，则称该次执行达到了<strong>顺序一致性</strong>。</p><p>==越是宽松的一致性模型，能容纳的事件排列可能性就越多；反之越严格则越少。==</p><p>顺序一致性有两个要求：</p><ul><li>任何一次读都能读到某个数据的最近一次写的数据。</li><li>系统的所有进程的顺序一致，而且是合理的。即不需要和全局时钟下的顺序一致，错的话一起错，对的话一起对。</li></ul><h4 id="例子1">例子1</h4><p><img src="https://lotabout.me/2019/QQA-What-is-Sequential-Consistency/Sequential-Consistency.svg" alt="Sequential Consistency" /></p><p>图中 <code>W(X, 1)</code> 代表将 1 写入变量 X；<code>R(X, 1)</code> 代表读取变量 X，值为 1；横轴代表时间；矩形的长短代表指令持续的时间长短，所以上图其实表示的是多核 CPU 的一次执行结果。</p><p>我们找到了指令的一个排序，排序中各个 CPU 的指令顺序得以保持（如 <code>C: R(X, 1)</code> 在 <code>C: R(X, 2)</code> 之前），这个排序的执行结果与 CPU 分开执行的结果一致，因此该 CPU 的执行是满足顺序一致性的。</p><p>注意到==顺序一致性关心的是 CPU 内部执行指令的顺序，而不关心 CPU 之间的相对顺序。==</p><h4 id="例子2">例子2</h4><p><img src="https://img-blog.csdn.net/20180721214208274?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NoYW8yMDE2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70" alt="这里写图片描述" /></p><p>Write(x, 4)：写入x=4<br />Read(x, 0)：读出x=0</p><p>1）图a是满足顺序一致性，但是不满足强一致性的。</p><p>原因在于，从全局时钟的观点来看，P2进程对变量X的读操作在P1进程对变量X的写操作之后，然而读出来的却是旧的数据。</p><p>但是这个图却是满足顺序一致性的，因为两个进程P1，P2的一致性并没有冲突。从这两个进程的角度来看，顺序应该是这样的：</p><p>Write(y,2) , Read(x,0) , Write(x,4), Read(y,2)，</p><p>每个进程内部的读写顺序都是合理的，但是这个顺序与全局时钟下看到的顺序并不一样。</p><p>2）图b满足强一致性，因为每个读操作都读到了该变量的最新写的结果，同时两个进程看到的操作顺序与全局时钟的顺序一样，都是</p><p>Write(y,2) , Read(x,4) , Write(x,4), Read(y,2)。</p><p>3）图c不满足顺序一致性，当然也就不满足强一致性了。</p><p>因为从进程P1的角度看，它对变量Y的读操作返回了结果0。</p><p>那么就是说，P1进程的对变量Y的读操作在P2进程对变量Y的写操作之前，这意味着它认为的顺序是这样的：</p><p>write(x,4) , Read(y,0) , Write(y,2), Read(x,0)，</p><p>显然这个顺序又是不能被满足的，因为最后一个对变量x的读操作读出来也是旧的数据。因此这个顺序是有冲突的，不满足顺序一致性。</p><p><a href="https://blog.csdn.net/chao2016/article/details/81149674">https://blog.csdn.net/chao2016/article/details/81149674</a></p><h4 id="例子3">例子3</h4><p>一条朋友圈下面有多个人发表评论，<code>朋友圈</code>这个分布式系统，有两种客户端：<code>发朋友圈</code>的客户端负责写入数据，<code>读朋友圈</code>的客户端负责读取数据，当然很多时候同一个客户端既能读也能写。</p><p>接下来的问题是：</p><ul><li>这些看朋友圈的人，是否能看到全局一致的数据？即所有人看到的朋友圈都是同一个顺序排列的？</li></ul><p>显然，有很多时候，即便是在看同一个朋友圈下的评论回复，不同的人看到也不尽然都是同一个顺序的，所以以上的答案是否定的。那么就引入了下一个问题：</p><ul><li>如果不同的人看到的朋友圈（包括评论）顺序各有不同，这些顺序又该遵守怎样的规则才是合理的？</li></ul><p>一条朋友圈下面有多个人发表评论，可以认为这是一个<code>二维</code>的数据：</p><ul><li>进程（也就是发表评论的人）是一个维度。</li><li>时间又是另一个维度，即这些评论出现的先后顺序。</li></ul><p>但是在阅读这些评论的读者看来，需要将这一份<code>二维</code>的数据，去除掉不同进程这个维度，<code>压平</code>到只有本进程时间线这一个单一维度上面来，如图所示：</p><p><img src="https://www.codedump.info/media/imgs/20220710-weekly-22/wechat-2.png" alt="wechat-2" /></p><p>在上图中，在读进程<em>P</em>3的视角看来，两个写进程的事件，需要<code>压平</code>到本进程的时间线上进行排列，可以看到这些事件在<code>压平</code>之后有多种排列的可能性。</p><p>将多个写进程的事件进行排列，放到单进程的时间线上，这是一个排列组合问题，如果所有的写进程事件加起来一共有<code>n</code>个，那么这些事件的所有排列组合就是n!。比如事件<code>a</code>、<code>b</code>、<code>c</code>，不同的排列一共有这些：</p><pre><code class="language-java">{(a,b,c),(a,c,b),(b,a,c),(b,c,a),(c,a,b),(c,b,a)}</code></pre><p>一致性模型就是要回答：在所有的这些可能存在的事件排列组合中，按照要求的一致性严格程度，哪些是可以接受的，哪些不可能出现？</p><p>后面的讲述将看到：==越是宽松的一致性模型，能容纳的事件排列可能性就越多；反之越严格则越少。==</p><p>举一个违反这个条件的反例，如下图所示：</p><p><img src="https://www.codedump.info/media/imgs/20220710-weekly-22/program-order.png" alt="program-order" /></p><p>上图中：</p><ul><li>进程p1视角下：程序的执行顺序是先执行 P_1，再执行 P_2。</li><li>但是到了P3视角下重排事件之后，P1_2出现在了事件P1_1前面，这是不允许出现的，因为违反了原进程P1程序顺序了。</li></ul><p>但是，仅靠条件1还不足以满足顺序一致性，于是还有条件2：</p><ul><li>条件2：对变量的读写要表现得像FIFO一样先入先出，即<code>每次读到的都是最近写入的数据</code>。</li></ul><p><img src="https://www.codedump.info/media/imgs/20220710-weekly-22/FIFO.png" alt="FIFO" /></p><h4 id="特殊例子">特殊例子</h4><p>在顺序一致性模型下，第一个排列和第二个排列都被认为是正确的。</p><p><img src="https://www.codedump.info/media/imgs/20220710-weekly-22/seq-model-2.png" alt="seq-model-2" /></p><p>p1_1 , p2_1 , p3_1  和 p1_1 ， p3_1 ， p2_1 都被认为是对的，因为没有违反两个条件</p><blockquote><ul><li>任何一次读都能读到某个数据的最近一次写的数据。</li><li>系统的所有进程的顺序一致，而且是合理的。即不需要和全局时钟下的顺序一致，错的话一起错，对的话一起对。</li></ul></blockquote><p>第三个排列违反了条件2</p><p>顺序一致性在满足了条件1、2之后，对<code>不同进程的事件</code>之间的顺序没有硬性的要求，即便在感官直觉上某事件应该发生得更早，但是只要没有违反这两个条件就可以认为是满足顺序一致性模型的。</p><p>于是就出现了更严格的线性一致性，它基于顺序一致性的条件，对事件的先后顺序做了更严格的要求。</p><p><a href="https://www.codedump.info/post/20220710-weekly-22">https://www.codedump.info/post/20220710-weekly-22</a></p><h4 id="顺序一致性难吗">顺序一致性难吗？</h4><p>难，现代的多核 CPU 依然达不到顺序一致性。</p><p>我们知道 CPU 执行的主要瓶颈其实是在与内存交互，工程师为了让 CPU 能高速执行，在 CPU 内部使用了多级缓存。它的存在，使得即使 CPU 内部顺序执行指令，指令的结果也可能不满足顺序一致性：</p><p><img src="https://lotabout.me/2019/QQA-What-is-Sequential-Consistency/CPU-Cache.svg" alt="CPU Cache and Sequential Consistency" /></p><p>上图中 <code>(n)</code> 代表数据的读写步骤。如果 CPU 如上图执行，则得到的结果不满足顺序一致性。</p><p>另外 CPU 执行时会乱序执行指令。例如在一些情况下 CPU 会将数据写入的指令提前执行，因为写入内存是很耗时的。同样的，编译器在编译代码时也会重排代码中的指令的顺序，以提升整体的性能。</p><p>难以想象，没有了顺序一致性的保证，程序居然还能正确执行。其实，现代硬件体系遵循的其实是:</p><blockquote><p>sequential consistency for data race free programs</p></blockquote><p>即如果程序没有数据竞争，则 CPU 可以保证顺序一致性，而如果遇到数据竞争，就需要程序里手工使用一些数据同步的机制（如锁）。</p><p>工程领域总是伴随着各种权衡(trade-off)，显然保证顺序一致性对 CPU 的性能优化有太多的阻碍，而 CPU 的高性能又是我们所追求的，两害相权取其轻。</p><p><a href="https://lotabout.me/2019/QQA-What-is-Sequential-Consistency/">https://lotabout.me/2019/QQA-What-is-Sequential-Consistency/</a></p><h3 id="线性一致性-背景知识">线性一致性-背景知识</h3><p>分布式系统可以抽象成几个部分:</p><ul><li>Client</li><li>Server</li><li>Events<ul><li>Invocation</li><li>Response</li></ul></li><li>Operations<ul><li>Read</li><li>Write</li></ul></li></ul><p>一个分布式系统通常有两种角色，Client 和 Server。Client 通过发起请求来获取 Server 的服务。一次完整请求由两个事件组成，Invocation（以下简称 Inv）和 Response（以下简称 Resp）。一个请求中包含一个 Operation，有两种类型 Read 和 Write，最终会在 Server 上执行。</p><p>说了一堆不明所以的概念，现在来看如何用这些表示分布式系统的行为。</p><p><img src="https://img1.www.pingcap.com/prod/1_779a02dad8.png" alt="图例 1" /></p><p>上图展示了 Client A 的一个请求从发起到结束的过程。变量 x 的初始值是 1，“x R() A” 是一个事件 Inv 意思是 A 发起了读请求，相应的 “x OK(1) A” 就是事件 Resp，意思是 A 读到了 x 且值为 1，Server 执行读操作（Operation）。</p><h3 id="线性一致性">线性一致性</h3><p>最强的一致性要求</p><p>它基于顺序一致性的条件，对事件的先后顺序做了更严格的要求。</p><p>怎样才能达到线性一致？这就要求 Server 在执行 Operations 时需要满足以下三点：</p><ol><li>瞬间完成（或者原子性）</li><li>发生在 Inv 和 Resp 两个事件之间</li><li>反映出“最新”的值</li></ol><p>举一个例子，用以解释上面三点。</p><blockquote><p>另一种说法</p><ul><li>不能打乱单进程的程序顺序，同一个进程里的事件先后顺序要得到保留。</li><li>不同进程的事件，如果在时间上不重叠，即不是并发事件，那么要求这个先后顺序在重排之后保持一致。</li><li>每次读出来的都是最新的值，而且一旦形成了一个排列，要求系统中所有进程都是同样的一个排列。</li></ul></blockquote><h4 id="例子1-1">例子1</h4><p><img src="https://img1.www.pingcap.com/prod/2_a7d6409a25.png" alt="图例 2" /></p><p>先下结论，上图表示的行为满足线性一致。</p><p>对于同一个对象 x，其初始值为 1，客户端 ABCD 并发地进行了请求，按照真实时间（real-time）顺序，各个事件的发生顺序如上图所示。</p><p>对于任意一次请求都需要一段时间才能完成，例如 A，“x R() A” 到 “x Ok(1) A” 之间的那条线段就代表那次请求花费的时间，而请求中的读操作在 Server 上的执行时间是很短的，相对于整个请求可以认为瞬间，读操作表示为点，并且在该线段上。</p><p>线性一致性中没有规定读操作发生的时刻，也就说该点可以在线段上的任意位置，可以在中点，也可以在最后，当然在最开始也无妨。</p><p>下面说第三点。</p><p>反映出“最新”的值？我觉得三点中最难理解就是它了。</p><p>先不急于对“最新”下定义，来看看上图中 x 所有可能的值，显然只有 1 和 2。</p><p>四个次请求中只有 B 进行了写请求，改变了 x 的值，我们从 B 着手分析，明确 x 在各个时刻的值。</p><p>由于不能确定 B 的 W（写操作）在哪个时刻发生，能确定的只有一个区间，因此可以引入<strong>上下限</strong>的概念。</p><p>对于 x=1，它的上下限为<strong>开始到事件“x W(2) B”</strong>，在这个范围内所有的读操作必定读到 1。对于 x=2，它的上下限为 <strong>事件“x Ok() B”</strong> 到结束，在这个范围内所有的读操作必定读到 2。</p><p>那么“x W(2) B”到“x Ok() B”这段范围，x 的值是什么？<strong>1 或者 2</strong>。由此可以将 x 分为三个阶段，各阶段&quot;最新&quot;的值如下图所示：</p><p><img src="https://img1.www.pingcap.com/prod/3_19ff54b5b4.png" alt="图例 3" /></p><p>清楚了 x 的变化后理解例子中 A C D 的读到结果就很容易了。</p><p>最后返回的 D 读到了 1，看起来是 “stale read”，其实并不是，它仍满足线性一致性。</p><p>==D 请求横跨了三个阶段，而读可能发生在任意时刻，所以 1 或 2 都行。==同理，A 读到的值也可以是 2。C 就不太一样了，C 只有读到了 2 才能满足线性一致。</p><p>因为 “x R() C” 发生在 “x Ok() B” 之后（happen before ），可以推出 R 发生在 W 之后，那么 R 一定得读到 W 完成之后的结果：2。</p><p><strong>一句话概括：在分布式系统上实现寄存器语义。</strong></p><blockquote><p>一旦我们将一个变量设置为某个值，例如 a，读取时就会返回 a，直到我们再次对值做了变更。读取一个变量返回最近写入的值。我们称这种系统为有单一值的变量 —— 一个寄存器。</p></blockquote><p><a href="https://blog.csdn.net/u013200380/article/details/113050620">https://blog.csdn.net/u013200380/article/details/113050620</a></p><h4 id="例子2-1">例子2</h4><p>如果是线性一致性</p><p>下图里只有 <code>p1_1 , p2_1, p3_1</code>是满足线性一致性的排列了</p><p><img src="https://www.codedump.info/media/imgs/20220710-weekly-22/seq-model-2.png" alt="seq-model-2" /></p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202210121639281.png" alt="image-20221012163923123" /></p><p>这还是最开始解释顺序一致性模型的图，但是在线性一致性的条件下，找不到能够满足条件的排列了。</p><p>这是因为：</p><ul><li>事件 P2_1 和 P1_2 都在事件 P1_1 之后，这个顺序需要得到保持。</li><li>而事件 P3_1 在事件 P2_1 和 P1_2 之后，这个顺序也需要得到保持。</li><li>如果保持了前面两个顺序，那么 P3_1 执行的时候，必然读不出来A，而应该是B或者C（即 P2_1 或者 P1_2的执行结果）。</li></ul><h4 id="顺序一致性和线性一致性总结">顺序一致性和线性一致性总结</h4><p>可以看到，如果满足线性一致性，就一定满足顺序一致性，因为后者的条件是前者的真子集。</p><p>除了满足这些条件以外，这两个一致性还有一个要求：==系统中所有进程的顺序是一致的，即如果系统中的进程A按照要求使用了某一种排序，即便有其他排序的可能性存在，系统中的其他进程也必须使用这种排序，系统中只能用一种满足要求的排序。==</p><p>这个要求，使得满足顺序和线性一致性的系统，对外看起来“表现得像只有一个副本”一样。</p><p>但因果一致性则与此不同：只要满足因果一致性的条件，即便不同进程的事件排列不一致也没有关系。</p><h4 id="关联问题线性一致性和序列化linearizability-and-serializability">关联问题：线性一致性和序列化（Linearizability and Serializability）</h4><p>Serializability: 数据库领域的ACID中的I。 数据库的四种隔离级别，由弱到强分别是Read Uncommitted,Read Committed(RC),Repeatable Read(RR)和Serializable。</p><p>Serializable的含义是：对并发事务包含的操作进行调度后的结果和某种把这些事务一个接一个的执行之后的结果一样。最简单的一种调度实现就是真的把所有的事务进行排队，一个个的执行，显然这满足Serializability，问题就是性能。可以看出Serializability是与数据库事务相关的一个概念，一个事务包含多个读，写操作，这些操作由涉及到多个数据对象。</p><ul><li>Linearizability: 针对单个操作，单个数据对象而说的。属于CAP中C这个范畴。一个数据被更新后，能够立马被后续的读操作读到。</li><li>Strict Serializability: 同时满足Serializability和Linearizability。</li></ul><p>==例子：==</p><p>两个事务T1,T2，T1先开始，更新数据对象o，T1提交。接着T2开始，读数据对象o，提交。以下两种调度：</p><ol><li>T1,T2，满足Serializability，也满足Linearizability。</li><li>T2,T1，满足Serializability，不满足Linearizability，因为T1之前更新的数据T2读不到。</li></ol><h3 id="因果一致性">因果一致性</h3><p>因果一致性，属于弱一致性，因为在Causal consistency中，==只对有因果关系的事件有顺序要求==。</p><p>没有因果一致性时会发生如下情形：</p><ul><li>夏侯铁柱在朋友圈发表状态“我戒指丢了”</li><li>夏侯铁柱在同一条状态下评论“我找到啦”</li><li>诸葛建国在同一条状态下评论“太棒了”</li><li>远在美国的键盘侠看到“我戒指丢了”“太棒了”，开始喷诸葛建国</li><li>远在美国的键盘侠看到“我戒指丢了”“我找到啦”“太棒了”，意识到喷错人了</li></ul><p>所以很多系统采用因果一致性系统来避免这种问题，例如微信的朋友圈就采用了因果一致性，可以参考：<a href="https://www.useit.com.cn/thread-10587-1-1.html">https://www.useit.com.cn/thread-10587-1-1.html</a></p><p><img src="http://vermouth-blog-image.oss-accelerate.aliyuncs.com/monitor/0fdd02d5-1d9b-44ac-941f-5a61d06f5eb5.jpg?x-oss-process=style/watermark" alt="img" /></p><h4 id="例子">例子</h4><p>以<code>评论朋友圈</code>这个行为来解释因果一致性再合适不过：</p><ul><li>评论另一个用户的评论：相当于进程给另一个进程发消息，肯定要求满足<code>happen-before</code>关系，即先有了评论，才能针对这个评论发表评论。</li><li>同一个用户的评论：相当于同一个进程的事件，也是必须满足<code>happen-before</code>关系才行。</li></ul><p>以下图为例：</p><p><img src="https://www.codedump.info/media/imgs/20220710-weekly-22/casual-model.png" alt="casual-model" /></p><p>一共有4个朋友圈的读者，它们看到的评论顺序都各不一样：</p><ul><li>最上面的两个读者，读到的顺序都满足因果一致性，因此即便是不一样的顺序也是正确的。</li><li>最下面的两个读者，顺序都不满足因果一致性：<ul><li>A回复B这个事件出现在了B回复A之前，不符合多进程之间的<code>happen-before</code>关系。</li><li>A回复C这个事件在进程A中应该在A回复B之前，不符合同一进程的事件之间的先后顺序。</li></ul></li></ul><h3 id="最终一致性">最终一致性</h3><p>最终一致性这个词大家听到的次数应该是最多的，也是弱一致性，不过因为大多数场景下用户可以接受，应用也就比较广泛。</p><p>理念：不保证在任意时刻任意节点上的同一份数据都是相同的，但是随着时间的迁移，不同节点上的同一份数据总是在向趋同的方向变化。</p><p>简单说，就是在一段时间后，节点间的数据会最终达到一致状态。</p><p>redis主备、mongoDB、乃至mysql热备都可以算是最终一致性，甚至如果我记录操作日志，然后在副本故障了100天之后手动在副本上执行日志以达成一致，也算是符合最终一致性的定义。有人说最终一致性就是没有一致性，因为没人可以知道什么时候算是最终。</p><p>最终一致其实分支很多，以下都是他的变种：</p><ul><li>Causal consistency（因果一致性）</li><li>Read-your-writes consistency （读己所写一致性）</li><li>Session consistency （会话一致性）</li><li>Monotonic read consistency （单调读一致性）</li><li>Monotonic write consistency （单调写一致性）</li></ul><p>BASE理论中的 E，就是Eventual consistency最终一致</p><h2 id="总结">总结</h2><ul><li><p>在分布式系统中，多个进程组合在一起协调工作，产生多个事件，事件之间可以有多种排列的可能性。</p></li><li><p>一致性模型本质上要回答这个问题：按照该一致性模型定义，怎样的事件发生顺序的排列才符合要求？</p></li><li><p>顺序一致性和线性一致性都意图让系统中所有进程<code>看起来</code>有统一的全局事件顺序，但是两者的要求不同，顺序一致性：</p><ul><li>条件1：每个进程的执行顺序要和该进程的程序执行顺序保持一致。</li><li>条件2：对变量的读写要表现得像FIFO一样先入先出，即每次读到的都是最近写入的数据。</li></ul><p>只要满足这两个条件，顺序一致性对事件之间的先后顺序并没有硬性要求，而线性一致性在此基础上多了条件3：</p><ul><li>条件3：不同进程的事件，如果在时间上不重叠，即不是并发事件，那么要求这个先后顺序在重排之后保持一致。</li></ul></li><li><p>因果一致性是更弱的一致性，只要满足<code>happen-before</code>关系即可。由于<code>happen-before</code>关系实际上是由Lamport时钟定义的，这是一种逻辑时钟，所以不同的读者看到的先后顺序可能会有点<code>反直觉</code>，但是只要满足<code>happen-before</code>关系就是正确的。</p></li></ul><p>大佬的总结链接：<a href="https://www.codedump.info/post/20220710-weekly-22/#%E6%80%BB%E7%BB%93">https://www.codedump.info/post/20220710-weekly-22/#%E6%80%BB%E7%BB%93</a></p>]]>
                    </description>
                    <pubDate>Wed, 12 Oct 2022 18:29:15 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[10.11 ｜ 下次提CAP的时候，记得加FLP不可能定理、上PACELC理论、NWR策略]]>
                    </title>
                    <link>/archives/cap-pacelc-nwr</link>
                    <description>
                            <![CDATA[<h2 id="cap">CAP</h2><p>其中C代表一致性 (Consistency)，A代表可用性 (Availability)，P代表分区容错性 (Partition tolerance)。</p><p><img src="https://pdai.tech/_images/arch/arch-cap-1.png" alt="img" /></p><h3 id="如何理解-cap">如何理解 CAP</h3><ul><li><code>一致性 (Consistency)</code>: 一个写操作返回成功，那么之后的读请求都必须读到这个新数据；如果返回失败，那么所有读操作都不能读到这个数据。所有节点访问同一份最新的数据。</li><li><code>可用性 (Availability)</code>: 对数据更新具备高可用性，请求能够及时处理，不会一直等待，即使出现节点失效。</li><li><code>分区容错性 (Partition tolerance)</code>: 能容忍网络分区，在网络断开的情况下，被分隔的节点仍能正常对外提供服务。</li></ul><p>理解CAP理论最简单的方式是想象两个副本处于分区两侧，即两个副本之间的网络断开，不能通信。</p><ul><li>如果允许其中一个副本更新，则会导致数据不一致，即丧失了C性质。</li><li>如果为了保证一致性，将分区某一侧的副本设置为不可用，那么又丧失了A性质。</li><li>除非两个副本可以互相通信，才能既保证C又保证A，这又会导致丧失P性质。</li></ul><p>一般来说使用网络通信的分布式系统，无法舍弃P性质，那么就只能在一致性和可用性上做一个艰难的选择。</p><h3 id="pacelc理论">PACELC理论</h3><p>A 中是有一定争议的，很长时间才返回，虽然可用，但是业务上可能不能接受。并且，系统大部分时间下，分区都是平稳运行的，并不会出错，在这种情况下，系统设计要均衡的其实是延迟与数据一致性的问题，为了保证数据一致性，写入与读取的延迟就会增高。这就引出了 PACELC 理论。 PAC就是CAP，E是else，L是Latency延迟，C是 Consistency。</p><p><img src="https://wuchangping.oss-cn-hangzhou.aliyuncs.com/distributed/theory/distributed-cap-pacelc-1.PNG" alt="cap-pacelc" /></p><p>如果发生了P ，那么只能保 A or C</p><p>如果没有发生P， 那么就在 L 和 C之前权衡，如果保证了低延时，数据一致性就会降低（副本数量少），如果保证了较高的数据一致性，就会带来相对较高的延时问题（需要同步的副本多）</p><p>PACELC理论更进一步描述了即使在没有Partition的场景下，也存在Latency和Consistency之间的取舍，从而为分布式系统的Consistency模型提供了一个更为完整的理论依据。</p><h3 id="pacelc例子1">PACELC例子1</h3><p><img src="https://wuchangping.oss-cn-hangzhou.aliyuncs.com/distributed/theory/distributed-cap-pacelc-2.PNG" alt="consistency-latency" /></p><p>在强一致性复制场景下，需要三副本都下盘才能返回OK确认信息给client端，假设Master节点向 Slave 节点复制数据，时延的限制是 20ms，有时候，slave 2 硬盘或网络出现故障，Master 往 Slave 复制数据的时延超过 了20ms，这个时候如果还一直等待 slave 2 返回结果再通知给client就会出现性能和时延抖动，而且这种抖动是经常会发生的长尾效应。</p><p>依据PACELC理论，我们可以在 consistency和Latency之间做个取舍，比如 slave 2 节点的时延超过 20ms了，就不等待slave 2 返回，master 和 slave 1 返回结果给client即可（此时同步节点大于总结点数的一半），如果 slave 2 出现 超时的 次数超过 5次那么就认为 这个节点可能出现故障，打个故障标签，进行后续的处理。采用这种方式可以消除写时的长尾抖动，获得更优雅的写时性能曲线。</p><h3 id="pacelc例子2-主从同步">PACELC例子2-主从同步</h3><p>举个日常例子，主从同步。</p><p>我们业务代码经常可能存在数据写入后立刻查询的操作，因为线上数据库上读写分离，在业务高峰期，存在主从延迟，解决方案一般有两种：</p><ol><li><strong>写操作完后Sleep一段微小时间，让数据库完成主从同步</strong></li><li><strong>写操作后完后，直接通过数据库访问层的中间件指定读操作读主库数据</strong></li></ol><p>可以明显看出，这存在在时延（Latency）和一致性（Consistency）上做了权衡，选择方案一，偏向一致性，选择方案二，偏向于低时延。</p><p>以MySQL主从复制为例，提供了三种模式：</p><p>异步模式：主库执行完客户端提交的事务，立即将结果返给客户端，不关心从库是否已经接收并处理。由于数据同步的延时，客户端在从库上可能读不到最新数据。这种模式对MySQL是性能最佳的，但是用户需要权衡，业务能否忍受这种延时。<br />全同步复制：主库执行完客户端提交的事务，所有的从库都执行了该事务才返回结果。这样保证强一致性，但是响应时间变长了。<br />半同步复制：主库在执行完客户端提交的事务后，等待至少一个从库接收到并写到 relay log 中，才返回给客户端。这样做延迟小了很多，相比于异步复制，数据更加不容易丢失。</p><h3 id="关联问题eureka属于ap系统吗它明明没有放弃一致性啊">关联问题：eureka属于AP系统吗？它明明没有放弃一致性啊？</h3><p>描述AP和CP时，通常都会以eureka和zookeeper来具体。eureka是AP的代表作，zookeeper则是CP的代表作。二者之所以这样归类，是因为：</p><ul><li>eureka各节点互相独立、平等的，各节点都提供查询和注册服务（读、写请求）。当发生网络分区，eureka各节点依旧可以接收和注册服务。并且当丢失过多客户端时，节点会进入自我保护（接收新服务注册、不删除过期服务）。在该种模式下，eureka集群剩下最后一个节点，也可以向外提供服务。尽管向外提供的数据可能是过期的数据。</li><li>zookeeper采用的过半原则，由leader处理写请求。当发生网络分区时，leader由于丢失过半的follower，从而处理不了客户端的请求，需要重新选举新leader，期间服务将不可用。糟糕的是，如果集群中没有过半的节点存活，将选举不出新leader，服务将一直处于不可用状态。</li></ul><p>回答eureka没有放弃一致性的问题，还得回顾A、C之间的抉择。这二者需要二选一的情况下，一定是发生了网络分区的情况。eureka集群正常运行时，各节点之间可以正常通讯、保持心跳、复制数据，以此保持数据的一致性。但发生网络分区时，eureka确实选择了可用性，而放弃了一致性。</p><h2 id="flp不可能定理">FLP不可能定理</h2><p>FLP 不可能定理是分布式系统领域最重要的定理之一，它给出了一个非常重要的结论：在网络可靠并且存在节点失效的异步模型系统中，不存在一个可以解决一致性问题的确定性算法。</p><p>这个定理其实也就是告诉我们不要浪费时间去为异步分布式系统设计在任意场景上都能够实现共识的算法，异步系统完全没有办法保证能在有限时间内达成一致。</p><p>论文地址：<a href="https://groups.csail.mit.edu/tds/papers/Lynch/jacm85.pdf">Impossibility of Distributed Consensuswith One Faulty Process</a></p><h2 id="base">BASE</h2><p>BASE 理论是对 CAP 理论的延伸，核心思想是即使无法做到强一致性（Strong Consistency，CAP 的一致性就是强一致性），但应用可以采用适合的方式达到最终一致性（Eventual Consitency）</p><p><strong>Basically Available</strong>（基本可用）分布式系统在出现不可预知故障的时候，允许损失部分可用性</p><p><strong>Soft state</strong>（软状态）软状态也称为弱状态，和硬状态相对，是指允许系统中的数据存在中间状态，并认为该中间状态的存在不会影响系统的整体可用性，即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。</p><p><strong>Eventually consistent</strong>（最终一致性）最终一致性强调的是系统中所有的数据副本，在经过一段时间的同步后，最终能够达到一个一致的状态。因此，最终一致性的本质是需要系统保证最终数据能够达到一致，而不需要实时保证系统数据的强一致性</p><h3 id="cap-与-base-关系">CAP 与 BASE 关系</h3><p>BASE是对CAP中一致性和可用性权衡的结果，其来源于对大规模互联网系统分布式实践的结论，是基于CAP定理逐步演化而来的，其核心思想是即使无法做到强一致性（Strong consistency），更具体地说，是对 CAP 中 AP 方案的一个补充。其基本思路就是：通过业务，牺牲强一致性而获得可用性，并允许数据在一段时间内是不一致的，但是最终达到一致性状态。</p><p><img src="https://pdai.tech/_images/arch/arch-cap-2.png" alt="img" /></p><h3 id="cap-与-acid-关系">CAP 与 ACID 关系</h3><p>ACID 是传统数据库常用的设计理念，追求强一致性模型。BASE 支持的是大型分布式系统，提出通过牺牲强一致性获得高可用性。</p><p>数据库中多个事务并发会存在哪些问题？</p><ul><li>脏读：事务T1读取了T2更改的x，但是T2在实际存储数据时可能出错回滚了，这时T1读取的实际是无效的数据，这种情况下就是脏读</li><li>不可重复读：是说在T1读取x时，由于中间T2更改了x，所以T1前后两次读取的x值不相同，这就是所谓的不可重复读</li><li>幻读：在T1读取符合某个条件的所有记录时，T2增加了一条符合该条件的记录，这就导致T1执行过程中前后读取的记录可能不一致，即T2之后读取时会多出一条记录。</li></ul><p>为了解决这些问题，事务提出四种隔离级别来规避上述问题。而解决的就是ACID中的C（一致性），所以ACID中的C（一致性）可以理解为不出现脏读、幻读、不可重复读的问题。可以把它称为“内部一致性”，解决的是数据库内部的一致性问题。</p><p>CP中的C（一致性），相对好理解，我把它理解为“外部一致性”。就分布式系统而言的，针对客户端的请求，无论访问那个节点，都能获得最新的相同的值。</p><p>ACID 和 BASE 代表了两种截然相反的设计哲学，在分布式系统设计的场景中，系统组件对一致性要求是不同的，因此 ACID 和 BASE 又会结合使用。</p><h2 id="nwr策略-quorum协议">NWR策略-Quorum协议</h2><p>NWR是一种在分布式存储系统中用于控制一致性级别的一种策略。这个三个字母分别代表着：</p><ul><li>N：分布式系统中，一个有多少个副本数据</li><li>W：处理一次写请求，需要更新多少个副本数据</li><li>R：处理一次读请求，需要读取多少个副本数据</li></ul><p>NWR分别设置不同的值时，将会产生不同的一致性效果。</p><ul><li>W+R&gt;N ，整个系统对于客户端的请求能==保证强一致性==。因为写请求和读请求一定存在一个相交的副本，读取的时候返回该副本的数据即可。</li><li>W+R&lt;=N，整个系统对于客户端的请求则不能保证强一致性。</li></ul><p><strong>例子 1</strong></p><p>基于NWR的性质，我们可以动态的调节系统的一致性效果。还可以根据业务场景动态调整响应速度。以5节点集群为例，在保证强一致性的情况下，需要提高读请求的效率，则可以设置R=2、W=3 或者R=1、W=4。当需要提高写请求效率时，则可以设置W=2、R=3或者W=1、R=4。</p><p><strong>例子 2</strong></p><p>当我们需要高可写的环境的时候，我们可以配置W=1，如果N=3，那么R = 3。这个时候只要写任何节点成功就认为成功，但是读的时候必须从所有的节点都读出数据</p><p>如果我们要求读的高效率，我们可以配置 W=N，R=1。这个时候任何一个节点读成功就认为成功，但是写的时候必须写所有三个节点成功才认为成功。</p><p>W、R的大小，直接影响其对应的处理效率。主要注意，读写请求的效率==取决于最慢的副本处理速度==。</p><p>不同的NWR取值代表了不同的倾向</p><p>如果设定N=3，W=3，R=1，那么强调的是强一致性，写数据的时候一定要把所有的副本刷新，杜绝中间状态。</p><p>如果N=3，R=1，W=1，则代表的是可用性，这种情况下一致性就被牺牲掉了。</p><p>将 PACELC 均衡权力交给用户</p><h2 id="微服务基础-康威定律">微服务基础-康威定律</h2><p>微服务这个概念很早就提出了， 真正火起来是在2016年左右，而康威定律(Conway's Law)就是微服务理论基础。</p><p>第一定律</p><p>组织沟通方式会通过系统设计表达出来</p><p>就是说架构的布局和组织结构会有相似。</p><p>第二定律</p><p>时间再多一件事情也不可能做得完美，但总有时间做完一件事情</p><p>一口气吃不成胖子，先搞定能搞定的。</p><p>第三定律</p><p>线型系统和线型组织架构间潜在的异质同态特性</p><p>种瓜得瓜，做独立自治的子系统减少沟通成本。</p><p>第四定律</p><p>大的系统组织总是比小系统更倾向于分解</p><p>合久必分，分而治之。</p><h2 id="refernce">Refernce</h2><p><a href="http://www.choudan.net/2013/08/07/CAP%E7%90%86%E8%AE%BA%E5%92%8CNWR%E7%AD%96%E7%95%A5.html">http://www.choudan.net/2013/08/07/CAP%E7%90%86%E8%AE%BA%E5%92%8CNWR%E7%AD%96%E7%95%A5.html</a></p><p><a href="https://blog.csdn.net/m0_68850571/article/details/126140636">https://blog.csdn.net/m0_68850571/article/details/126140636</a></p><p><a href="https://www.changping.me/2020/04/10/distributed-theory-cap-pacelc/">https://www.changping.me/2020/04/10/distributed-theory-cap-pacelc/</a></p><p><a href="https://pdai.tech/md/dev-spec/spec/dev-microservice-kangwei.html">https://pdai.tech/md/dev-spec/spec/dev-microservice-kangwei.html</a></p><p><a href="https://www.52code.net/a/8xjTPFSabM">https://www.52code.net/a/8xjTPFSabM</a></p><p><a href="https://pdai.tech/md/arch/arch-z-theory.html">https://pdai.tech/md/arch/arch-z-theory.html</a></p><p><a href="https://cloud.tencent.com/developer/article/1752382">https://cloud.tencent.com/developer/article/1752382</a></p>]]>
                    </description>
                    <pubDate>Tue, 11 Oct 2022 20:07:43 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[9.27 | a++,++a 在JVM发生了什么？]]>
                    </title>
                    <link>/archives/927aazai-jvm-fa-sheng-le-shen-me-</link>
                    <description>
                            <![CDATA[<h2 id="aaa-a">a=a++，a =++a</h2><p>下列代码输出是？从JVM的角度讲讲发生了什么</p><pre><code class="language-java">    public static void main(String[] args) {        int a = 10;        int b = 20;        int c = 30;        a++;        b = b++;        c = ++c;        System.out.println(a);        System.out.println(b);        System.out.println(c);     }</code></pre><p>部分字节码：</p><pre><code> stack=2, locals=4, args_size=1         0: bipush        10         2: istore_1         3: bipush        20         5: istore_2         6: bipush        30         8: istore_3         9: iinc          1, 1        12: iload_2        13: iinc          2, 1        16: istore_2        17: iinc          3, 1        20: iload_3        21: istore_3</code></pre><p>（请忽略下图中运行时常量池里的指令）<br />此例中，主要涉及以下几部分组件。<br />堆，存放对象<br />执行引擎，用来执行指令<br />堆栈，存放变量表和操作数栈<br />方法区，方法字节码会载入方法区</p><p><img src="https://img-blog.csdnimg.cn/20210210230332114.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MDI4MDU3Ng==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述" /></p><p>指令科普：</p><p>istore_x  将操作数栈栈顶元素弹出，放入局部变量表的 slot x中</p><p>iload_x 将 局部变量中x位置的元素  放到操作数栈中</p><p>iinc 1,1  (iinc， （value1，value2） value1是对哪个位置的数操作，value2是给value1加多少)</p><p>对于a</p><pre><code class="language-java">       9: iinc          1, 1 // 将局部变量1号位+1，自增后，1号位置 11</code></pre><p>对于b</p><pre><code class="language-java">iload_2  //将局部变量2号位置放入操作数栈中，此时操作数栈 20iinc          2, 1 // 将局部变量2号位+1，自增后，2号位置 21，操作数中 20istore_2   //将操作数栈栈顶元素弹出，放入局部变量表的2号位置中 此时，2号位置20，操作数中20 </code></pre><p>对于c</p><pre><code class="language-java">iinc          3, 1 // 将局部变量3号位+1，自增后，3号位置 31，操作数中 空 iload_3    // 将3号位置放入操作数栈，操作数中 31istore_3  // 将操作数栈栈顶元素弹出，放入局部变量表的3号位置中，将31赋值给31，此时c=31</code></pre><p>输出</p><p>a=11</p><p>b=20</p><p>c=31</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202209271812184.png" alt="image-20220927181203099" /></p><p>ps：如果此例子看不懂请移步这里：<a href="https://github.com/erdengk/notes/blob/main/%E7%AC%94%E8%AE%B0/1.4Jvm%20%E7%9B%B8%E5%85%B3/3%20%E7%B1%BB%E5%8A%A0%E8%BD%BD.md#2%E5%AD%97%E8%8A%82%E7%A0%81%E6%8C%87%E4%BB%A4">图解方法流程</a></p>]]>
                    </description>
                    <pubDate>Tue, 27 Sep 2022 20:41:07 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[9.24 ｜ 讲讲操作系统的多级页表，为什么多级页表会省空间？]]>
                    </title>
                    <link>/archives/924jiang-jiang-cao-zuo-xi-tong-de-duo-ji-ye-biao--wei-shen-me-duo-ji-ye-biao-hui-sheng-kong-jian-</link>
                    <description>
                            <![CDATA[<h2 id="924--讲讲操作系统的多级页表为什么多级页表会省空间">9.24 ｜ 讲讲操作系统的多级页表，为什么多级页表会省空间？</h2><p><strong>多级页表本质上是一个时间换空间的策略，通过增加一定的地址访问时间来减少对空间的占用</strong>。</p><blockquote><p>多级页表作用：通过只为进程实际使用的那些虚拟地址内存区请求页表来减少内存使用量（出自《深入理解Linux内核》第三版51页）</p></blockquote><p>想要把虚拟内存地址，映射到物理内存地址，最直观的方法，就是来建立一张映射表。这个映射表，能够实现虚拟内存里面的页，到物理内存里面的页的一一映射。这个映射表，在计算机里面，就叫做<strong>页表</strong></p><p>在一个实际的程序地址里面，虚拟内存占用的地址空间，通常是两端连续的空间，而不是完全随机的内存地址。</p><p>如果我们只有一个页表，那就需要在这一个页表里将所有的地址都映射出来，而在其中的大部分地址，其实都是没有利用到的（比如租了100个库房，只用了10个，剩下的就一直空着浪费钱），绝大部分空间 其实都是被浪费掉的。</p><p>那么如何进行优化呢？核心思想就在于 <strong>按需分配</strong> ，也就是说：有多少合法的虚拟页号，我们就维护一个多大的映射，并为此使用 多大的内存用来保存映射。这是因为，每个应用的地址空间最开始都是空的，或者说所有的虚拟页号均不合法，那么这样的页表 自然不需要占用任何内存。</p><h3 id="优化例子"><a href="https://rcore-os.gitcode.host/rCore-Tutorial-Book-v3/chapter4/3sv39-implementation-1.html#id6">优化例子</a></h3><p>设想我们要维护 一个字符串的多重集，集合中所有的字符串的字符集均为 α={a,b,c} ，长度均为一个给定的常数 n 。该字符串集合一开始为空集。我们要支持两种操作，第一种是将一个字符串插入集合，第二种是查询一个字符串在当前 的集合中出现了多少次。</p><p>简单起见，假设 n=3 。那么我们可能会建立这样一颗 <strong>字典树</strong> (Trie) ：</p><p><img src="https://raw.githubusercontent.com/erdengk/picGo/main/img/202209241554409.png" alt="../_images/trie.png" /></p><p>对于题目要求的两种操作，我们只需根据输入的 字符串中的每个字符在字典树上自上而下对应走出一步，最终就能够找到字典树中维护的它的计数。之后我们可以将其直接返回或者 加一。</p><p>这样的优点是举例了所有情况，缺点是维护了一些可能不存在的节点，但这些节点确实占用了空间。</p><p>可以这样优化：</p><p><img src="https://rcore-os.gitcode.host/rCore-Tutorial-Book-v3/_images/trie-1.png" alt="../_images/trie-1.png" /></p><p>一开始仅存在一个根节点。在我们插入字符串 <code>acb</code> 的过程中，我们只需要分配 <code>a</code> 和 <code>ac</code> 两个节点。</p><p>如果后续再插入一个字符串，那么 <strong>至多分配两个新节点</strong> ，因为如果走的路径上有节点已经存在，就无需重复分配了，只需增加计数。字典树中节点的数目（或者说字典树消耗的内存）是随着插入字符串的数目逐渐线性增加的。</p><p>==多级页表也是类似的思想，如果这种情况没有出现，就不分配给具体的地址。==</p><h3 id="普通页表">普通页表</h3><p><img src="http://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BA%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/assets/22bb79129f6363ac26be47b35748500f.jpeg" alt="img" /></p><p>对于一个内存地址转换，其实就是这样三个步骤：</p><ol><li>把虚拟内存地址，切分成页号和偏移量的组合；</li><li>从页表里面，查询出虚拟页号，对应的物理页号；</li><li>直接拿物理页号，加上前面的偏移量，就得到了物理内存地址。</li></ol><p><img src="http://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BA%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/assets/07cd4c3344690055240f215404a286dd.jpeg" alt="img" /></p><h3 id="多级页表">多级页表</h3><p>偏移量的部分和上面简单页表一样不变，但是原先的页号部分，我们把它拆成四段，从高到低，分成 4 级到 1 级这样 4 个页表索引。</p><p><img src="http://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BA%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/assets/614034116a840ef565feda078d73cb76.jpeg" alt="img" /></p><p>我们先通过 4 级页表索引，找到 4 级页表里面对应的条目（Entry）。这个条目里存放的是一张 3 级页表所在的位置。4 级页面里面的每一个条目，都对应着一张 3 级页表，所以我们可能有多张 3 级页表。</p><p>找到对应这张 3 级页表之后，我们用 3 级索引去找到对应的 3 级索引的条目。3 级索引的条目再会指向一个 2 级页表。同样的，2 级页表里我们可以用 2 级索引指向一个 1 级页表。</p><p>而最后一层的 1 级页表里面的条目，对应的数据内容就是物理页号了。在拿到了物理页号之后，我们同样可以用“页号 + 偏移量”的方式，来获取最终的物理内存地址。</p><p>我们可能有很多张 1 级页表、2 级页表，乃至 3 级页表。但是，因为实际的虚拟内存空间通常是连续的，我们很可能只需要很少的 2 级页表，甚至只需要 1 张 3 级页表就够了。</p><p>多级页表就像一个多叉树的数据结构，所以我们常常称它为<strong>页表树</strong>（Page Table Tree）。因为虚拟内存地址分布的连续性，树的第一层节点的指针，很多就是空的，也就不需要有对应的子树了。所谓不需要子树，其实就是不需要对应的 2 级、3 级的页表。找到最终的物理页号，就好像通过一个特定的访问路径，走到树最底层的叶子节点。</p><p><img src="http://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BA%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/assets/5ba17a3ecf3f9ce4a65546de480fcc4e.jpeg" alt="img" /></p><blockquote><p>多层分页表就好像把完整的电话号码分成区号。我们把同一地区的电话号码以及对应的人名记录同通一个小本子上。再用一个上级本子记录区号和各个小本子的对应关系。如果某个区号没有使用，那么我们只需要在上级本子上把该区号标记为空。同样，一级分页表中0x01记录为空，说明了以0x01开头的虚拟地址段没有使用，相应的二级表就不需要存在。正是通过这一手段，多层分页表占据的空间要比单层分页表少了很多。</p><p>多层分页表还有另一个优势。单层分页表必须存在于连续的内存空间。而多层分页表的二级表，可以散步于内存的不同位置。这样的话，操作系统就可以利用零碎空间来存储分页表。</p></blockquote><h3 id="总结">总结</h3><p>单页表相当于一个缓存了所有情况的集合，优点是访问速度快，缺点是占用空间大</p><p>多级页表相当于只缓存已经存在的情况，优点是占用空间较少，缺点是访问时间相对较长。</p><h3 id="背诵版">背诵版</h3><p>多级页表本质上是一个时间换空间的策略，通过增加一定的访问地址时间来减少对空间的占用。</p><p>操作系统需要将虚拟内存地址翻译为物理内存地址，而记录对应关系最简单的办法，就是把对应关系记录在一张表中。为了加快翻译速度，这个表必须加载在内存中。这个表就是页表。</p><p>如果页表直接把所有的对应关系记录到同一个表中，会有很多位置都是浪费了的，对于任何一个应用进程，其进程空间真正用到的地址都相当有限的。</p><p>而对于每一个进程，都有属于自己独立的虚拟内存地址空间。这也就意味着，每一个进程都需要这样一个页表。当进程多了之后，页表占用的空间也会随之增大。</p><p>多层分页表就好像把完整的电话号码分成区号。我们把同一地区的电话号码以及对应的人名记录同通一个小本子上。再用一个上级本子记录区号和各个小本子的对应关系。如果某个区号没有使用，那么我们只需要在上级本子上把该区号标记为空。同样，一级分页表中记录为空，说明了以这个一级页表开头的虚拟地址段没有使用，相应的二级表就不需要存在。正是通过这一手段，多层分页表占据的空间要比单层分页表少了很多。</p><p>单层分页表必须存在于连续的内存空间。而多层分页表的二级表，可以散步于内存的不同位置。这样的话，操作系统就可以利用零碎空间来存储分页表。</p><h2 id="参考">参考</h2><p>推荐：<a href="https://rcore-os.gitcode.host/rCore-Tutorial-Book-v3/chapter4/3sv39-implementation-1.html#id6">https://rcore-os.gitcode.host/rCore-Tutorial-Book-v3/chapter4/3sv39-implementation-1.html#id6</a></p><p>推荐：<a href="https://www.cnblogs.com/vamei/p/9329278.html">https://www.cnblogs.com/vamei/p/9329278.html</a></p><p><a href="https://blog.csdn.net/phosphenesvision/article/details/118616334">https://blog.csdn.net/phosphenesvision/article/details/118616334</a></p><p><a href="https://www.i4k.xyz/article/forDreamYue/78887035">https://www.i4k.xyz/article/forDreamYue/78887035</a></p><p><a href="https://blog.csdn.net/zhizhengguan/article/details/121276581">https://blog.csdn.net/zhizhengguan/article/details/121276581</a></p><p><a href="https://www.jianshu.com/p/242ba363e4ed">https://www.jianshu.com/p/242ba363e4ed</a></p><p>推荐：<a href="http://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BA%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/40%20%20%E7%90%86%E8%A7%A3%E5%86%85%E5%AD%98%EF%BC%88%E4%B8%8A%EF%BC%89%EF%BC%9A%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98%E5%92%8C%E5%86%85%E5%AD%98%E4%BF%9D%E6%8A%A4%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F.md">http://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BA%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/40%20%20%E7%90%86%E8%A7%A3%E5%86%85%E5%AD%98%EF%BC%88%E4%B8%8A%EF%BC%89%EF%BC%9A%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98%E5%92%8C%E5%86%85%E5%AD%98%E4%BF%9D%E6%8A%A4%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F.md</a></p>]]>
                    </description>
                    <pubDate>Sat, 24 Sep 2022 16:45:57 CST</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[9.22 ｜ 手写一个排他锁，当多线程运行时只有线程名字为指定名字的线程能获取到锁]]>
                    </title>
                    <link>/archives/922手写一个排他锁当多线程运行时只有线程名字为指定名字的线程能获取到锁</link>
                    <description>
                            <![CDATA[<p><a href="https://github.com/erdengk/code-exercise/blob/fe8cc12a2094311e193b94c23eaaa58f2478d425/src/dailyExercise/Lock/CreateLock.java">源代码链接</a></p><h2 id="手写一个排他锁">手写一个排他锁</h2><p>要求当多线程运行时只有线程名字为指定名字的线程能获取到锁</p><h3 id="步骤">步骤</h3><ol><li>实现 lock 接口</li><li>写一个静态类，继承 AbstractQueuedSynchronizer</li><li>重写 aqs 里面的方法，完成需求</li><li>aqs 里只有五个方法可以被重写<ol><li>tryAcquire tryRelease  排他锁 加锁、解锁</li><li>tryAcquireShared  tryReleaseShared  共享锁 加锁 解锁</li><li>isHeldExclusively  当前线程是否被线程独占的方法</li></ol></li></ol><pre><code class="language-java">    private static class Sync extends AbstractQueuedSynchronizer {        // 加锁        protected boolean tryAcquire(int arg) {            // 线程名字必须是 AQS-Lock 才能加锁            if (!Thread.currentThread().getName().equals(&quot;AQS-Lock&quot;)) {                return false;            }            if (compareAndSetState(0, arg)) {                // 设置为当前线程                setExclusiveOwnerThread(Thread.currentThread());                return true;            }            return false;        }        // 解锁        protected boolean tryRelease(int arg) {            if (getState() == 0) {                throw new IllegalStateException();            }            // 此处不用cas的原因是，既然要调用解锁，那自然是自身持有锁，有锁，代表自己有一个单独的私人线程            // 所以不涉及多线程问题，无需cas            setState(0);            return true;        }        Condition getCondition(){            return  new ConditionObject();        }    }</code></pre><p>测试用例</p><pre><code class="language-java"> private static CreateLock createLock = new CreateLock();    public static void main(String[] args) {        Thread A = new Thread(() -&gt; {            testLock();            while (true) {            }        });        Thread B = new Thread(() -&gt; {            testLock();        });        //  只有 A 能拿到锁，因为加锁限制了线程名字        A.setName(&quot;AQS-Lock&quot;);        B.setName(&quot;Lock&quot;);        A.start();        B.start();    }    private static void testLock() {        createLock.lock();        try {            System.out.println(&quot;当前获取到锁的线程名称是：&quot;                    + Thread.currentThread().getName());        } catch (Exception e) {            e.printStackTrace();        } finally {            createLock.unlock();        }    }</code></pre><p>输出结果</p><pre><code class="language-bash">当前获取到锁的线程名称是：AQS-Lock</code></pre><p>然后一直等待。。。（因为线程A的 while true ）</p><h2 id="q2-说一下-多线程情况下-reentrantlock-公平锁加锁过程">q2 说一下 多线程情况下 ReentrantLock 公平锁加锁过程？</h2><p>先定义一下公平锁和非公平锁</p><h3 id="公平锁">公平锁</h3><p>现在有ABC三条线程, A线程获取到了锁，BC线程获取失败，BC线程会加入到同步队列的尾端。</p><p>A线程释放锁后, B线程收到唤醒通知，进行锁的争抢。</p><p>就这在这时，一个新来的线程D也来争抢了，D线程看到B正在排队(D线程其实是调用AQS源码里边的 hasQueuedPredecessors 方法) ，就放弃争抢，直接加入同步队列尾端。继续等待</p><h3 id="非公平锁">非公平锁</h3><p>现在有ABC三条线程，A线程获取到了锁，BC线程获取失败，BC线程会加入到同步队列的微端。A线程释放锁后，B线程收到唤醒通知，进行锁的争抢。</p><p>就这在这时候，一个新来的线程D也来争抢了</p><p>D线程很不讲武德，直接和B线程进行争抢。如果D线程抢夺失败，加入同步队列。</p><p>如果D线程成功，对B线程不公平。对C也不公平,因为C也在排队。<br />此外 C 线程不会争抢锁，因为只有前置节点通知后续节点才会唤醒，也就是说 C 线程只能被 B 唤醒，唤醒的前提是B线程争抢锁成功，并且B线程释放锁之后才会通知 C 。</p><h3 id="加锁成功的线程">加锁成功的线程</h3><p><img src="https://pdai.tech/_images/thread/java-thread-x-juc-reentrantlock-5.png" alt="image" /></p><ol><li><p>先调用 FairSync 里的 lock（）方法</p></li><li><p>使用 AQS 的 模版方法 acquire， acquire (AQS) 会调用tryAcquire (我们重写的方法)</p></li><li><p>抢占成功后会 setExclusiveOwnerThread(current) ，设置当前线程持有锁</p></li></ol><h3 id="加锁失败的线程">加锁失败的线程</h3><p><img src="https://pdai.tech/_images/thread/java-thread-x-juc-reentrantlock-6.png" alt="image" /></p><p>整体流程如上，简单叙述一下：</p><p>如果获取失败，当前线程就会被添加到同步队列尾端。</p><pre><code class="language-java">public final void acquire(int arg) {    if (!tryAcquire(arg) &amp;&amp;        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))        selfInterrupt();}</code></pre><p>添加到尾端用的是 addWaiter 方法，addWaiter 方法会进行一次cas添加，如果添加失败， 则调用enq（死循环添加，一定要成功，如果添加成功，就会再次调用 ）</p><pre><code class="language-java">private Node addWaiter(Node mode) {    Node node = new Node(Thread.currentThread(), mode);    Node pred = tail;    // 如果队列不为空, 使用 CAS 方式将当前节点设为尾节点    if (pred != null) {        node.prev = pred;        if (compareAndSetTail(pred, node)) {            pred.next = node;            return node;        }    }    // 队列为空、CAS失败，将节点插入队列    enq(node);    return node;}</code></pre><p>在 enq 方法里判断当前节点的前置节点是不是 head 节点，如果是，并且加锁成功，就算加锁成功</p><pre><code class="language-java">private Node enq(final Node node) {    for (;;) {        Node t = tail;        if (t == null) { // Must initialize            if (compareAndSetHead(new Node()))                tail = head;        } else {            node.prev = t;            if (compareAndSetTail(t, node)) {                t.next = node;                return t;            }        }    }}</code></pre><p>获取锁失败后, 判断是否把当前线程挂起</p><p>调用  shouldParkAfterFailedAcquire 和 parkAndCheckInterrupt</p><pre><code class="language-java">final boolean acquireQueued(final Node node, int arg) {    boolean failed = true;    try {        boolean interrupted = false;        for (;;) {            final Node p = node.predecessor();            // 当前节点的前驱就是head节点时, 再次尝试获取锁            if (p == head &amp;&amp; tryAcquire(arg)) {                setHead(node);                p.next = null; // help GC                failed = false;                return interrupted;            }            // 获取锁失败后, 判断是否把当前线程挂起            if (shouldParkAfterFailedAcquire(p, node) &amp;&amp;                parkAndCheckInterrupt())                interrupted = true;        }    } finally {        if (failed)            cancelAcquire(node);    }}</code></pre><p>在 shouldParkAfterFailedAcquire 中，如果前置节点的状态是 signal，就等待，如果是 cancel 取消状态，将其移出，如果是其他状态，就<br />替换为 signal 状态，然后自己等待</p><pre><code class="language-private">    int ws = pred.waitStatus;    if (ws == Node.SIGNAL)    // SIGNAL 设置了前一个节点完结唤醒        return true;    if (ws &gt; 0) {        do {            node.prev = pred = pred.prev;        } while (pred.waitStatus &gt; 0);        pred.next = node;    } else {        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);    }    return false;}</code></pre><p>如果还是失败，在acquireQueued 方法里，调用 selfInterrupt() 中断方法：</p><pre><code class="language-java"> // 当前线程进入waite状态，且将前驱节点的转态设置为signal，用于唤醒自己，返回中断状态状态  //注意，这里会清除中断状态！！  if (shouldParkAfterFailedAcquire(p, node) &amp;&amp;      parkAndCheckInterrupt())      interrupted = true; //如果等待过程中被中断过就将interrupted标记置为true</code></pre><p>在acquireQueued(final Node node, int arg) 中，获取锁的方式是一个死循环，成功：会将的标志位failed（标记当前Node是否成功获取资源）置为false。</p><p>如果失败：抛出异常，则执行执行finally中cancelAcquire(node)方法，取消当前线程请求资源的操作。该方法负责将需要取消的node踢出等待队列</p><h2 id="参考">参考</h2><p><a href="https://pdai.tech/md/java/thread/java-thread-x-lock-ReentrantLock.html#%e5%85%ac%e5%b9%b3%e9%94%81">https://pdai.tech/md/java/thread/java-thread-x-lock-ReentrantLock.html#%e5%85%ac%e5%b9%b3%e9%94%81</a></p><p><a href="https://segmentfault.com/a/1190000023497508">https://segmentfault.com/a/1190000023497508</a></p>]]>
                    </description>
                    <pubDate>Thu, 22 Sep 2022 21:15:10 CST</pubDate>
                </item>
    </channel>
</rss>