<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="https://www.nichenjie.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.nichenjie.com/" rel="alternate" type="text/html" /><updated>2021-10-26T23:35:50-04:00</updated><id>https://www.nichenjie.com/feed.xml</id><title type="html">倪晨杰的博客 Chenjie’s blog</title><subtitle>A subspace of the www universe.</subtitle><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><entry><title type="html">如何组装一台平衡高效的 Chia P图机（避坑指南）</title><link href="https://www.nichenjie.com/diary/pitfalls-of-assembling-a-chia-plotting-rig/" rel="alternate" type="text/html" title="如何组装一台平衡高效的 Chia P图机（避坑指南）" /><published>2021-05-23T17:08:49-04:00</published><updated>2021-05-23T17:08:49-04:00</updated><id>https://www.nichenjie.com/diary/pitfalls-of-assembling-a-chia-plotting-rig</id><content type="html" xml:base="https://www.nichenjie.com/diary/pitfalls-of-assembling-a-chia-plotting-rig/">&lt;p&gt;P 图是奇亚币的农场主们首先需要考虑的问题，在短期内 P 图会成为限制全网占用空间上升速度的主要瓶颈，或者简单来说就是在短期内 P 图的速度决定了你“挖”奇亚币的速度，而从长期来看（如果 Chia 能活到那一天的话），硬盘容量将会成为最终的瓶颈。&lt;/p&gt;

&lt;h1 id=&quot;用词解释&quot;&gt;用词解释&lt;/h1&gt;

&lt;p&gt;为了方便朋友们理解我的意思，我在这里先解释一下我的一些 Chia 用词习惯：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Chia 就是奇亚币，它是一个加密货币，也有人称之为 Chia coin&lt;/li&gt;
  &lt;li&gt;P 图就是 Plotting 或者 Creating plots，&lt;a href=&quot;https://github.com/Chia-Network/chia-blockchain-gui/blob/74c480767032a80872e933fac07631a7ae1fcb96/src/locales/zh-CN/messages.po#L83&quot;&gt;官方 GUI&lt;/a&gt; 中把这个翻译为「开垦农田」&lt;/li&gt;
  &lt;li&gt;“挖”奇亚币分为两步，第一步是 P 图（开垦农田），第二步是 Farming (耕种农田)，你只有在第二步才有可能获得奇亚币的奖励&lt;/li&gt;
  &lt;li&gt;3P, 4P, nP 意思就是说同时并发开垦 3 块，4 块，n 块农田&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;最优情况&quot;&gt;最优情况&lt;/h1&gt;

&lt;p&gt;组装一台高效 P 图机的核心是平衡二字，你不希望某一个硬件成为你 P 图性能的瓶颈，以下是 P 一张 k32 图 (101.3 GiB) 所需要的资源（假设你使用 SSD 作为临时目录）：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;两个 CPU &lt;strong&gt;线程&lt;/strong&gt; (Threads)
    &lt;ul&gt;
      &lt;li&gt;对于支持超线程技术 (Hyper-Threading) 的 Intel CPU 来说，这相当于&lt;strong&gt;一个核心&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;对于支持 SMT 的 AMD CPU 来说，这也相当于&lt;strong&gt;一个核心&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;CPU 单核性能越高，P 图速度越快&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;3389 MiB ≈ 3.55 GB 内存，可以简单记为 4 GB 内存
    &lt;ul&gt;
      &lt;li&gt;增加内存对 P 图速度好像没什么提升&lt;/li&gt;
      &lt;li&gt;内存频率 3000 MHz 左右就足够了，再高对 P 图速度好像也没什么提升&lt;/li&gt;
    &lt;/ul&gt;

    &lt;blockquote&gt;
      &lt;p&gt;Efficient plotting of k=32 with 2 threads is now possible with buffer size of &lt;strong&gt;3389 MiB&lt;/strong&gt; in bitfield mode by shrinking entry sizes to reduce memory and IO usage.&lt;/p&gt;

      &lt;p&gt;Source: &lt;a href=&quot;https://github.com/Chia-Network/chiapos/releases/tag/1.0.1&quot;&gt;https://github.com/Chia-Network/chiapos/releases/tag/1.0.1&lt;/a&gt;&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;239 GiB (256.6 GB) SSD 的临时空间，实测可能需要更多，所以这里留点余量，可以简单记为 300 GB 的固态空间
    &lt;blockquote&gt;
      &lt;p&gt;Source: &lt;a href=&quot;https://github.com/Chia-Network/chia-blockchain/wiki/k-sizes#storage-requirements&quot;&gt;https://github.com/Chia-Network/chia-blockchain/wiki/k-sizes#storage-requirements&lt;/a&gt;&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;固态 200 MB/s 的连续写入速度 (Sequential write speed)
    &lt;ul&gt;
      &lt;li&gt;在这个最优情况下，P 一张 k32 只需要 4-5 小时左右。实测如果保证 300 MB/s，那么就可以将 P 图时间缩短到 3 小时 50 分钟。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;消耗固态 1.8 TiBW ≈ 1.98 TBW 的耐久度
    &lt;blockquote&gt;
      &lt;p&gt;TBW, or terabytes written, is generally how SSD drive life is measured. &lt;strong&gt;One k32 writes 1.8TiB in non-bitfield mode&lt;/strong&gt; and 1.6 TiB with bitfield enabled.&lt;/p&gt;

      &lt;p&gt;Source: &lt;a href=&quot;https://www.chia.net/2021/02/22/plotting-basics.html&quot;&gt;https://www.chia.net/2021/02/22/plotting-basics.html&lt;/a&gt;&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;举例说明&quot;&gt;举例说明&lt;/h1&gt;

&lt;p&gt;你需要按照上述最优情况的比例去搭配你的硬件，如果你还是不太明白，可以看下面几个例子：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;案例一是我好几年前配的台式机&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; CPU: Intel i7-7700K，默频 4.2 GHz，睿频 4.5 GHz, 四核八线程
 内存: 4*8 GB 海盗船 DDR4，XMP 超频到 3000 MHz
 SSD:
   - Intel 600p 256 GB M.2 NVMe TLC SSD - 系统盘
   - Intel 660p 2 TB M.2 NVMe QLC SSD - Chia 临时目录
 机械: Toshiba N300 12TB NAS CMR 7200 RPM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;✅ 这台机子 CPU 的单核性能比较高，适合 P 图用，内存频率也 ok。&lt;br /&gt;
 ❌ 这个配置的问题是 CPU 核心数和内存没有搭配好，四核配 16 GB 内存就足够了，因为 CPU 最多也只能支持同时 P 四张 k32 的图，多余的 16 GB 内存就浪费了。这配置还有一个问题就是用作 Chia 临时目录的 660p SSD，QLC 颗粒连续写入速度很低并且 TBW 也很低，不适合用作临时盘，而且之前说了目前的瓶颈在 CPU 上，最多开 4P，那么临时盘只要 1.2 TB 就够了，这里 2 TB 没有什么大问题。如果你的配置瓶颈是 3P 的话，临时盘 SSD 只需要 1 TB 就够了。You get the idea.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;案例二是最近朋友为 P 图特意配的机子&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; CPU: AMD 3970X，默频 3.7 GHz，睿频 4.5 GHz, 32 核 64 线程
 内存: 8*16 GB DDR4，XMP 超频到 3000 MHz
 SSD: WD_BLACK SN750 NVMe 3D NAND TLC SSD 2*2 TB
 机械: Seagate IronWolf 5*12TB NAS 7200 RPM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;✅ 这个配置就比案例一的更均衡了，CPU 核心和内存比例正好 1:4，SSD 选的是 3D NAND TLC 颗粒，2 TB 的耐久度有 1200 TBW，持续写入速度也能保持在 1600 MB/s 左右，一张 SSD 6P I/O 不会成为瓶颈，2 TB 的容量也能支持同时开 6P。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;需要注意的一些坑&quot;&gt;需要注意的一些坑&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;固态要买 M.2 版型 (Form factor) NVMe 接口 (Interface) 的 SSD，不要选 2.5 英寸的 SATA SSD 或者 M.2 版型 SATA 接口的 SSD，因为 SATA 接口的实际最高速度只有 550 MB/s，这会给并发开垦带来瓶颈，况且 NVMe SSD 和 SATA SSD 现在价格也差不多。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;不要把系统盘作为开垦的临时目录，因为一旦系统盘写报废了就没法正常开机进系统了。正确的做法应该是选一个小的 SSD 作为系统盘（大概 128 GB 或者 256 GB），如果你不想占用 M.2 槽位的话，完全可以用 2.5 英寸的 SATA SSD 作为系统盘。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;机械硬盘要选择能支持 24*7 不间断工作的，NAS 盘或者监控盘会比企业盘要便宜一些。尽量选择 10 TB 以上的，这样连续写入速度会比较快，也可以在相同容量下节省主板的 SATA 口。我不推荐用外置硬盘，因为它们不是为 24*7 工作而设计的，后续故障可能会比较多，不过如果你愿意折腾，并且外置硬盘价格美丽还是可以考虑的。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;选择固态不能单单看突发写入速度 (Burst write speed) 或者官网标称的连续写入速度或 PCIe 接口速度，关键要看 Sustained sequential write speed (也被称作 Sequential steady state write speed) 指标，如下图：&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/mdres/posts/2021/sustained-sequential-write-speed.jpg&quot; alt=&quot;Sequential steady state write workload&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;图片来源：tomshardware.com&lt;/p&gt;

    &lt;p&gt;图片中每个 SSD 前 100 GB 左右基本都是最快的，因为它们都有 SLC 缓存，而 Chia P 图的过程需要对固态写入 TB 级别的数据，所以 SLC 缓存的速度并不能真实地反应 P 图的速度，这就是为什么有些盘标称快，但是实际 P 下来很慢的缘故了。这个 Sustained sequential write speed 通常就是 SSD 在 P 图上的 I/O 瓶颈，不建议用 QLC 颗粒的固态 P 图（像案例一），因为 QLC 固态在 SLC 缓存用尽之后写入速度只有 170 MB/s 左右，而且 TBW 很低。推荐用 TLC 或者 MLC 的固态做临时盘，他们一般速度和 TBW 都比 QLC 盘更高一些。需要注意的是 TLC 盘之间也是有差异的，一般 TBW 越高，持续写入速度就越低，比如像这里的希捷 FireCuda 520，2 TB 的有 3600 TBW，但是持续写入速度稳定之后只有 600 MB/s 左右，这就不太适合 P 盘，总之还是这两个字，平衡！&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;</content><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><category term="diary" /><category term="日常小记" /><summary type="html">P 图是奇亚币的农场主们首先需要考虑的问题，在短期内 P 图会成为限制全网占用空间上升速度的主要瓶颈，或者简单来说就是在短期内 P 图的速度决定了你“挖”奇亚币的速度，而从长期来看（如果 Chia 能活到那一天的话），硬盘容量将会成为最终的瓶颈。</summary></entry><entry><title type="html">生命在于折腾——记一次不断倒腾让 CS:GO 流畅运行的经历</title><link href="https://www.nichenjie.com/diary/how-i-get-cs-go-running-smoothly-without-lag/" rel="alternate" type="text/html" title="生命在于折腾——记一次不断倒腾让 CS:GO 流畅运行的经历" /><published>2021-01-12T18:50:49-05:00</published><updated>2021-01-12T18:50:49-05:00</updated><id>https://www.nichenjie.com/diary/how-i-get-cs-go-running-smoothly-without-lag</id><content type="html" xml:base="https://www.nichenjie.com/diary/how-i-get-cs-go-running-smoothly-without-lag/">&lt;h2 id=&quot;2021年1月12日原文&quot;&gt;2021年1月12日原文&lt;/h2&gt;

