<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
<channel>
<atom:link href="https://www.timochan.cn/feed" rel="self" type="application/rss+xml"/>
<title>TimochanのBlog</title>
<link>https://www.timochan.cn</link>
<description>Let&apos;s start learning</description>
<language>zh-CN</language>
<copyright>© timochan </copyright>
<pubDate>Sun, 15 Mar 2026 15:54:27 GMT</pubDate>
<generator>Mix Space CMS (https://github.com/mx-space)</generator>
<docs>https://mx-space.js.org</docs>
<image>
    <url>https://www.timochan.cn/api/objects/icon/9s6tbcvax674yv2m88.jpg</url>
    <title>TimochanのBlog</title>
    <link>https://www.timochan.cn</link>
</image>
<item>
    <title>从一加到小米：从「TEE 损坏」到「TEE 自身完备」</title>
    <link>https://www.timochan.cn/posts/any_pen/from_oneplus_to_xiaomi</link>
    <pubDate>Sun, 15 Mar 2026 06:00:12 GMT</pubDate>
    <description>长官，我是小米人

原本我其实更偏向一加。

原因很简单：一加的 BootLoader 解锁一直相对</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://www.timochan.cn/posts/any_pen/from_oneplus_to_xiaomi'>https://www.timochan.cn/posts/any_pen/from_oneplus_to_xiaomi</a></blockquote>
      <blockquote>
<p>长官，我是小米人</p>
</blockquote>
<p>原本我其实更偏向一加。</p>
<p>原因很简单：<strong>一加的 BootLoader 解锁一直相对省心</strong>。对我这种本来就喜欢折腾系统的人来说，设备能不能顺利解锁，几乎会直接影响购买意愿。</p>
<p>反过来看，小米这几年在解锁上的门槛确实高了不少：</p>
<ul>
<li>要申请</li>
<li>要等待</li>
<li>甚至还要小米高考</li>
</ul>
<p>对只想折腾系统的人来说，这套流程多少有点劝退。所以一开始，我其实是打算继续买一加的。</p>
<p>结果后来情况变了。</p>
<p>小米这边突然爆出了新的解锁漏洞，相当于把原本最麻烦的门槛直接绕过去了。再加上这一代机器<strong>价格确实很香</strong>，3899 拿下旗舰机，几个因素叠加下来，我最后还是入手了 <strong>Xiaomi 17 标准版</strong> 16+512。</p>
<p>关于漏洞细节，可以去看 <a href="https://www.bilibili.com/video/BV1CDP9zQEJS">3.8 解锁节漏洞解析深度解析小米 8e5 系列漏洞解锁 BL 原理</a>。</p>
<h2>准备动作</h2>
<p>我最后选的是酷安上 <strong>白羊唐黎明</strong> 的官改 ROM，版本是：<strong>3.0.301.0</strong></p>
<p>这个包并不是直接拿来刷就行，它需要配合指定的官方底包：<strong>3.0.44.0</strong></p>
<p>所以整套流程的第一步，不是直接梭哈官改，而是<strong>先把官方底包刷进去</strong>。</p>
<p>和一加类似，一加那边阿木大侠维护了一个一加 ROM 站，可以直接检索下载一加的 ROM，小米这边也有 ，可以快速检索 ROM。</p>
<ul>
<li><a href="https://xiaomirom.org">https://xiaomirom.org</a></li>
<li><a href="https://xiaomirom.com">https://xiaomirom.com</a></li>
</ul>
<p>刷机工具选择的是 <a href="https://xiaomiflashtool.com">MiFlash</a>，看起来足够简单？
MiFlash 本身是 Windows 下的线刷工具，常见做法就是搭配 <strong>Fastboot 固件</strong> 使用。它也自带一些驱动，正常情况下装好后就能直接识别设备。</p>
<p>不过这里有个我自己踩过的坑，必须单独提一下：</p>
<blockquote>
<p><strong>MiFlash 最好放在中文 Windows 环境下运行。</strong></p>
</blockquote>
<p>如果你用的是其他非 <code>ZH-CN</code> 的语言环境，可能会碰到一些莫名其妙的报错。表面上看像是驱动问题、路径问题，甚至像底包有问题，结果最后一排查，根源其实是环境。所以如果你想尽量少走弯路，<strong>直接在中文环境下操作</strong>会省事很多。当时我甚至都开始怀疑 mirom 下载的包有问题了。</p>
<h2>刷官方底包</h2>
<p>先把下载好的 <strong>Fastboot 线刷包</strong> 解压到任意目录。</p>
<p>然后让手机进入 <strong>BootLoader</strong>。</p>
<p>这一点我想刻意讲清楚，因为很多文章喜欢笼统地写“进入 Fastboot 模式”，但这个说法其实非常模糊，如果是一加转小米，更容易把人带偏。</p>
<p>在小米设备上：</p>
<pre><code class="language-bash">adb reboot bootloader</code></pre><p>如果不用命令，也可以关机后按住：<strong>音量下 + 电源键</strong> 进入 BootLoader 界面。</p>
<p>之所以要写得这么细，还有另一个原因：不同厂商对“Fastboot”这个词的使用场景并不一致。比如在一加上， Recovery / fastbootd 界面里本身也能刷 Fastboot 包，所以“Fastboot”这个词本来就不够精确，因为存在用户态的 Fastboot -&gt; Fastbootd，也存在解锁后的 BootLoader Fastboot。统一叫 BootLoader，反而最不会出歧义。

进入之后，打开 MiFlash，流程很标准：</p>
<ol>
<li>点击 <strong>Driver</strong> 安装驱动</li>
<li>点击 <strong>刷新设备</strong>，确认手机已经被识别</li>
<li>选择刚刚解压好的底包目录</li>
</ol>
<p>这里最关键的一步一定要记住：</p>
<div class="container banner error"><p>右下角选择「全部删除」，不要选「删除并回锁」</p>
</div><p>如果这里手滑回锁，会变得麻烦，你还得重新利用漏洞解锁，44 版本还好，还可以利用漏洞解锁。</p>
<p>不得不提 miflash 的默认选项真的有点大病。</p>
<div class="container banner warning"><p>这里还要额外提醒一个<strong>非常关键</strong>的点。
官改版本是 <strong>3.0.301.0</strong>，而这个版本对应的 <strong>Android 安全补丁级别是 2026-02-01</strong>。这个补丁已经<strong>修复了骁龙 8e5 的漏洞利用</strong>。也就是说： <strong>一旦你在这个版本上执行回锁，后面基本就没法再用这条漏洞路线重新解锁了。</strong></p>
</div><p>这不是简单的“麻烦一点”，而是真有可能直接把后路堵死。如果你真的想回锁了，出于保留退路的考虑，建议是走降级回锁这条路，永不更新，这样才还有继续解锁的机会，所以这一步千万不要心存侥幸。</p>
<p></p>
<p>确认没问题之后，点击 <strong>Flash</strong>，接下来耐心等它刷完即可。</p>
<h2>刷官改 ROM</h2>
<p>底包刷完后，先让手机正常开机。快速走完初始化流程，确认都没问题之后，再重新进入 <strong>BootLoader</strong>，把官改包解压出来。</p>
<p>如果包里附带驱动，那就先把驱动装一下。接着一般直接双击它自带的刷机脚本，剩下的就是等进度条跑完、手机自动重启。</p>
<p>到这里，官改 ROM 基本就刷好了。</p>
<p></p>
<h2>Root：我选择了SukiSU-Ultra</h2>
<p>官改包里其实自带了 KernelSU，但我没有沿用这一套。我选择的是 <strong>SukiSU-Ultra</strong>。  至于原因，其实非常朴素：主要是 <strong>SukiSU-Ultra 的图标好看</strong>，没别的。</p>
<p>我的做法也很直接：</p>
<ol>
<li>从官改包里拿出来 <code>init_boot.img</code> ，adb push 到手机里面</li>
<li>让 SukiSU-Ultra 对 init-boot 进行修补</li>
<li>把修补后的镜像刷回设备</li>
<li>直接切换到 <strong>SukiSU-Ultra</strong></li>
</ol>
<p>刷入命令是 </p>
<pre><code class="language-bash">adb reboot bootloader
fastboot flash init_boot_ab .\kernelsu_patched_20260314_152108.img</code></pre><p>Root 定下来之后，后面的模块环境就比较清晰了。<strong>Meta Module</strong> 用的是 <strong>Hybrid Mount</strong>。<br>这种东西平时不一定最显眼，但底层挂载方案其实会直接影响整体体验，所以我这里干脆一步到位，直接用了它。</p>
<h3>Play 完整性与环境处理：TEE 模拟器组合拳</h3>
<p>这一部分，我最后采用的组合是：</p>
<ul>
<li><strong>ZygiskNext</strong></li>
<li><strong>TEE Simulator</strong></li>
<li><strong>Integrity-Box</strong></li>
</ul>
<p>项目地址：</p>
<ul>
<li><strong>ZygiskNext</strong>：<a href="https://github.com/Dr-TSNG/ZygiskNext">https://github.com/Dr-TSNG/ZygiskNext</a></li>
<li><strong>Integrity-Box</strong>：<a href="https://github.com/MeowDump/Integrity-Box">https://github.com/MeowDump/Integrity-Box</a></li>
<li><strong>TEE Simulator</strong>：<a href="https://github.com/JingMatrix/TEESimulator">https://github.com/JingMatrix/TEESimulator</a></li>
</ul>
<h3>为什么不用 Tricky Store</h3>
<p>原因很简单：<strong>Tricky Store 现在已经闭源了</strong>。  对我来说，这就不再是最优选。</p>
<p>而且从 Integrity-Box 的项目说明来看，它本身的前置条件就是：</p>
<ul>
<li><strong>Official Tricky Store / TEE Simulator</strong> 二选一</li>
<li><strong>ZygiskNext / ReZygisk</strong> 二选一</li>
</ul>
<p>所以我的选择非常明确： <strong>ZygiskNext + TEE Simulator + Integrity-Box</strong></p>
<h3>模块刷入顺序</h3>
<p>我的顺序是：</p>
<ol>
<li><strong>ZygiskNext</strong></li>
<li><strong>TEE Simulator</strong></li>
<li><strong>Integrity-Box</strong></li>
</ol>
<p>刷完之后重启即可。</p>
<p>顺带一提，ZygiskNext 本身的定位也很明确：它是 <strong>Zygisk 的独立实现</strong>，主要给 KernelSU 等环境提供 Zygisk API 支持，用来替代 Magisk 内置的 Zygisk。这一点对于后面整套模块的兼容性很关键。</p>
<p>而 Integrity-Box 则更像是一个总控型工具：既管 Play Integrity，也管 Keybox 实现，还会处理 target、keybox、认证状态、系统清理等一整套东西。它自己 README 里写得也很直白，本质上就是一个 <strong>Play Integrity 与系统环境管理工具箱</strong>。</p>
<p>关于 TS 模块的 WebUI，我选择了 Tricky Addon Enhanced，因为它能自动把新安装的 App 添加到 TEE Simulator 的 Target  中，避免我去手动设置。</p>
<p>
</p>
<h3>TEE 完整</h3>
<p>如果只看表面，这一套主要解决的是这些问题：</p>
<ul>
<li><strong>Play 完整性</strong></li>
<li><strong>系统环境信号</strong></li>
<li><strong>Root 隐藏</strong></li>
<li><strong>应用对 BootLoader 解锁状态的检测</strong></li>
</ul>
<p>但如果只把重点放在“能不能过完整性”，其实还不够。对我来说，这次折腾里真正有意思的地方反而是：<strong>TEE 本身是不是完整的</strong></p>
<p>以前在一加上，BootLoader 解锁之后经常会碰到一个很典型的问题：<strong>TEE 损坏</strong>
这是高通给的机制，解锁 BL 以后 TEE 假死，OPPO 的做法是切换密钥槽，这个槽的密钥不完整，三星就更离谱，直接熔断，没办法玩，小米比较特殊，魔改了 TEE 是 miTEE，解锁后不掉。</p>
<p>系统当然还是能刷，Root 当然也还能做，甚至可以折腾得很深。但底层信任链一旦断掉，很多事情就总有种“补出来的感觉”。</p>
<p>这次换到小米上，用我现在这套方案之后，最让我满意的点反而不是“完整性能不能过”，而是：<strong>TEE 本身就是完整的</strong></p>
<p>这件事对我来说，比单纯看到几项检测变绿更有意义。  也正因为这样，这篇文章标题里写的 <strong>“从 TEE 损坏到 TEE 自身完整可用”</strong>，其实比“刷机成功”更接近我这次折腾真正想表达的东西。</p>
<h3>HyperCeiler</h3>
<p>好像叫做西米露？这个我也很喜欢，定位上有点像 ColorOS 的 <strong>Lucky Tool</strong>，但我自己会更偏向它一点；这样说有点倒反天罡，应该是先有西米露，后有 Lucky Tool 类似的工具。</p>
<p>它主要是拿来改：</p>
<ul>
<li>系统行为</li>
<li>界面逻辑</li>
<li>细节设置</li>
</ul>
<p>属于那种<strong>刷完之后基本会第一时间装上</strong>的工具。</p>
<h2>总结：为什么我执着于「TEE 完整」</h2>
<p>这次折腾下来，我始终在意的一件事，其实不是“检测能不能过”，而是：**TEE 本身到底是不是完整的。**很多人玩 Root、模块和完整性环境，最终目标往往很明确：  <strong>把各种检测绕过去。</strong>
比如：</p>
<ul>
<li>Play Integrity 过了</li>
<li>国内银行 App 能正常打开</li>
<li>国内钱包功能可以使用</li>
</ul>
<p>对不少人来说，只要结果达成，中间到底是怎么实现的，并没有那么重要。但这是一场猫捉老鼠的游戏，检测与绕过是一直在对抗的。我这次更在意的，反而是另一件事：TEE 到底是<strong>真实可信</strong>，还是只是<strong>伪装出来的</strong>。</p>
<p>原因也很简单：<strong>Android 的信任体系，正在发生变化。</strong></p>
<h3>本地 Keybox 的时代，正在结束</h3>
<p>以前 Android 设备的硬件认证，在很大程度上依赖 <strong>本地 Keybox</strong>。</p>
<p>设备出厂时，会在 <strong>TEE</strong> 中写入一组密钥。当应用发起 <strong>硬件级 Attestation</strong> 时，TEE 就会使用这些 Keybox Key 来签名并证明一些关键信息，例如：</p>
<ul>
<li>设备型号</li>
<li>Boot 状态</li>
<li>Verified Boot 状态</li>
<li>系统完整性</li>
</ul>
<p>所以过去很多“过检测”的方案，本质上都是这一套思路：</p>
<pre><code class="language-text">拿到泄露的 Keybox
↓
导入到设备
↓
伪装成官方设备</code></pre><p>这一套在过去几年里确实非常流行，也确实有效。但问题同样很明显：对于 Google 来说，<strong>Keybox 一旦泄露，就很难彻底回收。</strong></p>
<p>如果 Google 想吊销某个泄露的 Keybox，整个流程其实很复杂：</p>
<ul>
<li>收集泄露证据（报告给对应的 OEM，说明有吊销的必要性）</li>
<li>更新吊销列表</li>
<li>推送到系统组件</li>
<li>等设备更新生效</li>
</ul>
<p>这个过程周期很长，而且很难做到真正实时。也正因为如此，Google 一直在推进本地 Keybox 信任到云端的 RKP 信任</p>
<h3>Google 正在全面转向 RKP</h3>
<p>现在 Google 正在逐步推进新的体系：<strong>Android Remote Key Provisioning（RKP）</strong></p>
<p>RKP 的核心思路很直接： <strong>设备不再长期持有 Attestation Key，而是改为通过 Google 云端动态下发。</strong></p>
<p>简化后的流程大致是这样：</p>
<pre><code class="language-text">设备 TEE
↓
向 Google RKP 服务请求 Attestation Key
↓
Google 下发短期证书
↓
TEE 使用该证书完成硬件 Attestation</code></pre><p>这里有两个非常关键的变化。</p>
<h4>1. 证书是短期的</h4>
<p>RKP 下发的不是长期固定证书，而是<strong>短期证书</strong>。典型有效期通常只有：两周。到期之后，设备需要重新向云端申请新的证书。</p>
<h4>2. Google 可以更快吊销</h4>
<p>如果 Google 发现某个设备密钥泄露、异常，或者某条链路存在风险，那么它不再需要沿用过去那套笨重的 Keybox 吊销流程。它只需要在云端：吊销对应设备的 Attestation Key。这样一来，设备去做 TEE Challenge 请求的时候，直接认定是失败。</p>
<h3>这对“伪装方案”意味着什么</h3>
<p>这件事带来的变化，其实已经非常明显了。过去的逻辑大概是：</p>
<pre><code class="language-text">泄露 Keybox
↓
导入设备
↓
长期稳定使用</code></pre><p>而未来更可能变成：</p>
<pre><code class="language-text">没有 Google 云端签发的有效 Attestation Key
↓
硬件认证直接失败</code></pre><p>换句话说： <strong>依赖泄露 Keybox 来伪装 TEE、伪装官方设备的路线，未来只会越来越难走。</strong></p>
<p>过去那种“拿到一套东西，导进去，长期稳定骗过检测”的思路，在新体系下未必还能持续成立。</p>
<h3>我在 OnePlus 上遇到过的真实情况</h3>
<p>这一点，其实我在 OnePlus 上已经切身遇到过了。</p>
<p>有时候即使你已经做到这些：</p>
<ul>
<li>Play Integrity 全绿</li>
<li>环境隐藏得很彻底</li>
<li>Root 检测基本全部绕过</li>
</ul>
<p><strong>Google Wallet 依然有可能识别出设备状态异常。</strong></p>
<p>最典型的提示通常就是：</p>
<pre><code class="language-text">This device doesn't meet security requirements</code></pre><p>也就是说，哪怕系统层面的环境已经“看起来很干净”，Wallet 依然可能判断这台设备<strong>没有通过官方安全认证</strong>。</p>
<p>类似的问题，在一些海外银行 App 上也能看到。</p>
<p>甚至还有一种说法是：**抖音的设备安全检测级别非常高。**一些逆向分析的结论甚至认为，抖音在设备检测上的强度，可能还高于部分银行 App。  </p>
<p>当然，具体实现细节外界很难完全确认，但有一点基本可以确定： <strong>越来越多的 App，正在直接依赖硬件 Attestation 的结果。</strong></p>
<p>这意味着，单纯“把表层环境伪装干净”，未来未必还够。</p>
<h3>为什么我更在意「TEE 本身完整」</h3>
<p>也正因为这样，这次我在小米上的思路，其实和以前不太一样。我不太想继续走这种路线：</p>
<pre><code class="language-text">伪造环境
↓
伪造 Key
↓
尽量骗过检测</code></pre><p>我更希望做到的是：</p>
<pre><code class="language-text">TEE 本身完整
↓
硬件 Attestation 正常
↓
系统只是 Root</code></pre><p>换句话说就是：Soter Key 是正常的，能够正常使用 WeChat Pay 的指纹，而并非使用模块代替输入密码</p>
<p>这也是为什么这篇文章标题里，我会专门写一句：<strong>从「TEE 损坏」到「TEE 自身完备」</strong></p>
<p>对我来说，这比单纯“过了完整性检测”更有意义。<br>因为如果未来 Android 的认证体系继续全面转向 <strong>RKP</strong>，那么现在很多流行的绕过方式，迟早都可能逐渐失效。</p>
<p>而真正更稳定、也更有长期价值的方案，往往反而是最朴素的那一种：</p>
<ul>
<li>设备本身可信</li>
<li>TEE 完整</li>
<li>信任链存在</li>
</ul>
<p>至于剩下的折腾，无非只是系统层面的修改而已。</p>
<h2>展示</h2>
<div class="container">
</div><h2>引用</h2>
<ul>
<li><a href="https://blog.grtsinry43.com/posts/xiaomi-17-bootloader-unlock-custom-rom">Xiaomi 17 标准版刷机折腾记：解锁、官改ROM与必备模块</a></li>
</ul>

      <p style='text-align: right'>
      <a href='https://www.timochan.cn/posts/any_pen/from_oneplus_to_xiaomi#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">69b64aec8fe87390b076e91d</guid>
  <category>posts</category>
<category>随笔</category>
 </item>
  <item>
    <title>都 2025 年了，还不试试 PostgreSQL？</title>
    <link>https://www.timochan.cn/posts/study/mysql_vs_postgresql_correctness_not_convenience</link>
    <pubDate>Sat, 08 Nov 2025 15:31:55 GMT</pubDate>
    <description>一、前言：MySQL 已经成了惰性的象征，而非技术的选择

MySQL 曾经是互联网时代的功臣，它简</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://www.timochan.cn/posts/study/mysql_vs_postgresql_correctness_not_convenience'>https://www.timochan.cn/posts/study/mysql_vs_postgresql_correctness_not_convenience</a></blockquote>
      <h2>一、前言：MySQL 已经成了惰性的象征，而非技术的选择</h2>
<p>MySQL 曾经是互联网时代的功臣，它简单、便宜、够快。但到了 2025 年，它更多代表的是行业的<strong>惯性与保守</strong>。人们继续用它，不是因为它先进，而是因为它“还活着”。然而，如果你把目光放到数据库设计层面，就会发现：<strong>MySQL 根本不是一个完整的关系数据库，而是一个带 SQL 外壳的存储系统。</strong></p>
<p>它的事务，只覆盖了一部分数据；
它的 ACID，是有注脚的；
它的优化器，是随缘的；
它的触发器，是残废的；
它的约束，是可关闭的。</p>
<p>MySQL 靠“够用”生存；
PostgreSQL 靠“正确”延续。</p>
<p>两者之间的区别，不是实现多少特性，
而是——<strong>是否尊重数据库科学本身。</strong></p>
<hr>
<h2>二、优化器：MySQL 靠猜，PostgreSQL 靠算</h2>
<p>MySQL 的查询优化器还停留在上个世纪。它基于规则，不基于代价。</p>
<pre><code class="language-sql">CREATE TABLE orders (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  user_id INT,
  status VARCHAR(20),
  created_at DATETIME,
  INDEX idx_user_status (user_id, status)
);

EXPLAIN SELECT * FROM orders WHERE user_id = 42 AND status = 'done';
EXPLAIN SELECT * FROM orders WHERE status = 'done' AND user_id = 42;</code></pre><p>逻辑上完全相同的两条 SQL：</p>
<ul>
<li>第一条走索引；</li>
<li>第二条却全表扫描。</li>
</ul>
<p>因为 MySQL 优化器死板地按索引定义顺序匹配列，不会重排谓词，也不计算组合代价。稍不注意写法，性能直接爆炸。</p>
<p>而 PostgreSQL 的优化器是真正的代价模型（Cost-Based Optimizer）。它通过列统计与数据分布做决策，执行计划稳定、可预测。</p>
<blockquote>
<p>PostgreSQL 的计划是理性计算；
 MySQL 的计划是随机猜测。</p>
</blockquote>
<p>当你的系统需要确定性性能，MySQL 这个优化器就成了炸弹。</p>
<hr>
<h2>三、ACID 的幻觉：回滚之后，MySQL “干净地”抹掉历史</h2>
<p>MySQL 的最大谎言，是那句印在官网上的口号：</p>
<blockquote>
<p>“InnoDB fully supports ACID transactions.”</p>
</blockquote>
<p>这句话听上去像承诺，实际上是<strong>选择性履行</strong>。遇见 DDL，MySQL 立刻撕毁契约。</p>
<p>看看这一段再平常不过的表迁移事务：</p>
<pre><code class="language-sql">START TRANSACTION;

-- 1. 改名原表
RENAME TABLE metrics TO metrics_1;

-- 2. 按旧结构创建新表
CREATE TABLE metrics LIKE metrics_1;

-- 3. 导入旧数据
INSERT INTO metrics SELECT * FROM metrics_1;

-- 4. 删除旧表
DROP TABLE metrics_1;

-- 5. 写入日志（假设这里出错）
INSERT INTO system_events(event_type, description)
VALUES ('table_upgrade', 'metrics table upgraded');

ROLLBACK;</code></pre><p><strong>你以为 <code>ROLLBACK</code> 是“回到从前”？</strong>
在 MySQL 里，它意味着“请擦干净尸体再走”。</p>
<p>执行之后你会得到：</p>
<ul>
<li>原表 <code>metrics</code> 被改名再删除；</li>
<li>新表 <code>metrics</code> 还在，但空无一物；</li>
<li>数据彻底消失；</li>
<li>那条日志既没写入，也没留下痕迹。</li>
</ul>
<p>你手动发起了回滚，MySQL 则帮你<strong>干净地抹掉了历史。</strong></p>
<p>更荒谬的是，这不是 bug，而是<strong>官方设计</strong>。 任何 DDL（<code>RENAME</code>、<code>CREATE</code>、<code>DROP</code>）都会触发隐式提交。事务还没结束，它就自作主张地写死文件。</p>
<p>结果是：**回滚只是摆设，原子性形同虚设。**你的事务，不是安全网，而是引爆器。出错时，它炸的不是异常，而是数据本身。</p>
<hr>
<p>PostgreSQL 的对比：真正的事务，是一次数据库级时间穿越</p>
<p>在 PostgreSQL 中，同样的操作是完全事务化的：</p>
<pre><code class="language-sql">BEGIN;

ALTER TABLE metrics RENAME TO metrics_1;
CREATE TABLE metrics (LIKE metrics_1 INCLUDING ALL);
INSERT INTO metrics SELECT * FROM metrics_1;
DROP TABLE metrics_1;
INSERT INTO system_events(event_type, description)
VALUES ('table_upgrade', 'metrics table upgraded');

ROLLBACK;</code></pre><p>一旦执行 <code>ROLLBACK</code>：</p>
<ul>
<li>所有表、结构、数据、索引全部回退；</li>
<li>WAL 写前日志完整重放；</li>
<li>系统状态恢复如初，连指针都不漏一页。</li>
</ul>
<p>这不仅仅是“支持 DDL 事务”，这是<strong>数据库哲学分界线的实证</strong>：</p>
<blockquote>
<p>PostgreSQL 的事务作用于整个数据库状态；
MySQL 的事务只作用于部分数据文件。</p>
</blockquote>
<p>前者是有意识的系统，它理解什么叫“一致性”、“原子性”、“时间线”；后者只是一个文件操作堆栈——连“状态”都不懂。</p>
<p>毫不夸张地说：</p>
<p>PostgreSQL 的事务是一个<strong>原子行为</strong>；
MySQL 的事务是一个<strong>概率事件</strong>。</p>
<p>前者以逻辑守护数据；
后者赌机器别出错。</p>
<p><strong>PostgreSQL 管整个宇宙；MySQL 只管几张文件。</strong>
这是工程实现的鸿沟，更是理念上的耻辱。</p>
<hr>
<h2>四、触发器与逻辑：MySQL 的断肢，PostgreSQL 的神经系统</h2>
<p>MySQL 到今天的触发体系依旧严重残缺：</p>
<ul>
<li>每个事件只能定义一个触发器；</li>
<li>不支持语句级触发；</li>
<li>不支持条件触发；</li>
<li>调试如地狱，复用无可能。</li>
</ul>
<p>2025 年，你依然能看到这样的报错信息：</p>
<pre><code class="language-">ERROR 1235 (HY000): This version of MySQL doesn't yet support multiple triggers for the same table.</code></pre><p>而 PostgreSQL 的触发体系，是成熟的事务内逻辑层：</p>
<ul>
<li>行级与语句级触发并存；</li>
<li>支持条件判断（<code>WHEN</code>）；</li>
<li>可指定顺序、共存多个；</li>
<li>可用多语言编写（PL/pgSQL、Python、C）。</li>
</ul>
<p>在 PostgreSQL，触发器能形成业务层逻辑护城河；
 在 MySQL，它只是挂件。</p>
<hr>
<h2>五、约束与一致性：MySQL 允许造假，PostgreSQL 不允许撒谎</h2>
<p>MySQL 允许你在一行命令里掐死完整性保障：</p>
<pre><code class="language-sql">SET FOREIGN_KEY_CHECKS = 0;</code></pre><p>然后导入任意垃圾数据。再恢复检查，它也不会重验。
完美的“装死”机制。</p>
<p>PostgreSQL 没有这种妥协选项。
约束永远生效、永远执行。
它不会假装一致 —— 它要么成功，要么拒绝。</p>
<p><strong>MySQL 教你撒谎；PostgreSQL 逼你诚实。</strong></p>
<p>更离谱的是，MySQL 在处理外键与复合索引时的行为，完全超出直觉。</p>
<p>假设你有一个主表与子表结构如下：</p>
<pre><code class="language-sql">CREATE TABLE users (
  id INT PRIMARY KEY,
  name VARCHAR(50)
);

CREATE TABLE orders (
  id INT PRIMARY KEY,
  user_id INT,
  name VARCHAR(50),
  INDEX idx_user (user_id, name),
  FOREIGN KEY (user_id) REFERENCES users(id)
);</code></pre><p>理论上，这里的外键只约束 <code>user_id</code>，与 <code>name</code> 无关。但在 MySQL 中，只因为你建立了联合索引 <code>(user_id, name)</code>，它会在某些版本（尤其 5.x 与早期 8.0）中<strong>无端把第二列 <code>name</code> 一并纳入外键校验逻辑</strong>。任何 <code>name</code> 冲突、甚至非唯一匹配，都会触发外键报错。这意味着你根本没定义外键到 <code>name</code>，却被 MySQL 的外键机制“顺手管了”。</p>
<p><strong>PostgreSQL 不会做这种事。</strong>
它认得标准：外键依赖主键或唯一约束列，不会跨字段、不会超范围、不会瞎猜。</p>
<p>MySQL 的问题在于：它将“联合索引”视作“外键实现细节”，把数据约束混在索引选型里，最终让行为变得既不确定又难以调试。</p>
<p>PostgreSQL 则严格区分：索引是优化器的工具，外键是一致性的契约。MySQL 把契约和工具绑死在一起。</p>
<p>当你加个索引时，你同时改变了逻辑规则——这不是数据库，这是雷区。</p>
<hr>
<h2>六、“数据库只是大号 Excel”？</h2>
<p>不，那只是被 MySQL 教坏的一代人</p>
<p>有人说：</p>
<blockquote>
<p>“逻辑不要放数据库，数据库只是存储。”</p>
</blockquote>
<p>这句话听上去理性，其实是悲哀。</p>
<p>悲哀的是：MySQL 把开发者养成了“不信任数据库”的人。</p>
<p>因为：</p>
<ul>
<li>事务不完整；</li>
<li>约束能关；</li>
<li>触发器假死；</li>
<li>优化器靠缘分。</li>
</ul>
<p>于是程序员被迫把一致性逻辑搬到应用层，再对自己说：“逻辑不应在数据库中做。”</p>
<p>结果就是 ORM、幂等、防重复、补偿机制满天飞。只是因为 MySQL 从未完成应尽职责。</p>
<p>而 SQL 标准在 1992 年就已完整确立：</p>
<ul>
<li>标准事务语义（包含 DDL）；</li>
<li>外键与约束机制；</li>
<li>触发器与存储过程；</li>
<li>视图、模式、授权体系。</li>
</ul>
<p>换句话说，在 MySQL 出生之前，SQL 世界已经有了成熟、完整、被各大数据库验证过的科学定义。</p>
<p>但到了 1995 年，MySQL 出场时，它做了一个惊人的选择：
它没有遵守科学，不继承标准，而是自创一套残废版 SQL，命名为——“My SQL”。注意那个 “My”：它不是对个人的归属表达，而是一个注脚</p>
<blockquote>
<p>“我只承认属于我自己的 SQL 规则。”</p>
</blockquote>
<p>于是它扭曲了语言逻辑、删掉了事务 DDL、阉割了触发器、弱化了外键，再把这些残缺包装成“轻量”“高性能”“互联网友好”。
事实上，那不过是权衡实现复杂度后的<strong>技术懒惰与规范背叛</strong>。</p>
<p>这就是 MySQL 的原罪：当全世界都在遵守《SQL-92》， 它却在实现 “Only My SQL”。</p>
<p>结果，MySQL 教坏了一代开发者：大家开始认为数据库就是 CRUD 容器；开始把一致性逻辑扔回应用代码；一边疲于修补，一边自诩解耦优雅。</p>
<p>MySQL 不止是技术问题，它是一种文化病毒 ——它让人们习惯无标准、无事务、无尊严的数据库生态， 并且还为此自豪。</p>
<p>当他们说“数据库只是 Excel”，真正的意思是：</p>
<blockquote>
<p>“我们用的 MySQL 就像 Excel——能存点数据，却没灵魂。”</p>
</blockquote>
<hr>
<h2>七、有人说“事务里做 DDL 不科学”？</h2>
<p>不，那只是被 MySQL 吓坏的工程师自我安慰</p>
<p>会有人批评文中这一点，说：</p>
<blockquote>
<p>“在事务里执行 DDL 是不科学的设计。”</p>
</blockquote>
<p>这句话听起来高冷，实际上是 <strong>MySQL 弱点导致的错觉</strong>。他们不是在阐述数据库原理，而是在为 MySQL 找借口。</p>
<p>事实是：事务中执行 DDL 并不反常，这本应是关系数据库的标准语义。
 <strong>但因为 MySQL 拉跨，他们被迫认为‘不能做’，然后自我合理化。</strong></p>
<p>他们记住的是 MySQL 的崩溃方式，
于是开始以为数据库就该如此；
于是把“不敢”包装成“原则”；
把数据库降级成“存储层”；
再用代码去弥补数据库应有的功能。</p>
<p>PostgreSQL 没这个问题。
你可以在事务里安全地改表、建表、删表、回滚。
因为它的 DDL 就是事务的一部分，
它不装模作样，不偷偷提交。</p>
<p>所以请停止把 MySQL 当作数据库的定义。
它只是数据库的简化版、阉割版、历史遗迹。</p>
<blockquote>
<p>真正科学的，是 PostgreSQL；
真正错误的，是被 MySQL 教坏的世界。</p>
</blockquote>
<p><strong>要正确性，就别怕高级。</strong>
<strong>要数据库，就别怕事务中的 DDL。</strong></p>
<p>MySQL 的恐惧，不该成为你的惯性。
真正的数据库，不需要妥协。</p>
<p><strong>MySQL 教人屈服；PostgreSQL 教人尊重。</strong></p>
<h2>八、分库分表：互联网最成功的错误设计</h2>
<p>所谓“分库分表”，在今天被吹嘘成互联网架构的成功案例。但事实恰恰相反——它不是进化结果，而是 <strong>MySQL 贫瘠设计的自我赎罪。</strong></p>
<p>MySQL 从来没有真正的分区机制、全局索引、全局统计信息，也没有跨表事务优化器。当数据量增大，它无法逻辑扩展，只能物理切割。
于是“分库分表”登场——不是因为聪明，而是因为没办法。</p>
<p>从此，应用层开始接管数据库的职责。程序员被迫在业务代码中：</p>
<ul>
<li>自行计算分片位置；</li>
<li>写路由中间件决定 SQL 去哪；</li>
<li>实现伪分布式事务补偿；</li>
<li>拼接跨库聚合查询；</li>
<li>再写一层定时脚本同步数据。</li>
</ul>
<p>这一切，只是为了修补一个不支持现代分区能力的数据库。而这些补丁行为，居然被包装成“高并发经验”，仿佛“用应用弥补数据库的残缺”就成了架构智慧。这就像一辆没有刹车的汽车，司机们开始总结撞墙减速的技巧， 然后把它写进《高速驾驶指南》。</p>
<p><strong>分库分表从来不是架构突破，而是数据库退化的症状。</strong></p>
<p>PostgreSQL 从未需要靠这种土法生存。它的分区、并行与事务一致性都在数据库层自然发生。它遵循 SQL 标准，并实现了真正意义上的<strong>逻辑分区表</strong>——在保持事务一致的同时，可无限水平扩展。</p>
<p>例如，一个标准的时间分区表：</p>
<pre><code class="language-sql">-- 创建主表并定义分区键
CREATE TABLE logs (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL,
    action TEXT,
    created_at TIMESTAMP NOT NULL
) PARTITION BY RANGE (created_at);

-- 创建分区表
CREATE TABLE logs_2024 PARTITION OF logs
    FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');

CREATE TABLE logs_2025 PARTITION OF logs
    FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');

-- 插入数据时自动路由到正确分区
INSERT INTO logs (user_id, action, created_at)
VALUES (1, 'login', now());

-- 查询仍然是针对一个逻辑整体
SELECT user_id, COUNT(*) FROM logs
WHERE created_at &gt;= '2025-01-01'
GROUP BY user_id;

-- 扩展新分区只需一句
CREATE TABLE logs_2026 PARTITION OF logs
    FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');</code></pre><p>数据量再大，它依然是一个逻辑整体。分区是扩展，不是切割；事务仍完整，优化依然智能；一致性从未退让。</p>
<p>因为 PostgreSQL 的设计宗旨是：</p>
<blockquote>
<p><strong>当系统变大，正确性不该变小。</strong></p>
</blockquote>
<p>而 MySQL 的哲学是另一种：</p>
<blockquote>
<p>“先跑起来，崩溃再想办法。”</p>
</blockquote>
<p>于是，一个数据库不承担数据库的职责，行业就开始弥补它的缺陷——写代理、造中间件、讲分片策略、造轮子、开大会、出白皮书。所有人都在修补 MySQL 的伤口，而非构建数据库的未来。</p>
<p>如果说 PostgreSQL 推动了数据库技术的演化，那么 MySQL 推动的，只是<strong>分库分表的产业链</strong>。它让无数人困在自造的迷宫里，同时以此误以为“这就是大规模架构的真相”。</p>
<p>真相是：**成熟的数据库不需要你去分它。**分库分表不是荣誉勋章，而是系统设计的病历单。它见证的不是成功，而是退化——见证了一个数据库如何拒绝成长，又如何让整个行业去替它长大。</p>
<blockquote>
<p>PostgreSQL 让系统扩展正确性；
MySQL 让系统扩展复杂性。</p>
</blockquote>
<p>分库分表不是智慧，是悲剧的形式美。</p>
<h2>九、结语：要正确性，不要幻觉</h2>
<p>MySQL 的哲学是：<strong>差不多就行</strong>。</p>
<p>PostgreSQL 的哲学是：<strong>必须正确，否则失败。</strong></p>
<table>
<thead>
<tr>
<th>对比项</th>
<th>MySQL 5.7</th>
<th>PostgreSQL 12</th>
</tr>
</thead>
<tbody><tr>
<td><strong>事务原子性</strong></td>
<td>仅 DML，DDL 会隐式提交</td>
<td><strong>全局原子性</strong></td>
</tr>
<tr>
<td><strong>优化器</strong></td>
<td>规则匹配，性能漂移</td>
<td><strong>成本模型，推理稳定</strong></td>
</tr>
<tr>
<td><strong>外键与约束</strong></td>
<td>可关闭或跳过</td>
<td><strong>严格强制执行</strong></td>
</tr>
<tr>
<td><strong>触发器</strong></td>
<td>功能残缺</td>
<td><strong>事务级完整</strong></td>
</tr>
<tr>
<td><strong>DDL 事务</strong></td>
<td>不支持，必隐式提交</td>
<td><strong>完全支持，可回滚</strong></td>
</tr>
<tr>
<td><strong>SQL 标准</strong></td>
<td>方言化实现</td>
<td><strong>完全兼容 ANSI SQL</strong></td>
</tr>
<tr>
<td><strong>扩展方式</strong></td>
<td><strong>分库分表（应用层路由）</strong></td>
<td><strong>原生分区表（数据库层）</strong></td>
</tr>
<tr>
<td><strong>事务一致性</strong></td>
<td><strong>跨库 XA，慢如狗</strong></td>
<td><strong>全局 ACID</strong></td>
</tr>
<tr>
<td><strong>查询语法</strong></td>
<td><strong>动态拼接</strong></td>
<td><strong>统一 SQL</strong></td>
</tr>
<tr>
<td><strong>扩容成本</strong></td>
<td><strong>停机 + 迁移</strong></td>
<td><strong><code>ATTACH PARTITION</code></strong></td>
</tr>
<tr>
<td><strong>是否优雅</strong></td>
<td><strong>像修下水道</strong></td>
<td><strong>像写 SQL</strong></td>
</tr>
</tbody></table>
<p>到了 2025 年，<br>如果你还在忍受一个：</p>
<ul>
<li><code>ROLLBACK</code> 会删光你表的数据库；  </li>
<li>允许你关闭外键检查的数据库；  </li>
<li>靠猜测计划运行的数据库；  </li>
<li><strong>需要你写中间件来“分库分表”的数据库</strong></li>
</ul>
<p>那你不是在用数据库，  <strong>你是在赌数据库别出事故</strong>。</p>
<p><strong>MySQL 属于过去</strong> —— 它是“<strong>差不多</strong>”的象征；  <strong>PostgreSQL 属于未来</strong> —— 它是“<strong>正确性</strong>”的代名词。</p>
<blockquote>
<p><strong>停止为 MySQL 的残缺买单。</strong><br><strong>真正的架构师，不造轮子补洞，而是选择一个不用补的数据库。</strong></p>
</blockquote>
<p><strong>要么 PostgreSQL，要么幻觉。</strong><br><strong>要么正确，要么坍塌。</strong></p>

      <p style='text-align: right'>
      <a href='https://www.timochan.cn/posts/study/mysql_vs_postgresql_correctness_not_convenience#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">690f626bc488aab406f8a306</guid>
  <category>posts</category>
<category>学习</category>
 </item>
  <item>
    <title>如何用旁路网关接管内网 IPv6 代理：RA 双路由优先级实战</title>
    <link>https://www.timochan.cn/posts/jc/catwrt_ipv6_dual_ra</link>
    <pubDate>Sun, 06 Jul 2025 12:26:42 GMT</pubDate>
    <description>前言

最近笔者搬到新地方工作，租的房子自带中国移动的光纤入户。图方便，就直接把之前购买的华为 CP</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://www.timochan.cn/posts/jc/catwrt_ipv6_dual_ra'>https://www.timochan.cn/posts/jc/catwrt_ipv6_dual_ra</a></blockquote>
      <h2>前言</h2>
<p>最近笔者搬到新地方工作，租的房子自带中国移动的光纤入户。图方便，就直接把之前购买的华为 CPE 当作主路由使用。然而使用 5G Wi-Fi 时总是莫名其妙断流，起初我以为是 R2S 设备过热，花了不少时间优化散热方案。直到有天晚上漏接了整晚消息，第二天排查才发现——问题根本在 CPE 本身！</p>
<p>虽然配有千兆网口，但实测 PC 与 R2S 点对点传输时只能跑到 600 Mbps，而且还有 120 次丢包重传，实在难以接受。在 <a href="https://www.miaoer.net">miaoer</a> 的推荐下，我在京东入手了中兴巡天 AX3000。测试发现内网点对点速率是 940 Mbps，在什么都不变的情况下，零丢包重传。它的后台管理很简洁，基本没什么可调的地方，不过值得欣慰的是，它支持为单个设备定制 DHCP 设置，包括独立下发 IPv4 地址和网关。就凭这点，旁路网关方案就能跑起来。</p>
<p>众所周知，旁路网关是对现有网络拓扑改动最小的代理方案。对于 IPv4 来说，只需手动为终端设置网关，或在主路由绑定 MAC 地址下发定制 DHCP 即可。但如今 IPv6 越来越普及，每个设备都能轻松获得全球唯一的 IPv6 地址，穿透打洞也更简单。那么，旁路网关能否也“喝口 IPv6 的汤”呢？</p>
<h2>准备条件</h2>
<h3>设备列表</h3>
<table>
<thead>
<tr>
<th>设备名称</th>
<th>固件/型号</th>
<th>角色</th>
<th>备注</th>
</tr>
</thead>
<tbody><tr>
<td>R2S</td>
<td>CatWrt.v24.11.rkarm64</td>
<td>旁路网关</td>
<td>用于提供 IPv4/IPv6 代理</td>
</tr>
<tr>
<td>中兴巡天 AX3000</td>
<td>官方固件（简洁后台）</td>
<td>主路由</td>
<td>支持定制 DHCP 下发</td>
</tr>
<tr>
<td>中国移动光猫</td>
<td>默认运营商设备</td>
<td>入户网关</td>
<td>工作在路由模式，不支持桥接</td>
</tr>
</tbody></table>
<h3>网络拓扑图</h3>
<p></p>
<h2>实践</h2>
<h3>原理</h3>
<p>在 IPv4 网络中，我们依赖 DHCP 下发 IP、网关和 DNS 信息，想定制给特定设备分配的网络参数，只需在主路由配置即可。</p>
<p>而 IPv6 的机制则不同，它将地址和路由信息的下发分成了两个部分：</p>
<ul>
<li><p><strong>DHCPv6</strong>：负责分配 IPv6 地址和 DNS；</p>
</li>
<li><p><strong>RA（Router Advertisement）</strong>：负责通告路由，同时也可带上 DNS。</p>
</li>
</ul>
<p>因此，我们可以将 DHCPv6 的工作交给主路由，而将 RA 的广播任务交由旁路网关来完成。这样一来，终端设备就会默认使用旁路网关作为 IPv6 出口路由。特别是在手机等非 root 设备上，无法手动设置 IPv6 网关的情况下，这种方式就显得尤为重要。</p>
<p>若由主路由负责 RA 广播，则终端自然会使用主路由作为默认 IPv6 网关，流量也就不会走旁路了。因此，<strong>必须让旁路网关承担 主 RA 的角色，才能实现 IPv6 默认走代理</strong>。</p>
<h3>操作</h3>
<h4>主路由设置</h4>
<p>确保光猫和 AX3000 已开启 IPv6 支持，并启用 LAN 端的 DHCPv6：</p>
<p></p>
<p>关闭主路由的 RA 广播功能（即“路由通告”）：</p>
<p></p>
<p>其余 IPv6 功能保持默认或开启状态即可。</p>
<h4>旁路网关设置（R2S）</h4>
<p>LAN 接口配置示例如下：</p>
<p></p>
<p>IPv6 路由前缀可以从主路由上拿</p>
<p></p>
<p>关闭 CatWrt 中的 DHCP 功能：</p>
<p></p>
<p>IPv6 设置示例：</p>
<p></p>
<p>其中：</p>
<ul>
<li>服务器模式：表示设备主动广播 RA，宣告自身为 IPv6 网关；</li>
<li>中继模式：则是仅转发给上游；</li>
<li>NPD 代理无需开启；</li>
<li>DNS 填写旁路网关的 <code>Link-Local</code> 地址即可（如 <code>fe80::xxxx</code>）。</li>
</ul>
<h2>成果</h2>
<p>PC IPv6 信息如下：</p>
<p></p>
<p>ip add 输出</p>
<pre><code class="language-bash">❯ ip add
3: wlan0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether xx brd ff:ff:ff:ff:ff:ff permaddr xx
    inet 192.168.100.2/24 brd 192.168.100.255 scope global noprefixroute wlan0
       valid_lft forever preferred_lft forever
    inet6 2409:8a20:423:e684:2/128 scope global dynamic noprefixroute 
       valid_lft 186269sec preferred_lft 99869sec
    inet6 2409:8a20:423:e684::xxxx/64 scope global noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::839c:251c:581b:42a5/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
</code></pre><p>ip -6 route 输出</p>
<pre><code class="language-bash">❯ ip -6 route
::1 dev lo proto kernel metric 30 pref medium
2409:8a20:423:e684:2 dev wlan0 proto kernel metric 600 pref medium
2409:8a20:423:e684::/64 dev wlan0 proto ra metric 600 pref medium
fe80::/64 dev wlan0 proto kernel metric 1024 pref medium
default via fe80::e8fe:1bff:fe6e:614c dev wlan0 proto ra metric 600 pref medium</code></pre><p>访问效果</p>
<pre><code class="language-bash">❯ curl -v https://www.google.com           
* Host www.google.com:443 was resolved.
* IPv6: 2404:6800:4005:81e::2004
* IPv4: 142.250.198.68
*   Trying [2404:6800:4005:81e::2004]:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / id-ecPublicKey
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=www.google.com
*  start date: Jun 17 20:03:51 2025 GMT
*  expire date: Sep  9 20:03:50 2025 GMT
*  subjectAltName: host "www.google.com" matched cert's "www.google.com"
*  issuer: C=US; O=Google Trust Services; CN=WE2
*  SSL certificate verify ok.
*   Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA256
*   Certificate level 1: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA384
*   Certificate level 2: Public key type EC/secp384r1 (384/192 Bits/secBits), signed using ecdsa-with-SHA384
* Connected to www.google.com (2404:6800:4005:81e::2004) port 443
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://www.google.com/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: www.google.com]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.14.1]
* [HTTP/2] [1] [accept: */*]
&gt; GET / HTTP/2
&gt; Host: www.google.com
&gt; User-Agent: curl/8.14.1
&gt; Accept: */*
&gt; 
* Request completely sent off
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
&lt; HTTP/2 200 </code></pre><h2>小结</h2>
<p>其实在这里，仍然存在一个问题值得深思：<strong>如果让旁路网关承担 RA（Router Advertisement）的职责，那么一旦它宕机，整个内网的 IPv6 网络将不可用</strong>。这显然违背了旁路网关“<strong>最小侵入原则</strong>”的设计初衷。</p>
<p>那么该如何解决这个问题呢？</p>
<p>答案是：<strong>为内网配置多个 RA 源，设定优先级即可。</strong></p>
<p>在 IPv6 网络中，允许多个设备同时发送 RA，只要优先级设计合理，客户端会自动选择最优路由。我们可以通过以下方式实现主备切换：</p>
<ul>
<li><strong>旁路网关</strong> 作为 <strong>主 RA 广播者</strong>，优先级设置为高（或默认）；</li>
<li><strong>主路由器</strong> 也启用 RA，但将其优先级设置为低（low）作为备用。</li>
</ul>
<p>配置方法示例：</p>
<p>打开主路由的“路由通告”功能，并将优先级设置为 <strong>低（low）</strong>：</p>
<p></p>
<p>此时，内网将拥有两个 RA 广播源：</p>
<ul>
<li><strong>旁路网关</strong>：广播默认路由，优先级较高（中）；</li>
<li><strong>主路由器</strong>：也广播默认路由，优先级低。</li>
</ul>
<p>可以通过如下命令查看实际的 IPv6 路由表：</p>
<pre><code class="language-bash">❯ ip -6 route
::1 dev lo proto kernel metric 30 pref medium
2409:8a20:423:e684:2 dev wlan0 proto kernel metric 600 pref medium
2409:8a20:423:e684::/64 dev wlan0 proto ra metric 600 pref medium
fe80::/64 dev wlan0 proto kernel metric 1024 pref medium
default via fe80::e8fe:1bff:fe6e:614c dev wlan0 proto ra metric 600 pref medium
default via fe80::5 dev wlan0 proto ra metric 601 pref low</code></pre><p>可以看到：</p>
<ul>
<li><code>fe80::e8fe:1bff:fe6e:614c</code> 是旁路网关下发的默认路由，优先级为 <code>medium</code>，metric 更低，因此默认使用；</li>
<li><code>fe80::5</code> 是主路由器的默认路由，优先级为 <code>low</code>，metric 稍高，作为备选。</li>
</ul>
<p>一旦旁路网关失联，<strong>内核的邻居不可达检测（NUD）</strong> 会将其标记为“不可达”，此时系统会自动切换到主路由器广播的低优先级默认路由，从而保证内网设备的 IPv6 网络依旧可以正常使用。</p>
<p>故障演练，让旁路网关宕机</p>
<p>路由信息如下</p>
<pre><code class="language-bash">❯ ip -6 route
::1 dev lo proto kernel metric 30 pref medium
2409:8a20:423:e684:2 dev wlan0 proto kernel metric 600 pref medium
2409:8a20:423:e684::/64 dev wlan0 proto ra metric 600 pref medium
fe80::/64 dev wlan0 proto kernel metric 1024 pref medium
unreachable default via fe80::e8fe:1bff:fe6e:614c dev wlan0 proto ra metric 600 pref medium
default via fe80::5 dev wlan0 proto ra metric 601 pref low</code></pre>
      <p style='text-align: right'>
      <a href='https://www.timochan.cn/posts/jc/catwrt_ipv6_dual_ra#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">686a6b82e496a463d89e4fa6</guid>
  <category>posts</category>
<category>教程</category>
 </item>
  <item>
    <title>毕业季</title>
    <link>https://www.timochan.cn/notes/45</link>
    <pubDate>Sat, 07 Jun 2025 14:47:44 GMT</pubDate>
    <description>我们终将奔赴各自的那片碧海蓝天， 谢谢你，曾陪我走过那些无悔的岁月。

四年的时光转瞬即逝，仿佛昨日</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://www.timochan.cn/notes/45'>https://www.timochan.cn/notes/45</a></blockquote>
      <blockquote>
<p>我们终将奔赴各自的那片碧海蓝天， 谢谢你，曾陪我走过那些无悔的岁月。</p>
</blockquote>
<p>四年的时光转瞬即逝，仿佛昨日还在初来乍到的校园中懵懂张望，转眼却已站在离别的渡口，迎着夏风收拾青春的行囊。在翻阅档案、整理资料的这一刻，我终于看到了四年前高中班主任在评价表的综合评语写下的一句话：“望今后能够更开朗些，更多发展自己的爱好，争取从各个方面来加强自己的能力。”</p>
<p>一瞬间，往昔如潮水般涌来。我想，他或许早已察觉，当时的我已失去了对高中知识学习的热情。我最热切的目光，早已投向计算机的万千宇宙。课堂上，他曾严厉批评那些“上课还在琢磨微信是怎么发消息”的学生——可那时的我，已经沉迷于一个远比高中课本更浩瀚的世界。</p>
<p>我知道，那份对计算机的热爱，并不是浅尝辄止的爱好，而是深入骨血的执念。在衡水式的高压模式下，我的精神长期处于焦虑和压抑的状态，至今仍常常在梦中惊醒，梦见年级主任的小黑屋惩罚、义务劳动、课间跑操、学生课堂和课间查班、禁止听课式罚站……那些伤痕并未随时间愈合，只是被藏在心底最深处。</p>
<p>可即便如此，我最终选择了计算机这条路——不是为了逃避现实的荒芜，而是因为这是我真正想走的方向，哪怕父母暂时不理解，但他们也宽容。</p>
<p>热爱，从未因风雨褪色，哪怕它最终变成了工作。世人常说，把爱好变成工作，最终会丧失那份热情，这个爱好就被毁掉了。而我却始终相信，真正的热爱是不会被磨灭的。也许，这就是班主任当年所期待的“从各方面增强能力”吧——只是我以我的方式，走出了那条属于自己的路。</p>
<p>大学四年，有幸遇到一群虽不完美却值得铭记的室友。他们也许会在深夜突击抄作业，偶尔有些小毛病让我苦笑摇头，但他们在我生病时送饭、陪诊、排队挂号，在我实习期间帮忙递交材料、邮寄物品，在我奔波与焦虑中给予我切实的帮助与陪伴。是他们，用琐碎却真挚的日常温暖，构筑了我大学岁月中最朴素却最可贵的友谊。若不是他们的支持，我或许早已在孤独与压力中闭口不言，错失许多与世界温柔相处的机会。是他们，让我学会信任，也让我拥有一个更加健全与柔软的人格。</p>
<p>感谢我的队友们，是与他们的协作与碰撞，让我清晰地意识到：我或许不适合信息安全这条路。也正因如此，我才能更早地找到那条真正契合自己的方向。</p>
<p>感谢我的导师，不仅在专业上给予我方向上的点拨，更在<strong>学习与生活的边界之间，教会了我如何看待问题、如何处事为人</strong>。通过组织学术分享会与技术交流会，他促使实验室内的知识不再沉默于个体，而能在成员之间流动、生长。正是这种氛围，让我接触到更多元的认知路径，也不断激发我探索未知领域的热情与勇气。在他的引导下，我逐渐懂得：真正的成长，不仅是技术能力的提升，更是对世界认知方式的拓展与重塑。</p>
<p>感谢百度提供的实习机会，让我得以走出象牙塔，亲身参与到真实业务的运维体系中。在这段宝贵的实习经历中，我不仅学习到了 SRE 理论在生产环境中如何真正落地，也体会到跨部门协作沟通的重要性，理解了在复杂系统下如何推进降本增效、保障服务稳定的实际路径。感谢我的百度 mentor，很多原本抽象的理念，在实际工作中被一点点具象化、拆解为流程与机制，在潜移默化中，我学会了如何将理论转化为实践，如何用工程思维解决问题，如何以系统性的视角看待服务质量。这段经历，既是一次技术的淬火，更是职业认知与思维方式的革新。</p>
<p>毕业不是告别的终点，而是奔赴远方的起点。愿此去，前程似锦；归来时，仍有少年模样。山高路远，愿我们在各自的海阔天空中，再次相逢。</p>
<p>BGM：<a href="https://music.163.com/song?id=33911781">secret base <del>君がくれたもの</del> (10 years after Ver.)</a></p>

      <p style='text-align: right'>
      <a href='https://www.timochan.cn/notes/45#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">68445110e496a463d8889438</guid>
  <category>notes</category>
false
 </item>
  <item>
    <title>容器（一）</title>
    <link>https://www.timochan.cn/posts/any_pen/conatiner_one</link>
    <pubDate>Tue, 25 Feb 2025 11:21:39 GMT</pubDate>
    <description>容器技术发扬光大

都知道 Docker 开启了容器时代，但是 Docker 的使用的 namesp</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://www.timochan.cn/posts/any_pen/conatiner_one'>https://www.timochan.cn/posts/any_pen/conatiner_one</a></blockquote>
      <h2>容器技术发扬光大</h2>
<p>都知道 Docker 开启了容器时代，但是 Docker 的使用的 namespace、cgroups 并不是啥新鲜技术，这两项东西在 Linux 内核里面早已准备好了。话虽如此，容器技术在当时并不流行，和人们想象中的 PAAS 还有差距。</p>
<p>那 Docker 的创新点在哪？UnionFS，这是 Docker 相较于当时其他容器化技术创新的一点，搞定了容器运行时的环境问题，rootfs 可以为程序提供一个类似于宿主机的文件环境，UnionFS 方便了容器的构建、分发，使用。要知道在当时早已有基于 namespace 和 cgroups 的 LXC 容器化技术，但和其他容器化技术一样，早已不温不火了。</p>
<h2>容器编排花落谁家</h2>
<p>Docker 虽然把容器化技术发扬光大，让 PAAS 平台都接纳了 Docker 这个容器运行时，但当时 Docker 是没有官方的编排系统的，而且 当时 Docker 很多东西都是闭源的，没有提供 API 可用于编排系统开发，导致社区也无法去提供相关方案，在当时， PAAS 厂商只能自行实现自己的方案，Docker Compose 都是后来自救的产物。</p>
<p>恰逢此时，Google 发现了 Docker 在容器编排领域的劣势，基于 Google 自己的编排系统  Borg，吸收其精华开发了现在大名鼎鼎的 Kubernetes（k8s）。相较于 Docker 的闭源，k8s 在一开始就取得了开发者的青睐，在良好的社区领导下，开源社区的力量让 k8s 的发展速度非常之快，也是 CNCF 第一个毕业项目。当然 Docker 此时也没坐以待毙，开发了适用于单机编排的 Compose，集群编排的 Swarm，当然，从结果就知道了，Swarm 并未掀起什么浪花。同期还有其他容器编排系统，比如 Mesos。Docker 为了自救还把自己的容器引擎独立了出来，也就是后来的 Containerd ，捐赠给了 CNCF。至此（Docker 赔了夫人又折兵，被榨干了），以后也就 Dockerhub 这个容器仓库、Compose这个单机编排工具耳熟能详了，至于 Swarm，基本没有市占率。群雄逐鹿，k8s 成为了最后的王者，企业容器编排的首选方案。</p>
<h2>个人学习之路</h2>
<p>小故事讲完了，我个人的集群学习之路反而不是从 k8s 开始的，而是 Docker Swarm。它开启了我对集群的认识，让我感受到原来跨主机编排（集群编排）的魅力，虽然引入了一堆新的问题，但是集群网络的互联互通是真的很舒服。一个节点的容器可以访问另一个节点的容器，而不是通过 gateway(apisix/nginx)等中间件来暴露两者来进行互联。Docker Swarm 操作也简单，Docker 软件套件自带，非常适合入门学习集群相关的理念，作为跳板上手 k8s。</p>
<p>现在的 k8s 调用链，kubelet -&gt; containerd -&gt; containerd-runc-shim -&gt; runc </p>
<p>曾经的 k8s 调用链，kubelet -&gt; docker-shim -&gt; docker -&gt; containerd -&gt; containerd-runc-shim -&gt; runc </p>
<p>runc 也是最底层的容器运行时，负责最基础的运行时功能，可以看到在这里面有两个 shim（垫片），其实就是个中间件，用来翻译 API 调用，也保证了底层组件对上层是透明的。</p>
<p>可以看到在 Containerd 成熟之后，k8s 果断抛弃了 Docker。一部分是竞争，一部分是维护起来太费力了，Docker 发版的话，kubelet 为了兼容，必须跟着强制发版，而且 Docker 自己也是调用 Containerd，那为啥不直接用 Containerd 呢？还减少一层调用。</p>

      <p style='text-align: right'>
      <a href='https://www.timochan.cn/posts/any_pen/conatiner_one#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">67bda7c3c36e2abe66943f68</guid>
  <category>posts</category>
<category>随笔</category>
 </item>
  <item>
    <title>OnePlus ACE 3 开箱体验</title>
    <link>https://www.timochan.cn/notes/44</link>
    <pubDate>Sun, 06 Oct 2024 08:41:23 GMT</pubDate>
    <description>前言

实习了三个月，存了一些工资，原本打算攒钱租个新房子，结果没想到提前结束了在腾讯云的实习。既然</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://www.timochan.cn/notes/44'>https://www.timochan.cn/notes/44</a></blockquote>
      <h2>前言</h2>
<p>实习了三个月，存了一些工资，原本打算攒钱租个新房子，结果没想到提前结束了在腾讯云的实习。既然如此，干脆给自己换个新手机吧！我原来的手机是 <strong>realme V15 8+128</strong>，用了三年多，现在连打企业微信的卡都卡顿得厉害。它搭载的是天玑 800U 处理器，按性能排行来看，也就稍微比 <strong>HuaWei Nova 11 SE</strong> 强一些，而两者的售价也都一样——1999 元。</p>
<p>那该换什么手机呢？考虑到 <strong>Xiaomi</strong> 现在越来越严格的 BootLoader 解锁政策，我果断选择了 <strong>OnePlus</strong>。OnePlus 解锁方便，也不需要像小米那样通过答题考试，个人实在不喜欢这种流程。</p>
<p>最后我锁定了 <strong>OnePlus ACE 3</strong>，16+512GB 的版本。一次性解决了内存和存储焦虑，再也不用担心下载个游戏没存储空间了。</p>
<p>至于颜色，我选了 <strong>月海蓝</strong>，觉得挺好看的。</p>
<p></p>
<p>不过，不得不吐槽一下 OnePlus 的包装盒和充电线。通体红色，总给我一种违和感。如果换成蓝色，不是更搭配嘛。</p>
<h2>使用体验</h2>
<p>这款手机定位中端，因此在拍照方面有所妥协，主摄使用的是 <strong>IMX890</strong>，据说是旗舰机的长焦？不过拍照效果明显比我之前的 realme V15 好得多。</p>
<p>操作系统方面，因为是 <strong>ColorOS</strong>，没有遇到一些奇奇怪怪的 BUG。相比之下，<strong>realme UI</strong> 现在已经处于一种“爹不疼娘不爱的”状态。OnePlus 毕竟是 OPPO 的“亲儿子”，realme UI 感觉像个“干儿子”。</p>
<p>当时我买 realme V15 的时候，realme 还没完全成为性价比的代表，手机没有红外，也没有 NFC。结果买了一年不到，这些功能全上了，真是“怨种”的体验。如今，像 <strong>NFC</strong> 这种功能，用起来简直太方便了：支付宝支付、公交地铁、POS机刷卡，都只需要轻轻一碰。之前我为了坐车方便，还特意买了一个支持 NFC 的手环。有人可能问为什么不用二维码？每次看到一大堆人挤在闸机口，掏出手机打开二维码，加载半天，我在后面都替他们着急。有了 NFC，进站速度提升，大家都不耽误时间，或者提前加载二维码也行呀....   二维码刷卡不一定有优惠，而交通卡在本地刷卡是有折扣的。</p>
<p><strong>三段式按钮</strong> 调节静音、震动和响铃模式的设计也很贴心，物理开关非常方便，不需要去找图标。</p>
<p>再说说红外功能，虽然看似鸡肋，但实际上特别实用。操控电视、空调这类家电，遥控器不一定随手可得，但手机是“嵌”在身体里的，所以手机肯定随身带。屏幕的显示效果也比我之前的手机细腻得多，还支持 <strong>1-120Hz</strong> 的无级自适应。不过目前 Android 端的适配感觉还不是很到位。手机的曲面屏设计握持手感非常好，<strong>玻璃背板 + 金属中框</strong> 的质感一流。最后，<strong>骁龙 8 Gen 2</strong> 处理器在性能上简直把我的天玑 800U 吊打。从 <a href="https://www.socpk.com/">socpk</a> 的综合性能来看，综合性能是天玑 800U 的四倍！这种升级体验就像从 <strong>速龙时代</strong> 直接跃升到 <strong>锐龙时代</strong>，让人震撼。系统动画流畅得不像话，之前为了减轻处理器负担，我都是尽量关闭动画的。</p>
<h2>总结</h2>
<p>经济基础决定上层建筑。自己挣钱自己花，不用跟家长商量，也不会受到他们的干预。现在更换手机的目标已经达成，接下来就是组装一台台式机了！</p>
<p>文中有一个 Follow 邀请码？你知道它在哪里么？</p>
<p><del><a href="https://www.timochan.cn/api/objects/file/8r806hgw1r2acpofp7.png">https://www.timochan.cn/api/objects/file/8r806hgw1r2acpofp7.png</a></del></p>

      <p style='text-align: right'>
      <a href='https://www.timochan.cn/notes/44#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">67024d3351847e08b16ee863</guid>
  <category>notes</category>
false
 </item>
  <item>
    <title>离别</title>
    <link>https://www.timochan.cn/notes/43</link>
    <pubDate>Fri, 27 Sep 2024 14:43:11 GMT</pubDate>
    <description>前言

古语有云：“天下无不散之筵席。”光阴荏苒，韶华易逝。三个月的腾讯云实习时光悄然划过指间，如水</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://www.timochan.cn/notes/43'>https://www.timochan.cn/notes/43</a></blockquote>
      <h2>前言</h2>
<p>古语有云：“天下无不散之筵席。”光阴荏苒，韶华易逝。三个月的腾讯云实习时光悄然划过指间，如水东流，不复回首。如今，到了启程告别之时，我将带着一份留恋与憧憬，踏上新的旅程，去探寻未曾触及的风景，迎接尚未相识的事物。</p>
<h2>其他</h2>
<ul>
<li><p><strong>Follow 项目</strong></p>
<p>近日，我一直在跟进名为 <em>follow</em> 的项目，担任其 AUR 软件包的维护者。岂料不久前，一个 AUR User 把我的包提了 Delete Request，令我一时愤愤不平。还好，AUR 的 Admin，似乎见多了这种情况，直接将具争议的软件包移除，解决了矛盾点。更有趣的是，偶然逛闲鱼时，竟发现 <em>follow</em> 的邀请码竟被卖到了每个七十元之高价，实在令我感到震惊。不禁感叹，现在经济真的是不景气呀，连一个 Beta 的邀请码都要卖。</p>
</li>
<li><p><strong>购入新服务器</strong></p>
<p>适逢腾讯云 lighthouse 四周年庆典之际，优惠不容错过，遂又购入一台服务器，作为我的 k8s 集群中的 Worker Node。至此，我的 k8s 集群终于得以扩容，日后再也不会遭人调侃不如 k3s 的轻量集群了。此事虽小，却不乏成就感，足以令我在未来的架构规划中更为得心应手。</p>
</li>
<li><p><strong>k8s 持续学习</strong></p>
<p>在实习的过程中，我深感自身 Kubernetes 领域的知识尚且薄弱，虽不至茫然，然则不足之处仍显而易见。因此，近来我不懈努力，努力学习，力求补齐短板，使技术层面更加完善。相信日后再遇复杂场景，必能从容应对，游刃有余。“知其然，知其所以然”是我的学习目标。</p>
</li>
</ul>
<h2>总结</h2>
<p>如果让我去寻找别的地方，我可能会不自觉的去对比一下在腾讯云的实习经历和感受吧。</p>
<p>文中有一个 follow 邀请码，你知道在哪里么？<del>VTJGc2RHVmtYMThmQko0dTBMSWhueWlWUHF3UHNWNmtyQlo0TytTWXpxND0=</del></p>

      <p style='text-align: right'>
      <a href='https://www.timochan.cn/notes/43#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">66f6c47fcb70bf6e74263e64</guid>
  <category>notes</category>
false
 </item>
  <item>
    <title>初入职场：租房与生活初体验</title>
    <link>https://www.timochan.cn/notes/42</link>
    <pubDate>Sun, 25 Aug 2024 15:23:47 GMT</pubDate>
    <description>前言

最近我在 Tencent Cloud 实习，初来乍到，就深刻感受到了 Tencent 作为国</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://www.timochan.cn/notes/42'>https://www.timochan.cn/notes/42</a></blockquote>
      <h2>前言</h2>
<p>最近我在 Tencent Cloud 实习，初来乍到，就深刻感受到了 Tencent 作为国内顶级互联网企业，在企业组网方面卓越的技术实力。相比自己在家里搭建一个简单的国内外分流网络，企业组网要面对的挑战则复杂得多——如何实现多地域内网的有效隔离？网络容量该如何规划冗余？接入方式和认证机制又该如何设计？如何隔离开发环境？这些问题在我逐步接触内网的过程中，逐渐体会出其复杂性与独特的魅力。所以有的时候真不是大企业问的难，是人家天天都在和这些打交道。</p>
<h2>工作环境</h2>
<p>这里的工作氛围令人愉快，与前辈们相处融洽，他们总是乐于解答我的问题（除非实在太忙）。即便前辈忙碌时，我也可以耐心等待合适的时机再提问。团队氛围自由宽松，工作环境舒适，没有严格的着装要求，偶尔上班稍微迟到也不会有太大问题。但，有些公司却因为迟到而扣钱，甚至对员工形象有严格要求。对比之下，高下立判，好的企业注重实际工作表现，而不会在这些表面功夫上计较。在这里工作，感觉与在学校实验室差不多，甚至更加轻松（至少工作时间没那么长~）。</p>
<h2>租房经历</h2>
<p>租房是大学生步入社会的第一课。由于初来乍到、手头拮据，我选择了一个相对便宜的城中村（其实叫商业村更贴切）。白天环境还算安静，勉强还能接受，但一到晚上，情况就截然不同了。</p>
<p>最近一段时间，后面的烧烤摊常常有人聚在一起喝酒、撸串、猜拳，而房子的隔音效果极差，我甚至能清晰地听到他们猜拳的内容。这种吵闹的环境让我休息不好，感到十分疲惫，于是打算在租约到期前搬走。新住处还在考察中，计划周末去实地查看。</p>
<p>城中村看似便宜，但实际情况并非如此。电费高达 1.5 元一度，房东可能通过一个户号统一缴费，导致每个人都要按最高档的标准 AA，这种“被抽血”的感觉真是让人不爽。</p>
<p>而且，这个城中村的环境极其混乱，各种人员鱼龙混杂，商户提供的服务，成分很复杂，既有正常的商业活动，也有不少见不得光的“生意”，比如信用卡套现、花呗套现、白条套现，甚至一些“上门服务”。我真切感受到这里的环境脏乱差，人员复杂，因此打算尽快搬到一个更干净、舒适的地方。</p>
<h2>消费水平</h2>
<p>这里的消费水平着实不低，尤其是在我居住的城中村。如果离开这片区域，消费水平大约能降低 20%；而如果进一步远离这个区，甚至能减少 20%-50%。</p>
<p>有时候想吃点好的，却担心食材的卫生情况，比如在我取快递时，看到店主竟然把猪头肉放在门口晾晒，周围还盘旋着一群苍蝇……这让我感到无语至极。即便是吃个简单的黄焖鸡米饭，也要花费 30 元，这样的物价实在难以接受。相比之下，在郑州，类似的菜品价格仅为 15-20 元，分量更足，配菜也更丰富。</p>
<p>这边的水果店真是让我大开眼界。大夏天居然卖橙子，一斤八块，随便拿四个就三斤多了？！结果橙子切开后，里面干巴巴的，完全没水分，简直像被吸血鬼抽干了一样.... 也许是我没有生活经验，不会过日子吧，在村子里面哪哪都踩雷，还不如去外面的华润万家买水果啥的，至少不会故意打个黄光灯/红光灯。最可笑的是，华润万家的水果品质比城中村好，价格还便宜。😤🤗</p>
<p>可以说，这片区域真的不适合居住，我打算尽快搬离。</p>
<h2>未来计划</h2>
<p>《黑神话：悟空》发布了，我的 Steam 库里已经有了一份豪华版，现计划攒一台新电脑，配置暂定为 12400f/12490f + 6750gre，准备好好体验一下曾经想玩的游戏（短期内估计没希望）。</p>
<p>搬家也是近期的重要计划之一。我打算找一个离公司稍远的房子，这样每天上下班可以骑自行车锻炼，强制自己完成每日的运动量。此外，我希望新房子里有厨房，这样下班后可以自己动手做饭，提升厨艺。</p>
<h2>对后来人的建议</h2>
<p>如果你手头宽裕，收入也还不错，我建议一开始就选择一个相对舒适的住处。毕竟，良好的休息是一天的开始，谁也不希望半夜被喝酒猜拳的吵闹声吵醒吧？另外，建议房租水电等费用不要超过收入的三分之一，否则你的生活质量可能会受到影响。</p>
<p>关于租房软件，如果你的城市有自如这样的自营房源，可以优先考虑，或者使用贝壳找房？至少贝壳的价格相对真实（不真实可以举报）。远离 58 系的平台，比如 58 同城、安居客等，它们常常发布一些低价房源来吸引流量，等你过去看房时，却告知没有这套房源，然后带你看其他房子，实际上就是在骗人。个人认为，贝壳可以作为一个重要参考，有时通过正规中介确实能省不少心，当然享受了服务就应该付出应有的代价。</p>

      <p style='text-align: right'>
      <a href='https://www.timochan.cn/notes/42#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">66cb4c8321d69bab5294090a</guid>
  <category>notes</category>
false
 </item>
  <item>
    <title>CatWrt 使用经验</title>
    <link>https://www.timochan.cn/posts/study/catwrt_usage_tips</link>
    <pubDate>Sat, 20 Jul 2024 17:20:46 GMT</pubDate>
    <description>Proxy 软件 DNS 解析模式怎么选？

DNS 解析模式大致分为 Redir-Host 和 F</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://www.timochan.cn/posts/study/catwrt_usage_tips'>https://www.timochan.cn/posts/study/catwrt_usage_tips</a></blockquote>
      <h2>Proxy 软件 DNS 解析模式怎么选？</h2>
<p>DNS 解析模式大致分为 Redir-Host 和 Fake-IP 两大类。</p>
<h3>Fake-IP</h3>
<p>什么是 Fake-IP 模式呢？</p>
<p>通俗地讲，Fake-IP 模式是指 Proxy 软件在处理 DNS 请求时，首先将域名解析到内网 IP 池中，并记住这个域名和内网 IP 的映射关系，然后 Proxy 软件会根据域名分流规则处理这些请求：</p>
<ul>
<li><strong>在 Proxy 链中的域名</strong>：使用 Fallback DNS（通常为国外 DNS）进行实际解析或直接封装为 Proxy 流量发送到对应的服务器。</li>
<li><strong>在 Direct 链中的域名</strong>：使用 NameServer（通常为国内 DNS）进行实际解析。</li>
</ul>
<p>当你对这些内网 IP 发起请求时，Proxy 软件会检查映射表，找到对应的域名，并根据分流规则将流量处理为 Direct 或 Proxy 流量。一般情况下，Meta Core 的配置如下：</p>
<pre><code class="language-yaml">fake-ip-range: 192.18.0.0/16</code></pre><p>当你的 DNS 请求被 Meta Core 劫持后，返回的 DNS 解析结果就会是这个 IP 池中的地址。</p>
<p>这种做法的目的是：</p>
<ul>
<li><strong>对抗首次解析的干扰</strong>：减少已知 Proxy 域名的 DNS 泄露。第一次的 DNS 解析都会被 Proxy 软件根据分流规则处理，避免国内 DNS 泄露已知的 Proxy 域名。</li>
<li><strong>利用国内 DNS 的速度优势</strong>：在访问国内服务时，解析速度不受影响。</li>
</ul>
<p>然而，这种模式也有一些代价：</p>
<ul>
<li><strong>部分软件的验证</strong>：如果发现是内网网段，可能认为被中间人攻击，拒绝正常工作。</li>
<li><strong>一些软件无法使用</strong>：比如 UWP 应用，BT、PT 等应用可能会有问题。UWP 应用尚且可以通过 fake-ip-filter 去解决，那其他类型的情况呢？</li>
</ul>
<p>综合来看，Fake-IP 只适合大多数普通用户，他们只需要 Proxy 功能，而不对网络进行深入探索，不深度使用 BT、PT 等应用。</p>
<h3>Redir-Host</h3>
<p>现在说说 Redir-Host 模式。</p>
<p>通俗地讲，Redir-Host 不会将域名解析到内网 IP 池中。你的 DNS 查询会首先使用 NameServer 进行查询，当域名属于 Proxy 域名时，调用 Fallback DNS 进行二次查询。如果 NameServer 和 Fallback DNS 设置为同一个，你会明显观察到 Proxy 域名的查询时延是非 Proxy 域名的两倍。在正确设置下，Redir-Host 模式应始终返回域名的真实 IP，自然没有 Fake-IP 的问题。</p>
<p>然而，这种模式也有一些代价：首次解析使用 NameServer，无论域名是什么，首次解析都会通过 NameServer 进行。当 Proxy 软件匹配分流规则时，如果发现域名在 Proxy 链中，就会调用 Fallback DNS 进行二次查询，确保解析结果没有污染。结果是 Proxy 域名可能会在国内 DNS 泄露。</p>
<p>但也有解决办法：使用无污染的 DNS，例如，自建上游 DNS 或使用 Google DNS。这样就不需要 Fallback DNS，因为你已经能保证 DNS 的纯净，Proxy 域名不会传递给大陆 DNS，在这个过程中，你应该会使用加密 DNS，这样可以防止中间人劫持等。可以使用 <a href="https://ipleak.net">ipleak</a> 检查 Redir-Host 模式下的 DNS 泄露。如果没有一个大陆 DNS，则认为可以。</p>
<p>我个人强烈推荐 Redir-Host 模式，因为这个模式才是符合直觉的，不会造成很多非预期行为。</p>
<p>如果想详细了解这些，请在评论区告诉我，我会考虑再写一篇。</p>
<h2>防火墙的 IP 动态伪装</h2>
<p>这个名字有些拗口，直接称为 NAT 功能总开关更清晰明了。开启该功能即启用该接口的 NAT 模式，如果在 WAN 口开启，来自 LAN 口的流量会进行 FORWARD + NAT。</p>
<h2>防火墙的 MSS 钳制</h2>
<p>这个名字也不太好理解，称为 MTU 匹配功能开关更清晰明了。其功能非常简单：将发送的数据包匹配到当前接口的 MTU。当数据包大于 MTU 值时，会进行分包发送，使数据包更加碎片化，可能增加丢包率，网络延迟明显增大等，用户会观察到网页加载时间变长。打开这个开关可以避免这些问题，提高网页加载速度。</p>
<p>开启该功能开关后，可以防止 IP 分片，以及超大数据包导致的网络延迟。</p>
<p>这个功能有代价吗？当然有。CPU 处理数据包会有额外的性能开销，增加负载，可能影响极限性能。</p>
<p>如何手动调整网卡的 MTU 值呢？</p>
<p>首先应测试目标接口的 MTU 值。因为我的 CatWrt 是旁路网关，我就测试 PC 到该网关的 MTU 值。</p>
<pre><code class="language-">ping -M do -s 1472 175.45.176.100 # 175.45.176.100 为 CatWrt 的 LAN（v4）口地址</code></pre><p>如果数据包过大，会返回如下信息：</p>
<pre><code class="language-">ping: local error: message too long</code></pre><p>示例命令设置的数据包大小为 1472 字节，可以以 2 字节为梯度逐步减小数据包大小，直到找到合适的大小。假设 1472 字节的大小成功 ping 通，对于 IPv4 的计算方法如下：</p>
<p>1472 + 8（ICMP 报文长度）+ 20 （IPv4 头部长度）= 1500</p>
<p>对于 IPv6，假设 1450 字节成功，计算方法如下：</p>
<p>1450 + 8（ICMP 报文长度）+ 40（IPv6 头部长度）= 1498</p>
<p>这个值可以在 CatWrt 的接口设置中调整。如果你的 LANv6 和 LANv4（IPv6 和 IPv4 逻辑接口）绑定的是同一个物理接口，建议以 IPv6 设置 CatWrt  LAN 接口的 MTU 值，然后修改 PC 网络接口的 MTU 值（可以不修改，正常的都会去自动设置 MTU 值），与之对应。如图所示：</p>
<p></p>

      <p style='text-align: right'>
      <a href='https://www.timochan.cn/posts/study/catwrt_usage_tips#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">669bf1ee465bceb8128a9b5e</guid>
  <category>posts</category>
<category>学习</category>
 </item>
  <item>
    <title>旁路网关：使用 CatWrt 来提升网络体验</title>
    <link>https://www.timochan.cn/posts/jc/using_catwrt_to_enhance_network_experience</link>
    <pubDate>Wed, 17 Jul 2024 15:55:01 GMT</pubDate>
    <description>前言

最近笔者外出实习，购买了一台 HUAWEI CPE 用于上网（主要是电信的签约有些坑）。mi</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://www.timochan.cn/posts/jc/using_catwrt_to_enhance_network_experience'>https://www.timochan.cn/posts/jc/using_catwrt_to_enhance_network_experience</a></blockquote>
      <h2>前言</h2>
<p>最近笔者外出实习，购买了一台 HUAWEI CPE 用于上网（主要是电信的签约有些坑）。<a href="https://www.miaoer.xyz">miaoer</a> 得知后，送了一台已经刷好 CatWrt（OpenWrt）系统的 R2S 给我体验。当然，我也简单体验了一下路由级别的 Proxy，突然理解了为什么他们对这个如此热衷。</p>
<h2>网络拓扑图</h2>
<p>我的网络拓扑非常简单，如下所示：</p>
<p></p>
<h2>CPE 设置</h2>
<p>在 CPE 端，对手机设置了 DHCPv6 黑名单，不向手机下发 v6 相关的 IP 配置信息，同时将 DNS 设置为 CatWrt，然后对 MAC 和 IP 进行静态绑定</p>
<h2>CatWrt 设置</h2>
<h3>软件配置</h3>
<p>关于 OpenWrt，其实我早在虚拟机中体验过。给其他群友解决软路由问题时，也曾了解过相关的软件生态。大部分软件都强耦合 dnsmasq 这个 DNS + DHCP 软件，虽然简单，但我个人觉得在 OpenWrt 中使用它容易引发很多非预期行为。</p>
<p>首先，我禁用了 dnsmasq 的启动，不允许其自启并关闭该软件（虽然没完全关闭，但至少不再捣乱）。</p>
<p></p>
<p>我希望在内网中使用 AdGuard Home 作为 DNS 解析器，并将我的 DNS 信息加密传送到 DNS 服务器。这一步很简单，通过 WebUI 配置即可。但需注意，AdGuard Home 不能接管 53 端口，可以将其设置为 8053 端口。配置截图如下：</p>
<p></p>
<p>你可能会问，那么谁接管 53 端口呢？当然是 Proxy Software，让 Meta Core 接管 53 端口，这样 Meta 可以第一时间获取 DNS 解析请求，并根据域名进行分流，最大化 Meta 的规则作用。</p>
<p>第一步是，将 Meta 的 DNS 设置为 53 端口。</p>
<p></p>
<p>然后开启自定义上游 DNS，地址为 127.0.0.1:8053，将 DNS 请求转发给 AdGuard Home。</p>
<p>然后使用 redir-host + 混合模式，并开启 Meta Core 的 IPv6 支持。</p>
<p></p>
<h3>接口配置</h3>
<p>我对 v6 也有追求，所以开启了 Meta Core 的 v6 支持。这需要让 CatWrt 也拥有一个 v6 地址。通过 WebUI 配置这一步很简单，效果如下：</p>
<p></p>
<p>在主路由上，我固定了 CatWrt 的 V4 和 V6 地址。</p>
<p>最后，只需在需要接入的终端设备上设置自定义 IP 地址，网关指向软路由（CatWrt）即可。</p>
<h2>成品</h2>
<p>最终效果如图：</p>
<p></p>
<p>可见，已经实现了域名分流。</p>
<p>DNS 查询流程图：</p>
<p></p>
<h2>问题</h2>
<p><strong>Q：手机 WI-FI 不支持自定义 IPv6，但 Meta 开启了 V6 支持，该如何解决？</strong></p>
<p><strong>A：</strong> 在主路由一侧，不对手机下发 v6 IP 配置。</p>

      <p style='text-align: right'>
      <a href='https://www.timochan.cn/posts/jc/using_catwrt_to_enhance_network_experience#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">6697e955465bceb812884a3c</guid>
  <category>posts</category>
<category>教程</category>
 </item>
  
</channel>
</rss>