&lt;p&gt;故事得从我初中开始说起（大概是 2008-09 年左右），在我中预、初一的时候我被一款 FPS 游戏所吸引，当时寒暑假里我的大部分时间都被这个游戏所占据，可以说当时的我对于这款游戏的热爱已经到了近乎疯狂的地步。半夜里会偷偷设置闹钟起床，为了不被父母发现带着耳机去玩；放学后会为了能赶在父母下班回家之前多玩一会儿而打车回家；初中电脑课上在学校电脑里偷偷安装这个游戏，最后被叫家长。可以说这款游戏贯穿了我的初中时代，这款游戏就是“穿越火线”。我喜欢这款游戏，主要因为它很耐玩，就像 Kiki 喜欢英雄无敌6一样，不过不同的是穿越火线是一个联机游戏，在不同玩家的线上竞争中也增加了游戏的趣味性。当年的游戏中有很多不氪金的高手，他们往往拿着最朴素的黑色武器但却凭借着超高的技艺大杀四方。自从火麒麟问世之后的穿越火线就开始走下坡路了，在我大一暑假期间还玩过一阵子，不过早已经没了当时的乐趣。&lt;/p&gt;

&lt;p&gt;昨天逛知乎发现社区里还有不少和我类似的老玩家，读了其中一篇回答，真的深有同感，这里摘录一些我仍然记忆犹新的片段，以下引用自 @90ago 的回答：（&lt;a href=&quot;https://www.zhihu.com/question/31731341/answer/55840095&quot;&gt;穿越火线为什么走下坡路了？请从多个方面详细点的说说好么 - 90ago的回答 - 知乎&lt;/a&gt;）&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;当时，人们很愿意充一个qq会员，领取一把红色的会员消音m4。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;沙漠灰，躲在后花园，拿着一把ak狙，换子弹速度快，对面人一来，4杀，战斗结束。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;记得，那时，沙漠灰，b点，有个bug可以安包进去。（我在补充一下：好像是跳到箱子的角上然后按包，如果你的位置不是太靠近角上，包就会卡到箱子里区，最后即使 T 全被杀光，菜鸟 CT 来找包的话就就会浪费很多时间，提高 T 方的胜率）&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;我爱当个人英雄。沙漠灰，最后1v4，我，普通m4。小道杀一个，掉了个m4瞄准镜枪，老子不捡！出去，中门，又一个。上楼梯，一个人在那捡枪，又一个。掉包，躲着，队友文字提醒我人走了。进B，扔个闪光，打，又一个，拆包。完美结束，爽。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;总之满满的都是回忆，CF 在引入氪金武器之后就大大减少了我们这个不怎么氪金玩家们的游戏乐趣，后来我也就慢慢的也弃坑了，但是我因为它而喜欢上了 FPS 游戏，最近疫情期间我正好有一些空余时间，于是就想试试 CS:GO，消遣消遣，找找当年的感觉，没想到 CS:GO 的优化似乎不如穿越火线，花了好久才最终使其流畅运行。&lt;/p&gt;

&lt;p&gt;CS:GO 是 Steam 游戏平台上的一款免费游戏，我觉得与穿越火线最大区别就是&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;每局战斗开始之前买装备&lt;/li&gt;
  &lt;li&gt;游戏手感很不同，可能更接近现实？&lt;/li&gt;
  &lt;li&gt;画质更好，游戏更加平衡&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;上周的某一天下班之后，我兴致勃勃地打开 Steam 把 CS:GO 添加到我的 library 里面，然后下载等待其安装完成。过了15分钟左右，我打开游戏，在 intro 的动画播放时我就隐约感觉到卡顿，然后我直接打开了一局游戏，发现帧数很低，转动视角有明显卡顿，估计当时帧数大概在 30 FPS 以下，于是我把画质光效什么的调到最低，发现帧数略微哟一些提高，可能到 40 FPS 左右，不过比起之前穿越火线的丝滑手感，这个我显然是无法接受的。不过这个也是意料之中的，因为我电脑里只有 7700K 的 Intel® HD Graphics 630 集成显卡，CS:GO 需要比这个集显3D图形渲染能力更强一些的显卡。&lt;/p&gt;

&lt;p&gt;既然在自己现有的电脑上跑不起来，我忽然想到 Kiki 有一台 2015 年顶配的 15 吋 MBP，搭载了 Radeon R9 M370X 独立显卡，于是乎我立刻在 MacOS 上装好了 Steam，下载游戏，打开……结果非常失望，调用 OpenGL 接口的 CS:GO 比我台式机集显还要卡，我去……&lt;/p&gt;

&lt;p&gt;Ok, 我又思忖了一下，好像最近云游戏（Cloud Gaming）挺火的，于是乎说干就干，查了很多 reddit 的攻略，决定使用 Amazon EC2 G4 Instances + Parsec 这个组合实现，感谢 &lt;a href=&quot;https://github.com/jamesstringerparsec&quot;&gt;@jamesstringerparsec&lt;/a&gt; 提供的 Windows 下&lt;a href=&quot;https://github.com/parsec-cloud/Parsec-Cloud-Preparation-Tool&quot;&gt;一键环境部署工具&lt;/a&gt;，一番折腾后终于可以跑起来了，我在台式机上装好 Parsec 客户端，然后连接远端的 EC2 服务器，下载 Steam 安装游戏。打开游戏后第一感觉是比本地要流畅不少，画质可能由于压缩原因还是牺牲了一些。然后我打开一局游戏玩了一会儿，发现一个很奇怪的 bug，差不多玩 5-10 秒就会卡一下，我根据官网的 &lt;a href=&quot;https://support.parsec.app/hc/en-us/articles/115002683371-Troubleshooting-Lag-Latency-and-Quality-Issues&quot;&gt;Troubleshooting Lag, Latency and Quality Issues&lt;/a&gt; 指南查了一下，没有发现任何问题 Decode and Encode 延迟都正常，网络带宽还有很多的富余，网络延迟也是小于 40 ms 的。我后续又尝试了魔改各种参数，各种排列组合，包括英伟达控制面板，始终都没法解决这个问题。最后我又尝试了把 OS 换到 Windows Server 2016 以及 Azure 平台的 NV6 Tesla M60 显卡，问题依旧。&lt;del&gt;如果在阅读这篇文章的你解决了这个问题，一定要告诉我哈！&lt;/del&gt; 已解决，见&lt;a href=&quot;#最终的问题解决办法&quot;&gt;最终的问题解决办法&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;你觉得我会就此罢休？我这个人一折腾就停不下来了，在尝试了台式机集显，MBP 独显以及云游戏后我决定购买我人生中的第一张正版显卡（对的你没有看错，之前在国内因为图便宜在X宝买了一张盗版的 GTX 显卡）。直接上图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2021/rx570.jpg&quot; alt=&quot;MSI Gaming Radeon RX 570 256-bit 8GB GDRR5 DirectX 12 VR Ready CFX Graphcis Card (RX 570 Armor 8G OC)&quot; /&gt;&lt;/p&gt;

&lt;p&gt;亚马逊的快递很给力，两三天就送到了。拿到显卡之后我就立马给我的 ROG STRIX Z270E 主板装上了，开机直接点亮，打上驱动，非常顺利，熟练地打开 Steam launch game，与预想的差不多，画质高了不少，打一局游戏看看？我的天，这次又是另外一种卡顿，就是你明明已经走到前面，但是又瞬移回来了。妈蛋……玩个游戏怎么那么费劲，没办法，只能上网搜搜，希望能有解决方法。经过一顿搜索，我觉得问题有很大概率出在我的网络上，于是在 reddit 网友们的推荐下，我用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net_graph 1&lt;/code&gt; 命令打开了游戏画面以及网络状态详细参数的显示，发现 loss 和 choke 一直都是 0，换句话说就是 UDP 没有任何丢包的迹象，延迟一直维持在 30-50 ms 的区间。虽然这里显示没有丢包，我仍然怀疑是网络问题，于是我在里多伦多最近的 Azure 数据中心的 Canada Central 区用&lt;a href=&quot;https://github.com/hwdsl2/setup-ipsec-vpn&quot;&gt;这个&lt;/a&gt;脚本搭建了一个 IPsec VPN，我到 VPN 服务器的延迟大约在 15-20 ms 左右（P.S. 由于 FPS 游戏对于延迟非常敏感，尽量连接物理距离短的服务器）。搭好 VPN 之后，我用 Windows 自带的客户端连接了这个 VPN：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2021/azure-vpn.jpg&quot; alt=&quot;Azure VPN&quot; /&gt;&lt;/p&gt;

&lt;p&gt;然后开了一局游戏，奇迹发生了！卡顿消失了！！！终于可以愉快地游戏了，这年头玩个游戏都要会点 Linux :)&lt;/p&gt;

&lt;h2 id=&quot;2021年1月14日更新&quot;&gt;2021年1月14日更新&lt;/h2&gt;

&lt;p&gt;后来好像开了 VPN 也还是不管用，重启了路由器就好了。&lt;/p&gt;

&lt;h2 id=&quot;2021年1月23日更新&quot;&gt;2021年1月23日更新&lt;/h2&gt;

&lt;p&gt;前两天我用 &lt;a href=&quot;https://www.pingplotter.com/&quot;&gt;PingPlotter&lt;/a&gt; 和 &lt;a href=&quot;https://packetlosstest.com/&quot;&gt;Packet Loss Test&lt;/a&gt; 测试了一下发现确实是丢包造成的卡顿，大致的故障表现就是起先延迟正常，但是每隔 5-10 秒就 spike 一下。于是我打电话给 Fido tech support 然后描述了一下这个情况，他们今天派了一个师傅过来看。师傅大概是中午12点半左右到的，他先查看了一下我这幢楼外面的光纤信号，然后打电话给我说好像是外面光纤的信号问题，说他们需要 24-48 小时调一下，应该会好。我将信将疑，感觉是他敷衍我，于是我就又问他要了个新的路由器，然后我自己换上之后，问题就立刻解决了xD. 我试了试 Amazon EC2 G4 Instances + Parsec 的云游戏组合，发现 5-10 秒卡一下的问题消失了，不过体验还是没有本地独显跑的好，主要就是画质不好和 input lag 有些高，如果不玩这种 FPS 游戏，input lag 应该基本没有太大影响，但是画质问题是现在云游戏的“通病”，期待未来 &lt;a href=&quot;https://en.wikipedia.org/wiki/AV1&quot;&gt;AV1&lt;/a&gt; 编码对于画质的改善。&lt;/p&gt;

&lt;p&gt;事情到这里终于有了一个圆满的结局，怎么样，这次折腾够折腾不？&lt;/p&gt;

&lt;h2 id=&quot;2021年1月25日更新&quot;&gt;2021年1月25日更新&lt;/h2&gt;

&lt;p&gt;这个卡顿现象在换好路由器后昨天又发生了，妈蛋。。。在跟 Rogers Home Internet L2 support 通了长达2小时的电话后还是没有结果，他们帮我 escalate 了一下 ticket，最后说如果还是不能解决的话他们也没有办法了，你只能去换一家 ISP (P.S. 这里插一句，如果你家有很多人一起使用，并且你要玩低延迟的 FPS 类型游戏，直接选 Bell Fibre，原因之后会讲)。说到这里我非常感谢帮我 troubleshoot 的小哥 Vincent (可能是&lt;a href=&quot;https://www.linkedin.com/in/vincent-tan-53554873/?originalSubdomain=ca&quot;&gt;这位&lt;/a&gt;？)，他说话很实在，看得出在尽力帮我解决问题。我们在相互感谢后挂断了电话，可是问题仍然没有解决，依我以前的性格估计就放弃了，我当时真的有点怀疑是什么非常奇怪的 bug 导致的，理论上都说不通。。。可是！！我当天正好有点时间，于是在网上又是一顿搜索，开始是怀疑路由器的问题，因为新换的路由器也是同一型号的。后来再仔细搜了搜，发现很多人在讨论这个叫做 &lt;a href=&quot;https://en.wikipedia.org/wiki/Bufferbloat&quot;&gt;Bufferbloat&lt;/a&gt; 的问题，虽然问题也跟延迟有关，但是我刚开始不以为然，因为大多数人都是在 exaggerate 了带宽之后才发生的这个问题。后来我在检查了我的 motionEye 树莓派之后我貌似发现了一点端倪，由于我的 Fido 上传带宽只有 10 Mbps，我的 motionEye 每过几秒都会占用差不多 5 Mbps，我把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nload&lt;/code&gt; 显示的带宽占用图表和我的延迟图作对比，惊奇地发现它们的 pattern 竟然非常吻合，每当上传带宽占用的时候，延迟必然会出现一个小的 spike，有时候是 80 ms，而有时候甚至到了 300+ ms。到这里我还是不敢 100% 确定这就是问题所在，于是我又开了一局 CS:GO，把画面调成窗口模式，把两个图表放在旁边作对比，发现每次卡顿之前必有 spike，所以这就证明了问题确实和这个是相关联的。&lt;/p&gt;

&lt;h2 id=&quot;最终的问题解决办法&quot;&gt;最终的问题解决办法&lt;/h2&gt;

&lt;p&gt;该问题在 CS:GO 里的表现是 rollback/teleport lag, 虽然人物已经走到了某个位置，但是突然又闪回几秒前的位置。这是由于 UDP 丢包导致的，可以使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf&lt;/code&gt; 来进行 UDP 丢包测试以确定问题。确定了 Bufferbloat 的问题之后，解决它就很容易了：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;如果你的路由器支持 QoS 的功能，打开它就大功告成了。&lt;/li&gt;
  &lt;li&gt;如果不支持 QoS 的话，最简单的不花钱的办法就是限制网速，如果路由器支持网速限制的话就在路由器里把网速限制为你 plan 的 90%-95% 左右。如果路由器不支持限速，那只能在系统里限速，Linux 推荐用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wondershaper&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;一劳永逸花钱的办法有升级 plan，更换支持 QoS 限速的路由器。&lt;/li&gt;
&lt;/ol&gt;</content><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><category term="diary" /><category term="日常小记" /><summary type="html">2021年1月12日原文</summary></entry><entry><title type="html">如何让异国联机游戏成为可能？记疫情期间和女票一起玩饥荒联机版</title><link href="https://www.nichenjie.com/diary/how-to-make-multiplayer-online-gaming-across-continent-possible/" rel="alternate" type="text/html" title="如何让异国联机游戏成为可能？记疫情期间和女票一起玩饥荒联机版" /><published>2021-01-10T13:38:49-05:00</published><updated>2021-01-10T13:38:49-05:00</updated><id>https://www.nichenjie.com/diary/how-to-make-multiplayer-online-gaming-across-continent-possible</id><content type="html" xml:base="https://www.nichenjie.com/diary/how-to-make-multiplayer-online-gaming-across-continent-possible/">&lt;p&gt;2020 年底圣诞节前女票回国，在隔离期间我们想隔空找点乐子，于是在网络上一通搜寻之后下载了 Steam 上的饥荒联机版，也就是 Don’t Starve Together。由于这款游戏对于联机性能的渣优化，导致我不得不动用我的 Linux 技能来提高我们异国联机的可玩性。不过值得称赞这款游戏的开发公司 Klei Entertainment 的一点是游戏以及社区的高度开放性，玩家可以自由地搭建独立服务器（dedicated server）以及开发各种模组（mod）。&lt;/p&gt;

&lt;p&gt;官方提供了独立服务器搭建教程，你们可以在&lt;a href=&quot;https://forums.kleientertainment.com/forums/topic/64441-dedicated-server-quick-setup-guide-linux/&quot;&gt;这里&lt;/a&gt;找到，我这里使用了 Linux 来搭建的主要原因是我需要将服务器搭建在云平台上来降低物理延迟，如果你只是想在家通过局域网和朋友联机的话是不需要搭建独立服务器的，游戏客户端本身就支持创建服务器来实现联机的功能。我将服务器搭建在了 AWS 北加利福尼亚州的 EC2 上，使用的系统是 Ubuntu 18.04 (AMI name: ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-20201026)，由于 OS 本身是 64 位的，所以需要记得执行这条命令来打开多架构支持功能，不然 32 位的软件装不上：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dpkg --add-architecture i386
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里需要说明的是，我在多伦多，女票在哈尔滨，我选择将服务器放在北加利福尼亚州的原因主要有以下几点：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;我比较喜欢进攻怪物，为了不掉血就需要使用一个叫 “&lt;a href=&quot;https://steamcommunity.com/sharedfiles/filedetails/?id=910645073&quot;&gt;kiting&lt;/a&gt;” 的技巧。服务器离我的物理距离更短意味着我能有一个相对更低的游戏延迟，这对于 kiting 的成功率帮助特别大。其实日本东京也是很不错的选择，具体选哪个就要看哪一方更好战。&lt;/li&gt;
  &lt;li&gt;中美之间的网络质量要比中欧好得多，延迟上中美要比中欧低 100-150 ms。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;如果你使用的是 AWS，还有一个进一步优化延迟的方法就是使用 AWS Global Accelerator，它能利用边缘节点来将数据包转发到 AWS 骨干网络上，不走公网，从而达到降低延迟，提高网络稳定性的目的。AWS 侧具体配置方式的话可以参考&lt;a href=&quot;https://docs.aws.amazon.com/global-accelerator/latest/dg/introduction-get-started.html&quot;&gt;官方文档&lt;/a&gt;，配置完之后会生成两个任播 (anycast) IP 地址。在饥荒客户端内点击键盘上的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~&lt;/code&gt; 键打开控制台，输入&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;c_connect(&quot;&amp;lt;这里填 AWS Global Accelerator 生成的任意一个 IP 地址&amp;gt;&quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后输入房间密码，就可以进房间游戏啦。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2021/dst-dedicated-server.jpg&quot; alt=&quot;服务器&quot; /&gt;
(P.S. 1.截图的时候正好服务器在东京，2. 忽略服务器名字。。。)&lt;/p&gt;

&lt;p&gt;搭建完服务器就可以愉快的玩耍了，女票喜欢玩温蒂，因为她有一个 twin sister 叫阿比盖尔，它能帮助温蒂杀敌和抵挡伤害；而我比较喜欢玩薇格弗德，她只吃肉擅长进攻，开局就有战斗长矛和头盔，她对敌人的伤害是普通人的 125%，而受到的伤害只有普通人的 85%。大家也可以体验一下其他角色，每个角色都有自己擅长的和欠缺的点，人物属性设计得还是很平均的。&lt;/p&gt;

&lt;p&gt;初期我们感觉这个游戏比较难上手，对新手不太友好，游戏里的道具花样很多，不看教程的话只有通过不断地尝试来知道不同道具的属性，以下是我们开局的策略，希望能帮助到刚开始玩的你们：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;补血：普通人补血吃蝴蝶翅膀，蝴蝶在白天花朵上可以刷出来，抓蝴蝶的方法就是先走到蝴蝶旁边然后多按几次 control(ctrl)+F 快捷键。薇格弗德可以通过打怪来补血。&lt;/li&gt;
  &lt;li&gt;补理智/脑残/精神：不推荐摘花，因为你把花摘了就没蝴蝶补血了，所以普通人最简单的回理智的方法就是吃烤熟的绿蘑菇和仙人掌。薇格弗德也可以通过打怪来回理智。&lt;/li&gt;
  &lt;li&gt;补饥饿值：普通人可以通过吃浆果和蝴蝶翅膀来回复饥饿值，薇格弗德因为只吃肉，所以前期需要依靠吃烤（怪物）肉来回饥饿值。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;其他的技巧可以网络上参考别人的分享，希望大家可以熬过冬天 :)&lt;/p&gt;</content><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><category term="diary" /><category term="日常小记" /><summary type="html">2020 年底圣诞节前女票回国，在隔离期间我们想隔空找点乐子，于是在网络上一通搜寻之后下载了 Steam 上的饥荒联机版，也就是 Don’t Starve Together。由于这款游戏对于联机性能的渣优化，导致我不得不动用我的 Linux 技能来提高我们异国联机的可玩性。不过值得称赞这款游戏的开发公司 Klei Entertainment 的一点是游戏以及社区的高度开放性，玩家可以自由地搭建独立服务器（dedicated server）以及开发各种模组（mod）。</summary></entry><entry><title type="html">2020，我的年终总结</title><link href="https://www.nichenjie.com/diary/2020-my-annual-summary/" rel="alternate" type="text/html" title="2020，我的年终总结" /><published>2020-12-31T11:20:49-05:00</published><updated>2020-12-31T11:20:49-05:00</updated><id>https://www.nichenjie.com/diary/2020-my-annual-summary</id><content type="html" xml:base="https://www.nichenjie.com/diary/2020-my-annual-summary/">&lt;p&gt;2020 是一个多灾多难的一年，这一年就仿佛上帝要惩罚贪婪的人类，数以百万计人的生命定格在了 2020，全世界的人们每天的大部分时间都只能待在家里，用电话和视频的方式与外界沟通。然而 2020 对于生活在这个蓝色星球的其他动物们而言，是一个自由自在，少有人类侵扰的一年。很多人都认为人类是食物链最顶端的动物，大自然似乎在 2020 这一年给出了它的答案。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/raccoon.jpg&quot; alt=&quot;Raccoon laying on handrail&quot; /&gt;&lt;/p&gt;

&lt;p&gt;我的 2020 都在加拿大度过，因为全球气候变暖，这一年的加拿大比往年暖和了不少，甚至都出现了好几天我的家乡上海温度零下，而多伦多零上的情况。相对“暖和”的气候对于我这个南方人实在是太友好了，有时候都不敢相信自己生活在一个冰雪国度。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/shanghai-weather.jpg&quot; alt=&quot;Shanghai weather forecast&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/toronto-weather.jpg&quot; alt=&quot;Toronto weather forecast&quot; /&gt;&lt;/p&gt;

&lt;p&gt;每天清晨看到城市的天际线，一种豁达以及愉悦感油然而生，每一天都有新的事物等待去发现，新的问题等待去解决，还有新的想法等待去实现。2020，我在父母的帮助下在多伦多贷款安了家，感谢在背后一直支持着我的老爸老妈，没有你们就不会有现在的我。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/day.jpg&quot; alt=&quot;Day view from my condo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/night.jpg&quot; alt=&quot;Night view from my condo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Kiki 和我走到现在已经快两年了，在 2020 我们吃遍了多伦多的大街小巷，走遍了各种公园、瀑布、湖泊，第一次看了舞台剧 &lt;a href=&quot;https://en.wikipedia.org/wiki/Come_from_Away&quot;&gt;Come from Away&lt;/a&gt;，还有令我难忘的卡尔加里之行。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki1.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki2.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/us1.jpg&quot; alt=&quot;Us&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/come-from-away.jpg&quot; alt=&quot;Come From Away musical&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki-22-bday.jpg&quot; alt=&quot;Kiki 22 year-old birthday&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki3.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki4.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki5.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/jack1.jpg&quot; alt=&quot;Jack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki6.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki7.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki8.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki9.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/jack-24-bday.jpg&quot; alt=&quot;Jack 24 year-old birthday&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/lobster-rice-soup.jpg&quot; alt=&quot;Lobster rice soup&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/jack2.jpg&quot; alt=&quot;Jack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/jack3.jpg&quot; alt=&quot;Jack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/jack4.jpg&quot; alt=&quot;Jack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/lake.jpg&quot; alt=&quot;Lake&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki10.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki11.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/lake2.jpg&quot; alt=&quot;Lake&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/jack5.jpg&quot; alt=&quot;Jack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki12.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki13.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki14.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/kiki15.jpg&quot; alt=&quot;Kiki&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/us2.jpg&quot; alt=&quot;Us&quot; /&gt;&lt;/p&gt;

&lt;p&gt;不得不提的还有工作，我仍然在 &lt;a href=&quot;https://crowdmark.com/&quot;&gt;Crowdmark&lt;/a&gt; 全职上班，2020 年身边同事来了不少，不过也走了几个，总体来说我们员工人数翻翻，年营收也翻翻，前景非常可观。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/crowdmark.jpg&quot; alt=&quot;Crowdmark&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Goodbye 2020, wish you all the best in 2021! 最后 Kiki 和我在此祝大家新年快乐，心想事成，一切顺利。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/ending.jpg&quot; alt=&quot;Kiki and I in front of Lake Louise&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2020/toronto.jpg&quot; alt=&quot;Toronto city hall&quot; /&gt;&lt;/p&gt;</content><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><category term="diary" /><category term="日常小记" /><summary type="html">2020 是一个多灾多难的一年，这一年就仿佛上帝要惩罚贪婪的人类，数以百万计人的生命定格在了 2020，全世界的人们每天的大部分时间都只能待在家里，用电话和视频的方式与外界沟通。然而 2020 对于生活在这个蓝色星球的其他动物们而言，是一个自由自在，少有人类侵扰的一年。很多人都认为人类是食物链最顶端的动物，大自然似乎在 2020 这一年给出了它的答案。</summary></entry><entry><title type="html">23岁的我都在想/做些什么？</title><link href="https://www.nichenjie.com/diary/my-thoughts-at-the-age-of-23/" rel="alternate" type="text/html" title="23岁的我都在想/做些什么？" /><published>2019-12-03T09:05:49-05:00</published><updated>2019-12-03T09:05:49-05:00</updated><id>https://www.nichenjie.com/diary/my-thoughts-at-the-age-of-23</id><content type="html" xml:base="https://www.nichenjie.com/diary/my-thoughts-at-the-age-of-23/">&lt;p&gt;上个月刚过完生日，转眼我就23了，我想借机分享一下近况和些许感悟，遂作文以记之。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/11/me-at-23.jpg&quot; alt=&quot;23岁的我和安卓生日蛋糕&quot; /&gt;&lt;/p&gt;

&lt;p&gt;这段时间神经网络盛行，硅谷巨头们都将大量人力财力投入于设计、开发和训练神经网络。每天我都会收到很多关于 AI 和 Machine Learning 的邮件，这里“最烦人”的要数亚麻了，几乎天天给我推销他们家的 SageMaker，说的我都快心动了，可是一看 pricing 再算了算 GPU cost，就感觉它太没有诚意了。&lt;/p&gt;

&lt;p&gt;前两天我在和 KiKi 讨论一个我不经意间开脑洞的问题，问题大概就是人会不会也是外太空某种生物所设计出来的神经网络，我们被训练和优化到能够自行高效地处理复杂的逻辑。KiKi 说人与其他动物和机器最大的区别就是情感，我不敢苟同，我觉得情感包含了这个星球上最为复杂的逻辑，AI 终有一天可以实现和理解它的。当下就算 AI 再牛逼，每一个只能做好一件事，不得不承认的是我们距离 General purpose AI 机器还有很遥远的距离，要让不同架构的神经网络之间相互协作，共同完成任务是相当困难的，这不也反映在了人类社会中吗？&lt;/p&gt;

&lt;p&gt;最近我才有些意识到，今年我慢慢从一个急性子转变为了一个不那么急性子的人，有些事也不那么追求完美了，但是还是有些拖延的毛病。常听长辈讲，很多事上了年纪会慢慢看开，我这咋年纪都还没上呢，思想意识却更新得那么快呢？&lt;/p&gt;</content><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><category term="diary" /><category term="日常小记" /><summary type="html">上个月刚过完生日，转眼我就23了，我想借机分享一下近况和些许感悟，遂作文以记之。</summary></entry><entry><title type="html">AWS 静态网站“完美”搭建方案</title><link href="https://www.nichenjie.com/programming/static-website-hosting-leveraging-amazon-aws/" rel="alternate" type="text/html" title="AWS 静态网站“完美”搭建方案" /><published>2019-11-16T14:08:49-05:00</published><updated>2019-11-16T14:08:49-05:00</updated><id>https://www.nichenjie.com/programming/static-website-hosting-leveraging-amazon-aws</id><content type="html" xml:base="https://www.nichenjie.com/programming/static-website-hosting-leveraging-amazon-aws/">&lt;p&gt;本文介绍了使用 AWS S3, CloudFront, Certificate Manager 以及 Route 53 的一种“完美”静态免费 SSL/HTTPS 网站部署方案。它的特点有安全，响应速度快，高可用（High availability），高可扩展性（High scalability）以及高数据可用性（Data availability）。除此之外还具备负载均衡（Load balancing），容灾（Disaster Recovery），内容分发（CDN / Content Delivery）的能力。&lt;/p&gt;

&lt;p&gt;感谢你点击并浏览本文，希望这篇文章/教程对你有所帮助。如果你不想听我 BB，可以直接跳转到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;部署教程&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&quot;注意&quot;&gt;注意&lt;/h2&gt;

&lt;p&gt;本文讨论的范畴仅仅是&lt;strong&gt;静态&lt;/strong&gt;网站（static website），例如 Jekyll, Hugo 等，换句话说网站只包含静态内容（html, css, js）。如果你在寻找像 WordPress 那种有 PHP 后端且有数据库连接的动态网站部署方案，那么抱歉，本文讨论的方案并不适合你，动态网站的搭建一般需要 AWS EC2 以及/或 RDS 服务。&lt;/p&gt;

&lt;h2 id=&quot;博客配置详情&quot;&gt;博客配置详情&lt;/h2&gt;

&lt;p&gt;本文会以&lt;a href=&quot;https://github.com/chenjie/www.nichenjie.com&quot;&gt;此 Jekyll 博客&lt;/a&gt;的搭建和部署为例，你可以随便点击页面上的链接🔗来测试此方案的效果，具体详细参数/说明：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Ruby: 2.6.5
Jekyll: 3.5
AWS S3 Bucket Region: Canada (Central)
域名托管：已从 GoDaddy 转到 AWS Route 53 ($12)
SSL 证书：AWS Certificate Manager
CDN: AWS CloudFront ALL Edge Locations （使用全球所有边缘服务器）
CI: Travis CI （包含从自动化测试，搭建到部署）
SCM: Git(Hub)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;部署方案讨论&quot;&gt;部署方案讨论&lt;/h2&gt;

&lt;p&gt;为了控制本文的篇幅长度，关于不同网站部署方案的讨论，请移步至&lt;a href=&quot;/programming/ways-to-deploy-a-website/&quot;&gt;这篇文章&lt;/a&gt;。&lt;/p&gt;

&lt;h2 id=&quot;动机&quot;&gt;动机&lt;/h2&gt;

&lt;p&gt;我最近一直在研究 AWS 相关服务，目的有两个，一个是帮 G 部署可以横向自由扩展（has horizontal scalability）的 Moodle，另一个是将其应用到工作上，因为 Crowdmark 的生产环境也是部署在 AWS 上的。最开始的时候这个博客是部署在免费的 GitHub Pages 上，它有免费的 SSL 证书，用 Travis CI 部署起来也相当方便，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt; deployment code snippet 如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;deploy:
- provider: pages
  skip-cleanup: true
  github-token: &quot;$GITHUB_TOKEN&quot;
  keep-history: true
  on:
    branch: master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;但是开发后发现 GH Pages 不支持其他自定义主题，比如这个博客正在使用的 &lt;a href=&quot;https://mademistakes.com/work/minimal-mistakes-jekyll-theme/&quot;&gt;Minimal Mistakes&lt;/a&gt;，正巧的是当时阿里云给我的学生特惠批下来了，于是乎就开始着手把博客部署到 ECS (等同于 AWS 中的 EC2) 上。所以在好一段时间里，我的网站都是部署在阿里云美西硅谷的 ECS 上的。因为博客是静态编译的，所以迁移工程相对简单，只需要搞定一点 Ops 的东西就 ok 了，完整 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt; 设置如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;language: ruby
rvm:
- 2.4.1
addons:
  apt:
    packages:
    - libcurl4-openssl-dev
cache: bundler
before_install:
- sudo update-ca-certificates
install:
- bundle install
before_script:
- chmod +x ./script/cibuild
script: &quot;./script/cibuild&quot;
branches:
  only:
  - master
env:
  global:
  - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
  - JEKYLL_ENV=production
sudo: false
before_deploy:
- openssl aes-256-cbc -K $encrypted_209f5601644c_key -iv $encrypted_209f5601644c_iv
  -in deploy_rsa.enc -out deploy_rsa -d
- eval &quot;$(ssh-agent -s)&quot;
- chmod 600 ./deploy\_rsa
- ssh-add ./deploy\_rsa
- echo -e &quot;Host $DEPLOY_HOST\n\tPort $DEPLOY_HOST_SSH_PORT\n\tStrictHostKeyChecking no\n&quot; &amp;gt;&amp;gt; ~/.ssh/config
deploy:
- provider: script
  skip_cleanup: true
  script: rsync -rqz --delete-after _site/ $DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_DIRECTORY
  on:
    branch: master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里我稍微解释一下，第一步我在 ECS 上装好了 nginx，然后配置了虚拟主机，因为我这台服务器上还挂了别的网站。然后我选择了使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsync&lt;/code&gt; 部署静态文件，顾名思义 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsync&lt;/code&gt; 可以帮你同步两个文件夹，这就省去了我先删除，然后再 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scp&lt;/code&gt; 的过程。上面 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt; 中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_deploy&lt;/code&gt; 部分都在 set up ssh key，这样的话每次部署就不需要输入密码了。&lt;/p&gt;

&lt;p&gt;每次编译、检查加部署大约需要2分钟的时间，其实我对这个时间还是挺满意的，可是迁移完之后国内用户浏览的体验并没有得到很大的提升，可能是因为服务器在美西的关系，然后用的是学生乞丐版套餐。我后来尝试加了个 Cloudflare 免费的 CDN，效果甚微（PS. Cloudflare CDN 和别家的 CDN 有些不同，它需要你改域名的 nameserver），这个结果意料之中把，毕竟天下没有免费的午餐，一番折腾过后果断花了 12 两银子把域名从 GoDaddy 转到了 AWS Route 53。&lt;/p&gt;

&lt;h2 id=&quot;部署教程&quot;&gt;部署教程&lt;/h2&gt;

&lt;h3 id=&quot;step-1-创建并配置-s3-桶&quot;&gt;Step 1. 创建并配置 S3 桶&lt;/h3&gt;

&lt;p&gt;如果你想让 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.nichenjie.com&lt;/code&gt; 跳转到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nichenjie.com&lt;/code&gt;，那么就跟我一样创建两个 Bucket，分别命名为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.nichenjie.com&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nichenjie.com&lt;/code&gt;，如图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/11/s3-buckets.png&quot; alt=&quot;S3 Buckets&quot; /&gt;&lt;/p&gt;

&lt;p&gt;记得将两个桶的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Block all public access&lt;/code&gt; 设置为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Off&lt;/code&gt;，然后都打开 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Static website hosting&lt;/code&gt;，将其中一个桶设置跳转到主网站桶，如果你不需要跳转的话，那么这里创建一个桶就够了，后面把 CloudFront distribution 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CNAME&lt;/code&gt; 设置为两个。&lt;strong&gt;重要：&lt;/strong&gt;记住主桶 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Static website hosting&lt;/code&gt; 中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Endpoint&lt;/code&gt; URL，我这里是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://nichenjie.com.s3-website.ca-central-1.amazonaws.com&lt;/code&gt;，后面会使用到。&lt;/p&gt;

&lt;h3 id=&quot;step-2-配置-cloudfront-cdn&quot;&gt;Step 2. 配置 CloudFront CDN&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;重要：&lt;/strong&gt;Origin Domain Name 不能在下拉菜单中选择！那样有可能会不支持 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https&lt;/code&gt;，或出现权限问题。这个地方需要输入上面那个 S3 中带 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.s3-website.&lt;/code&gt; 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Endpoint&lt;/code&gt;，例如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://nichenjie.com.s3-website.ca-central-1.amazonaws.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;重要：&lt;/strong&gt;Default Root Object 需要设为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;如果你上面只创建了一个桶，那么这里只需要创建一个 Distribution，然后它的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CNAME&lt;/code&gt; 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.nichenjie.com&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nichenjie.com&lt;/code&gt;。如果你跟我一样是两个桶的话，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CNAME&lt;/code&gt; 分别指向两个桶。使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CNAME&lt;/code&gt; 需要开启 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https&lt;/code&gt; 协议，你可以到 AWS Certificate Manager (ACM) 中申请免费的 SSL 证书，申请成功后在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Custom SSL Certificate&lt;/code&gt; 中选择相应证书即可。小技巧：SSL Certificate 可以添加多个域名，也可以用泛域名，例如我申请的证书涵盖了 apex domain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nichenjie.com&lt;/code&gt; 以及所有的子域名 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*.nichenjie.com&lt;/code&gt;，这样今后在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ELB&lt;/code&gt; 或者其他 CloudFront Distro 中也可以使用该证书，只要有它们有同样的根域名。&lt;/p&gt;

&lt;p&gt;Cache Behavior Settings 这边我推荐 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Redirect HTTP to HTTPS&lt;/code&gt;，打开 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Compress Objects Automatically&lt;/code&gt;，也就是说在传输之前 CF 会用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gzip&lt;/code&gt; 的方式压缩内容。&lt;/p&gt;

&lt;p&gt;具体配置详情，可以参考截图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/11/cf1.png&quot; alt=&quot;CloudFront General&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/11/cf2.png&quot; alt=&quot;CloudFront Origins&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/11/cf3.png&quot; alt=&quot;CloudFront Cache Behavior Settings 1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/11/cf4.png&quot; alt=&quot;CloudFront Cache Behavior Settings 2&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;step-3-还有一丢丢配置&quot;&gt;Step 3. 还有一丢丢配置&lt;/h3&gt;

&lt;p&gt;在主桶的 Bucket Policy 中加入如下代码：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
    &quot;Sid&quot;: &quot;2&quot;,
    &quot;Effect&quot;: &quot;Allow&quot;,
    &quot;Principal&quot;: &quot;*&quot;,
    &quot;Action&quot;: &quot;s3:GetObject&quot;,
    &quot;Resource&quot;: &quot;arn:aws:s3:::&amp;lt;你主桶的名字&amp;gt;/*&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;加了这段规则之后，你的主桶上就会出现 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Public&lt;/code&gt; 的标签。&lt;/p&gt;

&lt;p&gt;最后，我们需要在 Route 53 中添加 A记录 ALIAS 规则分别把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.nichenjie.com&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nichenjie.com&lt;/code&gt; 指向相对应的 CloudFront Distribution 即可，配置如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/11/r53_1.png&quot; alt=&quot;Apex domain name&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/11/r53_2.png&quot; alt=&quot;Subdomain name&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;step-4-travis-ci-自动部署&quot;&gt;Step 4. Travis CI 自动部署&lt;/h3&gt;

&lt;p&gt;这里可以参考我现在的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt; 配置，你可以在&lt;a href=&quot;https://github.com/chenjie/www.nichenjie.com/blob/master/.travis.yml&quot;&gt;这里&lt;/a&gt;找到，主要就是以下代码：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;before_deploy:
  - pip install --user awscli
  - export PATH=$PATH:$HOME/.local/bin
  - chmod +x script/empty-bucket.sh
  - script/empty-bucket.sh

deploy:
  - provider: s3
    access_key_id: &quot;$AWS_ACCESS_KEY_ID&quot;
    secret_access_key: &quot;$AWS_SECRET_ACCESS_KEY&quot;
    bucket: nichenjie.com
    skip_cleanup: true
    region: ca-central-1
    local_dir: _site
    cache_control: &quot;public, max-age=3600&quot;

after_deploy:
  - chmod +x script/invalidate-cache.sh
  - script/invalidate-cache.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;script/empty-bucket.sh:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/usr/bin/env bash
set -e # halt script on error

aws s3 rm s3://nichenjie.com --recursive --region ca-central-1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;script/invalidate-cache.sh:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/usr/bin/env bash
set -e # halt script on error

aws cloudfront create-invalidation --distribution-id E3U0JG8KK5Y4U6 --paths &quot;/*&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;简单解释一下，每次我 Push 代码到我的 GitHub Repo 会 trigger CI，CI 用 Jekyll 编译我的静态博客，然后在检查完我博客中所有链接都没 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;404&lt;/code&gt; 后执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_deploy&lt;/code&gt;，这步包括安装 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws-cli&lt;/code&gt; 和清空主桶。在这些都执行完之后，deploy script 会被 trigger，将所有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_site&lt;/code&gt; 文件夹底下的文件都上传至我主桶的根目录，并且将 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metadata&lt;/code&gt; 中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cache_control&lt;/code&gt; 设定为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public, max-age=3600&lt;/code&gt;，缓存有助于降低 CF outgoing 流量以及 s3 的请求（PUT, GET等）费用。最后的最后，做一次 CF cache invalidation 来把更新数据 propagate 到所有全球的边缘（edge）服务器中。&lt;/p&gt;

&lt;h2 id=&quot;大功告成&quot;&gt;大功告成&lt;/h2&gt;

&lt;p&gt;Enjoy! 如果你有什么问题，欢迎在评论区中让我知道，你也可以直接在我的 &lt;a href=&quot;https://github.com/chenjie/www.nichenjie.com&quot;&gt;GitHub Repo&lt;/a&gt; 中 Open Issue 或者 PR. Thanks for reading till the end!&lt;/p&gt;</content><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><category term="programming" /><category term="aws" /><category term="s3" /><category term="cloudfront" /><summary type="html">本文介绍了使用 AWS S3, CloudFront, Certificate Manager 以及 Route 53 的一种“完美”静态免费 SSL/HTTPS 网站部署方案。它的特点有安全，响应速度快，高可用（High availability），高可扩展性（High scalability）以及高数据可用性（Data availability）。除此之外还具备负载均衡（Load balancing），容灾（Disaster Recovery），内容分发（CDN / Content Delivery）的能力。</summary></entry><entry><title type="html">关于部署网站的那些事儿</title><link href="https://www.nichenjie.com/programming/ways-to-deploy-a-website/" rel="alternate" type="text/html" title="关于部署网站的那些事儿" /><published>2019-11-14T00:00:00-05:00</published><updated>2019-11-15T23:27:00-05:00</updated><id>https://www.nichenjie.com/programming/ways-to-deploy-a-website</id><content type="html" xml:base="https://www.nichenjie.com/programming/ways-to-deploy-a-website/">&lt;p&gt;我还依稀记得，我第一次捣腾网站大致是在我小学五年级的时候。那时我小叔喜欢用自己家里的电脑开网站，搭建一些私服让别人玩，卖点游戏里的装备，以此赚点小钱。当时我对这个一窍不通，我只喜欢玩游戏，每次去小叔家里的第一件事情就是以最快的速度抢过电脑的控制权，打开游戏，然后沉浸在游戏的虚拟世界里，无法自拔。所以经常会出现的一个问题就是我和小叔抢电脑，他要维护他的网站，我要打我的游戏。我想你们应该也猜到了，小叔自然会让着我，一脸拿我没办法的样子，把所有他要用的那些窗口最小化，然后千叮咛万嘱咐叫我千万别手滑关了其中任何一个。现在想起这段经历，我觉得那就是我理想中梦幻般的童年，可是你们别忘了，当时还有一个 BOSS 级别的角色，哦不，应该是两个，那就是爸妈。&lt;/p&gt;

&lt;p&gt;按照我爸妈的话来说，因为他们的存在，让我戒了网瘾，摆脱了“网瘾少年”的称号。可当时的我并不这么认为，包括现在的我也不这么认为，可能我是对的，也有可能这只是我的倔强罢了。Anyway, 一段 BB 之后让我们进入正题。&lt;/p&gt;

&lt;h2 id=&quot;关键词解释老鸟可以忽略&quot;&gt;关键词解释（老鸟可以忽略）&lt;/h2&gt;

&lt;p&gt;首先我们要定义什么是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;部署&lt;/code&gt;网站，它跟开发/搭建网站不同，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;部署&lt;/code&gt;是将只有本地能够访问的网站传到服务器供其他在互联网上的人访问，所以&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;部署&lt;/code&gt;网站的前提是你必须得已经有一个写好的网站。如果这边我没有解释清楚的话，欢迎在文末评论区提问。&lt;/p&gt;

&lt;h2 id=&quot;一些部署网站的方式&quot;&gt;一些部署网站的方式&lt;/h2&gt;

&lt;p&gt;这边以我的过往个人经验结合公司网站使用的架构，我总结了一些部署网站的方式，后面我会讨论他们适合的用途和利弊。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;家庭&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DSL&lt;/code&gt;/光纤路由端口转发（Port forwarding）或开启&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DMZ主机&lt;/code&gt;：
    &lt;ol&gt;
      &lt;li&gt;部署在家里PC/台式机上&lt;/li&gt;
      &lt;li&gt;部署在软路由或其他低功耗设备上，如树莓派&lt;/li&gt;
      &lt;li&gt;部署在家庭中的独立企业级服务器/虚拟机内（如 VMware ESXi, Proxmox 等）&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;虚拟主机&lt;/li&gt;
  &lt;li&gt;静态网站托管（如 GitHub Page 等）&lt;/li&gt;
  &lt;li&gt;对象储存作为静态网站服务器（如 AWS S3, Azure Storage 等）&lt;/li&gt;
  &lt;li&gt;VPS（如搬瓦工，还有别的叫不上名字的小🐥等）&lt;/li&gt;
  &lt;li&gt;云服务器（如 AWS EC2, Azure Virtual Machines 等）&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;难易度排序越小越容易&quot;&gt;难易度排序（越小越容易）&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;如果你对计算机一窍不通（只会开机，点鼠标）：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2 &amp;lt; 4 &amp;lt; 3 &amp;lt; 5 &amp;lt; 6 &amp;lt; 1&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;如果你有一定的编程基础（会使用版本控制工具）：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3 &amp;lt; 4 &amp;lt; 2 &amp;lt; 5 &amp;lt; 6 &amp;lt; 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;不同部署方式的优劣分析&quot;&gt;不同部署方式的优劣分析&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;此法只适合用来测试，Proof of concept，或做一些简单的 Home automation，不适合在生产环境（Production environment）使用。它们共同的一个很大的弊端就是网络，一般家庭网络供应商（以下简称 ISP）不会提供固定的外网 IPv4 地址，具体原因请参考&lt;a href=&quot;https://en.wikipedia.org/wiki/IPv4_address_exhaustion&quot;&gt;维基百科&lt;/a&gt;，一般情况下都是动态 IP 地址，所谓动态 IP 就是每次 Modem 重启都有可能导致公网 IP 地址改变。当然，你不希望让用户通过 IP 地址来访问你的网站，那么你就需要 DDNS 服务来动态解析域名。说到这里，你应该发现了这个方法开始变得复杂起来，可是弊端还远不止这个。一般家庭小水管只有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10-20 Mbps&lt;/code&gt; 的上传（outgoing）速度，如果你的网站里包含很多图片或视频，那这也将是一个瓶颈。说完了网络，我们再来分别说说以下每一类各自的劣势。
    &lt;ol&gt;
      &lt;li&gt;7x24 小时一直将电脑开着做 Web server 非常耗电，电费有可能都超过了租用某些小主机的钱，而且家庭电脑中的硬件并不是为 7x24 小时连续工作而设计，最容易损坏的部件就是硬盘，还有散热和灰尘也是电脑的两大杀手。&lt;/li&gt;
      &lt;li&gt;Single board computer（比如树莓派，香橙派）确实很容易上手，而且用途很广，但是他们计算性能低，这导致了它们无法同时处理很多 concurrent network requests，导致多用户访问时的卡顿。&lt;/li&gt;
      &lt;li&gt;企业级服务器价格昂贵，洋垃圾则需要投入很长时间折腾硬件，稳定性也值得商榷。现在很多弹性服务器的存在正是为解决这个问题而生的，所以如果你不想在前期投入如此大的成本，那么可以移步其他部署方式。If you know what you are doing, 那么我觉得你也很有必要去申请一个静态 IP。你可以在服务器宿主机内安装 ESXi 或者 Proxmox，然后开很多虚拟机，可玩性很高。对了，服务器散热和噪音是不容忽视的，各项冗余也很有必要，这里就不再赘述了。&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;购买虚拟主机就相当于租用了一台 VPS 内的部分资源，它一般可以通过 Web UI 控制所有网站修改操作，这降低了部署网站的门槛。其实虚拟主机已经早已过气，因为 VPS 的价格甚至比它还要低，也就是说现在租一套房的价格比租一间房低，那么你还会选择租一间房吗？虚拟主机一般都是限制带宽和磁盘空间的，如果想要升级，那么它没有云服务器那样的弹性和灵活度。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;如果你会使用 Git 那么静态网站托管就再简单不过了，拿 GitHub Pages 举例，只要你把写好的/生成的静态网站源码添加并上传到 GitHub 上，新建一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gh-pages&lt;/code&gt; 分支，push 上去即可，参考&lt;a href=&quot;https://help.github.com/en/github/working-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site&quot;&gt;这里&lt;/a&gt;。这个方式的好处就是完全免费，Git 可以帮助你控制版本，如果你想要回到之前的任何一个版本，都是可以实现的。这个方法的弊端则是，只支持静态网站，大厂对国内用户并不友好，因为大多数服务器都在海外，用户浏览体验较差。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;在我看来，在对象储存中部署静态网站是现在最“完美”的静态网站部署方式，这个博客就是部署在 AWS S3 中的，结合其他 AWS 的服务使得这个博客有比较好的浏览体验。我之后会出一篇文章，教大家如何用 S3 结合 CDN 优化用户浏览博客的体验。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;VPS 是弹性为0️⃣的云服务器，除了这点，VPS 和云服务器的主要区别在于云服务器可以和别的 VPC 内的资源“互动”，比如和数据库，redis 缓存服务器等等，而 VPS 就是单独孤零零的一个 remote 虚拟机，就相当于在远程 24 小时运行的 Linux 电脑。部署网站的话则需要对 Linux DevOps 较为熟悉，如果从零开始学起，learning curve 会比较陡峭。哦对了，VPS 的优势一般在于带宽比较便宜，有些自带每月 1TB 流量。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;云服务器顾名思义，在“云”里。“云”以第一层含义是云端或者远程，第二层则是“云”和“云”之间很近，也就是说，打个比方虚拟机和数据库之间都在同一个数据中心里，这样虚拟机访问数据库的延迟就会降低。第三层含义则是 VPC，虚拟私人网络，它是基于 SDN 技术之上的，以后有时间也会和大家分享一些 SDN 相关内容，它非常强大，在我看来当下 AWS 如此成功的一个重要原因就在于它的 VPC。部署网站方面和 VPS 一样，需要 Ops 技术，可能比 VPS 更多。还有一个弊端就是流量费较高。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;总结&quot;&gt;总结&lt;/h2&gt;

&lt;p&gt;综上，部署网站的方式多种多样，具体选择哪个 depends on 你的需求，具体问题具体分析。好吧，这个总结就跟废话一样，下期出干货😁如果你喜欢我的文章，请在评论区留言让我知道，谢谢你啦！&lt;/p&gt;</content><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><category term="programming" /><category term="日常小记" /><summary type="html">我还依稀记得，我第一次捣腾网站大致是在我小学五年级的时候。那时我小叔喜欢用自己家里的电脑开网站，搭建一些私服让别人玩，卖点游戏里的装备，以此赚点小钱。当时我对这个一窍不通，我只喜欢玩游戏，每次去小叔家里的第一件事情就是以最快的速度抢过电脑的控制权，打开游戏，然后沉浸在游戏的虚拟世界里，无法自拔。所以经常会出现的一个问题就是我和小叔抢电脑，他要维护他的网站，我要打我的游戏。我想你们应该也猜到了，小叔自然会让着我，一脸拿我没办法的样子，把所有他要用的那些窗口最小化，然后千叮咛万嘱咐叫我千万别手滑关了其中任何一个。现在想起这段经历，我觉得那就是我理想中梦幻般的童年，可是你们别忘了，当时还有一个 BOSS 级别的角色，哦不，应该是两个，那就是爸妈。</summary></entry><entry><title type="html">🍐编程 (Pair Programming)</title><link href="https://www.nichenjie.com/diary/pair-coding/" rel="alternate" type="text/html" title="🍐编程 (Pair Programming)" /><published>2019-11-13T16:35:49-05:00</published><updated>2019-11-13T16:35:49-05:00</updated><id>https://www.nichenjie.com/diary/pair-coding</id><content type="html" xml:base="https://www.nichenjie.com/diary/pair-coding/">&lt;p&gt;今天和 J pair 了7个小时，感觉好累。J 傍晚送我到车站，我现在在回程的 Go Train 上。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/11/inside-waiting-go.jpg&quot; alt=&quot;车站内等火车&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/11/go-train-platform.jpg&quot; alt=&quot;站台的 Go Train&quot; /&gt;&lt;/p&gt;

&lt;p&gt;如果你从未结对编程过，那结对编程绝对要比你想象的更加 intense，消耗脑力。记得第一次去和 J pair，在回程的火车上我都睡着了，差点错过站。几次🍐下来渐渐感觉好些了，看 J 手指在键盘上飞舞，不得不承认我离它的生产效率还差得很远。&lt;/p&gt;

&lt;p&gt;继续加油吧，总有一天我会达到它的水平，只是不知道那需要多久。&lt;/p&gt;</content><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><category term="diary" /><category term="日常小记" /><summary type="html">今天和 J pair 了7个小时，感觉好累。J 傍晚送我到车站，我现在在回程的 Go Train 上。</summary></entry><entry><title type="html">生日的前一天</title><link href="https://www.nichenjie.com/diary/the-day-before-my-birthday/" rel="alternate" type="text/html" title="生日的前一天" /><published>2019-11-13T00:00:00-05:00</published><updated>2019-11-13T09:35:00-05:00</updated><id>https://www.nichenjie.com/diary/the-day-before-my-birthday</id><content type="html" xml:base="https://www.nichenjie.com/diary/the-day-before-my-birthday/">&lt;p&gt;一场大雪把多伦多正式带入了冬季，今年的第一场大雪来得比以往提前了半个多月，J说它的大蒜还没下地就已经要被大雪掩埋。&lt;/p&gt;

&lt;p&gt;我现在坐在驶向 Aldershot 的 Go Train 上，火车因为大雪 delay 了十多分钟，that’s toronto transit system，脾气就跟女人一样多变。今天去J的家里讨论项目，一起工作。还记得几个月前我第一次坐 Go Train，心里别提是有多兴奋和激动，然而现在已经没有了那份兴奋劲儿，码字的同时心里暗暗抱怨那些不遵守 Quiet Zone 的人。&lt;/p&gt;

&lt;p&gt;想到明天要过生日，我突然兴奋了起来，似乎我感觉已经好久没有过生日了，感谢我的女朋友 KiKi 明天从米西赶来给我过生日，第二天她又要早起坐 Go Bus commute 一个多小时去上班。她说给我买了生日蛋糕🍰，我让她自己多吃点，因为我知道她最爱吃蛋糕了。她的这份心意让我感动，这远比蛋糕本身的价值以及味道要重要的多。&lt;/p&gt;

&lt;p&gt;工作就跟往常一样无聊，生活还要继续，在生活中寻找乐趣，身边的人和加拿大的环境总能给我不一样的惊喜。&lt;/p&gt;</content><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><category term="diary" /><category term="日常小记" /><summary type="html">一场大雪把多伦多正式带入了冬季，今年的第一场大雪来得比以往提前了半个多月，J说它的大蒜还没下地就已经要被大雪掩埋。</summary></entry><entry><title type="html">大学和女友同课是什么体验？</title><link href="https://www.nichenjie.com/study/mat344-study-with-my-girlfriend-in-university/" rel="alternate" type="text/html" title="大学和女友同课是什么体验？" /><published>2019-04-18T00:00:00-04:00</published><updated>2019-11-11T00:00:00-05:00</updated><id>https://www.nichenjie.com/study/mat344-study-with-my-girlfriend-in-university</id><content type="html" xml:base="https://www.nichenjie.com/study/mat344-study-with-my-girlfriend-in-university/">&lt;p&gt;在多大学习的最后一学期有幸和 KiKi 女神同课 MAT344 (不是 cs 有点遗憾)，这也是我辅修数学的收官课。这学期 MAT344 的难度较往年提升了不少，Midterm 的画风跟水课完全不沾边。每周 lecture 学生的平均出勤率少于 50%，所以也不难想象 midterm 是有多惨烈了，部分愣头青还去了 math dept 投诉……&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/mdres/posts/2019/04/compaints.png&quot; alt=&quot;compaints&quot; /&gt;&lt;/p&gt;

&lt;p&gt;KiKi 女神在 midterm 之前的出勤率低于 50%，而之后的出勤率可谓超神，达到了 99.99%，你猜她唯一没来的那次是因为什么？（睡过了，逃。。）你们再猜，为什么她 midterm 前后出勤率竟有如此大的差距？(Hint: 不是因为 midterm 考砸了)&lt;/p&gt;

&lt;p&gt;言归正传：MAT344 这学期的两个 instructor 都非常认真负责，其中 Zachary Wolske 是我 223/224 的 TA，135 的 course instructor (TA coordinator)，就在这样的大环境下，KiKi 和我 midterm 之后奋起直追，希望最后能收获我们满意的结果（final还没出分）。&lt;/p&gt;

&lt;p&gt;【2019年11月11日更新】 Final 其实早就出分了，我家这个小仙女不让我说分数，她说谈分伤感情 😛&lt;/p&gt;

&lt;h2 id=&quot;struggles-and-blocks&quot;&gt;Struggles and blocks&lt;/h2&gt;

&lt;h3 id=&quot;1-combination-property&quot;&gt;1. Combination Property&lt;/h3&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
\binom{n}{k} = \binom{n-1}{k-1} + \binom{n-1}{k}
$$&lt;/div&gt;

&lt;h3 id=&quot;2-binomial-theorem&quot;&gt;2. Binomial Theorem&lt;/h3&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
(x+y)^n = \sum_{k=0}^{n} \binom{n}{k} x^{n-k} y^k
$$&lt;/div&gt;

&lt;h3 id=&quot;3-multinomial-coefficient&quot;&gt;3. Multinomial Coefficient&lt;/h3&gt;

&lt;p&gt;How many distinct rearrangements can be made using all of the letters of “BOOKKEEPING”?&lt;/p&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
\binom{11}{2,2,2,1,1,1,1,1} = \frac{11!}{2! \cdot 2! \cdot 2!}
$$&lt;/div&gt;

&lt;h3 id=&quot;4-recursive-formula&quot;&gt;4. Recursive Formula&lt;/h3&gt;

&lt;p&gt;Give a recursive formula for the function $g(n)$ that counts the number of ternary strings of length $n$ that do not contain $2002$ as a substring.&lt;/p&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
g(n) = 3g(n-1) - g(n-3) + 2g(n-4)
$$&lt;/div&gt;

&lt;h3 id=&quot;5-another-combination-property&quot;&gt;5. Another Combination Property&lt;/h3&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
\binom{n}{0} + \binom{n+1}{1} + ... + \binom{n+k}{k} = \binom{n+k+1}{k}
$$&lt;/div&gt;

&lt;h3 id=&quot;6-degree-sequence&quot;&gt;6. Degree Sequence&lt;/h3&gt;

&lt;p&gt;A &lt;em&gt;degree sequence&lt;/em&gt; of a graph is a list of the degrees of each vertex. Consider the following lists of six positive integers:&lt;/p&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
A = [3,2,2,1,1,1] \\
    B = [5,5,5,4,3,2] \\
    C = [5,5,4,4,3,3] \\
    D = [4,4,2,2,2,2] \\
    E = [3,3,3,3,3,3]
$$&lt;/div&gt;

&lt;p&gt;Determine which sequence(s):&lt;/p&gt;

&lt;p&gt;(a) cannot be the degree sequence of a graph:&lt;br /&gt;
&lt;strong&gt;Answer&lt;/strong&gt;: $B$ cannot be the degree sequence of any graph, because the first three vertices are connected to every other vertex in the graph – in particular, vertex 6. This means that vertex 6 should have degree at least $3$, which it doesn’t.&lt;/p&gt;

&lt;p&gt;(b) must be the degree sequence of an eulerian graph:&lt;br /&gt;
&lt;strong&gt;Answer&lt;/strong&gt;: $D$ must be the degree sequence of a Eulerian graph because every vertex has even degree.&lt;/p&gt;

&lt;p&gt;(c) must be the degree sequence of a hamiltonian graph:&lt;br /&gt;
&lt;strong&gt;Answer&lt;/strong&gt;: Degree sequences $C$ and $E$ must be that of a Hamiltonian graph because this graph has six vertices and every vertex has degree at least $\frac{6}{2}$. By Dirac’s theorem, it must have a Hamiltonian circuit.&lt;/p&gt;

&lt;p&gt;(d) could be the degree sequence of a tree:&lt;br /&gt;
&lt;strong&gt;Answer&lt;/strong&gt;: $A$ could be the degree sequence of a tree because the sum of the degrees is equal to $10$, so the number of edges is $5$, which is equal to the number of vertices minus $1$.&lt;/p&gt;

&lt;p&gt;(e) could be the degree sequence of a graph, but cannot be a planar graph:&lt;br /&gt;
&lt;strong&gt;Answer&lt;/strong&gt;: None of the graphs satisfy this condition.&lt;/p&gt;

&lt;h3 id=&quot;7-generating-functions&quot;&gt;7. Generating functions&lt;/h3&gt;

&lt;p&gt;Find the coefficient of $x^n$ in each of the generating functions below.&lt;/p&gt;

&lt;p&gt;(a) $\frac{1}{1+4x}$&lt;/p&gt;

&lt;p&gt;Generating function:&lt;/p&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
\frac{1}{1-(-4x)} = 1 - 4x + 16x^2 - 64x^3 + ... = \sum_{n=0}^{\infty} (-4x)^n
$$&lt;/div&gt;

&lt;p&gt;The coefficient of $x^n$ is&lt;/p&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
(-4)^n
$$&lt;/div&gt;

&lt;p&gt;(b) $\frac{1-x^{14}}{1-x}$&lt;/p&gt;

&lt;p&gt;Generating function:&lt;/p&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
\sum_{n=0}^{13} x^n = 1 + x + x^2 + ... + x^{13}
$$&lt;/div&gt;

&lt;p&gt;Therefore, the sequence corresponding to this generating function is&lt;/p&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
a_n = 
    \begin{cases} 
        1, &amp; 0 \le n \le 13\\
        0, &amp; n \ge 14
    \end{cases}
$$&lt;/div&gt;

&lt;p&gt;(c) $(1+x^3) \cdot (x^3 + x^4 + x^5 + …) \cdot (1 + x^5 + x^{10} + …)$&lt;/p&gt;

&lt;p&gt;The general expression of the coefficient ($a_n$) corresponding to $x^n$ is&lt;/p&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
a_n = 
    \begin{cases} 
        0, &amp; 0 \le n \le 2\\
        \lfloor \frac{n - 3}{5} \rfloor + \lfloor \frac{n - 6}{5} \rfloor + 2, &amp; n \ge 3
    \end{cases}
$$&lt;/div&gt;

&lt;h3 id=&quot;8-recurrence-relation&quot;&gt;8. Recurrence Relation&lt;/h3&gt;

&lt;p&gt;Solve the following linear, homogeneous, degree-2 recurrence relation:&lt;/p&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
b_n = 3b_{n-1} + 3b_{n-2}
$$&lt;/div&gt;

&lt;p&gt;where $b_1 = 4$ and $b_2 = 15$.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;kdmath&quot;&gt;$$
b_n = \left(\frac{1}{2} - \frac{5}{2\sqrt{21}}\right) \cdot \left(\frac{3-\sqrt{21}}{2}\right)^n + \left(\frac{1}{2} + \frac{5}{2\sqrt{21}}\right) \cdot \left(\frac{3+\sqrt{21}}{2}\right)^n
$$&lt;/div&gt;

&lt;p&gt;where $n \ge 0$ and $n \in \Z$.&lt;/p&gt;</content><author><name>倪晨杰 Chenjie Ni</name><email>hi@nichenjie.com</email></author><category term="study" /><category term="uoft" /><category term="mat344" /><summary type="html">在多大学习的最后一学期有幸和 KiKi 女神同课 MAT344 (不是 cs 有点遗憾)，这也是我辅修数学的收官课。这学期 MAT344 的难度较往年提升了不少，Midterm 的画风跟水课完全不沾边。每周 lecture 学生的平均出勤率少于 50%，所以也不难想象 midterm 是有多惨烈了，部分愣头青还去了 math dept 投诉……</summary></entry></feed>