<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on 旁注旁观</title><link>https://icorer.com/icorer_blog/posts/</link><description>Recent content in Posts on 旁注旁观</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 12 Nov 2026 11:30:00 +0800</lastBuildDate><atom:link href="https://icorer.com/icorer_blog/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>五个壶铃动作，三条轴心</title><link>https://icorer.com/icorer_blog/posts/training/five-kettlebell-moves-three-axes/</link><pubDate>Thu, 12 Nov 2026 11:30:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/training/five-kettlebell-moves-three-axes/</guid><description>五个动作可以归到三条轴上。髋管输出功率，肩管活动度，对角线管传递。抓举站在三条轴的交点上，所以它是最难被替换的那个。
片长 26 秒，无声，画面上是每个动作的阶段名和一句提示，文字跟这一页的语言一致。每段三到八秒，循环两个周期。
一、先把五个动作摆成一张图# 健身房里的推和拉几乎都在两个平面里完成，矢状面前推后拉，额状面侧平举。壶铃的这五个动作把身体带出了这两个平面，而且分工很清楚。
轴 动作 主要练什么 髋 摆动、高脚杯深蹲 后侧链的输出功率与力量 肩 绕头 肩带的环转与胸椎伸展 对角线 交叉身体划船、抓举 躯干的斜向传递与抗扭转 抓举同时用上三条轴。它在图上落在交点的位置，所以五个动作里只有它不能被别的动作顶替。剩下的四个各占一条轴的一端，换掉一个，那条轴还在。
图 1　五个动作在三轴图上的位置，抓举落在三条轴的交点，其余四个分居三条轴上轻点放大 把这套动作摊到基本动作模式上，能看出它的边界。八种模式里，有三项被完整覆盖，两项只有一半，三项没有。
动作模式 对应动作 覆盖 备注 蹲 高脚杯深蹲 有 双侧，前负荷，深度好 髋铰链 壶铃摆动 有 爆发性质，不是最大力量 水平拉 交叉身体划船 有 单侧，带旋转 垂直推 抓举的锁死位 半个 只有稳定，没有负荷推进 水平推 无 无 俯卧撑或卧推需另补 负重行走 无 无 农夫走、架式走 单腿 无 无 弓步、分腿蹲需另补 旋转与抗旋转 绕头、交叉划船 部分 核心控制，非弹道旋转 这张表决定了这套动作的用法。它补的是后侧链、肩关节、躯干旋转这三块，缺的是推和单腿。当成完整方案用，得往里加两个动作；当成补丁用，直接挂到现有计划上就行。
二、摆动练的是髋，手臂只负责传# 摆动和深蹲的分界线在膝盖。回摆到底的时候，小腿接近垂直，屈膝幅度在 20 到 30 度之间，骨盆向后平移，躯干像一块板整体前倾。膝盖再屈下去，动作就变成了深蹲，髋的功率从这条链上漏掉。
图 2　回摆到底时臀向后、小腿近乎垂直，躯干整体前倾轻点放大 顶髋的终点是站直。髋伸到底，臀大肌收紧，肋骨保持下沉，过了这个点再往后仰，负荷就从臀转移到腰椎。铃到胸高靠的是惯性，肩胛只是被动跟随，不主动上提。</description></item><item><title>不建向量库：SAG2 用一个 25.87 MiB 的 SQLite 索引拿到 86.62 召回</title><link>https://icorer.com/icorer_blog/posts/ai/sag2-embedding-free-retrieval/</link><pubDate>Wed, 11 Nov 2026 14:12:52 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/sag2-embedding-free-retrieval/</guid><description>语义判断可以挪到提问之后。索引只留词与词频，一个 SQLite 文件，建库 2.36 秒，MuSiQue 的 R@10 从 54.41 抬到 86.62。
原文是《SAG2: Embedding-Free Multi-Hop Retrieval with BM25 and JEV》，Zleap AI 的 Yuchao Wu，arXiv 编号 2610.22588，全文 15 页（arXiv 页面 ，PDF ）。代码在 Zleap-AI/SAG-Benchmark 。它是同一位作者前作 SAG 的续篇，SAG 用 MySQL 存事件与实体、用 Elasticsearch 存向量，这篇把两者都去掉。下面每个数字都能回到原文的表号，凡是我自己除出来的都标「我算」。
一、埃里克·霍特的出生地# 附录 A 里有一道具体的题，问埃里克·霍特出生在哪。语料里有一段讲霍特本人，它直接命中问题，也进了 BM25 的前一百。另一段讲蒙特贝洛，纽约州的那个地方，只有在知道「霍特出生在蒙特贝洛」之后才有用，而它和原问题的词重叠几乎为零，前一百里没有它。
SAG2 的流程是这样转的。种子只能从高分段落里取，霍特那段正好在里面。种子正文里的「蒙特贝洛」被当成一个可用的词，权重按四个因子算出来，然后拿这个词单独去查一遍索引，蒙特贝洛那段就进来了。最后十条里两段都在，这道题的召回从 50% 变成 100%。
这道题不是孤例。一千道 MuSiQue 题里，有 389 道的最终结果包含至少一段不在初始 BM25 前一百里的证据，这样补进来的段落一共 433 段。BM25 的 R@10 是 54.41，套上这套流程是 86.62。
指标 BM25 SAG2 差 MuSiQue R@10 54.</description></item><item><title>如果没有 KV cache，编码 agent 该怎么设计</title><link>https://icorer.com/icorer_blog/posts/ai/jev-harness-design/</link><pubDate>Wed, 11 Nov 2026 07:16:58 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/jev-harness-design/</guid><description>2026 年 9 月一份围绕 Jev 的设计笔记，用一句话把编码 agent 的六个毛病收在一起。假如语言模型没有 KV cache，今天这些 agent 会写成什么样。答案不在更强的模型上。它要求有人决定，每一轮往模型面前放什么。
片子两分多一点，中文配音，字幕烧在画面里，也可以用播放器关掉。
一、一个反问，六个症状# 今天的编码 agent 大多是一个循环、一个模型、几只工具。真正决定它好不好用的东西不在这个循环里，而在循环每转一次时递给模型的那段文本。
KV cache 是这段文本写成追加式记录的原因。复用缓存前缀几乎免费，改动靠前的任何一个字节，后面全部要重算。这条经济学没有写进任何设计文档，它写在账单里，并且决定了几乎所有主流 agent 的骨架。
把缓存当成不存在，会同时发生两件事。一是可以按状态显式设计，上下文是组装出来的。二是六个一直被人抱怨的缺陷露出同一个底。
症状 为什么它会存在 代价 路由失败 交回大模型时上下文被重算 混合路由比纯 frontier 更贵 工具挤占上下文 schema 必须常驻系统消息 无关工具的 token 照付，选择还更差 压缩压在问题之前 假设所有轮次共享一份状态 查询无关的压缩丢掉后面要用的信息 子 agent 很少启动 传什么进去、合并什么回来很难 并行度低 重启丢掉状态 有状态的记录会漂移 坏状态和好状态一起扔 内置能力之争 每个内置永久占用上下文 在易用和强大之间二选一 这份笔记给替代方案留了一个位置，叫 Jev。它不写代码，坐在模型旁边当决策层。harness 把当前状态交给它，包括目标、上下文、规则、可用动作和已执行动作，同时给一个预设问题，它返回类型化答案，取值为 choice、score 或 noul，各带一个概率。类型化带来的是可校验，harness 能卡阈值、能分支，不用解析散文。
轻点放大 笔记把这套东西压成一张表，六个高频决策点，一个问题一个类型化答案。
决策点 问 Jev 什么 返回什么 上下文 这一段对这个查询该有多可见 隐藏、短摘要、长摘要、全文 缓存 复用前缀还是重建 noul 加概率 路由 这个子任务能不能离开 frontier 选择加成本估计 工具 哪只工具对得上这个意图 排序结果，取前 k 权限 这条命令能不能跑 允许、询问、拒绝 安全 这个任务会碰哪些文件 敏感度分数 六个问题每轮都问，一次会话里问上千次。笔记把杠杆放在这个位置，模型那边没有。</description></item><item><title>多教师蒸馏按 token 分账</title><link>https://icorer.com/icorer_blog/posts/ai/mopd-token-share/</link><pubDate>Tue, 10 Nov 2026 07:02:51 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/mopd-token-share/</guid><description>TRL 的多教师在线蒸馏示例跑了 60 步。指令跟随拿了 20% 的 prompt，训练 token 只分到 1% 到 3%，它是三科里唯一没学动的。Open-MOPD 那篇论文把这个现象叫 token 预算错配，修完之后可回收的能力上限从 35.6% 提到 83.4%。
片子一分五十八秒，中文配音，字幕烧在画面里。
一、六十步之后，只有一条线没动# 2026 年 11 月，Hugging Face 的 Sergio Paniego 把 Open-MOPD 放出的三个专家接到 TRL 的 AsyncDistillationTrainer 上。学生是 SmolLM3-3B 的 SFT 检查点，三个教师分别用 GRPO 在数学、代码、指令跟随上训过。跑 60 步，大约是论文训练量的百分之一。
训练日志里出现两件事。teacher_token_frac 显示指令跟随每步只拿到 1% 到 3% 的训练 token，而它在 prompt 里占 20%。teacher_jsd 显示学生到数学、代码两个教师的距离一路往下，到指令跟随那个几乎是一条平线。
评测端跟着这个形状走。
模型 AIME24 AIME25 IFEval MixSFT 起点 17.5 19.2 67.5 60 步 MOPD 24.2 22.5 73.</description></item><item><title>本体构建的分水岭不在模型大小</title><link>https://icorer.com/icorer_blog/posts/ai/ontology-evolution/</link><pubDate>Mon, 09 Nov 2026 11:08:09 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/ontology-evolution/</guid><description>2025 年 12 月到 2026 年 11 月，六篇论文从三个方向收口到同一个结论。本体构建的瓶颈已经从「谁能把本体写出来」移到「谁能证明写出来的东西是对的」。下面每一个数字都能回到原文的某一节或某一张表。
片子两分十九秒，中文配音，字幕烧在画面里，也可以用播放器关掉。
一、同一个事故，现在可以量了# 一支队伍把 40 张表的关系库交给模型，生成一版本体。人工审了两天，改掉三分之一，剩下的签了字。三个月后有人问，某条 subclass 关系是哪来的，没人答得上来。它可能是从外键推出来的，也可能是从邻表名字猜的，区别在事后无法分辨。
这件事过去只能靠经验描述。2025 年 12 月，Burr 给了第一套统一的度量，54 个手工场景加 4 个真实数据库（PACMMOD 3(6) 第 305 篇）。2026 年 7 月，一份系统综述数完了这个方向的 30 篇论文、41 项研究（Semantic Web 17(4)）。2026 年 11 月 2 日，LLMs4OL 第三届的赛道报告发布，13 支队伍上榜。三份材料的规模差得很远，指向的问题一样。
轻点放大 二、第一个统一基准打碎了模型通吃这条说法# Burr 的 §1 先算旧账。作者按 Mosca 等人的方式复查了十个本体学习系统，结论是多数论文根本不评测，或者只做词法比对，连 F1 怎么算都不写。
他们的解法是把评测绑到 mapping 上（§4）。一个本体光有类名不算数，还得说清它对应数据库的哪张表、哪一列，真阳性按 mapping 算。这个改动把「名字像」和「指对了」分开，也顺手把词法 F1 的虚高暴露出来。
微基准（§6.2.1）的结果是这样。
系统 微基准 mapping F1 备注 Gemini 2.5 Pro，checklist 提示 0.</description></item><item><title>评测（Evals）：一个 AI 系统能不能用，看四个数字</title><link>https://icorer.com/icorer_blog/posts/ai/evals-honest-numbers/</link><pubDate>Mon, 09 Nov 2026 07:36:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/evals-honest-numbers/</guid><description>一个 eval 的钱主要花在读输出和标用例上，代码只占很小一块。这篇把它拆成四个部件，每个部件配一个可以自己复算的数字。
片子一分五十五秒，中文配音，字幕烧在画面里，也可以用播放器关掉。
一、两条规则放过的回答# 一家卖自行车和露营装备的网店，客服工单进到模型里。工单说，我上周退了车，退款还没到账，你们自己写着五个工作日。
系统的回复很客气，四段，引用了退换货那一节，两个必含事实也都在，五个工作日和二手商品 15% 的折旧费。两条代码规则同时放行，一条查有没有引用章节，一条查必含事实齐不齐。
模型判官判它失败。它多写了一句「总额度最多 15 个工作日」。
作者在 60 条测试用例上重跑了一遍，只有 11.7% 的回复能通过全部代码规则，而代码规则一条编造的断言都没抓到。这两个数字摆在一起，就是 eval 存在的理由。一段格式和引用都挑不出毛病的话，可以同时是错的，而错的那部分恰好是客户会当真照做的部分。
轻点放大 二、四个词，四条路# 概念 测什么 例子 常见误用 eval 你的系统在你的数据上 这个助手跑 60 条工单 拿它跟别人的模型比 benchmark 一个模型在一套公开题上 GSM8K、SWE-bench 拿它选产品路线 test 一个函数有没有返回预期值 JSON 能解析、不崩 以为通过就是对的 monitoring 上线之后的真实流量 每天抽样评一批工单 只在出事的时候看 四件事的差别不在精度，在数据归属。benchmark 的题是别人出的，eval 的题得你自己攒，攒不出来就没有 eval。原文给了一个比喻，模型是引擎，eval 是你的车在你这条路上的表现。这个比喻站得住，因为它顺手解释了另一件事，引擎评测拿第一的模型，到你这里答错客户的问题，两件事并不矛盾。
三、先读输出，再写判官# 任何自动判官动手之前，先把输出读一遍。作者读的是 60 条测试回复，逐条记一句失败原因，再把笔记并成类别。这批数据的结果是这样。
结果 条数 通过 34 缺必含事实 15 有编造的断言 12 检索到错误章节 8 没有回答问题 5 数值写错 2 过度承诺 1 60 条里 34 条通过，勉强过半。最大的两个问题合计 27 条，从 demo 里完全看不出来，因为 demo 只看一条。这张表就是后面所有判官的需求文档，按频次从高到低建。给不发生的失败写判官，得到的是一个好看但没用的数字。</description></item><item><title>公司多了一层地下室</title><link>https://icorer.com/icorer_blog/posts/essay/future-of-the-firm/</link><pubDate>Sun, 08 Nov 2026 12:40:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/essay/future-of-the-firm/</guid><description>一句话　两个二十四岁的人开始管团队，部下是机器。三种摆法都已在发生，多出来的那一层，账还没人填。
一、两个二十四岁的人# 我见过的组织图都印在 A4 纸上，横着印，竖着能压三排名字。最上面一个方块，往下分叉，叉到第三排就停了，再往下是空的，因为底下没人可管。
原文讲的是一件小事。写这篇文章的两个人在 OpenAI 带团队，都是二十四岁。按老规矩，这个岁数的人在会上做记录、写备忘录，熬上几年枯燥的活，才轮到一个可以自己做主的范围。他们没熬，直接有了部下，还不止一个，这些部下日夜上班，周末也不休。
二十四岁本身不稀奇。稀奇的是这一跳过了两级，一头一脚之间空出来的地方，谁也没说该放什么。
原文把 AI 的位置摆了三种，我做了一张简图放在下面。第一种在人底下，人人有一层地下室。第二种在人旁边，像同事一样跟人一起向经理汇报。第三种在人中间，上面是人，下面也是人，AI 在夹层里做协调。
轻点放大 这三种说法我都听过，区别在这一次讨论的是汇报关系，谁向谁交周报，谁在谁的评审会上签字。这个区别不小。汇报关系一动，办公室里的椅子就要重新摆一遍。
二、多出来的那层地下室# 第一种最不吓人。人还坐在原岗，汇报关系一条没改，唯一的变化是每张工位底下多出一层。原文管这层叫地下室。
地下室刚建成的时候，里面是一两个智能体，像刚来的实习生，写邮件、起草备忘录、随时回一句消息。实习生是要看着的，出错要骂，骂完要教。后来里面有了管理者、会计、律师，你不再带实习生，你在董事会里，它是一家小公司。
原文举了个会计，叫 Jace。他不用再一格一格翻电子表格，那些事由他手下的智能体翻。他现在做的活更像几年前他上司的活，而他上司又有了更大的范围。会计团队没有缩编，因为别的部门产出更高，要算的账反而更多。
原文给这笔账配了一句漂亮话，大意是 AI 接走你九成的工作，剩下那一成会被放大十倍。这句我抄在本子上，抄完又算了一遍。
九成乘十，是九份整活，比我今天干的还多。乘号两头只要有一头虚，等号后面就是空的。原文自己也留了余地，说岗位会变贵，产出高了目标也会跟着涨，但前提是需求真的跟着涨，人也还能为生产添点什么。它举了个反例，说我们拥有的东西多了很多，工作时间只少了一点。这个反例我信，我身边的人买到的东西是三十年前的三倍，闲下来的时间大概只多了半小时。
轻点放大 我不打算给这笔账判死刑，只想在账本边上加一栏。这一栏写的是交接。九成的活被接走以后，你得告诉接手的那一层九成的活是怎么干的。这件事在后一节。
三、插在中间当同事# 第二种比第一种体面。AI 不在地下室，在工位上，和人对面坐着，向同一个经理汇报。
原文的例子是一位家具公司的副总裁，叫 Sheila。她管过销售管过设计，没管过广告。她给了一支 AI 营销团队一笔预算，让它们卖一张新沙发。这支队伍自己分工，有的去访谈销售，有的去工厂确认能不能按时交货，剩下的拍样稿。稿子在自己人之间流转，不必过她的手。周一她收到一份方案，还附带一个问题，照片里那张沙发的蓝，是不是太蓝了。这种细节她自己看不出来。
我读这段时先想到的是行李。原文说一个岗位像一只装满任务的箱子，团队那只箱子塞得更满。箱子越好装满，越难替你装满，因为团队里哪怕只有一件活需要动手，就得给整支队伍配上手脚。
原文说，范围越大，越难做，反而越好用。难做的是建造，好用说的是采用。一把窄工具要全公司学它，一支能干整摊活的队伍只要老板点一下头。
轻点放大 原文在这一节还泼了一盆冷水，这盆我认。它说经济产量几乎全部来自组织，一个人单干能产出的东西少得可怜。拿「一个员工」当尺子去量机器，是把自己看轻了。要够用，就得够得上一群人。
这一句顺带把上一节那张图也改了。如果 AI 只是每张桌子旁边多一把椅子，公司里会多出成千上万个接口，每个接口都要有人盯。所以更可能的形状，是几支整建制的队伍一起进来，而不是一把椅子一把椅子地搬。
四、夹在中间的那一层# 第三种最难咽。人、AI、人，AI 夹在中间，有人得向它汇报。
原文的例子是一位 CEO，叫 Asha。AI 顾问提醒她，正要发布的产品有问题。查下去，是销售答应了一个工程没有做的功能。证据是 Slack 里的日常讨论，没有人写报告，甚至没有人察觉两边说的是两件事。顾问还发现一个在家办公的工程师，没人要求就先搭了底子，于是提醒她给这个人记一功。
这一段我信一半。信的一半是查资料这件事它确实干得了，把几百个频道和文档读一遍，找出那一条对不上的承诺，这活人干起来要两个通宵。不信的一半是这段太顺了，顺得像案例教学，现实里的误会往往不在文件里，在两个人见面点了一下头，谁也没记。
轻点放大 更有意思的是价钱。咨询公司站在企业头顶收钱已经几十年了，按小时计价，进门先做三十页幻灯片。AI 顾问便宜到可以不问价，可以一直在。顾问的聪明还是那点聪明，变的是价钱。价钱一降，它就变成了自来水。
自来水有个后果，原文说得很直白，权力往顶上走。过去信息不通，中层有中层的道理，离现场近的人做决定更快；现在看全局的成本几乎是零，决定就往上收。
原文再往前推一步，自动化的顺序可能从顶上开始。我们习惯想，机器先接走底层的活，判断留给人。可管理者的活大半在屏幕上，读、开会、权衡、做决定；底层反而常常要动手，被派去操作复印机的是实习生，不是他的老板。梯子从上面开始烧，这个画面在原文里配了一张图，一张嘴叼着骨头的手搭在最高的横档上。我看完把书合上了一会儿。
五、四笔账# 原文最后开了四笔账，一笔也没结。我照着抄一遍，把它的话和我的话分开写。
第一笔是繁文缛节。过去每次动手都贵，所以要瞄得准，规划周期、路线评审、审批委员会全是为瞄得准设的。做的成本压下来以后，原文主张少瞄准、多开火，先原型，再观察，再改方向。它顺着这条线往下推，说请示的成本比动手还高的时候，中间那层经理就没有存在的理由了。我信前半段，后半段要打问号，因为请示这件活要的往往是有人签字，正确倒在其次。
第二笔是自主权。原文说顶尖顾问人人都有，决策水平的差距缩小，老板就少了插手的理由。它自己又补了一句反面，同一套东西也能让老板把自己的口味推得更远，连锁餐厅要统一菜单，批量买料省钱，顾客也少踩雷。结论它给得挺乐观，说员工的范围会变大，只是要守的约束更清楚。我同意范围变大，约束更清楚这件事我保留看法。
第三笔是规模。它从科斯 1937 年那篇《企业的性质》讲起，问企业为什么要把生产放进自己的院子。一半答案是省交易成本，另一半是能把激励摆平，飞机公司买下发动机公司，是为了不让对方在合同没写的地方省钱凑合。AI 当了协调层，沟通成本往下掉，院子可以扩大，也可以缩小，原文两边都给了理由。这句我佩服，它没有硬凑一个答案。
第四笔是薪酬。人人都有同一个好顾问，差距应当缩小；人人的部下都被放大十倍，判断力的差价就摊在工资单上。两股力量对着拉，原文没有判谁赢，只留下一句问话，我们到底是在做判断，还是在照判断做。
轻点放大 六、我自己算的这笔账# 上面全是别人的账，我算自己的。
我这辈子只记过两种数，一种是工分，一种是排班。看到「多一层地下室」，我先想到的是排班表上多出来的一栏，那一栏该写谁的名字。</description></item><item><title>不再检索，改成问路：DecisionRAG 用决策模型在文档树上走</title><link>https://icorer.com/icorer_blog/posts/ai/decisionrag-retriever-free/</link><pubDate>Sun, 08 Nov 2026 12:06:43 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/decisionrag-retriever-free/</guid><description>检索的瓶颈不在候选池有多大，而在你让模型看见什么、以什么顺序看。DecisionRAG 把打分换成问路，2.68M 段的语料 1.7 秒给出 65.4 的首位命中；它同样清楚地输掉了三格。
中文配音版，2 分 53 秒。中文与英文两版内容一致。
原文是《Retriever-Free Retrieval: Navigating Documents with Decision Models》，Cornell 与 ASAPP，arXiv 编号 2610.35868，全文 21 页（arXiv 页面 ，PDF ）。下面每个数字都能回到原文的表号或附录号，凡是我自己算出来的都标了「我算」两个字。
一、错的那一条，排在第一# 论文开篇是一个具体的查询。诺兰在 2000 年拍的那部电影，主角是谁。BM25 和稠密检索都会把《角斗士》排到前面去。它也是 2000 年的电影，词像，向量也像。真正能回答问题的《记忆碎片》排在后面，甚至不在前几名。
检索器的接口只有一种比法，把查询和每个候选单独比一次。生成器已经换了两代，检索器还在做词频和余弦。
环节 现状 后果 词频 BM25 在 MultiDoc2Dial 上 R@1 20.6 词重合不等于可答 稠密 Qwen3-Embedding-8B 27.9 召回上限由一阶段定死 重排 8B 重排器把 27.9 抬到 33.6 只能重排已经给它的候选 生成式重排 GPT-5 重排 dense top-20 到 47.5 贵、慢，仍是两段式 论文把这件事叫作能力不对称。检索器漏掉的证据，生成器再强也捞不回来。这个判断没什么新意，有意思的是它选了哪条路来修。
二、之前到哪一步了# 修这条路有三族做法。
一族 代表 天花板在哪 一阶段 + 重排 BM25、SPLADE++、Qwen3-Embedding、BGE、Qwen3-Reranker-8B 重排的输入永远是一阶段给的 100 条 生成式 listwise RankGPT 一路，GPT-5 重排 一次只能看 20 条，成本按 token 走 让 LLM 走层级 MemWalker、PageIndex、LATTICE 每层都要生成一串编号，慢 第三族离这篇最近。它们已经有层级，也已经在每一层做选择，只是选择的方式是「生成」。同一套层级、同一套预算，换成 GPT-5 逐字写出要保留谁，在 ConditionalQA 上要 28.</description></item><item><title>同一张图，十五种写法，差 28 个百分点</title><link>https://icorer.com/icorer_blog/posts/ai/graph-serialization-15-formats/</link><pubDate>Sun, 08 Nov 2026 12:01:41 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/graph-serialization-15-formats/</guid><description>一句话。图怎么写进 prompt，是一个能测量的系统参数。抽取任务上它值 1.3 到 3.9 个百分点，结构化推理上值 28.4 个，而同一个模型家族里三个推理档位各有各的最优写法，最准的那一档用的 token 反而最少。
一、先把这一步的价格量出来# 假设你在做一件很普通的事。用户问了一句需要多跳才能回答的话，你的检索器从图数据库里捞出两跳邻域，封顶 450 条三元组，然后把这堆东西塞进 prompt。
塞进去的方式，你大概率是随手选的。json.dumps 一下，或者抄一段 turtle，或者干脆写成「A 认识 B」的句子。这篇文章说，这一步的选择能让同一个模型在同一个问题上的准确率差 28.2 个百分点。
数字来自 Oracle 的 Julien Yu、Mihaela Bornea、Avirup Sil、Katrin Kirchhoff 四位作者，论文投在 EMNLP 2026 Findings。他们在 110 道 Wikidata 题上跑 gpt-5.4，把子图和问题都固定住，提示也一字不改，只换序列化格式。jsonld 拿到 41.8%，adjacency 拿到 13.6%。
这件事不是第一次被量。TLAG 在合成图上报过 4.8 到 61.8 个点的差距，KG-LLM-Bench 在知识图谱理解任务上报过 17.5 个点。这篇要做的是把设计空间铺开，把推理档位算进去，再补一个真实子图的实验。
二、十五种写法是哪十五种# 论文按语义显性度把格式分成六个家族，共十五种。这十五种都是作者手写的序列化器，不对应现成库里的某个标准格式。
家族 格式 暴露什么 语义网与约束视图 turtle jsonld shacl_lite 类型、谓词、域与值域约束 结构化自然语言 text2kgbench entity_centric relation_indexed 实体与关系的可读描述 表格 markdown_table toon 节点表和边表 图语言 mermaid dot 拓扑的画法 连通性编码 adjacency edge_list structured 邻接关系本身 散文 nl_summary friendship 用句子讲一遍图 差别有多大，看两段就好。同一张五节点的小图，structured 写成两行集合。</description></item><item><title>被看见这件事</title><link>https://icorer.com/icorer_blog/posts/essay/attention-is-finite/</link><pubDate>Sat, 07 Nov 2026 18:02:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/essay/attention-is-finite/</guid><description>一句话　注意力是唯一没法多印的东西，于是围观成了生意。围观的人和被围观的人，后来都得想想自己还剩几分是自己的。
中文配音版，5 分 42 秒，全片硬字幕。
我住的这栋楼，楼道灯是声控的。晚上回家，走到三楼拐角，得先跺一脚，或者拍一下手。它不认人，只认响动。你轻手轻脚地走，它就一路黑着，逼你摸着扶手往上爬；你弄出点动静，它赏你十五秒光亮，然后准时熄灭，不管你走到哪儿了。
这盏灯可以当个模型用。这话我说了好几年，一直没想清楚它到底像什么，直到前些日子读了一封长信。
一、一封讲抢注意力的信# 信是一个开公司的人写的，讲怎么在社交平台上抢注意力。他讲得很有章法，从行情讲到岗位，再讲到具体该怎么做。我读完了，一个字也没打算照做。
我读的时候想的是另一件事。
钱是可以多印的。印多了，钱就毛了，一斤豆角要卖八块。注意力不能多印。一个下午就是那么长，你把它交给一件事，就没法同时交给另一件事。这两样东西的脾气正相反，钱越印越多，注意力越用越少。我这人有个毛病，凡事爱算账，算完多半也就搁下了。
有人把这件事叫注意力经济。这名字起得客气，像给一口井起了个学名。井水是有限的，来打水的人却越来越多，于是有人卖水，有人卖桶，还有人站在井边教别人怎么打水。至于井累不累，没有人问。
轻点放大 那封信讲的是怎么抢。我想的是抢到手之后会怎么样。信我折起来搁在桌角，第二天没再打开。
二、围观# 围观不是新东西。菜市口砍头那会儿，围的人也很多，还自带干粮。栅栏外面伸着一排脖子，看完回家还能就着这事吃两碗饭，谁也没想过自己正在替人定价。如今只是把场子搬到了屏幕上，围观的价格降到零，于是什么都有人围观，包括不值得围观的事。
围观看着不花钱。你不掏钱，只花一点时间，还觉得自己在评判世界。世上的账很少这么算。你多看谁一眼，谁就贵一分；你少看谁一眼，谁就矮一寸。定价这活儿其实是围观的人干的，只是没人给我们发工资。
我也围观。看见热闹，手比脑子快，先点开，再后悔。骂热搜的人和点热搜的人常常是同一批，这两件事在手指头上是同一个动作。这个道理我明白了很多年，一点用也没有。
三、被看见的人# 一个人被人看着，动作就变形。这不用什么理论，你试试在邻居的注视下吃一碗面，面条会突然变得很难夹。
看得久了，人就分不清哪张脸是自己的。他起初是装成那个样子，后来真的变成了那个样子，再后来，只剩下那个样子了。
有一种说法叫个人品牌，意思是你得把自己做成一块招牌。招牌本身没什么不好，招牌能让人远远认出这是谁家。麻烦在于，有人把招牌当成了铺子。招牌挂久了，人就在招牌后面住下了，屋里有没有货，他自己也懒得看。
轻点放大 四、一万个人知道你# 知道和认识是两码事。
轻点放大 一个人知道你，多半只是刷到过你三回，记得你的头像是个蓝的。一个人认识你，知道你怕什么，也看得出你嘴上说不在乎其实在乎，还记得你哪句话是真心的。前者能让你红，后者能让你活得像个人。
名声这东西是别人替你保管的。保管人今天心情好，给你挂着；明天风向变了，收走，连收条都不打。认识你的人保管的那点东西取不走，因为那是你们俩一起攒下来的。
所以我不太信「被更多人看见」本身有多大好处。看的人多，认识你的人不一定跟着多。
五、交出去，和留住# 不过也不能把注意力捂得太紧。
一个人要是一点都不给别人，日子就像一间锁着的屋子，干净，也没人进来，久了连敲门的声音都觉得陌生，还以为是风吹的。人总得被人看见一点。一个认真做事的人被看见，另一个认真做事的人就少走些弯路，这件事是好的。
分寸不好拿。我现在的办法是把一部分注意力挑人给出去，剩下的留住。这办法未必对，只是我用着顺手。我试过一个月不看任何推送，结果并没变聪明，只是脾气好了些，后来又慢慢坏了。坏到什么程度，我不说。
六、我还是轻轻走# 轻点放大 那盏灯听声音，不看人。你跺脚，它亮；你站着不动，它灭。它很公道，不记得谁，也不欠谁。这些年我走过不少灯火通明的地方，那些灯也是这个脾气，响一下，亮一下，没人问你是谁。
我现在上楼，习惯轻轻走。灯不亮，我就摸着扶手上去。黑是黑了点，可那几步路是我的。</description></item><item><title>字节搬走了，计算没跟过去：去中心化数据库的十年与四层账单</title><link>https://icorer.com/icorer_blog/posts/web3/web3db-field/</link><pubDate>Sat, 07 Nov 2026 12:31:38 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/web3db-field/</guid><description>一句话　这条赛道十年没解决的核心问题不是共识不够强，是计算没有跟着字节走。数据库不是一个东西，是四件事——写入顺序、字节位置、执行位置、读权限；六条路线，每家只买走了其中一层。
一、问题：一个停更四年的项目，还在被当作基线# 2016 年，「区块链数据库」是热词。BigchainDB 给的答案很直接：MongoDB 负责存，Tendermint 负责排顺序，每个节点都是整条链的副本，写入即定稿。它拿到 4,030 个 star，被写进无数篇综述和对比表。
GitHub API 上的事实是：最后一次代码推送 2024-07-04，最后一个正式版本 v2.2.2 停在 2020 年 9 月，后续工作交给了 IPDB 的 Planetmint。今天它仍然是审稿人最熟悉的「去中心化数据库」样本。
这不是孤例。Kwil 在 2025 年 4 月把去中心化技术卖给了 TRUF.NETWORK 并开源；Tableland 在 2023 年 4 月拿到 CoinFund 领投的 800 万美元 A 轮，累计融资 1,040 万；Space and Time 2025 年 5 月上主网，把整个叙事押在「用 ZK 证明查询结果正确」上；OrbitDB 做了十年，2025 年宣布 v3 功能完备，2026 年 4 月放出 v4 RC。
这条赛道的死亡名单和产品名单差不多长。它们死在同一个地方：每一家只把四层里的某一层去中心化了，然后宣称自己把整台数据库去中心化了。
轻点放大 二、四层账单：每条路线实际买走了哪一层# 数据库从来不是一个东西，是四件事：写入顺序、字节位置、执行位置、读权限。把四件事拆开，赛道上的所有分歧都变成同一道选择题——你打算为哪一层付去中心化的钱。
路线 · 代表 主张 买走的层 后果 BigchainDB 数据库即链 写入顺序 2020 停更 OrbitDB、GunDB 本地优先 副本同步 无 SQL Tableland SQLite 上链轨 命名权限 单写入者 Space and Time 证明结果 可验证性 证明成本 IPFS、Arweave 内容寻址 字节位置 无下推 Web3DB SQL + 链上 ACL 权限与主节点 20 节点崩 六行里没有一行是错的：账本数据库把写入顺序搬上链，P2P 把副本同步做成协议，Tableland 把表名和权限放到链上，Space and Time 把「结果对不对」做成证明，IPFS 只负责字节在哪，Web3DB 把权限和主节点选举一起搬。但没有一行能单独成立。</description></item><item><title>Project EVE：把 Agent 放进一个已经运行了二十三年的经济体</title><link>https://icorer.com/icorer_blog/posts/ai/agent-economy-project-eve/</link><pubDate>Sat, 07 Nov 2026 11:25:06 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/agent-economy-project-eve/</guid><description>一句话：这不是一次&amp;quot;AI 打游戏&amp;quot;的评测。它第一次把 Agent 经济体拆成可以记账的三层——执行效率、工具资本、信任成本——并且给出了每一层的单价：模型换代四个月，收益三倍；脚手架换作者，从天天沉船到十二小时零损失；而一个被指派的破坏者，几乎没有人能抓到。
一、为什么这次实验值得当真# 多数&amp;quot;AI 做交易&amp;quot;的演示，测的是模型背没背下来历史行情。EVE Online 不适合背，因为它的价格由玩家自己挖、自己造、自己打捞出来，报价簿参照 NASDAQ 设计，每天有超过 15,000 种商品在流转，而单个贸易枢纽（Jita）的体量约是第二大枢纽的十倍。这条供应链的中间层——矿物、精炼、组件、船坞、燃料——在二十三年里长出了巨型工程、战争经济、避税天堂和公司渗透。
换句话说，它同时具备了两样东西：一个真实摩擦的市场，和一套必须靠组织与信任才能运转的生产关系。而这两样，恰好是&amp;quot;Agent 经济体&amp;quot;这个词底下最难拆开的两半。
Anthropic 与 Fenris Creations 合作，让 Claude 在两个场景里各待了一段时间：
场景 任务与时间尺度 关键约束 EVE Online（模拟器） 单人交易，只求利润最大；两周 × 9 窗、六个月 × 2 窗 30 亿 ISK、5.6% 往返费、真实订单重放 EVE Frontier（线上） 四人一队，做教程与造舰；数小时到数天 亚秒战斗、情报会过期、船沉了回裸船 不干预真实玩家的原因很干净：自动交易在真实服务器上违规，所以市场部分用重放模拟器；Frontier 还在开发期、世界会定期重置，所以允许线上跑。这个边界很重要，它决定了后面哪些结论能外推、哪些不能。
二、实验一：三十亿 ISK 的做市商# 先看难度。买进再卖出，往返摩擦约 5.6%。在买卖双方都密集的商品上，市场已经足够有效，价差薄到没有肉。研究团队先跑了 20 多条规则策略作为基线，跨 9 个两周窗口——只有一条勉强不亏，而且只是勉强。
然后是模型。同一套环境、同一笔本金：
模型 两周期平均收益 六个月平均收益（相对本金） Opus 4.6 约 +4%（与最好的规则策略持平） 约 200% Opus 4.7 +16% — Opus 4.8 +22% — Fable 5 +43% 约 600% Opus 4.</description></item><item><title>据说奇点已经开始：一个旧人的三笔账</title><link>https://icorer.com/icorer_blog/posts/essay/singularity-three-ledgers/</link><pubDate>Sat, 07 Nov 2026 09:40:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/essay/singularity-three-ledgers/</guid><description>一句话　据说我们已经在奇点里了。词我不争，我只把原文那三笔账重算一遍：代码是谁写的、智能便宜到什么程度、人的那一栏里还剩什么。
说明：这是一次阅读的笔记。原文是 X 上的一篇长文（Miles Deutscher，2026 年），作者说他写了两天，还说「没有人准备好」。我不认识他，也不替他的话作保；文里的数字都是他给的，来源我在第七节列成一张表。我要做的只有一件事：算账。
一、先交代我是什么人# 我这辈子见过好几个「新时代」。
第一个叫信息高速公路。那年我在一个朋友家里，看他把电话线插进一台嗡嗡响的机器，屏幕上一行一行往外爬字，爬得比蜗牛快一点。他说，以后图书馆都在里面。我们都很激动。激动完了回家吃饭，饭还是那碗饭。
后来还有过很多个：多媒体、电子商务、Web2、元宇宙。一个比一个说得急。我慢慢养成一个习惯：听见「这次不一样」，先不问这话对不对，先问一句，账怎么算。
这篇文章值得算账。它不空，它给数字：80%、16 小时、−99.7%、−29%、+62%。数字是硬通货，比形容词好用。所以我不打算跟作者争「我们是不是已经在奇点里」——这个词本来就没有统一解释，争到最后是争定义。我只想把他的三笔账拿出来，就着灯，一笔一笔重算。
算账这件事不高级，但它诚实。我年轻的时候在乡下记过工分：一个工十分，十分折多少钱，队长说了不算，账本说了算。这些年我一直信账本，不信口号。
二、第一笔账：代码是谁写的# 原文的第一条证据是这样的：到 2026 年 5 月，合并进 Anthropic 生产代码库的代码里，超过 80% 是 Claude 写的，不是人写的。
我读到这里把茶杯放下了。
这句话跟「AI 帮我写代码」不是一回事，中间隔着一整个工种。九成是辅助，那是好用的自动补全；八成是主力，这是换了主角。我们那会儿讲徒弟出师，出师的意思是他能自己接活了。现在这个「徒弟」接的活，比师父多四倍。
作者还补了两条，我觉得比第一条更值得看。
一条是任务长度。2025 年最好的模型，能独立干完一件人类要干六个半钟头的活；2026 年这个数字涨到十六小时以上，两倍半。另一条是判断力：让模型自己提研究方案，2025 年 11 月它比人类研究员选对的时候占 51%，2026 年 4 月到了 64%。
三条放在一起，形状就出来了。
学者给这个东西起了名字，叫「递归自我改进」：AI 好到能帮忙造更好的 AI，更好的 AI 再造更好的，环越转越快。这解释了我一直没弄明白的一件事——为什么那些 CEO 说话是那个语气。他们不是在预测，他们是在汇报。
轻点放大 现在说一段不合时宜的话。80% 这个数字，我信；但这 80% 里有多少是「删掉一行、把变量改个名、补一条日志」，原文没有说，我也不知道。这不是怀疑作者，这是记账的习惯：分子好听，分母不响。一万个人写代码，和一百个人加上一万次调用生成代码，报出来的百分比一样，含义差得远。
不过就算打对折，这笔账也够吓人。因为它意味着人在这个环里换了个位置：以前人是主角，机器打下手；现在机器干活，人旁观。旁观是件很不舒服的事——你看戏的时候可以鼓掌，你在车间里当旁观者，就是被裁掉的那一个。
三、第二笔账：便宜到什么程度# 原文的第四点是价格：三年里推理成本降了约 99.7%，从 2023 年初的每百万 token 三十美元上下，降到 2026 年初的一毛钱美元。
我拿纸算了算。三十块降到一毛，是三百倍。换成日常的东西：一斤猪肉三块钱的时候，三百倍是一分钱。这不是打折，这是换了个世界。
我这辈子只见过一次这种降法，不是技术，是粮价——当然方向是反的。粮票取消那年，粮价往上跳，全城的人都在骂；但那以后买粮不用排队，不用托人，不用看人脸色。价格变动真正改的是另一件事：它把什么从「要紧」变成了「不要紧」。
轻点放大 还有一件事值得记下来：光 2026 年 10 月这一个月，16 家厂商发了 20 个模型。</description></item><item><title>Agent 记忆的四层栈与「梦境」回路：读 Anthropic 的记忆组件研究</title><link>https://icorer.com/icorer_blog/posts/ai/agent-memory-stack/</link><pubDate>Fri, 06 Nov 2026 22:10:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/agent-memory-stack/</guid><description>一句话　记忆不是把聊天记录存下来，而是在四层之间搬东西：下层真而难用，上层好用而易错；「梦境」（dreaming）就是那个在离线时段负责搬运、纠错与修补的工人。
本文的图按原文的数据与结构重绘；原文自带的十余张图表与截图，见文末的出处链接。
一、痛点：它能看见的只有这一次# 轻点放大 长期对话里的记忆问题有两个方向会同时发作：一是忘——每个新会话从零开始，上周的决策、踩过的坑、验证过的规则全没了；二是胀——为了不忘，把历史一股脑塞进上下文，于是注意力被稀释、成本上升、旧信息还和新事实打架。
Anthropic 在这篇文章开头借了克尔凯郭尔一句：生活只能倒着理解，却必须正着过。记忆设计撞上的是同一件事——在写下一条记忆的那一刻，你并不知道未来会不会需要它。所以真正难的是判断「此刻什么值得记」，以及「记错之后怎么改」。
文章对「agent 记忆」的定义很克制：只指 Claude 从经验（与用户的交互、被交代的任务）中获得、并能跨会话保留下来、作为上下文再读到的知识。它明确排除了另外三样：改权重、单次会话内的 in-context learning、以及压缩（compaction，用摘要替换旧轮次以便在新窗口继续）。
二、四层记忆栈# 轻点放大 把文章里的做法摞起来，是这样四层（这是本文的归纳，原文按主题分节，未画成这样的栈）：
层 是什么 谁写它 关键约束 1 原始层 会话记录（transcripts）、日志 系统自动 唯一的 ground truth；dreaming 拿它校验上面每一层 2 笔记层 规则、验证过的事实、踩过的坑 模型在会话中判断着写 写什么靠自己判断，比外部规则更有效（见第四节） 3 表征层 wiki：页 + 链接，相当于一张地图 dreaming 离线建、改、剪 会越写越大，甚至超过原文 4 注入层 每轮开头自动装载的常驻上下文 系统装载 + dreaming 上提 必须很小：Claude Code 只注入 MEMORY.md 前 200 行 / 25 KB 第四层的约束是全文最实用的一个工程结论：Claude Code 的自动记忆并不把全部记忆塞进每个会话，只加载 MEMORY.md 的前 200 行（或 25 KB），把这部分当作索引——告诉 Claude「你知道什么、去那里找」。原文还引了自己文档里的一条警告：指令文件越长，遵循度越低。所以顶层要小，dreaming 在顶层的主要工作其实是保持它小：把细节往下挪，只留链接。</description></item><item><title>一天一小时，一年365小时：Dan Koe 的深度专注里，哪一半能落地</title><link>https://icorer.com/icorer_blog/posts/essay/deep-focus-one-hour/</link><pubDate>Fri, 06 Nov 2026 11:50:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/essay/deep-focus-one-hour/</guid><description>一句话　这篇长文真正能给的不是「少刷手机」，是一张能算的预算表：一天 1 小时，一年 365 小时，等于 45 个完整工作日；先认这笔账，再谈专注。
材料边界先说清楚：原文是 Dan Koe 2026 年 1 月 19 日发在 X 上的长文《How to unlock extreme focus on command》，我读的是全文正文。下面每条数字都标来源：算的是我自己按原文给的数推的，原文是他引用的研究或他自己的经验值——两者不混着用。
一、先把账算出来：一小时到底是多少# 一天一小时，一年 365 小时（算的）。365 ÷ 8 = 45.6，也就是上满 45 天班，全花在自己身上（算的）。这句换算是全文的支点：先看清存量有多少。
然后是那串更狠的数：人有意识的处理带宽约每秒 50 bit，无意识约每秒 1100 万 bit（原文引用，未复核）。按这两条推，一生可用的有意识信息约 1250 亿 bit（原文）。1250 亿 ÷ 8 ≈ 15.8 GB（换算）——你这辈子的清醒带宽，装进一张存储卡还有富余。
轻点放大 原文由此推出一句反直觉的判断：他观察到的、没有把生活抵押出去的成功创意人与 CEO，身体上工作得很少，脑子却一直在跑——想、盘算、推演；等想法清楚了，执行速度快到别人追不上。所以「忙」不在他这套判断里。
二、三种工作，只有一种配得上你那一小时# 工作类型 长什么样 节奏 谁在干 建造 把一个项目做出来：产品、服务、品牌 高强度、成块 你，每天那一小时 维护 让造出来的东西活着：运营、客服、交付 稳定、常重复、可系统化 以后的你，或买来的时间 恢复 不盯任何目标，让突破性想法自己成形 潜意识的、被绝大多数人跳过 你，且必须排进日程 顺序是关键：先建造，造到能全职做这件事，再谈转进维护。多数人是反的——一天开十几个对齐会、回两百条消息，全是维护，一天结束时没有建造。</description></item><item><title>数据库的用户换了：Agent 时代的记录系统与上下文层</title><link>https://icorer.com/icorer_blog/posts/ai/agent-native-database/</link><pubDate>Fri, 06 Nov 2026 11:30:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/agent-native-database/</guid><description>一句话　数据库的头号用户从人换成了 Agent，于是它裂成两条腿：一条存状态、按需供给，一条供上下文、提前编译。真正变的不只是形态，是&amp;quot;检索&amp;quot;这件事的定义——从召回算法，变成编排框架加编译供给。
一、问题：报错是写给人看的# 先看一个不起眼的改动。Supabase 把自己全部报错信息翻出来重做了一遍：不再是 500 Internal Server Error，而是在返回文本里直接写明——你为什么触发这个错误、现在该执行哪条命令修、或者去读哪个 URL 的文档。
这个改动的动机是留存。人类程序员看到天书般的报错，会自己去 Google；Agent 看到同样的报错，会放弃并切到竞品。两家公司争的是&amp;quot;卡住之后它还愿不愿意再试一次&amp;quot;。
它暴露的是更底层的事：数据库的设计假设全部建立在&amp;quot;用户是人&amp;quot;之上。Dashboard 给人点，API 给人调，报错给人读，实例给人规划。把这些假设逐条拿掉，剩下的才是 Agent 需要的东西。
三个已经量化的断裂：
断裂 事实 来源 供给颗粒度 Supabase 周新建数据库 &amp;gt;100 万个，托管库从 800 万涨到近 5000 万（一年） 官网公布（YC 播客） 使用者身份 约 70% 的新增活动来自 Agent；72.1% 的组织已有 Agent 在生产运行 官网公布 / IDC FERS n=903 上下文成本 Agent 约 85% 的计算精力消耗在&amp;quot;重新发现&amp;quot;循环上，而非任务本身 Pinecone 估算 第三条最难缠。如果每次提问都要从零开始探索一遍语料，那么数据规模每涨一个量级，成本和延迟就跟着涨一个量级。
二、业界已经解决到什么程度# 过去 18 个月，这条线上发生的事可以压缩成五条可核对的主张，每条都带着后果。
主张 出处 后果 工具结果的交付方式比检索算法更能决定准确率；inline 交付下 grep 在每一个 Harness×模型组合上都胜过向量检索 PwC《Is Grep All You Need?</description></item><item><title>生产级 Agent 的七层：一次对「换个模型就好了」的证伪</title><link>https://icorer.com/icorer_blog/posts/ai/seven-layers-agent/</link><pubDate>Fri, 06 Nov 2026 09:20:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/seven-layers-agent/</guid><description>摘要　生产级 agent 的失败，绝大多数不发生在模型这一层。把「从模型到结果」的距离拆成七层——模型、指令与上下文、工具、记忆、循环、评测与护栏、人的签核——之后，最常见的那个动作（换模型、改提示词）恰好作用在唯一不太需要动的地方。本文重排了这篇指南的论证顺序，按证据强度给每条主张打了标，并补上它没谈的两件事：成本与可观测。
一、主张，和它的形状# 原文的骨架是一句招聘比喻：给一个天才新人一间没有入职培训、没有账号、没有笔记本、没有流程、没有复核的办公室，他一样干不成事——因为没人把这份工作搭起来。
这句话的形状值得注意：它其实是一份岗位说明书。七层里除了第一层，其余六层在做的事，都是公司给一个真实员工配的东西：入职文档、系统权限、笔记本、工作流、复核、最终签字权。所以这七层的顺序不能随便换——它是从招聘到上岗的顺序。
支撑它的两句外部引用也标得清楚：Anthropic 2025 年 6 月那句「最后一公里往往变成整段旅程」，以及 2025 年 9 月给 agent 的定义「LLM 自主地在循环里使用工具」。后者顺带划出一条边界：只回答一次问题的，不叫 agent。
二、七层，以及每层坏掉时的样子# 轻点放大 层 一句话职责 坏掉时的症状 最小可用做法 1 模型 读、规划、决定下一步 换模型、改提示词——最常见的那个错 先用最强模型打标，再按评测降级；锁死具体版本号，不用别名 2 指令与上下文 它动手之前看到的一切 答得像懂，但和你们的流程无关 拿一份团队真在用的 SOP 改写成系统提示词；稳定规则常驻，任务事实按次加载 3 工具 读数据、做事 能说不能做，或者一动手就越权 每个动作标读/写；优先用现成 MCP；给 agent 自己的受限凭据；输入收窄到 ID、绝对路径、固定日期 4 记忆 上下文窗口之外留下来的东西 一轮聊长就退化，上周的结论全丢 MEMORY.md + 只给它这一个文件写权限；长会话前压缩；每周删过期笔记 5 循环与编排 行动、看结果、再决定、停 跑不完、跑飞了、不知道哪一步坏的 把退出条件写进指令；代码里给 max_turns；开 tracing；周期性工作交给 cron 6 评测与护栏 判断它好不好，并在不好时拦住 分数对不上，或者一句提示词就能删掉生产库 20 条真实任务做评测集 + LLM 裁判；暂存库/测试账号/只读密钥；读私密数据 + 读不可信输入的工作流，对外发送必须有人把关 7 人的签核 最后一按 一封没人批准过的客户邮件发出去了 风险分三档；高风险动作走审批卡；记录谁批的 这张表里最容易被忽略的是第三层的输入约束。原文引的 Anthropic 那条判断很硬：「如果一个人类工程师都没法断定某个场景该用哪个工具，就不能指望 agent 做得更好。」以及他们做编码 agent 时的实话——花在优化工具上的时间比优化整体提示词还多。</description></item><item><title>一段提示词怎么长成公司大脑：拆 Recall 的四代、一条管道、四个工具</title><link>https://icorer.com/icorer_blog/posts/ai/recall-company-brain/</link><pubDate>Thu, 05 Nov 2026 22:40:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/recall-company-brain/</guid><description>一句话　它把「记住」做成了检索契约：上游只存原文、永不改写，索引与沙箱全是可重建的投影；服务器对召回负责，精确与引用交回给调用它的那台前沿模型。
材料是作者那篇长文，加上开源的 skill 仓库（Apache 之外的部分没开源，MIT，13 个 skill）。文中数字分两类：作者实测的，和我在仓库里数的，各自标注。
一、四代：每一代都被上一代的故障推着走# 轻点放大 阶段 形态 触发的故障 关键数字 4 月 一段 SKILL.md，告诉 agent 转录在哪（~/.claude/projects 下每会话一个 JSONL）、怎么 grep 全靠 agent 即兴，慢且不稳定 只有一份文件 5–6 月 三个脚本：find_sessions.py、extract_user_prompts.py、dump_turn_context.py 每次搜索读全盘，且读不了 Codex 7 月已 5,000+ 份、约 5 GB 7 月 一个 recall.py：SQLite 全文索引 + 实体表（PR 号、文件路径、job id），两种 harness 都读 单机、单人的上限 57 题冻结集上 top-5 从 23% → 63%，搜索 15.7s → 0.16s 8 月起 服务：collector → ingest → 存储 → 投影 → 沙箱，外挂四个 MCP 工具 需要跨机器、跨人 见下文 脚本写出来之后，agent 仍然大约每用一次脚本，就手动 grep 九次。工具没被采纳，不是因为不好用，而是因为它比「直接翻文件」还慢。</description></item><item><title>逐节读 DSec：每天 300 万个沙箱，DeepSeek 把 agent 训练的底座做成了什么</title><link>https://icorer.com/icorer_blog/posts/ai/deepseek-dsec-sandbox-platform/</link><pubDate>Thu, 05 Nov 2026 15:28:40 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/deepseek-dsec-sandbox-platform/</guid><description>一句话　这篇报告真正的贡献不是「又造了一个沙箱」，而是先把 agent 训练的沙箱负载量出来：请求按万级成批到达、CPU 只用掉申请的 5%、状态要留十几分钟到几小时、镜像几乎不复用。四个数字同时成立，平台就只能长成弹性执行平台，而不是一个容器运行时。
这篇文章读了什么、没读什么：材料只有 arXiv 上的 2609.22978v1（31 页，2026-09-19 投到 cs.DC，DeepSeek-AI 与清华，作者里有一位实习期博士生）。我没有集群、没有源码、也没有和作者聊过，所以下面全部是论文阅读笔记：数字都标了出自哪一节，凡是我自己的推断都写成「我的判断」，论文没给的我也直接说没给。没有复现，没有实测，也没有替作者做背书。
一、问题：什么时候「沙箱」会变成基础设施（§1）# §1 的推理链很短，但每一段都在收窄问题。
第一段先把 agent 的定义摆出来：模型不是给一段文本，而是和环境交互——读仓库、调工具、跑命令、看失败、改文件，computer-use 任务里还要操作浏览器和桌面。它靠反馈迭代直到任务完成。
第二段把这条链拆成流水线：环境与数据构造 → RL rollout → reward → 策略更新 → 定期评测。其中 rollout 和评测对沙箱压力最大，因为量大、并发高、还和训练循环耦合。第三段补上业界已经在做的事：异步 rollout 把「生成」和「策略优化」流水起来，用持续补充样本的方式压长尾。代价是同时有大量有状态的沙箱在飞，还会被策略更新或调度抢占打断。
第四段是全篇的题眼：每个 rollout 都要现搭一个任务专属环境，包含仓库、依赖、服务、评测脚本和 harness；这个环境要「足够像一台真机器」，能跑没改过的软件栈、包管理器、构建工具、浏览器、模拟器。「像真机器」这句话定了整个平台的成本结构——它排除了函数级的轻量抽象。
然后是七条负载属性，我按「对设计的影响」重排了一下：
属性 论文给的数字 它逼出的设计 成批到达 单任务最多 32K 个沙箱 调度、创建、镜像分发都不能有中心瓶颈 高密度 单节点 800 microVM / 3,200 容器 必须能安全超卖，还要管住干扰 有状态、长寿 p50 17 分钟，p99 超 3 小时（§4） 内存共享与回收变成硬需求 异构 OJ、SWE、安全、computer-use、Android 单一抽象不够，要多种后端 环境多样、复用低 eager pull 慢 1.</description></item><item><title>Open Responses：把 N×M 套适配器换成一份契约，代价写在每个字段的 MUST 里</title><link>https://icorer.com/icorer_blog/posts/ai/open-responses/</link><pubDate>Thu, 05 Nov 2026 08:20:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/open-responses/</guid><description>一句话　它把「消息」换成双向的条目、把流式换成状态机事件、把扩展做成有名字的旁路；于是端点地址和模型名从代码分支变成配置，而代价从适配器转移到了每个字段的语义细节上。
材料来自三处，都读过：规范全文（含 2026-01-15 与 2026-04-24 两个版本）、它的 TypeSpec schema 与仓库、以及 Databricks 与 Vercel 两个已上线实现的文档。数字分两类标注：仓库里数的，和 GitHub API 给的。
一、它规定的到底是什么# 一句话：以 OpenAI 的 Responses API 为底，定义 /v1/responses 这类端点上收发的请求与响应格式。规范自己划的范围很克制——只到 API 层，不碰模型，也不需要重新训练。
它真正定义的是三样东西，而不是一堆 JSON 字段：
零件 规范怎么说 为什么这么定 条目（Items） 上下文的最小单位，双向：既能作为输入给模型，也能作为输出返回 一次推理产出的是「若干个原子事件」，不是一段字符串 语义事件 流式不是文本增量，而是一系列有意义的状态迁移 客户端要能重建结构，而不是拼字符串 扩展 任何实现者可以做真超集；新类型必须带自己的 slug 前缀 供应商要有推出自研功能的空间，又不能互相撞车 轻点放大 它对「合规」的定义也写在里面：直接实现本规范，或者是它的一个真超集，都算合规。这句话很关键——它允许实现者往前加东西，只禁止把标准字段的含义改掉。
二、三个零件：条目、事件、状态机# 轻点放大 条目有四个性质，每一条都在解决具体问题：
多态：靠 type 判别。message 与 function_call 形状不同，客户端按类型分派，不再猜。 状态机：in_progress / incomplete / completed。有一条硬规矩——如果某个条目以 incomplete 结束，它必须是最后一个条目，且整个响应也必须是 incomplete。这就杜绝了「半截话后面又接了一句」的歧义。 可流式：第一个事件必须是 response.output_item.added，此时能给的字段都要给（消息至少给 role，函数调用至少给 name），其余字段用零值占位。这样客户端可以先把骨架画出来，再往里填。 可扩展：非标准条目必须以实现者 slug 打头，比如 openai:web_search_call。 内容还做了一次不对称切分：UserContent 与 ModelContent 是两个顶层联合类型。用户输入可以是文本、图片、音频等多种模态，模型输出在基础协议里只保证文本。这个不对称是有意为之——它让供应商以后加 output_image 之类的东西时，不用把用户那一侧也跟着泛化。</description></item><item><title>人生无意义，爱好是骗局，愤怒还得有力气</title><link>https://icorer.com/icorer_blog/posts/essay/meaningless-life-anger/</link><pubDate>Wed, 04 Nov 2026 21:48:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/essay/meaningless-life-anger/</guid><description>一句话　无意义不是坏消息，爱好是骗局也不是，真正要算的是力气：愤怒是一件体力活，而力气只会越来越少。
一、先把地板露出来# 轻点放大 人生没有意义，而且是偶然来的。这话现在说出来不算冒犯，但十年前我听了会不舒服，觉得说话的人站在高处往下看，手里还捏着一根烟。
后来我想明白了：无意义是底色，谈不上判决。你去菜场买一斤豆角，那斤豆角也没什么意义，它只是恰好长在那儿，恰好被你装了袋。人不比豆角高贵多少，区别只在于豆角不会在凌晨三点想这件事。
很多人把「人生没有意义」当坏消息，是因为下一步他们就要找一个意义补上。这个补法有风险。意义是自己盖的房子，盖得越满，塌下来砸得越重。有人把全部家当搬进「我要出人头地」里，四十岁那年楼板一响，人从二楼摔到一楼。而承认没意义的人本来住一楼，塌不出事。这句话管的是居住条件。
二、爱好是骗局，这是夸它# 轻点放大 既然底色是空的，文学、绘画、音乐算什么。我听过一句很不客气的说法：全是骗局。
起初觉得刻薄，后来觉得准确。这些东西不提供意义，不提供答案，也不负责拯救谁。它们做的是另一件事：让一段本来没有目的的时间，过得不那么难熬。像面条上那勺卤，卤不能算面条，可没有卤也能吃，只是吃得干。
问题不在艺术，在我们的订货单。人要吃饭，饭也不提供意义，却没人骂饭是骗局，因为我们对饭的要求低，热、咸、管饱就行。轮到文学音乐，忽然要求它承当灵魂、承当高贵、承当「人类精神的最后一块阵地」，它当然承当不起。承当不起就露馅，露馅就叫骗局。所以「骗局」这个说法，说的其实是我们的贪婪。
轻点放大 后来我给它换了个更朴素的词：消遣。人生像一趟没有终点的长途车，文学音乐是车窗外的风景。风景不能让你到站，但能让你少想几次跳车。你说这是自我安慰也对，可自我安慰是人的一项基本技能，跟系鞋带差不多。
三、愤怒是件体力活# 轻点放大 下面说愤怒。这一条是我这几年才承认的：愤怒要花力气。
二十几岁的时候力气多得没处使。一句不顺耳的话，我能气到半夜，把对方的话在脑子里重排一遍，找出最阴的那半句，再想一句回敬，想得很满意，然后睡着。那时候愤怒像自来水，拧开就有，还不用交水费。
后来它在涨价。四十岁还气，气完要喝水，要坐下，要在阳台上站一会儿。再往后，气到一半会分神：这口气生完，晚上还睡不睡，明天早上还起不起。于是愤怒成了消耗品，用一次少一次，人就开始挑对象了。
我算过一笔账：一次像样的愤怒，当晚的睡眠、那顿饭的胃口、那半天的注意力，差不多都得搭进去。年轻时不觉得，中年以后这笔账很清楚，你气完这一场，一天就过去了，而且什么也没多出来。
所以有些上了年纪的人发脾气，看着比年轻人温和，多半是预算不够。
四、光有愤怒不成，得有别的配套# 只有愤怒的人生是幼稚的。这话我一开始不服，觉得是在劝人认命。
后来发现它说的是另一件事：愤怒是一种反应，不是一种能力。它只能说明你不接受什么，说明不了你能做什么。被踩一脚就愤怒，这不算本事，狗也会。真正难的是配套的那些东西，会写、会画、会造、会算、会等，总得有一样拿得出手，能跟你的愤怒并排放着。
愤怒加上这套配套，事情才有点意思。它从「我不同意」变成了「我不同意，而且我做了一个别的东西出来」。前者是一句话，后者是一件东西。
我见过一些年轻时火气很旺的人，中年以后都安静了。安静分两种：一种是想通了，一种是想不出办法。这两种从外面看一模一样，都是端着杯子坐在那儿不说话，只有他们自己知道是哪一种。
五、只剩愤怒，是很难看的状况# 轻点放大 最难看的，是只剩愤怒。
别的什么都做不到，愤怒就成了唯一能证明自己还在的东西。这种状况的滑稽在于，它自己也知道自己没用，但它没有别的出口。像一个人被反锁在屋里，屋里只有一扇窗，窗外是一片空地，他还是每天去敲那扇窗，敲得很响，敲给谁听也不知道。
时间久了会变形。人开始把愤怒当事业，把「我在乎」当成「我做了」，把不学任何新东西说成是有骨气。这是一种很便宜的自尊，因为它的成本是零，收益却是自我感动。
要是愤怒真能解决问题，嗓门最大的那个人就该当市长。
六、剩下的时间# 把这几句话摊开，更像一个上了年纪的人给的忠告：别指望天上掉意义，别指望爱好救你，也别指望靠生气改变什么。剩下的时间，找一件能做的事，把它做完，然后去睡。
要真有什么遗憾，是力气这件事没法讨价还价。年轻时把力气都花在生气上，等到明白该干正事，剩下的力气只够生一小会儿气了。
这篇的念头来自陈丹青的一次谈话，我只是接着往下想。谢谢他。</description></item><item><title>把聊天框当 Agent OS，三十人的公司几周就碎：拆 Ankole 的五处断裂点</title><link>https://icorer.com/icorer_blog/posts/ai/ankole-agent-os/</link><pubDate>Wed, 04 Nov 2026 21:30:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/ankole-agent-os/</guid><description>一句话　把单机 harness 套上聊天框，只搬走了界面那一层；真正的差别在五件事——谁在说话、它记得什么、崩了之后活儿还在不在、它在哪台机器上动手、回复到底送没送到。
先说清楚这篇的材料边界：那篇文章的正文在 X 上要登录才能读，我拿到的只有它自己给出的主张和开头一段。所以下面不复述文章结构，而是把这个主张当成一道题来做——技术细节核对的是 Apache-2.0 的仓库（浅克隆，5,890 个文件）和它随仓库发的文档，包括一份 170 行的《取舍与已知限制》。数字分两类：官方文档写的，和我自己在克隆里数出来的，各自标注。
一、主张先摆出来# 原文的说法是：把聊天界面架在一个单用户 harness 上，或者往群里扔一个 bot，都不叫 Agent OS；把它放进三十人的公司，横跨运营、财务、法务，几周就会碎。
这句话方向是对的。把它拆成五处，每一处都有具体的失效方式。
轻点放大 问题 聊天框 + 单机 harness 团队 Agent OS 的答案 谁在说话 规矩写在系统提示词里 Principal + 运行时 AuthZ 它记得什么 每次从零，检索聊天记录 结构化世界模型，按权限交集召回 进程死了 这一轮工作消失 PostgreSQL 台账，从已提交处续跑 在哪动手 你自己的电脑 每 Agent 一台独立容器 回复送到没 发出去就算完 Delivery 意图，平台确认后再提交 二、谁在说话：权限不是提示词# Ankole 把所有人、Agent、内部服务统一成 (tenant_id, uid) 的 Principal，权限在控制面运行时求值：主体、权限组、Drive 的 ACL 锚点、动作，加上 CEL 条件，一起算。文档里有一句话值得抄下来——访问控制「永远不由提示词约定来执行」。
这条区分落到两种 Agent 上，差别很具体。Personal Assistant 与人一对一绑定，借所有者的共享权限，但保留自己的运行时身份，审计线上看得见是谁做的手脚。AI Colleague 用自己的授权，当它要做超出自身写权限的事（改一个受保护的知识对象），必须发一张 propose_action_card 等人批。群聊里 Agent 的广播回复不会唤醒其他 Agent，要协作就走 send_to_agent 开一条隔离的 peer 会话。</description></item><item><title>自动本体工程：英伟达 Auto-Ontology 的源码级拆解</title><link>https://icorer.com/icorer_blog/posts/ai/auto-ontology/</link><pubDate>Wed, 04 Nov 2026 20:41:07 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/auto-ontology/</guid><description>一句话：Auto-Ontology 把本体工程里最贵的那一个月自动化了——它读你的元数据和查询历史，编译出一张业务本体，再用 9 个只读工具交给 agent。但它交出来的是草稿：认证在这套代码里是展示用的徽章，不是查询路径上的闸门。
中文配音版（男声），2 分 04 秒。中英两版内容一致，另有英文配音版。
NVIDIA 在 2026 年 10 月 21 日的 GTC Berlin 上把它作为 Agent Knowledge Foundation 的一部分宣布，11 月 1 日以 Apache-2.0 开源。我读的是 caced11 这个提交（11 月 4 日克隆）的完整后端源码，下面是能逐条对回代码的判断。
一、一次不会报错的错# 一个 agent 能写出跑得通的 SQL，这件事又容易又危险：一条跑通、返回一个「看似合理却错误」数字的查询，不会报错。
最典型的现场是这张表。
轻点放大 财务有三个列都能叫 revenue；销售说的 bookings 和财务说的 revenue 是两回事；一个一对多 join 会让总数静默翻倍，而 SQL 完全合法。传统 text-to-SQL 研究默认难题是「生成语法正确的 SQL」，于是堆模型能力。Auto-Ontology 的判断相反：语法正确不等于语义正确，真正缺的是那层告诉 agent「数据在哪、什么意思、能不能用、怎么用、从哪来、什么相似」的上下文。
这层东西过去只活在数据工程师和业务人员脑子里。它的工作量集中在第一次交付——梳理来源表、定义对象关联、审核指标口径。这也是为什么大部分语义层项目死在第一周：平台装好了，然后没人能说清六个 revenue 定义里哪个是真的。
二、它站在哪条脉络上# 「用本体给数据加一层语义，再把查询翻译回去」不是新想法，但谁来写这层本体变过两次。
轻点放大 路线 本体/口径由谁写 后果 OBDA（本体驱动数据访问） 知识工程师人工建模，一条条映射 表达力强、推理可证；成本让它在企业里长期停在 PoC 语义层（dbt / Cube / LookML） 分析工程师写 YAML，人审 口径可信；从空白页到第一版仍要几周到几个月 LLM 起草 + 人审 模型给草稿，人签认证 第一天就有可审的东西；草稿与权威的界线必须由使用方自己划 学术上这两条线都有三十年积累。OBDA 的三层结构（数据源 / 映射 / 本体）与 Auto-Ontology 的 catalog / semantic FK / terms 几乎同构，区别只在于本体不再是人工建的。近三年这条线被 LLM 重写了一遍：《Towards Agentic Schema Refinement》（arXiv 2412.</description></item><item><title>一个人就是一支创意团队：Dan Koe 那封信里能拿走的与拿不走的</title><link>https://icorer.com/icorer_blog/posts/ai/one-person-creative-team/</link><pubDate>Wed, 04 Nov 2026 07:20:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/one-person-creative-team/</guid><description>一句话　那封信能带走的东西是岗位拆分，把创意总监的活拆成品牌策略、内容策略、写作与运营三件事。价码、工具推荐与那串增长数字属于它的销售面。
Dan Koe 十一月发了一封长信，主张最有价值的技能一直是抓住注意力。他给了三个数字撑起紧迫感，给了三个岗位撑起方法论，最后落到一个具体做法上，先免费替目标客户做十条帖子，再把成品递过去。
这封信是一封销售信。作者是 Eden 的创始人，信里同时推了 Eden 与一个 49 美元的写作工作坊。把这一层先摆出来，不影响它中间那段岗位拆分的价值。
一、三个数字，三条都不是普查# 先把信里的加速度拆开。三条数据都真实存在，口径各不相同。
轻点放大 高盛研究部 2023 年 4 月那篇说的是创作者经济的总可寻址市场，从 2500 亿美元走向 2027 年的约 4800 亿。这是该机构自己的模型估算，不是一次市场普查。
IAB 的创作者广告投放报告给的是美国品牌支出，2021 年 139 亿，2024 年 295 亿，2025 年 371 亿，2026 年的 439 亿是预测。信里把它写成五年三倍，两端数字都没错，只是终点还没发生。
第三条来自 WPP Media 2025 年中的全球广告预测，说创作者平台的广告收入这年首次超过传统媒体，创作者一侧大约 1850 亿美元。同样是预测值。
指标 值 来源 口径 创作者经济总量 2500 亿 → 4800 亿美元 高盛研究部，2023-04 预测 美国品牌创作者投放 139 亿（2021）→ 439 亿（2026） IAB 实测 + 预测 创作者广告收入 约 1850 亿美元（2025） WPP Media 预测 这三条放在一起能说明的只有一件事，注意力确实在往社交平台集中，规模也够大；两条是预测、一条是实测加预测，没有一条在讲个人成功率的分布。</description></item><item><title>认知投降：把活交给 agent，判断权不能交</title><link>https://icorer.com/icorer_blog/posts/ai/cognitive-surrender/</link><pubDate>Wed, 04 Nov 2026 06:54:07 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/cognitive-surrender/</guid><description>一句话　把活交出去没问题，把判断权交出去是另一件事。这条下坡分成三档，每一档都像上一档的合理延伸。
中文配音版，2 分 33 秒。英文版 2 分 41 秒，同样的镜头、同样的数字。
Addy Osmani 十一月在 X 上发了一篇长文，讲 agent 时代怎么保住批判性思考。他先把立场摆清楚，自己每天都在用，一天并行开好几个会话，写这篇不是劝人少用工具。
文章的主线在另一件事上。工具越好用，人越容易停止判断，而这件事恰好没有声音。
下面把它拆成一条能画出来的斜坡，补两组可以查的数字，最后说清楚哪一步他自己也没说满。
一、判断原来长在留白里# 过去的判断发生在提问和回答之间。你查资料、自己想一遍、再回来核对，中间这段时间里答案是你自己拼出来的。
现在这段时间按秒算。你读完一段写得很顺的回答，顺手就点了通过。
轻点放大 Osmani 用一句话点破这中间的差别。很多输出会写得不错，而且大体正确，但它们不要求你再看第二眼。
二、下坡分三档# 他排出一条频谱，我更愿意画成一条斜坡。
轻点放大 最上面一档叫委托，活递出去，结论还归你，你会核对一眼。中间一档叫转交，它的输出成了你的输入，你不再怀疑。最下面一档叫投降，它的答案就是你的答案，你连该查什么都想不起来。
认知投降这个词是沃顿的 Steven Shaw 和 Gideon Nave 在 2026 年 1 月提出的，出自他们那篇挂出来的预印本。两个人把双系统理论往下推了一层，加了 System 3，指的是发生在脑外的思考。
滑坡很少被人当场发现，因为每一步都是上一步的合理延伸。你上一份答案读完了，这一份就只扫骨架；再下一份，你连骨架都没看。等到有人在会上问起某一行，你发现自己讲不出来。
这份代价有个名字，叫认知债。代码看起来干净，测试是绿的，团队的心理模型在悄悄变薄。
三、两组实验，方向相反# Osmani 那篇偏经验，这里补两处可以查的数字。
第一组来自沃顿。三次预注册实验，一千三百七十二个人，九千五百九十三次 trial，被试在认知反射测验上作答，同时可以随时去问一个 AI。研究者用隐藏的种子提示随机决定模型答对还是答错。
结果是一个对称的摆动：模型答对时，准确率比不用模型高二十五个百分点；模型答错时，低十五个百分点。
轻点放大 扎人的地方在信心。出错之后，被试的自信还在涨。信心像是从模型那里借来的，而模型对什么事都很笃定。
第二组来自 Anthropic 自己对技能形成做的对照实验。研究者让工程师用 AI 辅助学一个陌生的 Python 库，再考一遍理解。
轻点放大 用 AI 写代码的那一组，理解测验比手写组低百分之十七，27 分制上低 4.15 分。把 AI 当作提问对象、追着问为什么要这么写的那一组，没有掉。</description></item><item><title>思维先于行动：JevAct 给 LLM Agent 加的决策门</title><link>https://icorer.com/icorer_blog/posts/ai/jevact-decision-gate/</link><pubDate>Tue, 03 Nov 2026 12:27:14 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/jevact-decision-gate/</guid><description>Agent 的动作在被执行之前，应该有一道能查、能算、能打回的门。JevAct 的做法是把这道门拆成两半。代码算工具记录能确定的事实，决策模型只回答“对话里到底说了什么”，再用一条布尔规则把两者合起来。它在 τ²-Telecom 上让八个 agent 全部变好，也清楚地暴露了自己的边界。
中文配音版，2 分 41 秒。中文与英文两版内容一致。
原文是《Think Before You Act》（IBM SIL，副标题 Decision Gate for LLM Agents），arXiv 编号 2610.38620，全文 18 页，点开就能读 arXiv 页面 ，也可以直接看 PDF 。这篇是我读完全文之后写的，下面的数字、阈值和局限都能在原文里逐条对回去。
一、提案即执行# ReAct 之类的 agent 循环有一个默认动作，模型说什么，harness 就执行什么。这在“回答错了还能下一轮改”的场景里问题不大，但有三类动作是不可逆的（§1）。
不可逆的动作 出错的代价 写调用（预订、取消、改设置） 改了数据库状态，有的改不回来 交班（转人工、告诉用户“没办法了”） agent 的尝试结束，用户被推给下一个人 不该发生的写（用户没要求） 越权，比答错更严重 现有方法各自解决一部分（§2），ReAct 交错推理与动作；Self-Refine、Reflexion 在事后批评、下一轮改；GuardAgent、AgentSpec、ShieldAgent、CUGA、ToolSafe、PolicyGuard、ToolFence 这一类做运行期策略约束（§2.2）；LLM-as-a-judge 让另一个大模型来评审（§2.3）。但“在这一条动作执行前，用一条可执行的规则判断它对不对”仍然是缺口，生成式的评审会给出解释，解释还要再被解析成“放行/拦截”；而用前沿模型逐条评审，成本又高。
论文的立场很明确，把这道门做成概率阈值化 + 可执行检查，而不是再找一个更大的模型来“讲道理”。
二、两种证据，各管一半# 轻点放大 图 1 agent 仍然负责提议，门只负责决定“执行还是打回”。
JevAct 是一条跑在 ReAct 循环外面的 harness。它不选动作，只做验证。关键在于把“这个动作对不对”拆成两类问题。
工具记录能确定的事实。预订创建于几小时前、免费托运额度是多少、这单是不是已经飞过一段、金额有没有超。这些交给代码算，因为算术与日期比较是决策模型最不擅长的。 只能从对话读出的事。用户到底要求了什么、有没有明确确认、某个排障步骤是不是试过。这些交给决策模型用是非题回答。 两条证据最后由一条布尔规则合成结论。这一步是论文的设计主张，确定性的部分不要交给概率模型，概率的部分不要硬塞进代码。
三、四个组件# 3.1 决策环的四个阶段# 每一步四阶段。</description></item><item><title>SecLog 精读：让「数据已交付」自己留下证据</title><link>https://icorer.com/icorer_blog/posts/web3/seclog-atomic-swap-secure-logging/</link><pubDate>Mon, 02 Nov 2026 20:30:28 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/seclog-atomic-swap-secure-logging/</guid><description>一句话：想让「用户无法否认收到数据」成立，不用信任 API，也不用把数据放上链——只要让解密数据的最后一半钥匙，只可能从一条会留下记录的路径里出来。
两分多钟的讲解片：钥匙怎么变成日志 → 两个事件的区别 → gas 那 8,000 的差额，以及我没复现出绝对值的部分。 这篇论文只有四页。它讲的事情也小：一次数据查询交付之后，怎么保证链上一定留下一条记录。小到你第一反应是「记个日志而已」，可跟着作者走完，会发现每一步都卡在同一个问题上——谁值得信任。
读完我最想记住的是一句话：区块链保证「写上去的改不掉」，可这里缺的是「该写的那一条一定会被写」。两句话很像，方向正好相反：一个管已经发生的，一个管还没发生的。
论文是 Hughes、Hossain、Tang、Jung、Chenli 五个人写的，发在 METAVERSE 2025（LNCS 16159，pp. 115–124）。四页，结构却很清楚：先说问题，再把前人工作分成两堆，然后给模型、协议和两条定理，最后用三个合约量 gas、老老实实谈代价。下面我就按这个顺序走。
一、签完那份同意书，后面的事你就不知道了# 假设你的病历在一家医院的库里。某天有人查了它——为了研究也好，为了别的什么也好，你分不清。
签字那一下你是知道的。之后呢？论文第一节把话说得很直：数据所有者对这个流程的了解，往往止步于最初签下共享协议的那一刻。此后的访问记录、访问时间、数据被拿去做了什么，全都与他无关。这不是体验问题。HIPAA、GDPR、CCPA 要的都是可追溯，而不透明的共享本身就踩在这三条线的红线上。
去中心化数据库（论文点了 recallnet 那份去中心化数据库清单）把所有权和控制权还给了数据所有者，算是解决了前半截。可所有权一回来，后半截露出来一个洞：没人负责记账。
这时候你会发现，「让谁记一下」这件事比想象中难。论文把三条看起来都能用的路都堵了：让用户自己确认收到？想赖账的人根本不会确认。让 API 单方面写日志？网络一抖，用户是真的没收到，那条日志就成了假的，顺便 API 还成了单点故障。那直接把共享行为写进区块链呢——论文自己的原话是，这样做保证不了日志的正确性和完整性。
看起来能用的办法 为什么不行 让用户确认收到数据 想否认收到的用户，本来就不会向 API 确认，确认这件事没有强制力 只让 API 写日志 网络问题会让用户真的没收到，日志于是写成假的；API 还成了单点故障 直接把共享行为存进区块链 区块链给的是不可篡改，不是「该写的那一条一定被写」 堵完这三条，作者转身去了另一个领域：公平交换。那里早就在用 HTLC 这类原子交换，把「拿到数据访问权」和「付款」绑成一次要么全有、要么全无的操作。
SecLog 的全部巧思就在这一步：把付款换成记录，原子性照样成立。因为在这个场景里，用户本来就不为取数付钱给 API；真正需要绑在一起的，是「拿到数据」和「有件事被触发」。
论文列了四条贡献，说得挺克制：一个能在去中心化环境下强制「共享成功即留痕」的协议、一份安全性证明、一组显示比付款型原子交换更省 gas 的仿真、以及开源代码（github.com/avocado-avery/SecLog）。
二、两条研究线各解决了一半，缺口留在中间# 论文的第二部分把前人工作分成两堆，正好对应下面这张图的两列——有意思的是，两堆各自都做得很扎实，却都漏了同一个角落。
轻点放大 先说区块链日志这一堆。Gao 用同态加密保护链上审计日志，保密性上去了，代价是把用户排除在「验证自己有没有被记上」之外。Cha 的 IoT 审计系统依赖可信基础设施。Zhao 和 López-Pimentel 把 Merkle 树的哈希和根记到链上，防篡改没问题，但明细留在链下，链下那份靠不靠得住只能靠假设。Hsu 把区块链和访问控制拼在 IoT 存储里，Cha 与 Hasan 用可信执行环境护住云日志。AuditChain、BlockAuditor、LogChain 更彻底一些，可是论文的评语一点没客气：它们仍然假设基础设施里的参与者是诚实的，也不处理漏记——也就是事件被悄悄排除、没人能发现。</description></item><item><title>Go 为什么成了 Agent 时代的默认语言</title><link>https://icorer.com/icorer_blog/posts/golang/go-agentic-language/</link><pubDate>Mon, 02 Nov 2026 10:00:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/golang/go-agentic-language/</guid><description>一句话：AI 把「写」的成本压到接近零之后，语言的价值就从「好写」挪到了「好审」——而 Go 过去十五年里的每一个取舍，恰好都压在审查这一侧。
这两篇原文是同一个月里的两篇文章，作者不同、场景不同，结论却撞在一起：Google Go 团队 8 月 11 日在开发者博客上写 《Why Go is an Ideal Language for AI-Assisted Software Engineering》 ；Steve Francia 在 spf13.com 上从 TypeScript 7.0 用 Go 重写 这件事切入，写的是同一件事的另一面。两篇都不是基准测试，都是论证文——所以下面每一条我都标了它是谁说的、有没有被复测。
一、问题：限速点换了位置# 先看一个具体场景。一个 coding agent 的工作循环是这样的：
实现 → 编译 → 测试 → 读失败信息 → 自我修正 → 回到第一步 人手写代码时，这个循环一小时跑十几次；一个 agent 跑同一个任务，会跑几十次。循环的成本被乘以几十倍，于是循环里最贵的那一步，决定了你选什么语言。
而最贵的一步已经不是生成：
环节 2023 年的成本 2026 年的成本 谁在付 写出一行代码 高 接近零 模型 读一行代码 中 中，但量涨了十倍 人的注意力（不可并行） 一次失败的循环 中 高：上下文 + API 费 + 时间 你和你的 token 账单 一次带 bug 的合并 高 更高：错误会被复制到后续每一轮 生产环境 Google 原文里有一句很朴素的判断：agent 在没有外部验证的情况下反复重构，第一遍可能 95% 正确，但每一遍都会把错误率累乘、污染上下文窗口，结果是准确率下降、token 成本上升。这句话没有附测量方法，属于作者的工程观察；但只要你跑过几轮长任务，就会认出这个形状。</description></item><item><title>Super-agent：把「会话」从用户手里拿走</title><link>https://icorer.com/icorer_blog/posts/ai/super-agent-design/</link><pubDate>Mon, 02 Nov 2026 06:30:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/super-agent-design/</guid><description>一句话：这篇长文里最值钱的不是那五个模块——模块会随部署形态变；最值钱的是一句判断：会话应该是系统的实现细节，不是用户的认知负担。下面把它拆开，再用它自己开源的 dsh-superagent-prototype 对一遍账。
原文 2026 年 10 月 31 日发布，开头就写明：这是架构思路探讨，不是产品功能说明。同日团队把原型放上 GitHub，MIT 协议，README 里同样写着「研究代码，不等于内部版本」。所以有两种读法：先当论文读，再当 PRD 读——两种读法给出的结论不一样，差别本身才是有用的部分。
一、问题：多任务的上限，是人的注意力# 作者的观察很克制，也很扎人：
单任务的上限取决于模型能力，多任务的上限取决于人的注意力。据我们观察，一个人通常只能同时跟进 3 到 5 个活跃 Session。
这句话没有附测量方法，但跑过三个 agent 并行的人大多会点头。原因不在人懒，而在现有 agent 把两件事焊死在了同一个对象上：
Session 同时承担 后果 模型上下文的容器 为了「连续」不敢换会话，为了「干净」又必须换 用户的项目管理单位 于是「关掉会话」等于「丢掉项目」 于是有了三条结构性限制：单会话同步阻塞、多任务上下文互相污染、设备一休眠就停。加 CLI、加 MCP、加连接器都改不了这三条——会话被当成了系统的边界。
二、它提了什么：五个模块# 原文主张四个特征——连续、高效、主动、持久——并且认为没有任何一个 ReAct Loop 能同时给出来。于是它们各自落到不同模块上：
特征 靠什么 掉了会怎样 连续 双层架构，所有信道汇到 Router 你得自己记住哪个会话里有哪句话 高效 上下文隔离的并发 Worker 一次只能推进一件事 主动 Trigger + 两级过滤 + 投机执行 永远等指令，等于一个更贵的命令行 持久 存算分离 + 端侧 daemon + Watchdog 电脑一合盖，活就停了 轻点放大 这套设计没有提出新理论，作者自己也这么说。它做的是把计算机系统里一串经典手法——两级调度、快慢路径、把上下文窗口当 cache、投机执行、存算分离、外部看门狗——搬到 agent 系统上。所以读的时候该问的是每个类比在哪里成立、在哪里失效。</description></item><item><title>去中心化、可信的 MCP 运行时：架构设计与实现</title><link>https://icorer.com/icorer_blog/posts/ai/trusted-mcp-runtime-architecture/</link><pubDate>Sun, 01 Nov 2026 12:00:00 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/trusted-mcp-runtime-architecture/</guid><description>一句话：把工具当成可寻址的产物、放进沙箱执行、用身份兜底，MCP 才配得上「可信」两个字。这是架构；后半篇是它的实现。
一、问题：Agent 的工具，是黑盒# Agent 的能力边界不是模型，而是它能调到的工具。可今天的工具是黑盒：第三方代码、一工具一容器、集中托管。
后果 现场表现 代价 来源不可验证 不知道跑的是哪一段字节，也不知道有没有被改过 不敢把敏感数据交给它 架构不可移植 x86 / ARM / RISC-V 各编一份二进制 工具到不了边缘 负载不可扩展 一容器一工具，冷启动 527–1119 ms、常驻 69–94 MB 小设备挂不起几个 工具这一层的问题落在信任上：你既不能核对它，也不能搬动它，还不能按需放它出去。
二、行业研究走到哪一步了# 近两年围绕「MCP + WebAssembly」的研究，把这件事拆得比较清楚了。归纳成三个缺口和一组对策（数据与设计主张来自公开论文，实测环境为 Intel NUC）：
缺口一：协议只有功能元数据。 MCP 的 tool schema 描述「叫什么、要什么参数、返回什么」，但没有「跑多久、吃不吃 CPU、数据在哪、能不能出设备」。调度器看不见执行需求，只能猜。
缺口二：冷启动与指令集把边缘挡在门外。 容器化 MCP server 冷启动 527–1119 ms、常驻 69–94 MB；原生二进制要为每种 ISA 单独构建。数据集里 22.3% 的 server 只支持本地 stdio、77.7% 只支持远程 HTTP、0% 两者都支持——传输方式在编译期就被写死。
缺口三：现有 SDK 绑死系统原语。 它们建在 thread / signal / socket 上，而 WASI 里这些都没有；于是 WASM 侧缺一个原生传输层，只能靠 sidecar 代理，反而把 WASM 省下的开销还了回去。</description></item><item><title>智胜合约：LLM与AI Agent在安全检测与利用中的应用深度分析</title><link>https://icorer.com/icorer_blog/posts/ai/a-deep-dive-research-report-on-the-application-scenarios-of-llms-and-ai-agents-in-smart-contract-security-auditing-and-attacks/</link><pubDate>Sun, 21 Dec 2025 19:05:12 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/a-deep-dive-research-report-on-the-application-scenarios-of-llms-and-ai-agents-in-smart-contract-security-auditing-and-attacks/</guid><description>轻点放大 执行摘要# 随着区块链技术和去中心化金融（DeFi）生态系统的指数级扩张，智能合约的安全性已成为制约Web3大规模应用的核心瓶颈。传统的安全范式——主要依赖于基于规则的静态分析工具、昂贵且不可扩展的人工审计——在面对日益复杂的逻辑漏洞时正显露疲态。本报告识别出当前领域的双重演进路径：防御侧利用多智能体协作（Multi-Agent）进行深度逻辑推理，以及攻击侧利用自主AI进行低成本、自动化的漏洞掠夺。
Web3安全正在进入“智能体对抗智能体”（Agent-vs-Agent）的新时代。
graph TD Root[Web3安全AI变革] subgraph Defense[防御侧: 智能化革命] D1[多智能体协作] D1_1[角色扮演] D1_2[集成学习] D1_3[领域微调] D2[核心框架] D2_1[LLMBugScanner] D2_2[LLM-SmartAudit] D2_3[Smartify] D2_4[AgentLISA] D3[关键能力] D3_1[语义理解] D3_2[逻辑推理] D3_3[自动修复] end subgraph Attack[攻击侧: 自动化升级] A1[自主攻击智能体] A1_1[低成本扫描] A1_2[零日漏洞发现] A2[SCONE-bench] A2_1[GPT-5/Claude表现] A2_2[攻击经济学] A3[攻击流程] A3_1[假设-测试-精炼] end subgraph Adversarial[对抗性安全] AD1[针对AI的攻击] AD1_1[RAG投毒] AD1_2[提示词注入] AD2[机器间经济] AD2_1[M2M支付 x402] AD2_2[实时防御层] end Root --> Defense Root --> Attack Root --> Adversarial D1 --> D1_1 D1 --> D1_2 D1 --> D1_3 D2 --> D2_1 D2 --> D2_2 D2 --> D2_3 D2 --> D2_4 D3 --> D3_1 D3 --> D3_2 D3 --> D3_3 A1 --> A1_1 A1 --> A1_2 A2 --> A2_1 A2 --> A2_2 A3 --> A3_1 AD1 --> AD1_1 AD1 --> AD1_2 AD2 --> AD2_1 AD2 --> AD2_2 style Root fill:#333,color:#fff,stroke-width:2px style Defense fill:#e8f5e9,stroke:#2e7d32,stroke-width:1px style Attack fill:#ffebee,stroke:#c62828,stroke-width:1px style Adversarial fill:#fff3e0,stroke:#ef6c00,stroke-width:1px I.</description></item><item><title>信任的架构：Web3.0 数据库和存储系统研究报告</title><link>https://icorer.com/icorer_blog/posts/web3/the-architecture-of-trust-a-research-report-on-web3.0-database-and-storage-systems/</link><pubDate>Thu, 18 Sep 2025 23:04:12 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/the-architecture-of-trust-a-research-report-on-web3.0-database-and-storage-systems/</guid><description>轻点放大 第一节：引言 - 从中心化到去中心化数据范式转变# 互联网的演进可以划分为不同的架构和哲学时代。当前的主导范式 Web 2.0，由交互式、用户驱动的平台定义，这些平台连接了全球。然而，这种模式建立在一个根本性的不对称之上：尽管用户创建内容和数据，但中心化公司拥有平台、控制数据并攫取绝大部分经济价值。这种中心化导致了系统性问题，包括单点故障、公司或国家行为者的审查，以及用户数据隐私和主权的持续侵蚀。Web 3.0，或称 Web3，代表了互联网数据层的根本性重构，提出了一种基于去中心化、用户所有权和可验证信任的新范式。
1.1 定义 Web3 数据层：从平台到协议# Web3 是互联网的下一次迭代，构建在公共区块链和去中心化点对点网络之上。它不仅仅是增量升级，而是一种结构性转变，旨在将互联网的基础从私有平台转移到开放、社区治理的协议。在 Web2 模型中，谷歌和 Meta 等公司提供服务以换取个人数据，这些数据成为它们的主要资产。这种安排使得用户对其自身的数字足迹几乎没有控制权。
Web3 旨在通过创建一个以用户为中心的互联网来瓦解这种模式，在这个互联网中，个人对其数据、数字资产和在线身份拥有直接的所有权和控制权。这通过利用将控制权从中心实体分散到网络参与者手中的技术来实现。核心主张是从用户是产品的网络向用户是所有者的网络转变。这种转变不仅对数据架构，而且对支撑数字世界的经济模型都具有深远的影响。这些新网络中产生的价值旨在分配给贡献给它们的用户、创作者和开发者，通常通过基于代币的经济系统，而不是集中在单一公司实体中。
1.2 Web2 和 Web3 数据哲学的对比# Web2 和 Web3 之间的哲学鸿沟最好通过比较它们数据管理和控制的核心原则来理解。将“租公寓（Web2）与拥有自己的房子（Web3）”进行类比，有效地捕捉了这种区别。在前者中，用户受制于房东的规则和意愿；在后者中，用户拥有主权和控制权。
在 Web2 中，数据驻留在由公司管理的中心化数据库中。这种架构虽然高效，但会产生固有的漏洞。它集中了数据，使其成为数据泄露的高价值目标，并建立了一个可用于审查或去平台化的中心控制点。对这个系统的信任寄托在中间人——平台所有者——手中，他们被期望作为用户数据的负责任的管理者。
相反，Web3 建立在去中心化原则之上。它通过加密所有权将控制权从这些中间人转移到个人用户手中。该系统被设计为“无需信任”，这个术语并非指没有信任，而是指将信任从易犯错误的人类机构转移到透明、可验证和数学强制执行的协议。交互由不可变的代码和数据管理，这些代码和数据已由网络集体验证，从而无需信任第三方来促进交易或正确管理数据。然而，这种新的安全模型将主要攻击面从公司服务器转移到协议层本身，因此需要一类新的安全学科，专注于智能合约审计和形式化验证，以确保底层代码的完整性。
特性 Web2 范式 Web3 范式 数据所有权 公司所有；用户授予平台许可。 用户通过加密密钥拥有和控制。 核心架构 中心化客户端-服务器模型；数据存储在私有数据库中。 去中心化点对点网络和分布式账本（区块链）。 信任模型 信任中心化中间人（公司、银行）。 “无需信任”；信任代码、密码学和经济激励。 隐私 数据是公司资产，通常在未经明确同意的情况下收集。 用户控制；通过密码学和用户主权增强隐私。 审查制度 平台和政府可以审查内容或去平台化用户。 抗审查；没有中央机构可以单方面删除数据或用户。 经济模型 平台数据货币化；广告驱动。 基于代币的经济；价值归属于用户、创作者和建设者。 1.3 区块链作为基础数据原语的作用# Web3 架构的核心是区块链技术，它作为其基础数据原语和“骨干”。区块链是一个去中心化、分布式且通常是公共的数字账本，它安全地记录跨大量计算机网络的交易。它充当一个数字会计系统，维护“谁拥有什么”的规范记录，并跟踪此记录随时间的所有更改。
其结构由数据“块”组成，这些数据块通过密码学方式“链接”到前一个区块，形成一个不间断且不可变的历史。一旦交易被网络验证并添加到链中，它就不能被更改或删除，提供了前所未有的数据完整性水平。由于这个账本由去中心化网络而不是单个服务器维护和验证，因此它能够抵御单点故障，并由其参与者集体管理，不归任何一个实体所有。这种不可变性、透明性和安全性的结合使区块链成为新的、更值得信赖的数据范式的基本构建块。
1.4 核心原则：无需信任、可验证性和可组合性# Web3 数据模型由其基础技术产生的一系列新兴属性定义。这些原则与 Web2 的封闭、专有系统截然不同。</description></item><item><title>AI智能体的高效工具设计：从原则、评估到高级实现</title><link>https://icorer.com/icorer_blog/posts/ai/building-effective-ai-agent-tools-design-evaluation-and-tool-masking/</link><pubDate>Fri, 12 Sep 2025 22:24:12 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ai/building-effective-ai-agent-tools-design-evaluation-and-tool-masking/</guid><description>轻点放大 引言：为非确定性系统构建工具# 生成式人工智能的演进已经进入了能够执行任务、与外部世界互动的全新阶段：智能体 AI（Agentic AI）。这些智能体系统的效能，在很大程度上取决于我们为其提供的工具的质量。然而，为智能体设计工具从根本上不同于传统的软件开发。传统软件是确定性系统之间的契约，而智能体工具则是确定性系统与非确定性系统（如大型语言模型）之间的新型契约 。
智能体在面对任务时，可能会选择调用工具，也可能依据通用知识作答，甚至可能产生幻觉或无法理解如何使用工具。这意味着我们必须重新思考软件编写方式，为智能体设计“符合人体工程学”（ergonomic）的工具——这些工具不仅对智能体而言直观易用，对人类而言也同样如此 。本报告将系统性地阐述如何构建和评估高质量的智能体工具，从核心设计原则出发，介绍一套完整的评估与迭代方法论，并深入探讨一种高级实现模式——工具掩码，最终为技术领导者提供一套可行的战略建议。
第一部分：高效工具的核心设计原则# 根据 Anthropic 的研究与实践，编写高效的工具需要遵循一套指导性原则，其核心在于优化智能体有限的“上下文”资源，并引导其走向高效、正确的解决路径 。
1.1 选择正确的工具：质量优于数量# 更多的工具并不总能带来更好的结果。一个常见的错误是简单地将现有软件功能或 API 端点直接封装成工具，而未考虑其是否适合智能体 。智能体与传统软件在感知和利用工具的方式上存在本质差异，即所谓的“可供性”（affordances）不同。
整合功能，而非简单封装：工具应当能够处理多个离散操作或 API 调用，将频繁链接的多步任务整合为单次调用。这不仅能丰富工具的响应内容，还能减少智能体的调用次数 。 示例：与其提供 list_users、list_events 和 create_event 三个独立的工具，不如设计一个 schedule_event 工具，该工具能一步完成查找空闲时间并安排会议的整个流程 。 示例：与其提供一个返回所有日志的 read_logs 工具，不如设计一个 search_logs 工具，它只返回相关的日志行和必要的上下文 。 明确且独特的目标：每个工具都应有清晰、独特的目标，避免功能重叠。这能帮助智能体像人类一样对任务进行分解，同时减少中间输出对上下文的消耗 。 避免上下文浪费：智能体的上下文窗口是有限的宝贵资源。应避免设计那些会返回大量无关信息、迫使智能体进行“暴力搜索”的工具。例如，一个返回所有联系人的 list_contacts 工具对智能体来说是低效的，更好的选择是 search_contacts 。 1.2 为工具划分命名空间# 当智能体可以访问数十甚至数百个工具时，清晰的功能边界至关重要。功能重叠或用途模糊的工具会让智能体感到困惑 。
使用前缀进行分组：通过为相关的工具组添加通用前缀（即命名空间），可以帮助智能体在不同工具集之间进行区分。这种命名方案的选择（前缀或后缀）会对评估结果产生不可忽视的影响，需要根据具体模型和评估进行选择 。 示例：按服务（如 asana_search, jira_search）和资源（如 asana_projects_search, asana_users_search）对工具进行命名，可以帮助智能体在正确的时间选择正确的工具 。 1.3 从工具中返回有意义的上下文# 工具的实现应确保只向智能体返回高信息量的信号，优先考虑上下文的相关性而非接口的灵活性 。
优先使用自然语言标识符：智能体处理自然语言名称、术语或标识符的能力远胜于处理晦涩的、机器生成的技术 ID（如 UUID）。将任意的字母数字 UUID 解析为具有语义意义的语言，可以显著提高检索任务的准确性并减少幻觉 。 避免低级技术细节：应避免在响应中包含 uuid、256px_image_url、mime_type 等低级技术标识符。像 name、image_url 和 file_type 这样能直接指导智能体后续行动的字段更具价值 。 提供灵活的响应格式：在某些情况下，智能体可能同时需要自然语言和技术 ID（例如，用于触发下游工具调用）。可以通过在工具中设置一个 response_format 枚举参数（如 concise 或 detailed）来让智能体控制响应的详细程度，从而在灵活性和 Token 效率之间取得平衡 。 1.</description></item><item><title>不止于并发：Go 语言 SIMD 提案深度解析</title><link>https://icorer.com/icorer_blog/posts/golang/an-in-depth-analysis-of-the-go-language-simd-proposal/</link><pubDate>Thu, 21 Aug 2025 22:05:12 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/golang/an-in-depth-analysis-of-the-go-language-simd-proposal/</guid><description>轻点放大 I. Go 语言中无形的性能天花板# Go 语言凭借其简洁的语法、强大的并发模型以及卓越的网络编程能力，在云原生和后端服务领域取得了无可争议的主导地位。其 goroutine 调度器和简单的并发原语使得构建高并发、可扩展的系统变得前所未有的简单。然而，在这种成功的背后，存在一个长期以来限制其应用边界的性能天花板：对于计算密集型、数据并行的任务，Go 的性能表现往往落后于 C++ 和 Rust 等传统系统语言。
这片性能的“无人区”正是单指令多数据流（SIMD）技术大显身手的领域。SIMD 是一种并行计算模型，允许 CPU 在一个指令周期内对多个数据元素执行相同的操作。我们可以用一个简单的图像处理任务来理解其威力：假设要增加一张图片的亮度，传统的标量（scalar）计算方式是逐个像素进行处理，一次调整一个像素点的亮度值。而 SIMD 方式则完全不同，它会将多个像素（例如 4 个、8 个甚至 16 个）打包成一个向量（vector），然后用一条指令同时完成所有这些像素的亮度调整。
下面的图表演示了标量计算与 SIMD 计算在处理数组相加时的根本区别：
graph TD subgraph Scalar[标量计算 Scalar] direction LR S1[A + B] --> S2[C] S3[A1 + B1] --> S4[C1] S5[A2 + B2] --> S6[C2] S7[A3 + B3] --> S8[C3] S2 --> S3 S4 --> S5 S6 --> S7 style S1 fill:#f9f,stroke:#333,stroke-width:2px style S3 fill:#f9f,stroke:#333,stroke-width:2px style S5 fill:#f9f,stroke:#333,stroke-width:2px style S7 fill:#f9f,stroke:#333,stroke-width:2px end subgraph Vector[SIMD 计算 Vector] direction LR V1[A0,A1,A2,A3 +] --> V2[C0,C1,C2,C3] style V1 fill:#ccf,stroke:#333,stroke-width:2px end 这里的关键在于区分两种并行模式：Go 的并发模型解决的是任务并行（task parallelism），即让成千上万个独立的 goroutine 宏观上同时运行；而 SIMD 解决的是数据并行（data parallelism），即在微观层面用单条指令处理批量数据。这种能力对于音视频编解码、密码学计算、科学模拟、机器学习以及现代数据库查询引擎等高性能领域至关重要。</description></item><item><title>DANP-Engine：下一代可信AI运行时，后量子安全护航</title><link>https://icorer.com/icorer_blog/posts/web3/danp-engine-ai-trust/</link><pubDate>Sun, 10 Aug 2025 13:15:12 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/danp-engine-ai-trust/</guid><description>轻点放大 引言：可信 AI 运行时的必然性演进# 人工智能正以前所未有的速度重塑产业格局与日常生活，但只有当信任成为其内在基础元素时，AI 的真正潜力才能被充分释放。随着 AI 系统日益自主化和普及化，确保其安全性、可靠性和伦理运行已不再是可选项，而是至关重要的核心要求。我们深入探讨 &amp;ldquo;可信 AI 运行时&amp;rdquo; 这一关键概念，它作为 AI 模型的安全可验证操作核心，如同传统软件依赖强健的运行时环境（如 Node.js 或 Python 解释器）一样，AI 系统需要专门的环境不仅执行提示和管理工具，更要从设计到部署全程保证 AI 的完整性、隐私性和伦理行为。本文将展示 DANP-Engine 如何整合前沿技术与原则，将信任直接工程化到 AI 核心中，应对负责任 AI 创新的多方面挑战。
从通用 AI 运行时到可信 AI 运行时的演进是不可避免且至关重要的进步。传统 AI 运行时主要关注处理提示、工具、上下文和对话流程，而与此同时，全球各类组织和监管机构对可信 AI 原则 —— 如公平性、安全性、隐私性、可解释性和问责制 —— 的重视日益增长。这种融合表明，抽象的信任原则必须具体地工程化到 AI 系统的操作层中。当 AI 从实验阶段过渡到高风险生产环境（如医疗健康、金融或自动驾驶）时，运行时成为这些原则被执行和验证的关键环节。因此，&amp;ldquo;可信&amp;rdquo; 正成为任何生产级 AI 运行时的必备前缀，反映了 AI 行业的成熟 —— 伦理考量不再是事后想法，而是核心架构要求。这种转变意味着未来的 AI 基础设施不仅要在性能或可扩展性上接受评估，更要在其内在的可信度上经受检验，促使开发者和组织采用将信任设计在内的框架。
一、AI 运行时解构：不止于执行# AI 运行时的作用类似于 Node.js 或 Python 解释器等传统软件解释器，但其操作范式有所不同：它接受提示作为其 &amp;ldquo;程序&amp;rdquo;，并利用一系列工具作为其 &amp;ldquo;标准库&amp;rdquo;。这种环境经过精心设计，以管理 AI 操作中固有的复杂性，包括各种工具的发现与链接、复杂的上下文管理、高效的内存处理，以及工具输出精确解析并重新注入 AI 操作流程。本质上，它充当着指挥和协调 AI 行为的 &amp;ldquo;大脑&amp;rdquo;。</description></item><item><title>基于区块链的PKI管理框架</title><link>https://icorer.com/icorer_blog/posts/web3/blockchain-based-pki/</link><pubDate>Sat, 16 Dec 2023 22:15:12 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/blockchain-based-pki/</guid><description>轻点放大 摘要 I.介绍 PKI问题及现有解决方案 基于日志的PKIs(Log-based PKIs) 信任网(WoT)（Web of Trust） 基于区块链的PKI（Blockchain-based PKI） II.背景 A.可信链（Chain of trust） B. 区块链技术 III. 相关工作 IV. 基于区块链的PKI框架 A.概述 B.设计方法论 C.架构 D.实现 E.区块链PKI的优势 V.评估和实验结果 A.性能 B.在以太坊中启动新CA的成本 C.局限性和挑战 VI. 结论 引用 摘要 公钥基础设施（PKI）是促进互联网上安全信息交换的基石技术。但是，由于证书颁发机构（CA）可能会被用来为最终用户颁发未经授权的证书，因此PKI面临风险。最近的许多违规事件表明，如果CA受到损害，相应最终用户的安全将面临风险。作为一种新型的解决方案，区块链技术有可能解决传统PKI系统的问题，特别是消除单点故障和对CA缺点的快速反应。区块链能够在公共且不可变的分布式账本中存储和管理数字证书，从容产生完全可追溯的历史日志。在这篇论文中我们设计和开发了一个基于区块链的PKI管理框架，用于颁发、验证和撤销X.509证书。评估和实验结果证实，所提出的框架提供了更可靠、更强大的PKI系统，且维护成本适中。
I.介绍 公钥基础设施（PKI）提供了一种通过互联网验证身份的安全方法。它定义了颁发、管理、验证和分发数字证书所需的策略和程序，以便安全地使用公钥加密。公钥的PKI管理通常基于证书标准X.509，该标准提供某些外部实体（证书颁发机构）对私钥所有权的验证。X.509证书被定义为公钥值与主题（例如域名）绑定的数据结构。绑定由受信任的证书颁发机构（CA）对每个证书进行数字签名来断言。CA可以通过深入验证私有证书持有者的身份来做出这一断言。
最近，知名CA的安全程序存在缺陷，表明CA的安全容易受到操作失误的影响。由于CA似乎是PKI中的单点故障，CA的错误或违规导致颁发未经授权的证书。例如，其中一件备受瞩目的是CA DigiNotar安全漏洞，导致利用该公司基础设施为知名域名颁发数百个流氓数字证书，其中包括google.com的一个。结果，在发现500多个假证书后，网络浏览器供应商被迫将荷兰CA DigiNotar颁发的所有证书列入黑名单。
在另外一个案例中，DigiCert Sdn是马来西亚的颁发机构。错误地颁发了22个弱SSL证书，这些证书可用于冒充网站和签署恶意软件。最终，主要浏览器不得不撤销对于DigiCert Sdn. Bhd颁发的所有证书的信任。（注：DigiCert Sdn. Bhd. 不隶属于美国公司 DigiCert, Inc.）美国大型证书颁发机构TrustWave也存在证书泄露问题。TrustWave承认，它向其中一位客户颁发了从属Root证书，以便该客户可以监控其内部网络上的流量。从属Root证书允许其持有者从Internet上的几乎任何域创建SSL证书。尽管TrustWave已经吊销该证书，并表示将不会向客户颁发从属跟证书，但这说明CA是多么容易犯错，以及这些失误的后果可能有多么严重。
PKI问题及现有解决方案# 提出了两种方法来解决SSL/TLS PKI问题：基于日志的PKI模式和点对点认证的去中心化网络（称为信任Web(WoT)）。
基于日志的PKIs(Log-based PKIs)# 该方法已被提议作为解决CA行为不当问题的新兴解决方案。其背后的想法是使用高度可用的公共日志服务器来监视和发布CA颁发的证书。这些公共日志通过确保最终客户只接受和信任公共记录的证书提供透明度。因此，CA的任何不当行为都会被用户和服务器检测到。Google的证书透明度（CT）是部署最广泛的基于日志的PKI，目前在Chrome和Firefox中都可用。与此同时，许多提案打算通过支持撤销和错误处理来扩展基于日志的PKI模式的功能。不幸的是，尽管有这些好处，基于日志的PKI仍然面对一些挑战，例如与证书吊销相关的挑战。
信任网(WoT)（Web of Trust）# WoT的方法是完全分散的：用户可以通过签署其公钥证书来指定其他人值得信赖。通过这样做，用户积累了包含他的公钥和来自认为他值得信赖的实体的数字签名证书。如果可以验证该证书包含她/他信任的某人的签名，则该证书将手打第三方的信任。该系统受益于其分布式特性，因为它消除了任何中心故障点。然而，这使得新用户或远程用户加入网络变得困难，因为WoT的某些现有成员通常必须亲自与新用户会面，以首次验证她/他的身份并签署公钥。此外，与基于CA的方法不同，WoT无法处理密钥撤销。一个用户被限制选择另外一个用户作为她/他的“指定撤销者“，有权在私钥丢失或泄露时撤销她/他的证书。当前的使用方法依赖于定期向浏览器推动撤销列表。但是，这种方法会使无效证书受到信任，直到浏览器的吊销列表得到下一次推送为止。
基于区块链的PKI（Blockchain-based PKI）# 基于区块链的PKI启发了很多研究，它们基于区块链技术构建安全的PKI系统。他们的主要论点是，基于区块链的解决方案可以融合基于日志的PKI和WoT方法的优点，并解决传统PKI系统的一些问题。一方面，区块链解决了基于日志PKI方法的潜在故障点和部署问题，我们将在稍后讨论。另一方面，基于区块链的方法减轻了新证书持有者对WoT的需求，以证明现有网络成员的可信度。
我们的主要贡献是一个完整的基于区块链的PKI框架来管理X.509证书。我们的框架包含多项创新。第一，我们扩展标准X.509证书以与基于区块链的PKI方法兼容，我们使用X.509的扩展字段用于嵌入区块链元数据。第二，我们设计并实现了基于区块链的PKI，为数字证书提供可靠的管理。
本文的其余部分安排如下：第二节介绍了证书验证机制（称为信任链）的背景，并介绍了区块链技术如何帮助构建安全的PKI系统。第三节探讨了使用区块链实施PKI的相关工作。第四节我们展示了基于区块链的PKI解决方案。第五节提供了评估结果和讨论。最后，第六节对本文进行了总结。
II.背景 在这一节，首先我们介绍信任链背后的想法，用于验证X.509证书。然后我们简要介绍了区块链技术以及如何使用它来构建PKI管理框架。
A.可信链（Chain of trust）# 传统的PKI系统是基于CA的，CA颁发签名证书，完全符合X.</description></item><item><title>Fleek Network：去中心化边缘平台</title><link>https://icorer.com/icorer_blog/posts/web3/fleek-network/</link><pubDate>Thu, 03 Aug 2023 22:15:12 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/fleek-network/</guid><description>轻点放大 概要 背景：网络的演变 现代Web堆栈的演变 Web3 的模块化和可组合式演变 将现代 Web 引入 Web3 Fleek Network：去中心化边缘平台 关键概念和性能优化 地理意识 智能路由&amp;amp;工作分配 无状态执行 无虚拟机核心 （VM-Less Core） 内置（外部可扩展）文件系统 内容可寻址核心 增量内容检索和验证 Fleek网络：协议 简洁链状态 Narwhal &amp;amp; Bullshark 共识 Delivery Acknowledgement SNARKs 基于绩效的声誉 Fleek Network: Services SDK 与Service交互 节点分配&amp;amp;洗牌 资源&amp;amp;商品 服务示例：边缘计算 在Fleek Network建设: Who, What &amp;amp; Why 构建/使用服务的想法 网络/边缘服务 Web 3 服务的特定用例 去中心化CDN 去中心化网站/应用程序托管 去中心化 IPFS Pinning 去中心化边缘计算（基于 Web3 协议） 区块链快照即服务 zkVM、EVM 和其他 VM 作为服务 替代Rollup Sequencer 临时Rollups 边缘证明生成 验证随机性 Web3 查询/事件 参考 附录A: 绩效信誉算法 概要 Fleek Network 是一个去中心化边缘平台，经过优化，可促进高性能 Web 服务（CDN、无服务器功能等）的部署和运行。Fleek Network的全球分布式、自主控制的边缘节点网络使开发者可以轻松创建和利用多种边缘服务。这些服务继承了加密且经济安全的基础设施，保障节点和地理范围覆盖、稳定且可预测的成本、以及网络上运行的所有服务的一致质量和性能。Fleek Network的目标是提供一个平台，所有Web3协议、中间件、服务和应用程序都可以从中受益，以进一步分散其堆栈，而无需牺牲成本、性能、复杂性或开发人员/终端用户体验。</description></item><item><title>CometBFT：提升Cosmos区块链共识新高度</title><link>https://icorer.com/icorer_blog/posts/cosmos/cosmos-meet-cometbft/</link><pubDate>Wed, 12 Jul 2023 21:25:16 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/cosmos/cosmos-meet-cometbft/</guid><description>轻点放大 Why Now? What’s Next? CometBFT 的目标是什么？ CometBFT 背后是谁？ 接下来的步骤是什么？ Common Questions CometBFT底层的共识算法是什么？ CometBFT 会放弃 Tendermint 共识算法吗？ Tendermint Core 是否会有多个竞争分叉为跨链提供动力？ 这会导致任何链分叉吗？ 如果我在基于 Tendermint Core 的网络上进行验证，我的操作是否存在任何问题？ tendermint-rs会发生什么？ tm-db 或 tm-load-test 会发生什么情况？ CometBFT，这是一个适用于链间及其他领域的状态机复制引擎！ CometBFT 是 Tendermint Core 的分叉和继承者，并将作为支持 Interchain Stack 的官方复制引擎。 CometBFT 的长期愿景是成为可靠、安全、大规模、特定应用区块链复制引擎的首选。
Interchain 基金会、Informal Systems、Cosmos SDK 团队以及 Cosmos 生态系统中的众多其他团队一直在共同努力。这篇文章解决了围绕此次发布的一些最重要的问题。请放心，我们一直在努力让升级或采用 CometBFT 尽可能顺利。我们将介绍背景详细信息、CometBFT 愿景和目标、这项工作背后的团队以及技术影响方面的后续步骤。
Why Now? 我们决定以这个新名称开发旗舰 Cosmos 共识引擎，以标志着席卷整个生态系统的多项重要变化。
在技术方面，跨链在过去几年中取得了显着的发展。我们生活在一个 IBC 原生的多链世界。 ABCI 2.0 是 Interchain Stack 中缺失的关键部分，设计或质量保证方面（例如模块化、集成或严格测试）也是如此。此外，放弃 Tendermint Core v0.35 和 v0.</description></item><item><title>Tendermint ABCI分布式KV存储引擎分析</title><link>https://icorer.com/icorer_blog/posts/web3/tendermint-distributed-kv-storage-engine-analysis/</link><pubDate>Tue, 23 May 2023 21:25:16 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/tendermint-distributed-kv-storage-engine-analysis/</guid><description>轻点放大 背景介绍 1.Tendermint KV 模块分析 1.1 ABCI应用拦截Tendermint状态机 1.2 ABCI应用Application结构体分析 1.3 ABCI应用处理Tendermint 区块Deliver事务 1.4 ABCI应用处理Tendermint 区块Commit事务 1.5 ABCI应用处理Tendermint 区块Query事务 1.6 ABCI应用处理Tendermint 区块Check事务 1.7 KV存储引擎状态处理 2.Tendermint KV运行实践 2.1 安装Tendermint 2.1.1 二进制安装 2.1.3 源代码安装 2.1.3 运行Tendermint 2.1.4 重新安装 2.2 Tendermint KV编译及运行 2.3 Tendermint KV 运行测试 2.3.1 Tendermint Core RPC 交易广播 2.3.2 Tendermint Core RPC 查询广播 3.总结 附录 背景介绍 Tendermint 是一个基于共识算法的分布式系统，它提供了一种在去中心化环境下实现可靠、安全、高效的数据存储和交互的方法。在这个环境中，一个分布式 KV 存储引擎是非常有用的，它可以让不同的节点在共享一个数据集合的同时保持数据的一致性和可靠性。
Tendermint 为分布式 KV 存储引擎提供了一些核心组件，其中最重要的是 ABCI（Application Blockchain Interface）接口和 KV 存储引擎。ABCI 接口定义了应用程序和 Tendermint Core 之间的交互协议，它规定了应用程序需要实现哪些方法以处理交易、查询和状态更改。Tendermint开源的 ts-db存储引擎则提供了一个标准的键值存储接口，可以将数据持久化到磁盘中，同时支持可插拔的存储引擎（例如 LevelDB、RocksDB 等）。</description></item><item><title>EIP-4844改进提议：分片Blob事务</title><link>https://icorer.com/icorer_blog/posts/web3/eip-4844---reduced-l2-fees/</link><pubDate>Mon, 27 Feb 2023 23:35:16 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/eip-4844---reduced-l2-fees/</guid><description>轻点放大 EIP-4844 分片Blob事务以简单、向前兼容的方式扩展以太坊的数据可用性。
一、摘要 二、动机 三、Specification 规范 3.1 Parameters 参数 3.2 Type aliases 类型别名 3.3 Cryptographic Helpers 加密助手 3.4 Helpers 3.5 New transaction type 新的交易类型 3.6 Header extension 头扩展 3.7 Beacon chain validation 信标链验证 3.8 Opcode to get versioned hashes 获取版本哈希的操作码 3.9 Point evaluation precompile 点评估预编译 3.10 Gas accounting 3.11 Networking 网络 四、基本原理 4.1 On the path to sharding 在分片的路上 4.2 How rollups would function 4.3 Versioned hashes &amp;amp; precompile return data 版本化哈希和预编译返回数据 4.</description></item><item><title>SBT vs SSI：Web3对数字身份解决方案的探索</title><link>https://icorer.com/icorer_blog/posts/web3/soulbound-tokens-vs-self-sovereign-identity/</link><pubDate>Wed, 14 Dec 2022 11:55:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/soulbound-tokens-vs-self-sovereign-identity/</guid><description>轻点放大 在题为“去中心化社会:寻找Web 3的灵魂”的研究论文中，以太坊(ETH)的联合创始人Vitalik Buterin 与 Glen Weyl、Puja Ahluwalia Ohlhaver 一起，介绍了“灵魂绑定令牌”(SBTs)的概念，作为对数字身份的一种全新看法。这篇文章谈到了数字身份在Web3中的重要性，以及满足Web3的高度金融化，建立同等数量的信任和社会关系的重要性。
然而，我们不禁注意到SBTs的用例与自我主权身份(SSI)所做的是多么接近。SSI已经在为创造一个可信的社会铺平道路。我们想比较Vitalik等人的灵魂绑定令牌假说和SSI，看看当我们进入Web3时，哪一个最有效。
在其最简单的形式中，灵魂绑定令牌是可以在数字钱包中显示的不可转移的可替换令牌。这些代币是由一个灵魂(个体)发给另一个灵魂的。他们不能和任何人交易。一旦获得一个SBT，它就被绑定到那个人身上，因此得名soulbound。
SSI使用数据发布者、验证者和持有者之间的关系来创建一个以用户为中心的模型。在这种模式下，持有者可以选择与验证者共享他们需要的确切信息(而不是更多)。然后，验证者可以将信息与发行者的签名(有时存储在区块链上)进行交叉引用，以确保持有人的数据是有效的。
SBT的吸引力在于它们的不可转让性，它们与接受者绑定在一起。它们可以用于代表其所有者声明凭证和形成在线身份。类似于一组徽章，您可以有多个SBT用于各种凭证，从驾驶执照到代表音乐会门票的令牌。
另一方面，SSI 的不同之处在于它们的默认可见性是私有的和账本外的，而 SBT 默认是公开的和账本上的。SSI侧重于允许用户控制他们的数据，并将发布的文档保存在私人数字钱包中，默认的隐私模式让持有者对他们的个人数据以及如何访问这些数据有更多的控制权。
SBT vs NFT vs SSI 轻点放大 作为一种身份解决方案，SBT 的功能类似于不可替代令牌 ( NFT )。关键区别在于它们缺乏可转移性。SBT 现在正在建设中，但面临一个关键障碍：隐私。
SBT 是 Web3 中表达自我的一种方式，类似于加密货币和 NFT 的所有权。然而，他们可以将现代面临的许多当前身份问题复制到一个新的公共和不可变平台上，这是 SBT 的主要缺点。
围绕SBTs的建立存在紧张关系，一些人担心它可能会建立一个公共的社会价值体系，类似于中国的社会信用体系。有人担心，如果被广泛采用，我们在现实世界中取得的成就和犯下的错误可能等同于与该行动相关的SBT。这将为你的每一项成就和犯下的每一个错误建立一个终身的账本，没有交易功能。
从这个意义上说，SBT不能避免人为错误；发行人有可能将SBT发送给不正确的持有人，这可能会导致许多隐私问题。已经有一个案例，一个人创造了一个“混蛋SBT”，一个令牌，使用与NFT相同的技术，但可以被发送给一个人，然后他只能通过支付费用来删除它。SBTs的这一方面有可能造成巨大的伤害，并可能贬低Web3的灵魂。
SSI 的存在是为了解决当前在以数字为中心的社会中面临的关键身份问题。通过创建一个用户控制他们的数据并有权将其发送给他们希望的任何人的系统，我们开始促进真正的数据所有权成为一种社会规范。公司和个人之间的数据交易可以像消息传递一样简单。通过不建立固有的面向公众的身份系统，SSI 可以解决数据盗窃和中心化数据孤岛的问题，而发行人和持有人之间没有任何歧义。
SBTs是建立在预先存在的Web3概念上的，比如NFT，这为社区采用它们提供了一条强有力的途径，特别是因为开发人员已经习惯了这种工具。然而，随着社区开始理解SBTs的公共性质以及由此产生的隐私问题(例如，在线行为的可追溯性)，他们将开始寻找保护隐私的替代方案。
另一方面，SSI近年来受到大学的青睐，并在管理机构中拥有强大的市场，特别是考虑到最近发生的事件，如新冠肺炎。对SSI的兴趣已经开始增长，欧盟委员会提议所有欧洲人都应该拥有一个安全的数字身份。这种政府采用水平将有利于SSI进一步扩展到教育和医疗保健等全球关键领域。
SBTs和SSI都因解决了Web3当前的身份混乱而获得公众关注。SBT寻求利用社区对NFT的熟悉程度来确保快速无缝的采用。然而，SSI希望通过专注于隐私的技术来解决这些问题，这项技术是经过多年研究开发出来的。尽管如此，这两个系统都有潜力为我们的数字生活增加价值。尽管如此，SSI是唯一一个足够深入地解决身份和隐私问题的方案，让Web3真正被大众接受，并将我们置于我们自己生态系统的中心。
了解更多# Ethereum&amp;rsquo;s Vitalik Buterin Lists &amp;lsquo;Worthwhile&amp;rsquo; Ideas for Developers to Work On 6 Key Points in Vitalik Buterin&amp;rsquo;s Vision for Ethereum Presented at EthCC These Are Some Topics Ethereum Developers Disagree With Vitalik Buterin On Crypto in 2022 Will Bring New and Older Emergent Trends to the Fore Where Do We Stand on Self-Sovereign Identity?</description></item><item><title>身份验证世界中的自主身份：架构和领域用例</title><link>https://icorer.com/icorer_blog/posts/web3/self-sovereign-identity-in-a-world-of-authenticationarchitecture-and-domain-usecases/</link><pubDate>Tue, 13 Dec 2022 11:55:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/self-sovereign-identity-in-a-world-of-authenticationarchitecture-and-domain-usecases/</guid><description>轻点放大 摘要 自我主权身份 (SSI) 预计将以某种形式成为每个人生活的一部分。在与第三方组织打交道时，验证和验证一个人是否是他们声称的真实人物的能力以及保护个人属性的能力可能会产生广泛的影响。利用区块链和其他去中心化技术，SSI 是一个不断发展的研究领域。在去中心化结构中保护个人信息的方面可能对公共和私营部门有益。
在本文中，我们描述了 SSI 框架架构以及跨领域（如医疗保健、金融、零售和政府）的可能用例。该论文还将 SSI 及其去中心化架构与当前广泛采用的公钥基础设施 (PKI) 模型进行了对比。
1.介绍 在数字领域有目的地验证您的身份的能力是大多数（如果不是全部）在线活动的基础。我们根据妥协对我们生活的负面影响，在不同级别保护这种在线身份。随着我们生活中越来越多的时间在网上进行交易，人们在管理数字身份的方式上也越来越精明。对所有帐户使用相同的“简单”密码曾经是一种常见的做法。现在这被视为灾难的根源，知道如果一个在线帐户被泄露，那么您的所有帐户都可能暴露 [1]。组织正在帮助用户转向需要多因素身份验证和更强密码的更安全的在线身份实践。这些步骤极大地提高了在线身份安全性，但标准在线身份管理系统的架构本质上是不安全的。区块链和去中心化身份的发展促成了自我主权身份 (SSI) 框架的创建。 SSI 框架在许多领域都有巨大的实现可能性，在这些领域中存在对个人隐私的驱动 [2]。
这些框架的开发旨在提高用户个人身份信息 (PII) 的整体安全性。 PII 的示例包括用户姓名、地址、护照号码、驾照号码、纳税人识别号码、患者识别号码、财务记录等。个人健康信息 (PHI) 是最受追捧的信息之一，黑客在 PII 之后，主要原因是医疗保健中使用的身份与社会安全号码 (SSN) 相关联，而社会安全号码对于个人来说永远不会改变 [3]。组织使用其他 PHI（例如家庭住址和电话号码）来确定身份可能会发生变化。使用窃取的 PHI 进行冒充会使个人陷入可能导致严重经济损失的境地。 SSI 在医疗保健行业的使用可以帮助保护用户数据并限制患者 PHI 的扩散。使用 SSI 模型的医疗保健提供者只有在获得患者批准/许可的情况下才能访问患者 PHI。
与公钥基础设施 (PKI) 类似，SSI 使用非对称密钥作为加密体系结构以及数字签名来确保对等方之间的安全通信 [4]。 PKI 利用一组中央机构来存储身份、证书和公共加密密钥的关联数据库。相反，SSI 使用去中心化账本技术 (DLT) 来关联去中心化标识符 (DID) 和公共加密密钥。在 SSI 实现中，DID 及其对称密钥对的公共部分是唯一可公开访问的与实体相关的信息。该实体保留他们认为合适时共享的身份信息详细信息。
本文描述了 SSI 体系结构及其主要组件，以及 PKI 和 SSI 中使用的机制之间的比较。我们还研究了如何在医疗保健、金融、零售和政府等不同领域利用 SSI，在这些领域中需要身份验证和数据安全，并且在某些情况下是法规要求的
本文介绍的架构是一个利用区块链、去中心化身份 (DID) 以及其他去中心化和加密技术的身份框架。该框架侧重于个人身份的自我主权理念。自我主权可以定义为可以控制自己身份的细节。这包括用户能够根据信息的预期接收者共享特定身份属性和获得的凭证的能力。用户将向接收者提供一个配置文件，其中该配置文件仅包括接收者为特定操作所需的那些身份详细信息。</description></item><item><title>Self-Sovereign Identity：什么是自我主权身份？</title><link>https://icorer.com/icorer_blog/posts/web3/what-is-self-sovereign-identity/</link><pubDate>Mon, 12 Dec 2022 11:55:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/what-is-self-sovereign-identity/</guid><description>轻点放大 如今，我们日常生活的许多方面都依赖数字服务，从在线购物到所谓的 Web2.0 中的金融服务。我们使用多个（如果不是数百个）帐户与不同的集中式网络平台（例如社交媒体或电子邮件服务）进行交互。问题是，当我们无法访问我们的帐户时，我们就会失去我们的数字身份，因为网站无法再识别我们是谁。这意味着我们实际上并不拥有我们的身份和数据。这有问题。我们需要收回数据和数字身份的所有权，而自主身份可以实现这一点，为我们进入 Web3.0 铺平道路。
自我主权身份是指一种让个人控制其数字身份的方法。自我主权身份 (SSI) 是一项运动，它声称数字身份应该与一个人的人类身份一样合法，同时所有人都可以访问、保护隐私并且不依赖于单一的政府或公司。
那么究竟什么是自我主权身份呢？自我主权身份是指一种让个人控制其数字身份的方法。为了更好地理解这个概念，让我们看一下两个模型：
Web 2.0 - 集中式模型 我们的电子邮件帐户、网站帐户和社交媒体帐户目前允许数字服务在线识别我们。我们要么为每个平台创建一个帐户，要么使用 Facebook 或 Google 等服务提供商提供的单点登录。无论我们使用哪种方法，我们的数据都由帐户提供商集中存储。这种模式产生了一些严重的问题：
管理困难：我们努力管理众多帐户以访问不同的数字平台。此外，这些平台可以单方面决定关闭我们的帐户，或代表我们管理它。
安全和依赖风险：由于我们的大多数帐户都与我们的电子邮件地址相关联，如果我们的电子邮件访问受到威胁，黑客可以通过“忘记我的密码”方法更改密码来轻松接管使用该电子邮件的其他帐户。例如，黑客可以伪装成数字化的你，并在 Facebook 上欺骗你的家人和朋友。
隐私的脆弱性：如果我们使用的服务被黑客入侵，我们的数据很可能会被泄露，因为它是集中存储的。根据身份盗窃研究中心的数据，到 2021 年 10 月，将近 2.815 亿人受到某种数据泄露的影响。
缺乏数据自主权：我们无法控制我们的数据如何被使用或与其他平台共享。更糟糕的是，这些数据是代表我们的身份。
轻点放大 Web 3.0 - 去中心化模型 为了克服中心化身份模型的上述所有问题，我们需要引入去中心化身份模型，从而实现自我主权身份。个人与对应方（例如个人、组织或物联网）之间的关系是点对点的。它不再依赖中心化的实体，而是利用去中心化的网络，即区块链技术。这种方法的一些好处：
弹性网络：区块链网络永远不会宕机，而集中式网络由公司运营。 可验证凭证：数据和信息由身份所有者选择的受信任方（例如政府和银行）作为凭证发布。如果授予访问权限，其他节点可以验证链上的凭证。 建立信任：不变性是区块链的本质，它确保了可验证凭证的真实性。例如，同行可以通过链上证明来验证文凭是否由大学颁发。 控制数据：自主身份的所有者可以决定何时共享凭据，以及共享哪些凭据。 自我主权身份是一种以用户为中心的数字身份，我们作为用户可以完全控制我们的在线身份，但它不仅适用于个人，也适用于组织甚至设备 (IoT) 或程序。我们相信在不久的将来，我们都将使用自主身份在数字世界中进行点对点交互，而不是依赖于其他方基于账户的数字身份。
身份类型 轻点放大 真实身份# 人类身份是一个复杂的话题，几个世纪以来哲学家们一直在争论这个问题，而我所说的任何话都无法解决这些争论。我将人的身份简化为两部分，这两部分对于一个人成为社会上有生产力的成员来说都是必不可少的。
内在同一性：这就是我们照镜子时所看到的。这是我们的性别认同、政治认同或文化认同。在我们与最亲密的知己的关系中，这就是我们的身份。它是我们固有的，是身份的最真实形式。
外在身份：这是其他人（通常是机构）识别我们的方式。驾照是最普遍的例子。虽然旨在证明您有资格在公共道路上行驶，但它也是金融机构、机场和酒吧识别您的方式。它之所以有效，是因为机构信任，并且有了驾照，您始终可以得到担保。而且它不仅限于政府、教育、专业和会员凭证都以同样的方式工作。
数字身份# 一些最大的社交媒体、博客和其他互联网平台的存在基本上是为了帮助人们表达他们内在的身份。但是（值得注意的是）仍然没有很好的方法来数字化管理我们的外在身份。我们仍然使用纸质文件和塑料卡来访问我们生活中一些最重要的服务，使我们身份的一些最敏感和最重要的方面受到欺诈。令人恐惧的是，在日益数字化的世界中，我们有时必须扫描、通过电子邮件发送或发送这些文件的照片才能完成一些基本的事情，例如获得购房资格或开设银行账户。
自我主权身份# 自我主权身份是真实身份与数字世界的结合，最终将使人们的生活更美好。它仍处于起步阶段，要真正使数字身份像现实世界一样合法，还有很长的路要走身份。但最近有几项非常有前途的技术进步代表了巨大的突破，其中最重要的是数字钱包的出现和可验证凭证的标准化，这些共同创造了一条首次将我们的外在身份在线化的途径。
技术组成 轻点放大 SSI 架构由 W3C 定义的七项关键技术组成。这七项技术是：
去中心化标识符：Decentralized Identifiers 可验证凭证：Verifiable Credentials 去中心化公钥基础设施：Decentralized Public Key Infrastructure 区块链和分布式账本技术：Blockchain and Distributed Ledger Technology 可验证数据注册表：Verifiable Data Registry 代理程序：Agents 数字钱包：Digital Wallets 接下来详细描述每一个组成部分：</description></item><item><title>采用零信任模型的13个必备功能</title><link>https://icorer.com/icorer_blog/posts/zerotrust/13-must-have-features-to-adopting-a-zero-trust-model/</link><pubDate>Sun, 11 Dec 2022 11:55:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/zerotrust/13-must-have-features-to-adopting-a-zero-trust-model/</guid><description>轻点放大 处理服务网格安全性的最佳方法是采用零信任模型，这意味着每个连接，无论其来源如何，都必须经过验证和保护。为了帮助您评估服务网格技术并实施零信任安全，我们展示了13个必备功能，以确保您的应用程序连接安全。
1. 传输层安全性（TLS 和 mTLS）# 提供端到端加密以保护任何一对端点之间的移动数据。它可能是最基本的组件，但令人惊讶的是并非所有服务网格都完全支持双向 TLS。 2.授权# 例如，Open Policy Agent (OPA) 将服务 API 策略定义为代码。授权是身份验证的另一面，一旦您验证了他们的身份，便可以控制谁可以访问哪些资源。
3.证书管理# 从集中式平台控制和执行 SSL 证书以验证连接。证书轮换可能是一个痛苦的管理步骤，应该从容应对。这应该是可扩展的以支持外部权限，这意味着它将与您已经使用的企业身份和访问管理解决方案一起工作。
4.基于角色的联合出入控制(RBAC)和委托# 向用户授予与其职责相适应的权限，并再次在所有地方始终如一地应用此权限。这些控制可以应用于不同级别的操作员管理服务网格，也适用于构建在网格中运行的应用程序的开发人员。
5.联合信任域# 跨环境安全地验证用户和应用程序，在任何地方一致地扩展验证策略。否则，您将花费大量精力尝试保持各种角色的更新和同步——并且可能会犯一些错误。
6.联邦信息处理标准 (FIP) 140-2# 意味着您的服务网格技术已经过验证，可以满足美国政府制定的特定严格安全标准。有许多政府法规和行业最佳实践，但 FIPS 是一种常用的安全基准方法。
7.多租户和隔离# 让服务网格中的用户和应用程序安全地共享资源。拥有 RBAC 后，您可以安全地定义谁可以触摸什么，并有效地为不同角色创建隔离的工作区。 服务网格的授权策略也可用于防止不需要的流量到达您的应用程序。
8. 内置 Web 应用程序防火墙 (WAF)# 筛选入站流量中的威胁并阻止攻击渗透到您的边界。对于任何暴露在互联网上的边缘网关来说，它对于传入的用户和应用程序连接请求都是必不可少的,WAF除了边界网关模型，还需要内置进入各类端点程序，让WAF可以增强东西流量应用层的安全性。
9.数据丢失防护 (DLP)# 监控数据泄露或泄露，以防止数据丢失和数据泄漏。如果您的应用程序以某种方式受到损害，您不希望数据逃离您的边界。
10.与机密管理集成# 对于管理密码、安全令牌和加密密钥等敏感凭证的 Kubernetes。您会惊奇地发现这些信息仍然被硬编码到应用程序中或以纯文本形式存储的频率。
11.多集群访问可观察性# 提供整个系统所有活动的完整日志聚合和可审计性。这对于事件发生后的实时监控和取证都非常有用。对于分布式应用程序，有必要获得一个整体视图。许多人使用 Prometheus 和 Grafana 等开源工具来实现可观察性。 12.漏洞扫描和发布# 查找、解决和警告系统中的任何弱点。安全性取决于其最薄弱的环节，因此检查您的防御措施是否存在漏洞非常重要。 13.集群中继的安全拉取模型# 在整个系统中安全地共享配置。这非常微妙，但您希望确保任何配置更改都在请求时分发到边缘，并且仅在请求时分发。
附录# What is mtls The zero trust authorization core What is Certificate Management RBAC vs.</description></item><item><title>Drand去中心化可验证随机数</title><link>https://icorer.com/icorer_blog/posts/web3/verifiable-random-number-drand-program-experiment/</link><pubDate>Thu, 08 Dec 2022 11:55:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/web3/verifiable-random-number-drand-program-experiment/</guid><description>轻点放大 Drand最初来自DEDIS 实验室，由于使用基于配对的密码学，drand 能够以非常简单和有效的方式生成随机性，并以可靠的方式将其交付给客户端。Drand 旨在成为一种分布式服务，以与应用程序无关、安全且高效的方式提供公共随机性。随着 drand 的成熟，越来越多的组织（包括 NIST、Cloudflare、Kudelski Security、智利大学和协议实验室）开始感兴趣，并决定共同努力建立一个跨越这些组织的 drand 网络。
Drand 旨在成为一种互联网基础设施级服务，为应用程序提供随机性，类似于 NTP 提供计时信息和证书透明服务器提供证书吊销信息的方式，Drand去中心化随机数方案可以提供 去中心化随机性与可验证性两大核心功能。
为什么去中心化随机性很重要 多年来，一代公共随机性(通常称为common coins)吸引了密码学研究社区的持续兴趣。许多分布式系统，包括各种共识机制、Tor等匿名网络或区块链系统，都假定可以访问这种公共随机性。例如，在最近的权益证明区块链中，矿工在每个时期都是通过一个共同的随机源随机选出的。然而，拥有一个不可偏置的、分布式的、可扩展的公共随机资源仍然是一个主要的缺失部分。目前存在一些集中式解决方案，尽管它们确实提供了一个统一的随机性来源，但这些信标既不可验证也不分散。可验证性是必要的。对于权益证明系统中的示例，可验证性是必要的，在该系统中，区块生产者需要证明他已被选为给定时期的矿工。
实验代码 package main import ( &amp;#34;context&amp;#34; &amp;#34;encoding/hex&amp;#34; &amp;#34;log&amp;#34; &amp;#34;time&amp;#34; &amp;#34;github.com/drand/drand/client&amp;#34; &amp;#34;github.com/drand/drand/client/http&amp;#34; ) var urls = []string{ &amp;#34;https://api.drand.sh&amp;#34;, &amp;#34;https://drand.cloudflare.com&amp;#34;, } var chainHash, _ = hex.DecodeString(&amp;#34;8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce&amp;#34;) func main() { c, err := client.New( client.From(http.ForURLs(urls, chainHash)...), client.WithChainHash(chainHash), ) if err != nil { log.Panicln(err) } t1, _ := time.ParseDuration(&amp;#34;-0h2m0s&amp;#34;) t2 := time.Now().Add(t1) round := c.</description></item><item><title>2022 万向区块链春季黑客松：IceFireDB 拿到了一等奖</title><link>https://icorer.com/icorer_blog/posts/icefiredb2022wanxiang/</link><pubDate>Tue, 14 Jun 2022 12:55:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/icefiredb2022wanxiang/</guid><description> 轻点放大 2022 万向区块链春季黑客松于 6 月 12 日收官。很幸运，也很感谢 Protocol Labs 把这份荣誉给了我们。除了高兴，更多是被认可之后的触动——接下来我们会更用力地把项目孵化下去。
这一届黑客松的主题是「元宇宙：区块链上的共享未来」，二十多支队伍参加，两天半、40 小时。
活动由万向区块链实验室主办，南京江北新区中央商务区建设管理办公室指导，Nervos、Protocol Labs、Qtum 赞助（按字母序），并得到北京大学区块链学生中心、北航区块链协会、北京邮电大学区块链协会、Dorahacks、耶鲁创投俱乐部等社群的支持。
线上与线下混合赛制。评委包括万向区块链通用架构技术部负责人杜满想、IEEE P3217 区块链系统应用接口规范工作组研究员林伟伟、Protocol Labs 开发者关系王龙飞、HashKey Capital 投资总监肖骁、Qtum 核心开发者郑义、Nervos 生态早期贡献者志贤等。
再次感谢主办方和 Protocol Labs 对 IceFireDB 的信任。
下面是获奖名单：
一等奖
IceFireDB：一个同时面向 web3 与 web2 的数据库。项目的核心目标，是帮应用更快地做到去中心化与数据不可篡改。
轻点放大</description></item><item><title>Gorilla：一个快速、可伸缩的内存时间序列数据库</title><link>https://icorer.com/icorer_blog/posts/gorilladb/</link><pubDate>Fri, 01 Apr 2022 17:26:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/gorilladb/</guid><description>摘要 大规模互联网服务旨在出现意外故障时保持高可用性和高响应性。提供这种服务通常需要在大量系统上每秒钟监测和分析数千万次测量，一个特别有效的解决方案是在时间序列数据库(TSDB)中存储和查询这种测量。TSDB设计中的一个关键挑战是如何在效率、可伸缩性和可靠性之间取得平衡。在本文中，我们介绍Gorilla系统，脸书的内存TSDB。我们的见解是，监控系统的用户不太重视单个数据点，而是更重视综合分析，对于快速检测和诊断持续问题的根本原因而言，最新数据点比旧数据点更有价值。Gorilla优化了写入和读取的高可用性，即使在出现故障时也是如此，代价是可能会在写入路径上丢弃少量数据。为了提高查询效率，我们积极利用压缩技术，如增量时间戳和异或浮点值，将Gorilla的存储空间减少了10倍。这使我们能够将Gorilla的数据存储在内存中，与传统数据库(HBase)支持的时间序列数据相比，查询延迟减少了73倍，查询吞吐量提高了14倍。这种性能改进带来了新的监控和调试工具，比如时序关联搜索和更密集的可视化工具。Gorilla还可以优雅地处理从单个节点到整个区域的故障，几乎没有运营开销。
一、介绍 大规模互联网服务即使在出现意外故障的情况下也能保持高可用性和对用户的响应。随着这些服务发展到支持全球客户，它们已经从运行在数百台机器上的几个系统扩展到服务数以千计的个人用户系统运行在数千台机器上，通常跨越多个地理复制的数据中心。
轻点放大 运行这些大规模服务的一个重要要求是准确监控底层系统的健康和性能，并在出现问题时快速识别和诊断问题。脸书使用时间序列数据库(TSDB)存储系统测量数据点，并在顶部提供快速查询功能。接下来，我们将指定监控和操作脸书需要满足的一些约束，然后描述Gorilla，这是我们新的内存TSDB，可以存储数千万个数据点(例如，CPU 负载、错误率、延迟等)。)并在几毫秒内响应对此数据的查询。
写占主导地位。我们对 TSDB 的主要要求是它应该始终可用于写入。由于我们有数百个公开数据项的系统，写入速率可能很容易超过每秒数千万个数据点。相比之下，读取速率通常要低几个数量级，因为它主要来自于观察“重要”时间序列数据的自动化系统、可视化系统或为希望诊断观察到问题的人类操作员提供仪表板。
状态转换。我们希望识别新软件发布中出现的问题、配置更改的意外副作用、网络中断以及导致重大状态转换的其他问题。因此，我们希望我们的TSDB支持短时间窗口内的细粒度聚合。在几十秒钟内显示状态转换的能力特别有价值，因为它允许自动化在问题变得广泛传播之前快速修复问题。
高可用性。即使网络分区或其他故障导致不同数据中心之间的连接断开，在任何给定数据中心内运行的系统都应该能够将数据写入本地TSDB机器，并且能够按需检索这些数据。
容错。我们希望将所有写入复制到多个区域，这样我们就可以在任何给定的数据中心或地理区域因灾难而丢失时幸存下来。
Gorilla是脸书的新TSDB，满足了这些限制。Gorilla用作进入监控系统的最新数据的直写缓存。我们的目标是确保大多数查询在几十毫秒内运行。Gorilla 的设计理念是，监控系统的用户不太重视单个数据点，而是更重视综合分析。此外，这些系统不存储任何用户数据，因此传统的 ACID保证不是TSDB的核心要求。 但是，高比例的写入必须始终成功，即使面临可能导致整个数据中心无法访问的灾难。此外，最近的数据点比旧的数据点具有更高的价值，因为直觉上，对于运营工程师来说，知道特定系统或服务现在是否被破坏比知道它是否在一个小时前被破坏更有价值，Gorilla 进行了优化，即使在出现故障的情况下也能保持高度的读写可用性，代价是可能会丢失少量数据写入路径。
高数据插入率、总数据量、实时聚合和可靠性要求带来了挑战。我们依次解决了这些问题。为了解决第一个要求，我们分析了 TSDB 操作数据存储(ODS),这是一个在脸书广泛使用的老的监控系统。我们注意到，对ODS的所有查询中，至少有85%是针对过去26小时内收集的数据。进一步的分析使我们能够确定，如果我们能够用内存中的数据库替换基于磁盘的数据库，我们可能能够为我们的用户提供最好的服务。此外，通过将这个内存中的数据库视为持久的基于磁盘的存储的缓存，我们可以实现具有基于磁盘的数据库的持久性的内存中系统的插入速度。
截至2015年春天，脸书的监控系统生成了超过20亿个独特的时间序列计数器，每秒钟增加约1200万个数据点。这代表每天超过1万亿个点。在每点16字节的情况下，产生的16TBRAM对于实际部署来说太耗费资源了。我们通过重新利用现有的基于XOR的浮点压缩方案来解决这一问题，使其以流的方式工作，从而允许我们将时间序列压缩到平均每点1.37字节，大小减少了12倍。
我们通过在不同的数据中心区域运行多个Gorilla实例并向每个实例传输数据流来满足可靠性要求，而不试图保证一致性。读取查询指向最近的可用Gorilla实例。请注意，这种设计利用了我们的观察，即在不影响数据聚合的情况下，单个数据点可能会丢失，除非Gorilla实例之间存在显著差异。Gorilla目前正在脸书的生产中运行，工程师们每天将其用于实时灭火和调试，并与Hive[27]和Scuba[3]等其他监控和分析系统结合使用，以检测和诊断问题。
二、背景和要求 2.1 操作数据存储# 脸书的大型基础设施由分布在多个数据中心的数百个系统组成，如果没有能够跟踪其运行状况和性能的监控系统，运营和管理这些基础设施将会非常困难。业务数据储存库是脸书监测系统的一个重要部分。ODS由一个时间序列数据库(TSDB)、一个查询服务以及一个探测和警报系统组成。ODS的TSDB 构建在 HBase存储系统之上，如[26]中所述。图1显示了ODS组织方式的高级视图。来自运行在脸书主机上的服务的时间序列数据由ODS写入服务收集并写入 HBase。
ODS时间序列数据有两个消费者。第一个消费者是依赖制图系统的工程师，该系统从ODS生成图形和其他时间序列数据的直观表示，用于交互式分析。第二个消费者是我们的自动警报系统，该系统从 ODS读取计数器，将它们与健康、性能和诊断指标的预设阈值进行比较，并向oncall工程师和自动补救系统发出警报。
2.1.1 监控系统读取性能问题# 2013 年初，脸书的监控团队意识到其HBase时序存储系统无法扩展处理未来的读取负载。虽然交互式图表的平均读取延迟是可以接受的，但是P90的查询时间增加到了几秒钟，阻碍了我们的自动化。此外，用户正在自我审查他们的用户年龄，因为即使是几千个时间序列的中等规模查询的交互式分析也需要几十秒钟才能执行。在稀疏数据集上执行的较大查询会超时，因为HBase数据存储被调整为优先写入。虽然我们基于HBase的TSDB效率低下，但我们很快就对存储系统进行了大规模更换，因为 ODS的HBase存储拥有大约2PB 的数据[5]。脸书的数据仓库解决方案Hive也不合适，因为它的查询延迟比ODS 高几个数量级，而查询延迟和效率是我们主要关心的问题[27]。
接下来，我们将注意力转向内存缓存。ODS已经使用了一个简单的通读缓存，但它主要是针对多个仪表板共享相同时间序列的图表系统。一个特别困难的场景是当仪表板查询最近的数据点，在缓存中错过，然后发出请求直接发送到 HBase 数据存储。我们还考虑了基于独立Memcache[20]的直写缓存，但拒绝了它，因为向现有时间序列添加新数据需要一个读/写周期，从而导致Memcache服务器的流量非常高。我们需要更有效的解决方案。
2.2 Gorilla要求# 考虑到这些因素，我们确定了新服务的以下要求:
由一个字符串键标识的20亿个唯一的时间序列。 每分钟增加7亿个数据点(时间戳和值)。 存储数据26小时。 峰值时每秒超过40,000次查询。 读取在不到一毫秒的时间内成功。 支持15秒粒度的时间序列(每个时间序列每分钟 4 个点)。 两个内存中、不在同一位置的副本(用于灾难恢复容量)。 即使单个服务器崩溃，也始终提供读取服务。 能够快速扫描所有内存中的数据。 支持每年至少2倍的增长。 在第3节与其他 TSDB 系统进行简单比较后，我们在第4节详细介绍Gorilla的实现，首先在第4.1 节讨论其新的时间戳和数据值压缩方案。然后，我们将在第 4.4 节中描述Gorilla如何在单节点故障和区域性灾难的情况下保持高可用性。我们将在第5节描述Gorilla如何启用新工具。最后，我们在第6节描述了我们开发和部署Gorilla的经验。
三、与 TSDB 系统的比较 有许多出版物详细介绍了数据挖掘技术，以有效地搜索、分类和聚类大量的时间序列数据[8,23,24]。这些系统展示了检查时间序列数据的许多用途，从聚类和分类[8,23]到异常检测[10,16] 到索引时间序列[9,12,24]。然而，很少有例子详细说明能够实时收集和存储大量时间序列数据的系统。Gorilla的设计侧重于对生产系统进行可靠的实时监控，与其他TSDB相比非常突出。Gorilla占据了一个有趣的设计空间，在面对优先于任何旧数据可用性的故障时，可用于读取和写入。
由于 Gorilla 从一开始就被设计为将所有数据存储在内存中，因此它的内存结构也不同于现有TSDB。但是，如果将Gorilla视为另一个磁盘上TSDB之前的时间序列数据内存存储的中间存储，那么Gorilla 可以用作任何 TSDB 的直写缓存(相对简单的修改)。Gorilla对摄取速度和水平扩展的关注与现有解决方案相似。</description></item><item><title>保护您的服务网格：十三项清单</title><link>https://icorer.com/icorer_blog/posts/13-item_checklist_for_securing_your_service_mesh/</link><pubDate>Thu, 17 Feb 2022 14:57:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/13-item_checklist_for_securing_your_service_mesh/</guid><description>世界各地的组织都在急于对其应用程序进行现代化改造，以便在云中 Kubernetes 编排的容器中运行。在此现代化过程中，这些公司必须计划保护其应用程序连接。当应用程序被重新平台化并重新构建为分布式微服务时，会出现新的连接模式，这些模式通常会促使构建一个或多个服务网格。
强大的服务网格可以处理南北连接（从边缘进入基于 Kubernetes 的应用程序）和东西连接（同一集群上的服务之间或不同集群之间）。但是，这些流量模式中的每一个都需要全面的安全性.
实现服务网格安全性的最佳方法是采用零信任模型，这意味着每个连接，无论其来源如何，都必须经过验证和保护。为了帮助您评估服务网格技术并实施零信任安全，我们提供了 13 个必备功能，以确保您的应用程序连接安全。这是清单：
传输层安全性（TLS 和 mTLS）提供端到端加密，以保护任何端点对之间的动态数据。它可能是最基本的组件，但令人惊讶的是，并非所有服务网格都完全支持双向 TLS。 内置 Web 应用程序防火墙 (WAF)可屏蔽入站流量以发现威胁并阻止攻击侵入您的周边。对于任何向 Internet 公开以接收传入用户和应用程序连接请求的边缘网关来说，这都是必不可少的。 数据丢失防护 (DLP)监控数据泄露或泄露，以防止数据丢失和数据泄露。如果您的应用程序以某种方式受到损害，您不希望数据泄露您的边界。 Kubernetes的机密管理集成，后者管理密码、安全令牌和加密密钥等敏感凭证。您会担心这些信息仍然被硬编码到应用程序中或以纯文本形式存储的频率。 证书管理从集中式平台控制和执行 SSL 证书以验证连接。证书轮换可能是一个痛苦的管理步骤，应该优雅地加以考虑。这应该可以扩展以支持外部权限，这意味着它将与您已经使用的企业身份和访问管理解决方案一起使用。 授权，例如使用开放策略代理 (OPA)，它将服务 API 策略定义为代码。授权是身份验证的另一面，一旦您验证了他们的身份，谁就可以访问哪些资源。 联合信任域可以安全地跨环境对用户和应用程序进行身份验证，从而在任何地方始终如一地扩展身份验证策略。如果没有这个，您将花费大量精力来尝试保持各种角色的更新和同步——并且可能会犯一些错误。 联合的基于角色的访问控制 (RBAC) 和委派向用户授予与其职责相符的权限，并且再次在任何地方始终如一地应用此权限。这些控制可以应用于管理服务网格的运营商的不同级别，也可以应用于构建在网格中运行的应用程序的开发人员。 多租户和隔离使服务网格中的用户和应用程序可以安全地共享资源。拥有 RBAC 后，您可以安全地定义谁可以接触什么，并为不同的角色有效地创建隔离的工作空间。Istio 的授权策略也可用于防止不需要的流量到达您的应用程序。 漏洞扫描和出版物发现、解决和警告系统中的任何弱点。安全性与其最薄弱的环节一样好，因此检查防御中的任何漏洞很重要。 多集群访问可观察性为整个系统的所有活动提供完整的日志聚合和可审计性。这对于事件后的实时监控和取证都很有用。对于分布式应用程序，有必要获得全局视图。许多人使用 Prometheus 和 Grafana 等开源工具来实现可观察性。 联邦信息处理标准 (FIP) 140-2意味着您的服务网格技术已经过验证，符合美国政府规定的特定严格安全标准。有许多政府法规和行业最佳实践，但 FIPS 是确定安全基准的一种常用方法。 集群中继的安全拉取模型在整个系统中安全地共享配置。这是非常微妙的，但是您要确保任何配置更改都在请求时分发到边缘，并且仅在请求时分发。 虽然严格来说不是服务网格的安全特性，但一个额外的考虑因素是企业支持的可用性和用于响应的定义服务级别协议 (SLA)。</description></item><item><title>使用区块链将零信任架构扩展到端点：最先进的审查</title><link>https://icorer.com/icorer_blog/posts/blockchain_with_zerotrust/</link><pubDate>Tue, 15 Feb 2022 23:50:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/blockchain_with_zerotrust/</guid><description>摘要 为了防御当今无边界网络中的横向移动，零信任架构(ZTA)的采用势头越来越猛。有了全面的 ZTA 实施，对手不太可能从受损的端点开始通过网络传播。然而，已经经过身份验证和授权的受损端点会话可以被用来执行有限的(尽管是恶意的)活动，最终使端点成为 ZTA 的致命弱点。为了有效地检测此类攻击，已经开发了具有基于攻击场景的方法的分布式协同入侵检测系统。尽管如此，高级持续威胁(APTs)已经证明了它们绕过这种方法的能力，并且成功率很高。因此，对手可以不被发现地通过或潜在地改变检测记录机制，以实现隐蔽的存在。最近，区块链技术在网络安全领域展示了可靠的使用案例。在本文中，受基于 ZTA 和区块链的入侵检测和防御的融合的推动，我们研究了如何将 ZTA 扩展到端点。也就是说，我们对 ZTA 模型、以端点为重点的真实体系结构以及基于区块链的入侵检测系统进行了最先进的审查。我们讨论了区块链的不变性增强检测过程的潜力，并确定了开放的挑战以及潜在的解决方案和未来的方向。
一、介绍 随着云计算的革命，大多数企业的资源和数据不再存储在内部。此外，最近的新冠肺炎疫情事件极大地改变了工作模式，因为大多数员工和企业不得不转向在家工作。在家工作(和远程工作)会给组织带来新的严重安全风险，因为许多“未经培训”的员工使用自己的设备连接到工作信息技术(IT)系统。云计算和远程工作是企业必须扩大其数字安全范围并适应当代趋势的例子。
在传统的基于外围的安全模型中，组织在外围的资源和资产被认为是良性的和可信的。边界通常由安全措施保护，如防火墙或入侵检测系统。这种模式在云计算和远程工作领域似乎不太有效，针对远程工作员工的几次网络攻击(例如[1-5])就表明了这一点。
信任是传统的基于边界的安全模型所依赖的基本原则。员工或合作者的设备和组织资产(即端点)通常在默认情况下是可信的，而不管其状况如何。如果攻击者能够控制这些端点中的任何一个，那么边界就会受到威胁，并且通过横向移动有可能实现对信息和数据的进一步访问。
防火墙、防病毒技术、入侵检测和防御系统(IDS/IPS)和网络应用防火墙(WAFs)，换句话说，大石墙和装甲前门，已经不足以保证现代 IT 和运营技术(OT)环境的安全[6]。基于外围的安全是多家公司采用的主要概念，尤其是当他们的数据驻留在内部数据中心时。建立在内部和外部差异基础上的传统防御模式正在过时[7]，而与此同时，威胁格局也在急剧演变[8]，最终导致基于外围的安全架构的衰落。
为了应对当今复杂的网络基础设施和当前不断发展的威胁形势，需要一种新的安全架构。ZTA 通过建立无边界的基于数字身份的边界脱颖而出，在这个边界中，数据处于安全架构的中心，破坏思维主导着威胁模型， 引领着访问控制环境、运营、托管环境、端点和互连基础架构。ZTA 提倡一种新的安全架构，默认情况下，任何设备、系统、用户或应用程序都不应该基于其在网络中的位置而受到固有的信任。相反，不管在什么地方，信任总是要赢得和验证的。然而，这并不一定意味着在ZTA 的情况下信任被消除，而是应该最小化，直到通过ZTA 信条和核心组成部分证明不是这样。
使用传统的基于边界的防御，如果坚定的攻击者能够在端点上建立经过身份验证和授权的立足点，他们仍然可以绕过 ZTA 安全健康检查。例如，操作系统内核中的潜在恶意软件可以篡改在 ZTA 环境中进行的安全检查。这最终导致绕过在 ZTA 实施的基本控制，这将允许攻击者除了横向移动之外，还执行一些以用户和设备为中心的恶意活动。因此，需要一种有效的入侵检测方法来解决端点的漏洞，这可以被视为 ZTAs 的致命弱点。
在本文中，我们旨在研究如何利用区块链的不变性增强入侵检测过程的潜力，将 ZTA 扩展到端点，以消除上述问题。为此，我们首先回顾零信任的核心原则、能力和要求。其次，我们对现有的现实世界零信任实现进行分类，并讨论它们的优缺点。第三，我们探索了区块链在开发和改进分布式协作入侵检测系统(DCIDSs)方面的潜力，该系统可以缓解ZTA 的致命弱点(即端点的脆弱性)。最后，我们讨论了开放的问题和挑战，并强调了ZTA和基于区块链的分布式入侵检测系统的潜在解决方案和研究方向。
据我们所知，这是第一个利用区块链技术成功将ZTA扩展到端点的工作。表1给出了本文中使用的主要缩写及其定义。
轻点放大 轻点放大 二、零信任（ZT） 在本节中，我们简要介绍了“零信任”和 ZTA 的历史，并讨论了零信任的核心原则、核心能力、模型和现有方法，包括现实世界的实现。
2.1 零信任架构的历史# 2004 年的杰里科论坛提出了去周边化的想法(当时是激进的)[3]，随后发展成为更广泛的零信任概念。早在2010 年，J. Kindervag [15]就创造了“零信任”一词；然而，在此之前，网络安全领域就存在零信任概念。美国国防部和国防信息系统局(DISA)提出了一项名为“黑核”的安全战略，并于 2007 年发表[16]。Black core讨论了从基于外围的安全架构向强调保护单个交易的安全架构的过渡。
云和移动计算的广泛采用极大地促进了 ZTAs 的发展，例如，作为其中的一部分，基于身份的架构等方法慢慢获得了关注和更广泛的接受。谷歌以“BeyondCorp”的名义发布了一系列关于如何实现零信任架构的六个文档[17-22]。BeyondCorp项目倡导去边界化的概念，认为基于边界的安全控制已经不够，安全应该扩展到用户和设备。由于这个项目，谷歌放弃了传统的基于虚拟专用网络(VPNs)的远程工作方式，并设法提供了一个合理的保证，即所有公司用户都可以通过不安全和不受管理的网络访问谷歌的网络。
2.2 从传统的周边架构到ZTA# 作为一种理念，“零信任”假设对用户、设备、工作负载和网络流量的信任不应被隐含地授予[15]，其结果是所有实体都必须被明确地验证、认证、授权和持续监控。零信任的核心目标之一是，一旦对手成功危及用户的设备，甚至简单地窃取他们的凭据，就会严重抑制对手横向移动的能力。因此，需要相应地塑造和准备信息技术基础设施。
传统的基于外围的安全架构会创建多个信任区域[2]。并非所有区域都遵守相同的规则或相同的信任级别。事实上，如果相关组件没有明确允许，用户甚至可能无法进入下一个区域。这被称为纵深防御，正如史密斯[23]所讨论的，并在图1中描述，或者称为城堡和护城河方法[24]。请注意，在到达大型机之前，不同的区域(互联网、非军事区、可信和特权)受到各种基于外围的控制的保护，例如本地代理、虚拟专用网网关、多个防火墙和应用程序服务。在这个例子(即图1)中，大型机是一个核心银行系统，负责所有交易，因此它被完全隔离在一个特权区域中。
轻点放大 与传统的安全架构不同，零信任要求从内到外进行思考、构建和保护。基于谷歌[19] [20]、Jericho[3]和Kindervag[15] [25]的上述工作，有一个直接和重要的观察， 即在ZTA，一旦网络位置依赖性变得无关紧要，虚拟专用网技术就可以被消除。简而言之，虚拟专用网允许远程工作的用户(在图1中用“远程员工”表示)通过安全的加密通道连接到办公室(在图1中用“可信”表示)。但是，应该通过其他方式保护端点，因为虚拟专用网加密只处理“远程员工”和“可信”区域之间的隧道。当“远程员工”通过身份验证并成功建立隧道时，他/她会收到“可信”区域的远程网络中的一个 IP 地址。在该隧道上， 从“远程员工”到“可信”区域的流量被解封并路由，因此导致“官方”后门。此外，被称为“虚拟专用网网关”的单一入口点充当体系结构和网络的单一故障点或扼杀点。因此，如果我们开始认为网络位置无关紧要，同时应用一组适当的控制，那么如果没有进一步的依赖关系 (例如，具有传统协议的应用程序)，就可以消除虚拟专用网络。也就是说，身份验证和授权以及策略实施应该立即向网络边缘和端点靠拢。</description></item><item><title>自主网络安全-保障未来颠覆性技术</title><link>https://icorer.com/icorer_blog/posts/autonomous_network_security_securing_future_disruptive_technologies/</link><pubDate>Fri, 28 Jan 2022 21:07:07 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/autonomous_network_security_securing_future_disruptive_technologies/</guid><description>From：2021 年 IEEE ⽹络安全与弹性国际会议 (CSR)
概述 这篇论文讲述自主网络安全知识的系统化。诸如物联网、人工智能和自治系统等颠覆性技术正变得越来越普通，而且通常很少或者根本没有网络安全保护，这种缺乏安全性导致的网络攻击面不断扩大。自主计算计划旨在通过使复杂计算系统自我管理来解决管理复杂计算系统的复杂性。自主系统包含应对网络攻击的属性，例如新技术的自我保护和自我修复。有许多关于自主网络安全的研究项目，采用不同的方法和目标技术，其中许多具有破坏性。本文回顾了自主计算，分析了自主网络安全的研究，并提供研究知识的系统化，本文最后确定自主网络安全方面的差距，以供未来研究。
一、介绍 随着恶意⾏为者变得善于发现和利⽤⽹络和计算机系统中的缺陷[1]，对计算机系统的攻击数量随着复杂程度和严重程度的增加⽽增加。新的颠覆性技术不断被引⼊并连接到企业⽹络和互联⽹，这些技术限制了有些甚⾄没有内置的⽹络安全。其中包括⽹络物理系统/物联⽹ (CPS/IoT)、⼈⼯智能(AI) 和⾃治系统等技术。计算系统通常会在事后添加⽹络安全，⽽不是从⼀开始就设计，尤其是新的颠覆性技术，尤其是匆忙推向市场的技术。
系统需要能够以⾃我管理的⽅式对攻击和固有的弱点做出反应，⽆论是单独还是与其他系统⼀起。将安全性本地嵌⼊到软件和硬件系统中将使它们能够对攻击做出反应，并单独保护和治愈⾃⼰，并且作为⼀个群体。从本质上讲，这是⽹络安全的⾃主⽅法。
伯纳尔等⼈[2]在2019 年确定了⽹络安全⽅⾯的⼀些研究挑战，并将“软件化和虚拟化CPS/IoT系统和移动⽹络中的⾃主安全编排和执⾏”列为第⼆名，仅次于“可互操作和可扩展的安全管理异构⽣态系统”。 他们指出，需要新的⾃主和上下⽂感知安全协调器，它们可以快速、动态地编排和实施适当的防御机制。
本⽂的⽬的是调查⾃主⽹络安全研究中的空⽩，并将这些知识系统化以探索未来的研究。该论⽂基于对⾃主⽹络安全⽂献的调查和⽅法分类。这提供了对未来研究可以帮助推动⾃主⽹络安全向前发展以保护未来颠覆性技术的洞察⼒。本⽂的其余部分结构如下：第⼆部分提供了⾃主计算(AC) 的背景以及如何将⽹络安全设想为⾃主系统的⼀部分。第三部分描述了⾃主⽹络安全的过去和当前研究。⼀些研究侧重于特定应⽤领域的⾃主⽹络安全，⽽其他研究则提供可⽤于⼀系列应⽤的⾃主⽹络安全框架。第四节提供了研究分类和分类知识库的系统化，第五节讨论了基于知识系统化的⽹络安全研究的差距，第六节提供了结论性意⻅。
二、背景 Kephart 和 Chess 在 2003 年的⾃主愿景论⽂[3]中将⾃主计算定义为“根据管理员的⾼级⽬标，可以⾃我管理的计算系统”。使⽤“⾃主计算”⼀词是因为⾃主神经系统管理⾝体功能，调整这些功能以满⾜⾝体需求，并为更⾼层次的认知活动释放有意识的活动。⽹络安全也是如此，它应该在维护服务的同时，根据当前的⽹络情况⾃动 调整和调整系统资源。Kephart 和 Chess 概述了⾃主系统应 具备的四个要素：
⾃我配置 ⾃我修复 ⾃我优化 ⾃我保护，也称为Self CHOP 提出了⼀个参考架构来实现能够适应不断变化的环境的Self CHOP 属性（图 1）。
轻点放大 Monitor、Analyze、Plan、Execute 和 Knowledge 组件统称为 MAPEK 架构。⾃主计算系统并未被设想为单⼀的独⽴系统，⽽是交互的、⾃我管理的系统，它们共同⼯作以实现其⽬标（图2）。
轻点放大 Self CHOP属性在[3]中定义为：
⾃配置：系统通过动态调整其资源来⾃动配置和重新配置⾃⾝的能⼒ ⾃我修复：系统从常规和意外事件中⾃动检测、诊断和修复硬件和软件的能⼒ ⾃我优化：系统和⼦组件监控其部件以检测性能下降同时不断寻求⾃我改进的能⼒ ⾃我保护：系统针对故障和恶意对系统的攻击能力能够⾃动检测和防御 自主安全CHOP属性可以为系统提供⽹络安全⽀持，以保护⾃⾝并从⽹络攻击中恢复。Kephart 将⾃我保护属性描述为保护系统免受⾃我修复属性⽆法纠正的恶意攻击或级联故障。其他Self CHOP属性也⽀持⾃保护属性，⾃修复属性在系统受到攻击后通过更新和脱落受损组件来修复系统，⾃配置属性帮助系统在禁⽤受损⼦系统后重新配置⾃⾝，⾃优化属性可以帮助系统通过攻击运⾏，然后重新配置后重新优化。
⾃主⽹络安全建⽴在⾃主视觉和参考架构的基础上，以开发⾃我管理能⼒，利⽤Self CHOP特性检测⽹络攻击并从⽹络攻击中恢复 [4]。⾃主⽹络安全不仅使⽤⾃主计算的Self CHOP特性，⽽且还互连⾃主元素，以提供⾃主元素之间的信息通信和共享，以共同应对攻击并从攻击中恢复。
三、自主网络安全方法 以下是对一系列领域实施自主网络安全的方法的调查，这些领域包括智能汽车、网络物理系统/物联网、工业控制系统、关键基础设施、自组织计算、高性能计算、云计算、企业计算和其他。一些方法集中在架构上，另一些集中在被保护的领域或底层技术上。以下描述了调查的不同方法。它们按照是否使用 MAPEK 参考体系结构、非MAPEK体系结构、实现特定的自主特性、是提供自主开发支持的框架还是自主安全开发工具来分组。
3.1 MAPEK方法# 3.1.1 认知和自主网络安全# Maymir Ducharme等人[5]在2015年描述了使用上下文分析和自主元素的分层网络，该网络从分层结构中的不同抽象层次提供系统元素的不同视图。具有更高级视图的自治元素将具有企业任务级上下文。更高级别的自治元素将根据公司功能的关键程度对这些功能进行优先排序，以便在紧急情况或网络攻击时维持运营。与安全相关的元素，如防火墙，将在层次结构中较低的抽象级别表示。
3.1.2 零信任# Eidle等在2017年提出利用autonomic网络安全实现网络零信任[6]。作者开发了一个网络安全测试平台，实现了基于观察、定向、决定、行动(OODA)模型的零信任网络的各个方面，该模型与 MAPEK 参考架构相似，平台观察网络用于监控和分析攻击特征的身份验证日志。他们集成了来自多个网络设备的威胁响应，以简化威胁的检测和缓解危害。</description></item><item><title>系统调用级二进制兼容的Unikernel虚拟机</title><link>https://icorer.com/icorer_blog/posts/system_call_level_binary_compatible_unikernel_virtual_machine/</link><pubDate>Mon, 24 Jan 2022 19:00:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/system_call_level_binary_compatible_unikernel_virtual_machine/</guid><description>一、背景# Unikernel 是最小的单一用途虚拟机，目前在研究领域非常受欢迎，但是目前想把已有的应用程序移植到当前的unikernel环境是很困难的。HermiTux是第一个提供与Linux应用程序的系统调用级二进制兼容的unikernel，它由一个管理程序和一个模拟负载及运行时Linux ABI的轻量级内核层组成。HermiTux将应用程序开发人员从移植软件的负担中解脱出来，同时通过硬件辅助虚拟化隔离、快速启动时间和低磁盘/内存占⽤、安全性等提供单核优势。通过二进制分析重写技术及共享库替换，可以快速实现系统调用和内核模块化。
论文中展示了HermiTux的独立架构特色，在x86-64和ARM aarch64 ISA架构上展示了一个原型，针对各种云以及边缘/嵌入式部署，也展示了HermiTux对⼀系列原⽣C/C++/Fortran/Python Linux 应⽤程序的兼容性。HermiTux与其他unikernel相比，也提供了相似程度的轻量级，并且在许多情况下与Linux性能相似，它在内存和计算密集型场景下性能开销平均损失3%，其I/O性能是可以接受的。
二、HermiTux对于Linux程序兼容性的思路# Unikernels在学术领域变得很流行，它以虚拟化LibOS模型为基础，这种模型也带来了很多好处，主要包括：提高安全性、性能改进、隔离性提升、降低成本等。这样的优势也增加了很多应用场景：云和边缘部署的微服务/基于Saas和Faas的软件、服务器应用程序、NFV、IOT、HPC等。尽管unikernel被视为容器领域具有吸引力的替代品，但unikernels仍然在行业中很难获得显著的牵引力，并且它们的采用率相当缓慢，主要原因是将遗留/现有的应用程序移植到unikernel模型很困难，有时候甚至是不可能的。
在大型程序中，移植复杂的代码库很困难，这是由于诸如不兼容/缺少库/函数、复杂的构建过程、缺乏开发工具（调试器/分析器）、不受支持的语言等因素存在。移植到unikernel环境，也需要程序员具备这方面的专业知识，巨大的移植负担是阻碍广泛采用unikernels最大的障碍之一。
HermiTux提出了一个新型的unikernel模型，他为常规Linux应用程序提供二进制兼容性，同时保留了unikernel的优势，它允许开发工作集中在unikernel这层。HermiTux原型是HermitCore unikernel的扩展，它能够运行原生的Linux可执行文件作为unikernel。通过提供这种基础设施，HermiTux将应用程序员的移植工作转变为unikernel层开发人员的支持工作，在这个模型下不仅可以让原生Linux应用程序透明地获得unikernel的好处，而且还可以运行以前不可移植的应用程序。使用HermiTux将遗留应用程序作为unikernel移植和运行是不存在的，HermiTux支持静态和动态链接的可执行文件、兼容多种语言（C/C++/Fortran/Python等）、编译器（GCC和LLVM）、全面优化（-O3）和剥离/混淆的二进制文件。它支持多线程和对称多处理器（SMP）、检查点/重启和迁移。
大多数现有的unikernel不提供任何类型的二进制兼容性，一些系统通过在C库级别进行接口适配来提供二进制兼容性，其作用类似于动态链接库。这可以防止它们通过系统调用来支持何种需要操作系统服务的应用程序，而无需通过C库。为了保障最大化的兼容性，HermiTux没有采用通用做法，在系统调用级别实现了所有应用程序和编译库使用的标准化接口。
三、HermiTux的挑战# HermiTux应对的第一个挑战是如何提供系统调用级别的二进制兼容性？，因此HermiTux根据Linux应用程序二进制接口ABI设置执行环境并在运行时模拟OS接口。基于自定义管理程序的ELF加载程序用于在单个空间虚拟机中与最小内核一起运行Linux二进制文件。程序运行的系统调用被重定向到unikernel提供的实现。
HermiTux应对的第二个挑战是如何在**提供二进制兼容性的同时保持unikernel的好处？**有些是自然具备的好处（小磁盘/内存占用、虚拟化强制隔离），而另一些（快速的系统调用、内核模块化）在假设无法访问源代码时会带来技术挑战。为了实现这些好处，HermiTux对于静态可执行文件使用了二进制重写与分析技术，并在运行时用一个可识别的unikernel的C库替代动态链接库的可执行文件。最后HermiTux针对低磁盘/内存占用和攻击面进行了优化，与现有的unikernel一样低或更低。
由于unikernel应用案例广泛，HermiTux当前目的是兼容服务器和嵌入式虚拟化场景，因此主要支持Intel x86-64和 ARM aarch64 (ARM64) 指令集架构 (ISA) 开发。HermiTux的设计基本原则是独立于架构，但是它的实现以及我们用来恢复unikernel的二进制重写/分析技术是ISA特定的。
总体来说，HermiTux做了以下出色工作：
一种新的unikernel模型，旨在执行本机Linux可执行程序，同时保持经典的unikernel优势。 提供可以在x86-64 和 aarch64 架构上的两个原型实现。 四、关键概念阐述# 4.1 Unikernels# unikernel是一个应用程序，它使用必要的库和一个精简OS层静态编译成一个二进制文件，能够作为虚拟机在管理程序上执行。Unikernel符合以下条件：
单一目的：一个unikernel只包含一个应用程序 单一地址空间：由于单一目的原则，所以unikernel不需要内存保护，因此应用程序和内核共享一个地址空间，所有代码都以最高权限级别执行。 这样的模型提供了显著的好处，在安全性方面提供了unikernel之间的强隔离，虚拟机管理程序让它成为云部署的良好候选者。此外unikernel仅包含运行给定应用程序所需的必要软件。结合非常小的内核尺寸，和常规VM相比，这导致应用程序攻击面显著减少。一些unikernel也是用提供内存安全保障的语言编写的。关于性能方面，unikernel系统调用很快，因为它们是常见的函数调用，特权级别之间没有代价昂贵的用户态与内核态切换。上下文切换也很快，因为没有页表切换或TLB刷新。除了由于小内核导致代码库减少之外，unikernel OS层通常是模块化的，可以将它们配置为仅包含给定应用程序的必要功能。
所有这些好处让unikernels的应用程序域非常丰富。他们非常适合运行大多数需要高度隔离的云应用程序和需要高性能、低操作系统开销的计算密集型作业的数据中心。unikernel减少的资源使用使它们特别适合嵌入式虚拟化，随着边缘计算和物联网等范式的出现，这个领域的重要性日益增加。由于unikernels的应用领域包括服务器和嵌入式机器，因此论文主要针对intel x86-64和 aarch64架构进行模型构建。
4.2将现有应用程序移植到Unikernel# 移植现有软件作为unikernel运行是很困难的，特别在某些情况下无法移植程序到unikernel环境，因为所有的程序都需要重新编译与链接。一个给定的unikernel支持一组有限的内核特性和软件库，如果不支持应用程序所需的函数、库或者特定版本的库，则该程序需要进行调整。在许多情况下，缺少函数/库意味着应用程序根本无法移植，此外unikernel使用复杂的构建基础架构，将一些遗留的应用程序（大型的Makefile、autotools、cmake）移植到unikernel工具链会很麻烦，更改编译器或者构建选项也是如此。
在如此大的移植成本上，所以unikernel发展缓慢是有原因的，一种解决方案是让unikernel为常规可执行文件提供二进制兼容性，同时仍保持经典 unikernel 的优势，例如⼩代码库/占⽤空间、快速启动时间、模块化等。这种新模型允许 unikernel 开发⼈员致⼒于推⼴unikernel 层以⽀持最⼤应⽤程序的数量，并减轻应⽤程序开 发⼈员的任何移植⼯作。这种⽅法还应该⽀持调试器等开发⼯具。在这种情况下，HermiTux 允许将 Linux ⼆进制⽂件作为unikernel 运⾏，同时保持上述优势。
4.3 轻量级虚拟化设计空间# 轻量级虚拟化设计空间包含unikernel、面向安全的LibOS、例如Graphene，以及带有软件和硬件强化技术的容器。HermiTux不需要应用程序移植工作，并且和其他二进制兼容的系统方案不同，不同点主要包括：
作为unikernel HermiTux运行硬件强制（扩展页表）虚拟机，这是一种从根本上比软件强制隔离（容器/软件LibOS）更强的隔离机制。当前在VM中运行容器以确保安全的趋势（clear containers）加强容器隔离的努力（gVisor）都表明了这一点，这通常用作支持unikernel与容器的安全依据。 HermiTux使更广泛的应用程序能够透明地无需任何移植工作即可获得unikernel的好处，无需修改代码以及维护单独分支的潜在复杂性。鉴于unikernel提供的安全性和减少占用空间的特性，这在当今的计算机系统环境中非常有价值，软件和硬件漏洞经常成为新闻，并且数据中心架构师正在寻求增加整合和减少资源/能源消耗的方法。二进制兼容允许HermiTux成为专有软件（其源代码不可用）作为unikernel运行的唯一方法。最后，HermiTux允许软件获得VM的传统优势，例如检查点/重启/迁移，而无需大量磁盘/内存占用的相关开销。 4.4 系统调用级二进制兼容# 两个现有的unikernel已经生成和应用程序的二进制兼容，OSv和Lupin Linux。需要注意的是，两者都提供二进制兼容性标准C库（libc）级别，unikernel包含一个动态加载程序，它在运行时捕获对libc函数的调用，例如printf、fopen并将它重定向到内核。
这种接口方法意味着假设所有系统调用都是通过libc进行的，当考虑到各种各样的现代应用程序二进制文件时，这并不成立。我们分析了整个Debian10 x86-64存储库 (主要，贡献 和 ⾮免费） 并统计了553个ELF可执⾏⽂件，包括⾄少⼀次调⽤系统调⽤指令：这些代表不通过libc 执⾏系统调⽤程序，因此 libc 级别的⼆进制兼容unikernel 不⽀持这些程序。这种有限的libc级兼容性组织了这些系统运行相对较大范围的应用程序，这些应用程序将从座位unikernel的执行中受益匪浅。举几个例子，大量的云服务是用Go语言编写的，Go是一种无须标准C库即可执行大多数系统调用的语言。此外，由于在系统调用层面缺乏兼容性，OSv不支持最流行的HPC共享内存编程框架OpenMP，最后libc接口排除了对静态二进制文件的支持。</description></item><item><title>阿里云FAASNET无服务器容器方案</title><link>https://icorer.com/icorer_blog/posts/alibaba_cloud_faasnet_serverless_container_solution/</link><pubDate>Tue, 18 Jan 2022 21:24:16 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/alibaba_cloud_faasnet_serverless_container_solution/</guid><description>背景# 这篇论文中采用容器化方案来实施ServerLess的落地过程，论文内部一方面基于大量的数据统计、一方面提出来FT树结构，用来优化容器冷启动。FAASNET是第一个为FaaS优化的容器运行时提供的端到端综合解决方案，FAASNET使用轻量级、分散和自适应的函数树来避免主要平台的瓶颈。
大会地址：https://www.usenix.org/conference/atc21/presentation/wang-ao 开源地址：https://github.com/mason-leap-lab/FaaSNet 一、网络流量的峰谷比# 轻点放大 就如上图所示，不同的应用场景下，流量的高峰和低峰的请求比例是不一样的，比如游戏、IOT场景下流量的峰谷比高于22，这种峰谷比也表明了ServerLess场景的优势。
二、容器的冷启动情况# 冷启动的延迟对于Faas提供商是致命的，阿里巴巴首先对于冷启动的分布情况作了调研：
对于北京地区，大约57%的镜像拉取时间超过45秒 对于上海地区，超过86%的镜像拉取时间至少需要80秒 显示超过50%和60%的函数调用请求花费至少80%和72%的整体函数启动时间来拉取容器镜像，这表明镜像拉取时间成为了大多数功能的冷启动成本。 冷启动的成本，还需要结合冷启动的间隔时间和功能持续时间来综合评价，在两个地区内部，大约49%的功能冷启动的到达时间小于1秒。
三、FAASNET技术内幕# 轻点放大 在图3(d)中可以看出北京地区的80%函数执行时间超过1秒，上海地区80%的函数执行时间小于32.5秒，90th百分位数为36.6秒，99th百分位数为45.6秒。这种分布说明冷启动优化是必要的。
优化容器配置的性能将为降低基于容器的云功能的冷启动成本带来巨大的好处。
2.1 设计概述# FAASNET将跨虚拟机的容器配置分散化和并行化，引入了名为函数树（FT）的抽象，以实现高效的容器配置规模。FAASNET将FT管理器组件和一个工作者组件整合进入FAAS调度器和虚拟机代理中，以协调FT管理，阿里的Faas平台主要包含以下几个组成部分，工作的主体组成包括：
网关：租户身份管理认证，将函数请求转发给FAAS调度器，将常规的容器镜像转换为I/O高效数据结构， 一个调度器负责为函数调用请求提供服务，将FAASNET FT管理器集成到调度器来管理函数数、简称FT，通过FT的增删API进行管理。一个FT是一个二进制的树状覆盖，它连接多个虚拟机，形成一个快速和可扩展的容器供应网络。每个虚拟机运行一个FAAS代理，负责虚拟机本地的功能管理。将一个FAASNET工作者集成到VM代理中，用于容器的供应任务。 在函数调用的路径上，如果没有足够的虚拟机、或者所有的虚拟机都很忙的情况下，调度器首先与虚拟机管理器进行通信，从空闲的虚拟机池中扩展出活动的虚拟机池。然后调度器查询其本地的FT元数据，并向FT的FAASNET工作者发起RPC请求，从而启动容器供应流程。容器运行时供应过程实际上是分散的， 并在FT尚未有容器运行的本地供应的虚拟机进行准备工作。调度器在关键路径之外，而FAASNET工作层根据需求获取函数容器层，并从分配的对等虚拟机中并行地创建容器运行时。 在函数部署路径上，网关将函数的常规容器镜像转换为I/O的有效格式，从面向租户的容器注册表中提取常规镜像，逐块压缩镜像层，创建一个包含格式相关信息的元数据文件（镜像清单），并将转换后的层及其清单分别写入阿里云内部的容器注册表和元数据存储。 2.2 FT功能树# 论文中针对重点强调在设计FT时做了以下选择：
FT是和函数进行绑定的，FAASNET以函数为粒度来管理FT。 FT具备解耦的数据面和控制面，FT的每个虚拟机工作者都具有等同的、简单的容器供应（数据平面）的角色，而全局树管理（控制平面）则交给调度器。 FAASNET采用平衡的二叉树结构，可以动态的适应工作负载。 这些选择结合阿里云，可以达到以下目标：
最大限度的减少容器镜像和层数据下载的I/O负载。 消除中央根节点的树状管理瓶颈和数据播种瓶颈、这里阿里内部镜像采用P2P分发，播种友好。 适应虚拟机的动态加入和离开。 轻点放大 以函数的粒度管理树， FAASNET为每一个至少被调用过一次但未回收的函数管理一个单独、唯一的树。图5说明一个横跨5个虚拟机的三级FT拓扑结构。函数容器镜像从书的根部虚拟机往下流，直到达到叶子节点。
平衡的二叉树，FAASNET的核心是平衡的二进制树，在二进制树中，除了根节点和叶子节点，每个树节点（宿主虚拟机）有一条传入边和两条传出边。这种设计可以有效限制每个虚拟机的并发下载操作的数量，以避免网络争用。一个有N个节点的平衡二叉树的高度为log(N)，这种关系也限制了函数镜像和层数据从顶部到底部的最多跳跃次数。树的高度会影响数据传播的效率，并且二叉树的结构可以动态变化，以适应工作负载的动态化。FAASNET把每个FT组织成一个平衡的二叉树，FT管理程序调用两个API：增加和删除，以动态地增加或缩小一个FT。
插入，FT的第一个节点会被当做根节点插入，FT管理器通过BFS（广度优先搜索）跟踪每个树节点的子节点数量，并将所有拥有0或1个子节点的节点存储在一个队列中。要插入一个新节点，FT管理器会从队列中挑选第一个节点作为新节点的父节点。
删除，调度器可能会回收闲置了一段时间的虚拟机（阿里云配置为15分钟），因此FAAS虚拟机的寿命是有限的。为了使用这种虚拟机的回收，FT管理器调用删除来回收虚拟机。删除操作也会在需要的时候重新平衡FT的结构。与二进制搜索树（如AVL、红黑树）不同，FT的节点没有可比较的键值（及其相关值）。因此，FT树的平衡算法只有当任何节点的左右子树的高度差大于1就会触发平衡操作。
2.3 FT与FAAS整合# 论文中的FT整合是在阿里云的FAAS环境中，主要整合了FAAS平台的调度器和虚拟机代理。阿里把FAASNET的FT管理器集成到阿里云的FAAS调度器中，并将FAASNET的VM工作者集成到阿里云的FASS-VM代理中用于调度管理FT的虚拟机。
通过FT管理者，调度器在每个虚拟机代理上启动一个FAASNET工作者，工作者负责：
为调度员的命令提供服务，执行镜像下载和容器供应的任务 管理虚拟机上的函数容器。 FT元数据管理，调度器维护一个内存映射表，记录&amp;lt;functionID,FT&amp;gt;键值对，他将一个函数ID映射到其相关的FT数据结构。一个FT数据结构管理着一组代表函数和虚拟机的内存对象，以跟踪虚拟机的地址：端口信息。调度器是分片的，是高度可用的。每个调度器分片会定期将内存中的元数据状态与运行etcd的分布式元数据服务器同步。
函数在虚拟机上的放置，为了提高效率，FAASNET允许一个虚拟机容纳属于同一个用户的多个函数。只要虚拟机有足够的内存来承载函数，一个虚拟机可能参与到多个重叠的FT的拓扑结构中。
轻点放大 图8显示了一个可能的FT布局的例子，为了避免网络瓶颈，FAASNET限制了一台虚拟机可以放置的函数数量，目前设置是20个。
容器供应协议，FAASNET设计了一个协议来协调调度器和容器之间的RPC通信。
轻点放大 调度器和FAASNET的虚拟工人，并促进容器的供应。在一个调用请求中，如果调度器发现没有足够的活动虚拟机为请求提供服务，或者当前所有虚拟机都忙于为请求提供服务，调度员会从空闲的虚拟机池中保留一个或多个新的虚拟机，然后进入容器供应流程。
当调度器将函数元数据发送给VM，VM一旦收到信息会执行两个任务。从元数据存储库加载并检查清单，获取镜像层的URL，并把URL信息持久化到VM的本地存储中。VM回复调度器表明自己已经准备好开始为请求的函数创建容器运行时，调度器收到回复后向VM发送一个创建容器的RPC请求，VM处理清单配置，并向调度器发送一个RPC表明容器已经成功创建。
FT容错，调度器定期ping虚拟机，可以快速检测虚拟机故障。如果一个虚拟机发生故障，调度器会通知FT管理器执行树平衡操作以修复FT拓扑结构。
2.4 FT设计讨论# FAASNET将元数据繁重的管理任务卸载到现有的FAAS调度器上，因此每个单独节点都扮演着从其父级对等获取数据的相同角色。FT的根节点没有父级对等物，而是从注册表中获取数据。FAASNET的FT设计可以完全消除到注册中心的I/O流量，只要一个FT至少有一个活跃的虚拟机存储所请求的容器。早些时候，我们的工作负载分析显示，一个典型的FAAS应用的吞吐量将始终高于0RPS，在实践中请求突发更有可能讲一个FT规模从1到N，而不是从0到N。
另一种设计是更细粒度的层（blobs）来管理拓扑关系。在这种方法中，每个单独的层形成一个逻辑树层，属于一个函数的容器镜像的层最终可能驻留在不同的虚拟机上。注意FAASNET的FT是层树模型的一个特例。
轻点放大 图10中显示了一个例子，在这个例子中，一个虚拟机中存储着不同函数容器镜像的层文件，因此当许多下游的虚拟机同事从这个虚拟机获取层时，可能会出现网络瓶颈。这是因为许多重叠的层树形成了一个完全连接的、端对端的网络拓扑结构。如果虚拟机用高带宽的网络连接，全对全的拓扑结构可能会有很好的规模。然而如果每个虚拟机都收到了资源限制，全对全的拓扑结构很容易造成网络瓶颈，阿里云内部使用的是2核CPU、4G内存、1Gbps网络的小型VM。
现有的容器分配技术依靠强大的根节点来完成一系列任务，包括数据播种、元数据管理、P2P拓扑结构管理。将这些框架移植到FAAS平台上，需要额外的、专用的、分片的根节点，这将给运营商增加不必要的成本。另一方面，FAASNET的FT设计使每个虚拟机工作者的逻辑保持简单，同时所有的调度逻辑卸载到现有的调度器。这种设计自然消除了网络I/O瓶颈和根节点的瓶颈。Kraken采用了基于层的拓扑结构，具有强大根节点。
2.5 优化# I/O高效的数据格式，常规的docker pull 和 docker start是低效和耗时的，因为整个容器镜像和所有层的数据都必须从远程容器注册中心下载，然后才能启动容器。为了解决这个问题，阿里云内部设计了一个新的基于块的镜像获取机制，这种机制使用了一种I/O高效的压缩数据文件格式。原始数据被分割成固定大小的块，并分别进行压缩。一个偏离表被用来记录压缩文件中每个压缩块的偏移量。</description></item><item><title>⽤于区块链可扩展性的⾼效能 FPGA-Redis 混合 NoSQL 缓存系统</title><link>https://icorer.com/icorer_blog/posts/blockchain_fpga_redis_nosql/</link><pubDate>Tue, 25 May 2021 22:35:12 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/blockchain_fpga_redis_nosql/</guid><description>一、FPGA-Redis介绍 鼓舞人心的区块链技术在加密货币以外的领域取得了很多采用和成功领域落地，因为它的好处已经被探索和成功测试。可扩展性是区块链的最大挑战之一，许多设备（轻量级节点）尤其是物联网依赖于完整的区块链服务器，因此需要减少服务器上的工作负载以获得高性能。这篇论文提出了一种高性能、高效的混合（多级）和分布式NoSQL缓存系统，用于提高区块链应用程序的可扩展（吞吐量）。我们研究了区块链中的性能瓶颈，并设计了一种高效的千兆以太网FPGA NoSQL缓存架构，该架构通过Hiredis C客户端与Redis数据库协同工作。Curl和Jansson用于连接区块链。我们为特定于区块链的高效缓存设计了一个定制的SHA-256核心。我们的结果显示，当FPGA上发生缓存命中时，性能提高了103倍。所提出的FPGA-Redis系统获得了高达4.09倍的改进，还实现了较小的FPGA面积利用率和较低的功耗。
二、概述 区块链技术激励了许多人，帮助许多企业和政府改进系统，解决了信任、安全、速度、成本、效率和中心化等诸多瓶颈问题。英国政府办公室的报告确认区块链可以保护数据、降低成本并为记录提供透明度。区块链由中本聪于2008年首次提出并支持加密货币（比特币）和许多其他用于医疗保健、身份管理、网络安全等应用程序。Corda是R3的区块链（由200多家公司组成的联盟，主要是金融机构），用于增强商业交易和网络，R3一直在为企业使用和探索区块链。
尽管区块链很强大，但可扩展性（低吞吐量、高延迟、存储问题和读取性能差）是其巨大的挑战，但研究较少。与非区块链应用程序相比，区块链应用程序的吞吐量要低很多。比特币和以太坊支持每秒3-4和15-20笔交易（TPS），而Visa和PayPal分别支持1667和193TPS，另一方面，与非区块链服务器相比，区块链服务器的查询响应（读取性能）也很差。例如在我们处理约每秒96个响应的区块链系统中，查询延迟超过10毫秒。同样，Blockcypher 区块链服务器⽀持每秒3个请求。与⾮区块 链服务器相⽐，Google和YouTube分别处理每秒84,405个请求和每秒85,021次观看。糟糕的读取性能是由于区块链的结构和巨大的尺寸（比特币超过288GB）以及区块链数据存储在硬盘上的事实。与用于存储Redis等NoSQL缓存的RAM（快150,000倍）不同，硬盘具有较高的访问延迟。由于这种糟糕的读取性能，现有的区块链无法处理有效服务器所需的每秒大量客户端请求。许多轻量级节点（数以千计的物联网设备和简化验证（SPV）节点），仅依赖区块链服务器来获取区块链数据，因为其庞大的规模，它们无法存储完整的区块链。现在越来越多的轻量级客户端使用区块链并将更多的工作放在区块链服务器上，因此必须减少区块链服务器上的工作量以提升性能，从而更好地扩展区块量应用程序。
NoSQL缓存是提高和增强区块量服务器读取性能的一种有效方式。Redis、Hadoop和Memcached等NoSQL缓存如今已广泛用于大型Web数据中心，例如Yahoo、Twitter、Facebook、Youtube甚至Google，其中数百个分布式NoSQL部署缓存服务器是为了改善许多性能和可伸缩问题并节省成本。NoSQL缓存具有非常高的性能进行大规模水平扩展的优势，并且比使用更强大的CPU和内存（垂直扩展）更新现有服务器更经济。水平扩展是指使用廉价商品服务器的副本来获得更好的性能，而不是传统的垂直扩展，其中将更强大的资源添加到单个服务器使系统更加昂贵。仅苹果公司就使用了超过75000个NoSQL缓存（Cassandra）表格系列集群来存储超过10PB的数据。
分布式 NoSQL 缓存由于其⾼性能以及区块链请求（尤其是块头请求）的时间局部性，可以极⼤地提⾼区块链服务器响应的吞吐量和延迟性能。许多轻量级节点（如简化⽀付验证节点（特殊⽬的公司 )在添加新块的⼏个⼩时内。
尽管具有⾼性能，但软件 NoSQL 缓存在⾼性能时会消耗⾼功率和更多CPU 资源（在⽹络处理上）。因此，当 FPGA 发⽣缓存命中时，使⽤ FPGA来降低功耗和 CPU 资源消耗并提⾼性能。然⽽，FPGA 中的⼩尺⼨和有限的内存给可以缓存在 FPGA 上的数据量带来了缺陷和限制，从⽽通过增加 FPGA 的未命中率来影响系统性能。
本⽂研究了区块链中的性能瓶颈，并提出了⼀种⾼效的**⾼性能混合分布式NoSQL FPGA-Redis 缓存**系统，以减少区块链服务器的⼯作负载并提⾼其性能。我们设计并实现了⼀个千兆以太⽹ FPGA ⽹络接⼝控制器 (NIC)，该控制器包含键值存储，⽤于有效地缓存 FPGA 上的区块链数据。Redis 软件缓存和 Redis 应⽤程序内置在 Redis 服务器 PC 中，它通过 FPGA 上实现的千兆总线主控直接内存地址 (BMD) PCI Express (PCIe) 端点连接到 NIC。Redis 应⽤程序使⽤Hiredis API（实现与Redis缓存对话的Redi 的C客⼾端）。整个缓存系统通过我们的服务器应⽤程序中内置的Curl和Jansson API 连接到全节点区块链服务器。
该系统改善了FPGA NoSQL缓存内存⼩的缺点，同时以更低的功耗提⾼了 软件缓存的性能。FPGA 和 Redis 协同⼯作。Redis 通过提供另⼀个缓存层来补充 FPGA 缓存的有限内存。当在 FPGA 上未找到请求的数据（发⽣缓存未命中）时，数据从 Redis（如果缓存）⽽不是存储在主内存中的主区块链中获取。由于 Redis ⽐主存更快，因此整个系统的性能得到了提⾼。反过来，FPGA 通过处理⽹络处理来降低Redis的⾼性能和CPU资源消耗。我们只在FPGA和Redis（包括缓存）上缓存频繁的请求（即块头、确认、块⾼度、时间跨度和 Merkle根），⽽在Redis上缓存不频繁和⼤数据请求（例如块请求）只要。此外，仅当FPGA上发⽣缓存未命中时才检查Redis 缓存。</description></item><item><title>TCP长连接在K8S环境下的负载均衡分析</title><link>https://icorer.com/icorer_blog/posts/cloudnative_k8s_tcp_upstream_balance/</link><pubDate>Fri, 25 Dec 2020 11:28:12 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/cloudnative_k8s_tcp_upstream_balance/</guid><description>K8S不支持长连接的负载均衡，所以负载可能不是很均衡。如果你在使用HTTP/2，gRPC, RSockets, AMQP 或者任何长连接场景，你需要考虑客户端负载均衡。
TL;DR: Kubernetes doesn&amp;rsquo;t load balance long-lived connections, and some Pods might receive more requests than others. If you&amp;rsquo;re using HTTP/2, gRPC, RSockets, AMQP or any other long-lived connection such as a database connection, you might want to consider client-side load balancing.
Kubernetes提供了两种方便的抽象来部署应用程序：Services 和 Deployments。 Deployments描述了在任何给定时间应运行哪种类型以及多少个应用程序副本的方法。每个应用程序都部署为Pod，并为其分配了IP地址；另一方面，Services类似于负载平衡器。它们旨在将流量分配给一组Pod。
轻点放大 轻点放大 轻点放大 轻点放大 将Services视为IP地址的集合通常很有用。每次您对Services提出请求时，都会从该列表中选择一个IP地址并将其用作目的地。 轻点放大 轻点放大 轻点放大 如果您有两个应用程序（例如前端和后端），则可以为每个应用程序使用Deployment和Service，然后将它们部署在集群中。 当前端应用发出请求时，不需要知道有多少Pod连接到后端服务；前端应用程序也不知道后端应用程序的各个IP地址。当它想要发出请求时，该请求将发送到IP地址不变的后端服务。 轻点放大 轻点放大 轻点放大 轻点放大 但是该服务的负载平衡策略是什么？
Kubernetes Services中的负载平衡# Kubernetes Services不存在，没有进程监听服务的IP地址和端口。
您可以通过访问Kubernetes集群中的任何节点并执行netstat -ntlp来检查是否存在这种情况。</description></item><item><title>微服务治理：APM-SkyWalking-PHP内核扩展源码分析</title><link>https://icorer.com/icorer_blog/posts/microservice_skywalking_php_kernel_source_analyze/</link><pubDate>Mon, 07 Sep 2020 14:42:13 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/microservice_skywalking_php_kernel_source_analyze/</guid><description>轻点放大 SkyWalking APM作为服务遥测的关键技术点，为了能够更好地运用这项技术，我们需要拥有把握这项技术的底层能力。目前公司在PHP领域存活不少业务系统，针对PHP领域的APM技术，我们首先从分析这款PHP内核扩展程序下手。
一. 总体架构# PHP内核在php-fpm运行模式下是短生命周期，短生命周期的脚本运行如果直接连接SkyWalking的oap-server会造成大量的性能损耗，而且php也不擅长grpc通信，因此借助mesh架构思想为PHP-FPM进程池增加一个数据SideCar，主要的结构如下图所示： 轻点放大 从上图可以看出，PHP内核扩展程序拦截内核运行数据（主要是关键的外部IO调用）、数据被发送给SideCar，SideCar流转数据到SkyWalking-Server，数据流还可以被SkyWalking进行分析、从而通过WebHook流转报警时间到相关后续平台里。
二. PHP内核扩展源码分析# 针对目前开源社区的SkyWalking-PHP内核源码进行分析，源码的分析主要包括以下几部分：
工程结构分析 关键生命周期分析 关键运行函数Hook分析 2.1 工程结构分析# SkyWalking PHP内核组件工程结构比较简单，主要是站在PHP内核基础上进行扩展设计与实现，主要包含的扩展文件有：
b64.h：base64编码函数的头文件、主要包含内存分配、base64字符表、b64_encode及b64_decode、b64_decode_ex的函数声明。 decode.c：base64序列化的函数具体实现。 encode.c：base64反序列化的函数具体实现。 components.h：针对skywalking协议中的component部分进行宏定义、这部分是apm协议的一部分，例如：tomcat、httpclient、dubbo、okhttp、grpc、jedis、更多查看附录1。 php_skywalking.h：关键的内核扩展声明部分，主要包括：APM协议宏定义、Redis指令类别、memcache指令类别、ContextCarrier上下文结构体、apm拦截所需的关键函数定义（具体见附录二），apm关键函数hook定义（具体见附录三），全局变量定义（具体见附录四）。 skywalking.c：具体内核扩展实现文件，里面包含了MI-MS、RI-RS、关键函数Hook等处理逻辑。 2.2 关键生命周期分析# 这块将针对内核扩展关键生命周期进行分析。
2.2.1 关键生命期函数Hook定义# static void (*ori_execute_ex)(zend_execute_data *execute_data); //PHP内核原始PHP层执行流程函数指针 static void (*ori_execute_internal)(zend_execute_data *execute_data, zval *return_value);//PHP原始内核执行函数指针 ZEND_API void sky_execute_ex(zend_execute_data *execute_data);//skywalking针对PHP层执行函数的替换指针 ZEND_API void sky_execute_internal(zend_execute_data *execute_data, zval *return_value);//skywalking针对原始内核执行函数的替换指针 2.2.2 php.ini配置解析周期# PHP_INI_BEGIN() #if SKY_DEBUG STD_PHP_INI_BOOLEAN(&amp;#34;skywalking.enable&amp;#34;, &amp;#34;1&amp;#34;, PHP_INI_ALL, OnUpdateBool, enable, zend_skywalking_globals, skywalking_globals) //读取skywalking.enable配置项 #else STD_PHP_INI_BOOLEAN(&amp;#34;skywalking.enable&amp;#34;, &amp;#34;0&amp;#34;, PHP_INI_ALL, OnUpdateBool, enable, zend_skywalking_globals, skywalking_globals) //读取skywalking.</description></item><item><title>微服务治理：服务遥测之APM-SkyWalking技术应用</title><link>https://icorer.com/icorer_blog/posts/microservice_governance_apm_application/</link><pubDate>Mon, 07 Sep 2020 13:33:12 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/microservice_governance_apm_application/</guid><description>一. 背景描述# 微服务应用过程中，如何构建微服务的可观测性，主要从以下三个方面进行考虑：
服务日志（log） 服务指标（metric） 服务链路（trace） 这三个服务监控领域有不同的技术栈进行支撑，但是如何快速构建一个基础的服务可观测能力？尽量减少业务的侵入性、尽量多的增加业界标准的观测指标，这里我就推荐APM技术体系，在APM技术领域中SkyWalking是一个优秀的解决方案。 轻点放大 二. 技术结构# SkyWalking 在我当前公司的落地领域中，主要围绕PHP、Go两大技术领域，JAVA生态拥有SkyWalking默认友好支撑，针对PHP、Go这两种技术栈，主要包含的APM体系技术结构如下图所示： 轻点放大 从技术结构图可以看出，APM技术体系主要包括以下几部分：
技术结构最底层采用了apache SkyWalking开源项目作为方案支撑。 Go生态使用Go2sky客户端进行APM数据丰富与数据包发送。 PHP生态由于自身短生命期的特征，分为PHP内核APM扩展和数据中转SideCar两部分，PHP内核扩展通过函数Hook机制完成Redis、MySQL、PDO、grpc等关键网络IO的拦截，并无感构建APM数据包结构，在RS周期发送APM数据包到SideCar，SideCar负责流转PHP内核的APM监控数据包到APM-Server上。 三. 关键领域监控# APM技术生态包含内容比较多，主要的使命就是对于服务应用进行运行态监控，这里主要阐述一下几方面的监控效果：
3.1 服务指标监控# 服务指标监控主要包括Apdex、平均响应时间、成功率、CPM、TP数据、也包括很多的服务EndPoint数据，主要用来阐述服务健康、性能、可靠性的指标数据。 轻点放大 3.2 服务调用链监控# 微服务场景下，调用关系复杂、服务调用关系层级深，所以APM构建了服务调用链监控体系，方面研发、架构对于自己服务的调用关系有较好的可视化效果，调用链也遵循OpenTracing协议，主要效果如下所示： 轻点放大 3.3 微服务内核Runtime监控# 服务监控除了需要对于服务自身的可靠性、服务之间的调用关系进行监控之外，还需要针对服务Runtime进行拦截分析，通常的实现方式有OAP编程、内核Runtime Hook方式，Runtime监控可以很好的监控服务不同EndPoint内部的关键不稳定点的性能情况，除了PDO、Redis、Mysql、GRPC等关键IO，也可以监控长时间的cpu计算等程序行为逻辑。 主要的效果图如下： 轻点放大 3.4 微服务拓扑关系监控# 针对微服务调用关系，除了可以使用全链路Trace这种表达形式，也可以通过更具有动感效果的拓扑关系图进行描述，在拓扑关系图中可以形象的显示服务的类别、服务的流量走向、服务的当前状态、服务调用间的频率等数据。相关的效果图如下所示: 轻点放大 三. 总结# APM技术体系对于微服务治理工作有超强的观测领域能力的弥补，增强服务的可观测程度，是微服务治理的重要工作。</description></item><item><title>UtahFS: Encrypted File Storage - 加密文件存储</title><link>https://icorer.com/icorer_blog/posts/utahfs_encrypted_file_storage/</link><pubDate>Sun, 14 Jun 2020 10:17:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/utahfs_encrypted_file_storage/</guid><description>加密是最强大的技术之一，每个人每天都在不知不觉中使用它。传输层加密现在已经无处不在，因为它是创建可信赖的Internet的基本工具，它可以保护通过Internet发送到目标目的地的数据。磁盘加密技术可以无所不在地保护您的数据，因为它可以防止任何窃取您设备的人也能够看到您台式机上的内容或阅读您的电子邮件。
这项技术的下一个改进是端到端加密，它是指只有最终用户才能访问其数据的系统，而没有任何中间服务提供商。这类加密的一些最流行的例子是WhatsApp 和Signal 等聊天应用。端到端加密显著降低了用户数据被服务提供商恶意窃取 或不当处理 的可能性。这是因为即使服务提供商丢失了数据，也没有人拥有解密数据的密钥！
轻点放大 几个月前，我意识到我的计算机上有很多敏感文件（我的日记，如果你一定知道的话），我担心会丢失，但我不喜欢将它们放入Google Drive或Dropbox之类。尽管Google和Dropbox是绝对值得信赖的公司，但它们不提供加密功能，在这种情况下，我确实希望完全控制自己的数据。
环顾四周，我很难找到符合我所有要求的东西：
会同时加密和验证目录结构，这意味着文件名是隐藏的，其他人不可能移动或重命名文件。 查看/更改大文件的一部分不需要下载并解密整个文件。 是开源的，并且有一个文档化的协议。 所以我开始建立这样一个系统！最终我把它称为“ UtahFS”，其代码在此处提供 。请注意，这个系统在Cloudflare的生产中没有使用：它是我在我们的研究团队 工作时构建的概念。这篇博客文章的其余部分描述了我为什么要像以前那样构建它，但是如果您想跳过它，则代码仓库中有关于实际使用它的文档。
Storage Layer(存储层)# 存储系统的第一个也是最重要的部分是…存储。为此，我使用对象存储 ，因为它是在别人的硬盘上存储数据的最便宜和最可靠的方法之一。对象存储只不过是一个由云提供程序托管的键值数据库，通常被调整为存储大约几千字节大小的值。有许多具有不同定价方案的不同提供商，例如Amazon S3，Backblaze B2和Wasabi。它们全部都能够存储TB级的数据，并且许多还提供地理冗余。
Data Layer(数据层)# 对我来说很重要的一个要求是，在能够读取一部分文件之前，不必下载和解密整个文件。这一点很重要的一个地方是音频和视频文件，因为它能够快速开始播放。另一个例子是ZIP文件：许多文件浏览器都具有浏览压缩档案（例如ZIP文件）的能力，而无需将其解压缩。要启用此功能，浏览器需要能够读取存档文件的特定部分，仅解压缩该部分，然后移动到其他位置。
在内部，UtahFS从不存储大于配置大小（默认为32 KB）的对象。如果文件中的数据量超过该数据量，则该文件将分成多个对象，这些对象通过跳表 连接。跳表是链接列表的稍微复杂一点的版本，它允许读者通过在每个块中存储指向比指向前一跳更远的其他指针来快速移动到随机位置。
当跳表中的块不再需要时，因为文件已被删除或截断，它们将被添加到特殊的“回收站”链接列表中。例如，当需要在其他位置使用块时，可以回收垃圾列表的元素，以创建新文件或将更多数据写入现有文件的末尾。这将最大限度地重用，意味着仅当垃圾箱列表为空时才需要创建新块。一些读者可能认为这是《计算机编程艺术：第一卷，2.2.3节》中描述的链接分配策略！ 轻点放大 使用链接分配的根本原因是，对于大多数操作而言，这是最有效的。 而且，这是一种分配内存的方法，该方法将与我们在接下来的三个部分中讨论的加密技术最兼容。
Encryption Layer(加密层)# 既然我们已经讨论了如何将文件分成块并通过跳表进行连接，我们就可以讨论如何实际保护数据。这有两个方面：
第一个是机密性，它对存储提供者隐藏每个块的内容。 只需使用AES-GCM加密每个块，并使用从用户密码中获得的密钥，即可实现这一点。
该方案虽然简单，但不提供前向保密或后向安全。前向保密意味着，如果用户的设备遭到破坏，攻击者将无法读取已删除的文件。后泄露安全性意味着一旦用户的设备不再泄露，攻击者将无法读取新文件。不幸的是，提供这两种保证之一意味着在用户的设备上存储加密密钥，这些密钥需要在设备之间同步，如果丢失，将使存档无法读取。
此方案也无法防止脱机密码破解，因为攻击者可以获取任何加密的块，并一直猜测密码，直到找到有效的块为止。通过使用Argon2（这使得猜测密码更为昂贵）和建议用户选择强密码，可以在一定程度上缓解这种情况。
我肯定会在将来改进加密方案，但认为上面列出的安全属性对于初始发行版来说太困难和脆弱。
Integrity Layer(完整性层)# 数据保护的第二个方面是完整性，它确保存储提供程序没有更改或删除任何内容。这是通过在用户数据上构建Merkle树来实现的。Merkle树在我们关于证书透明性的博客文章 中得到了深入的描述。Merkle树的根哈希值与版本号相关联，该版本号随每次更改而递增，并且根哈希值和版本号均使用从用户密码派生的密钥进行身份验证。这些数据存储在两个位置：对象存储数据库中的一个特殊密钥下，以及用户设备上的一个文件中。
每当用户想从存储提供程序读取一块数据时，他们首先请求远程存储的根目录，并检查它是否与磁盘上的相同，或者版本号是否大于磁盘上的版本号。检查版本号可防止存储提供程序将存档还原为未检测到的以前（有效）状态。然后，可以根据最新的根散列验证读取的任何数据，该散列可防止任何其他类型的修改或删除。
在此处使用Merkle树的好处与“证书透明性”的好处相同：它使我们能够验证单个数据，而无需立即下载并验证所有内容。 另一个用于数据完整性的常用工具称为消息身份验证码（Message Authentication Code，简称MAC），虽然它既简单又有效，但它无法只进行部分验证。
我们使用Merkle树不能防止的一件事是分叉，在分叉中，存储提供商向不同的用户显示不同版本的存档。然而，检测fork需要用户之间的某种流言蜚语，这已经超出了最初实现的范围。
Hiding Access Patterns(隐藏访问模式)# Oblivious RAM , or ORAM,是一种用于以随机方式对随机存取存储器进行读写的加密技术，它可以从存储器本身中隐藏执行了哪个操作（读或写）以及对该操作执行到了存储器的哪一部分！在我们的例子中，“内存”是我们的对象存储提供程序，这意味着我们要向他们隐藏我们正在访问的数据片段以及访问的原因。这对于防御流量分析攻击很有价值，在这种攻击中，对UtahFS这样的系统有详细了解的对手可以查看其发出的请求，并推断加密数据的内容。例如，他们可能会看到您定期上传数据，几乎从不下载，并推断您正在存储自动备份。
ORAM最简单的实现是始终读取整个内存空间，然后使用所有新值重写整个内存空间，只要您想读取或写入单个值。一个观察内存访问模式的对手将无法判断你真正想要的值，因为你总是触摸所有东西。然而，这将是极其低效的。
我们实际使用的结构称为Path ORAM ，它稍微抽象了一点这个简单的方案，使其更有效。首先，它将内存块组织成二叉树，其次，它保留一个客户端表，该表将应用程序级指针映射到二叉树中的随机叶。诀窍是允许一个值存在于任何内存块中，该内存块位于指定叶和二叉树根之间的路径上。
现在，当我们要查找指针指向的值时，我们在表中查找它的指定叶，并读取根和该叶之间路径上的所有节点。我们正在寻找的价值应该在这条路上，所以我们已经拥有了我们需要的！在没有任何其他信息的情况下，对手看到的只是我们从树上读到一条随机路径。 轻点放大 从树中读取的内容看起来像是一条随机路径，最终包含了我们正在寻找的数据。
但是，我们仍然需要隐藏我们是在读还是在写，并重新随机分配一些内存，以确保此查询不会与将来的其他查询相关联。 所以为了重新随机化，我们将刚读取的指针分配给新叶子，然后将值从存储在其之前的块中移到新叶子和旧叶子的父块中。（在最坏的情况下，我们可以使用根块，因为根是所有内容的父对象。）一旦将值移动到适当的块中，并完成应用程序的使用/修改，我们将对提取的所有块重新加密并将其写回内存。这将把值放在根和它的新叶之间的路径中，同时只改变我们已经获取的内存块。 轻点放大 这个结构很好，因为我们只需要触摸分配给二叉树中单个随机路径的内存，这是相对于内存总大小的对数工作量。但即使我们一次又一次地读同一个值，我们每次都会从树上碰到完全随机的路径！但是，额外的内存查找仍然会导致性能损失，这就是为什么ORAM支持是可选的。</description></item><item><title>云原生架构定义：12因素应用、微服务、自服务、API协作、抗脆弱性</title><link>https://icorer.com/icorer_blog/posts/cloudnative_12_factors/</link><pubDate>Fri, 15 May 2020 14:17:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/cloudnative_12_factors/</guid><description>一. 12因素应用 12因素应用是一系列云原生应用架构的模式集合，最初由Heroku提出。这些模式可以用来说明什么样的应用才是云原生应用。它们关注速度、安全、通过声明式配置扩展、可横向扩展的无状态/无共享进程以及部署环境的整体松耦合。如Cloud Foundry、Heroku和Amazon ElasticBeanstalk都对部署12因素应用进行了专门的优化。
在12因素的背景下，应用（或者叫app）指的是独立可部署单元。组织中经常把一些互相协作的可部署单元称作一个应用。
1.1 代码库# 每个可部署app在版本控制系统中都有一个独立的代码库，可以在不同的环境中部署多个实例。
1.2 依赖# App应该使用适当的工具（如Maven、Bundler、NPM）来对依赖进行显式的声明，而不该在部署环境中隐式的实现依赖。
1.3 配置# 配置或其他随发布环境（如部署、staging、生产）而变更的部分应当作为操作系统级的环境变量注入。
1.4 后端服务# 后端服务，例如数据库、消息代理应视为附加资源，并在所有环境中同等看待。
1.5 编译、发布、运行# 构建一个可部署的app组件并将它与配置绑定，根据这个组件/配置的组合来启动一个或者多个进程，这两个阶段是严格分离的。
1.6 进程# 该app执行一个或者多个无状态进程（例如master/work），它们之间不需要共享任何东西。任何需要的状态都置于后端服务（例如cache、对象存储等）。
1.7 端口绑定# 该应用程序是独立的，并通过端口绑定（包括HTTP）导出任何/所有服务。
1.8 并发# 并发通常通过水平扩展应用程序进程来实现（尽管如果需要的话进程也可以通过内部管理的线程多路复用来实现）。
1.9 可任意处置性# 通过快速迅速启动和优雅的终止进程，可以最大程度上的实现鲁棒性。这些方面允许快速弹性缩放、部署更改和从崩溃中恢复。
1.10 开发/生产平等# 通过保持开发、staging和生产环境尽可能的相同来实现持续交付和部署。
1.11 日志# 不管理日志文件，将日志视为事件流，允许执行环境通过集中式服务收集、聚合、索引和分析事件。
1.12 管理进程# 行政或管理类任务（如数据库迁移），应该在与app长期运行的相同的环境中一次性完成。
这些特性很适合快速部署应用程序，因为它们不需要对将要部署的环境做任何假定。对环境假设能够允许底层云平台使用简单而一致的机制，轻松实现自动化，快速配置新环境，并部署应用。以这种方式，十二因素应用模式能够帮我们优化应用的部署速度。
这些特性也很好地适用于突发需求，或者低成本地“丢弃”应用程序。应用程序环境本身是100％一次性的，因为任何应用程序状态，无论是内存还是持久性，都被提取到后端服务。这允许应用程序以易于自动化的非常简单和弹性的方式进行伸缩。在大多数情况下，底层平台只需将现有环境复制到所需的数目并启动进程。缩容是通过暂停正在运行的进程和删除环境来完成，无需设法地实现备份或以其他方式保存这些环境的状态。就这样，12因素应用模式帮助我们实现规模优化。
最后，应用程序的可处理性使得底层平台能够非常快速地从故障事件中恢复。
此外，将日志作为事件流处理能够极大程度上的增强应用程序运行时底层行为的可见性。
强制环境之间的等同、配置机制的一致性和后端服务管理使云平台能够为应用程序运行时架构的各个方面提供丰富的可见性。以这种方式，十二因素应用模式能够优化安全性。
二. 微服务 微服务将单体业务系统分解为多个“仅做好一件事”的可独立部署的服务。这件事通常代表某项业务能力，或者最小可提供业务价值的“原子“服务单元。
微服务架构通过以下几种方式为速度、安全、可扩展性赋能：
当我们将业务领域分解为可独立部署的有限能力的环境的同时，也将相关的变更周期解耦。只要变更限于单一有限的环境，并且服务继续履行其现有合约，那么这些更改可以独立于与其他业务来进行开展和部署。结果是实现了更频繁和快速的部署，从而实现了持续的价值流动。 通过扩展部署组织本身可以加快部署。由于沟通和协调的开销，添加更多的人，往往会使软件构建变得更加苦难。 弗雷德·布鲁克斯（Fred Brooks，人月神话作者）很多年前就教导我们，在软件项目的晚期增加更多的人力将会时软件项目更加延期。 然而，我们可以通过在有限的环境中构建更多的沙箱，而不是将所有的开发者都放在同一个沙箱中。 由于学习业务领域和现有代码的认知负担减少，并建立了与较小团队的关系，因此我们添加到每个沙箱的新开发人员可以更快速地提高并变得更高效。 可以加快采用新技术的步伐。大型单体应用架构通常与对技术堆栈的长期保证有关。这些保证的存在是为了减轻采用新技术的风险。采用了错误的技术在单体架构中的代价会更高，因为这些错误可能会影响整个企业架构。如果我们可以在单个整体的范围内采用新技术，将隔离并最大限度地降低风险，就像隔离和最小运行时故障的风险一样。 微服务提供独立、高效的服务扩展。单体架构也可以扩展，但要求我们扩展所有组件，而不仅仅是那些负载较重的组件。当且仅当相关联的负载需要它时，微服务才会被缩放。 三. 自服务敏捷架构 使用云原生应用架构的团队通常负责其应用的部署和持续运营。云原生应用的成功采纳者已经为团队提供了自服务平台。
正如我们创建业务能力团队为每个有界的环境构建微服务一样，我们还创建了一个能力小组，负责提供一个部署和运行这些微服务的平台。
这些平台中最大好处是为消费者提供主要的抽象层。通过基础架构即服务（IAAS），我们要求API创建虚拟服务器实例、网络和存储，然后应用各种形式的配置管理和自动化，以使我们的应用程序和支持服务能够运行。现在这种允许我们自定义应用和支持服务的平台正在不断涌现。
应用程序代码简单地以预构建的工件（可能是作为持续交付管道的一部分生成的）或Git远程的原始源代码的形式“推送”。 然后，平台构建应用程序工件，构建应用程序环境，部署应用程序，并启动必要的进程。 团队不必考虑他们的代码在哪里运行或如何到达那里，这些对用户都是透明得，因为平台会关注这些。
这样的模型同样适合于后端服务。需要数据库？ 消息队列或邮件服务器？ 只需要求平台来配合您的需求。平台现在支持各种SQL/NoSQL数据存储、消息队列、搜索引擎、缓存和其他重要的后端服务。这些服务实例然后可以“绑定”到您的应用程序，必要的凭据会自动注入到应用程序的环境中以供其使用。从而消除了大量凌乱而易出错的定制自动化。</description></item><item><title>HTTP/3与HTTP/2的性能比较</title><link>https://icorer.com/icorer_blog/posts/performance_comparison_between_http3_and_http2/</link><pubDate>Thu, 16 Apr 2020 15:17:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/performance_comparison_between_http3_and_http2/</guid><description>这是一篇来自cloudflare公司的博客译文，阐述了一些HTTP3与HTTP2的性能对比。 轻点放大 我们在去年Cloudflare的生日周宣布支持HTTP/3 ，它是HTTP/2的继承者。我们的目标是并且一直是帮助建立一个更好的互联网。在标准方面的合作是其中的一个重要部分，我们很幸运能在这里做到这一点。
尽管HTTP/3仍然处于草稿状态，但我们已经看到了很多用户的兴趣。到目前为止，已经有超过113000个区域激活了HTTP/3，如果您使用的是一个实验性的浏览器，那么可以使用新的协议访问这些区域！看到这么多人启用HTTP/3真是太棒了：通过HTTP/3访问真正的网站意味着浏览器有更多不同的属性可以测试。
当我们启动对HTTP/3的支持时，我们与Google合作，后者同时在Google Chrome中启动了实验性的支持。从那时起，我们看到更多的浏览器增加了实验性的支持：Firefox加入了他们的夜间版本，其他基于Chrome的浏览器，如Opera和Microsoft Edge通过底层Chrome浏览器引擎，Safari通过他们的技术预览。我们密切关注这些开发，并尽可能地与之合作；拥有一个拥有许多启用了HTTP/3的站点的大型网络，为浏览器实现者提供了一个极好的测试平台，可以用来测试代码。
那么，现在的情况如何，我们现在在哪里？# IETF标准化过程将协议开发为一系列文档草稿版本，最终目的是生成一个最终草稿版本，该版本可以标记为RFC。QUIC工作组的成员在分析、实现和互操作规范方面进行协作，以便找到工作不太正常的地方。我们在支持HTTP/3的Draft-23 的情况下启动了它，并一直在跟上每一个新的草案，其中27 是最新的。在每一份草案中，小组都提高了QUIC定义的质量，并更接近于关于其行为方式的“粗略共识”。为了避免永久性的分析瘫痪和无休止的调整，每一个新的草案都增加了对规范提出修改的门槛。这意味着版本之间的更改更小，最终的RFC应该与我们在生产中运行的协议非常匹配。
优点# HTTP/3的主要优点之一是提高了性能，特别是同时获取多个对象。使用HTTP/2，TCP连接中的任何中断（包丢失）都会阻塞所有流（行首阻塞）。因为HTTP/3是基于UDP的，如果一个数据包被丢弃，它只会中断一个流，而不是所有的流。
此外，HTTP/3还提供了0-RTT 支持，这意味着在建立连接时，通过消除来自服务器的TLS确认，后续连接可以更快地启动。这意味着客户端请求数据的速度要比完整的TLS协商快得多，这意味着网站可以更早地开始加载。
下面说明数据包丢失及其影响：HTTP/2多路复用两个请求。一个请求从客户端通过HTTP/2到达服务器，请求两个资源（我们将请求及其相关的响应涂成绿色和黄色）。响应被分成多个包，唉，一个包丢失了，所以两个请求都被延迟了。
轻点放大 轻点放大 上面显示了HTTP/3复用2个请求。一个影响黄色响应的数据包丢失，而绿色的数据包运行良好。
会话启动的改进意味着到服务器的“连接”启动得更快，这意味着浏览器开始更快地查看数据。我们很好奇有多大的进步，所以我们做了一些测试。为了衡量0-RTT支持带来的改进，我们运行了一些基准测试时间到第一字节（TTFB）。平均来说，对于HTTP/3，我们看到的第一个字节出现在176ms之后，而对于HTTP/2，我们看到的是201ms，这意味着HTTP/3的性能已经提高了12.4%！
轻点放大 有趣的是，并不是协议的每一个方面都受草案或RFC的约束。实现选择会影响性能，例如有效的分组传输 和拥塞控制算法的选择。拥塞控制是计算机和服务器用来适应过载网络的一种技术：通过丢弃数据包，传输随后会受到限制。因为QUIC是一种新的协议，要想使拥塞控制设计和实现正确，需要进行实验和调整。
为了提供安全和简单的起点，“丢失检测和拥塞控制”规范建议使用Reno 算法，但允许端点选择他们可能喜欢的任何算法。 我们从New Reno 开始，但我们从经验中知道，我们可以通过其他方式获得更好的性能。 我们最近已迁移到CUBIC，并且在我们的网络中，由于传输量较大且数据包丢失，CUBIC的性能比New Reno有所提高。 请继续关注，以获取更多详细信息。
对于我们现有的HTTP / 2堆栈，我们目前支持BBR v1 （TCP）。 这意味着在我们的测试中，我们没有进行精确的比较，因为这些拥塞控制算法在较小传输和较大传输之间的行为会有所不同。 话虽这么说，与HTTP / 2相比，使用HTTP / 3的小型网站已经有了加速。 对于较大的区域，改进后的HTTP / 2堆栈的拥塞控制在性能上大放异彩。
对于15KB的小测试页，HTTP/3平均需要443ms来加载，而HTTP/2则需要458ms。然而，一旦我们将页面大小增加到1MB，这种优势就消失了：在我们今天的网络上，HTTP/3的速度比HTTP/2稍慢，加载速度为2.33秒，而加载速度为2.30秒。
轻点放大 轻点放大 轻点放大 合成基准很有趣，但是我们想知道HTTP/3在现实世界中的表现。
为了衡量，我们希望第三方可以在我们的网络上加载网站，模仿浏览器。WebPageTest是一个常用的框架，它使用漂亮的瀑布图来度量页面加载时间。为了分析后端，我们使用了 Browser Insights ，以捕获我们的边缘看到的时间。然后，我们用一些自动化技术把这两部分结合在一起。
作为一个测试案例，我们决定使用这个博客 来监控性能。我们配置了分布在世界各地的webgetest实例，以便通过HTTP/2和HTTP/3加载这些站点。我们还启用了HTTP/3和浏览器洞察力。因此，每当我们的测试脚本启动一个网页测试，使用支持HTTP/3的浏览器加载网页时，浏览器分析就会报告数据。冲洗并重复HTTP/2以进行比较。
下图显示了真实页面blog.cloudflare.com 的页面加载时间，以比较HTTP/3和HTTP/2的性能。我们有从不同地理位置运行的这些性能度量。
轻点放大 如您所见，在北美，HTTP / 3性能仍落后于HTTP / 2性能，平均水平约为1-4％，在欧洲，亚洲和南美也看到了类似的结果。 我们怀疑这可能是由于拥塞算法不同所致：BBR v1上的HTTP / 2与CUBIC上的HTTP / 3不同。 将来，我们将努力在两者上支持相同的拥塞算法，以实现更准确的“苹果对苹果”比较。</description></item><item><title>Redis6客户端缓存的相关设计</title><link>https://icorer.com/icorer_blog/posts/related-design-of-redis6-client-cache/</link><pubDate>Mon, 16 Mar 2020 13:15:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/related-design-of-redis6-client-cache/</guid><description>这篇文章翻译自Redis官方博客，这篇文章阐述了Redis6中将如何支持客户端缓存功能。
纽约Redis一天结束了，我于5:30在酒店起床，仍然与意大利时区保持同步，并立即走在曼哈顿的街道上，完全爱上了风景和美好的生活感觉。 但是我在Redis 6发行版中的感觉是，可能是最重要的功能，即新版本的Redis协议（RESP3）的采用曲线将非常缓慢，这是有充分理由的： 明智的人会在没有充分理由的情况下避免使用工具。 毕竟我为什么要这么严重地改进协议？主要有两个原因，即为客户提供更多的语义答复，并开放使用旧协议难以实现的新功能。 对我来说，最重要的功能之一就是客户端缓存。
让我们回到一年前。我来到旧金山的Redis Conf 2018，当时我坚信客户端缓存是Redis未来最重要的事情。 如果我们需要快速存储和高速缓存，那么我们需要在客户端中存储信息的子集。这是对延迟较小且规模较大的数据提供服务的想法的自然扩展。事实上，几乎所有的大公司都已经这样做了，因为这是唯一的生存之道。然而，Redis无法在此过程中协助客户。 一个幸运的巧合希望Ben Malec在Redis Conf上确切地谈论客户端缓存[1]，仅使用Redis提供的工具和许多非常聪明的想法。
轻点放大 [1] https://www.youtube.com/watch?v=kliQLwSikO4 本采取的方法确实打开了我的想象。 Ben为了使他的设计工作而使用了两个关键思想。首先是使用Redis Cluster的“哈希槽”概念，以将key分为16k组。这样，客户端将无需跟踪每个key的有效性，但可以将单个元数据条目用于一组key。Ben使用Pub / Sub来更改键时发送通知，因此他需要应用程序各个部分的帮助，但是该架构非常可靠。 修改key？同时发布一条使它无效的消息。 在客户端，您是否在缓存key？记住缓存每个key的时间戳，并且在接收到无效消息时，还要记住每个插槽的无效时间。 当使用给定的缓存key时，通过检查缓存的key是否具有比该key所属的插槽接收到的失效时间戳更旧的时间戳，来进行懒惰驱逐：在这种情况下，该key是陈旧数据， 必须再次询问服务器。
看完演讲之后，我意识到这是在服务器内部使用的好主意，以便允许Redis为客户端完成部分工作，并让客户端缓存更简单、更有效,所以我回家后,写了一个文档描述设计[2]。
[2] https://groups.google.com/d/msg/redis-db/xfcnYkbutDw/kTwCozpBBwAJ 但是，要使我的设计正常工作，我必须专注于将Redis协议切换到更好的协议，因此我开始编写规范，然后编写RESP3的代码，以及其他Redis 6之类的东西，例如ACL等，并且客户端缓存加入了 由于缺乏时间，我以某种方式放弃了Redis的许多构想的巨大空间。
但是我还是在纽约街头思考这个想法。 后来和会议的朋友一起去吃午餐和喝咖啡休息时间。 当我回到酒店房间时，剩下的整个晚上都是在飞机起飞前的第二天，所以我开始遵循我一年前写给小组的建议，开始编写Redis 6客户端缓存的实现。 看起来仍然很棒。
Redis服务器辅助的客户端缓存，最终称为跟踪(但我可能会改变想法)，是一个非常简单的功能，由几个关键的想法组成。
key空间被划分为“缓存槽”，但它们比Ben使用的哈希槽大得多。 我们使用CRC64输出的24位，因此有超过1600万个不同的插槽。为什么这么多?因为我认为您希望有一个拥有1亿key的服务器，而一条无效消息应该只影响客户端缓存中的几个key。Redis中无效表的内存开销是130mb:一个8字节的数组，指向16M个条目。这对我来说是可以的，如果你想要这个功能，你就要充分利用你在客户端的所有内存，所以使用130MB的服务器端是可以的;您所赢得的是一个更细粒度的失效。
客户端通过简单的命令以opt方式启用该特性：
CLIENT TRACKING on 服务器会回复旧的+ OK，从那一刻开始，命令表中标记为“只读”的每个命令不仅会把键返回给调用者，而且还会产生副作用 客户端到目前为止请求的所有键的缓存插槽（但只有使用只读命令的键才是，这是服务器与客户端之间的协议）。Redis存储此信息的方法很简单。每个Redis客户端都有一个唯一的ID，因此，如果客户端ID 123执行有关将key散列到插槽1、2和5的MGET，我们将获得带有以下条目的无效表：
1 -&amp;gt; [123] 2 -&amp;gt; [123] 5 -&amp;gt; [123] 但是稍后客户端ID 444也会询问插槽5中的key，因此该表将如下所示：
5 -&amp;gt; [123, 444] 现在，其他一些客户端更改了插槽5中的某些key。发生的事情是Redis将检查Invalidation Table，以发现客户端123和444都可能在该插槽上缓存了key。我们将向这两个客户端发送无效消息，因此他们可以自由地以任何形式处理该消息：要么记住上一次插槽无效的时间戳记，然后以懒惰的方式检查时间戳记（或者 如果您更喜欢此渐进式“时期”：它比较安全），然后根据比较结果将其逐出。否则，客户端可以通过获取其在此特定插槽中缓存的内容的表来直接直接回收对象。这种具有24位哈希函数的方法不是问题，因为即使缓存了数千万个key，我们也不会有很长的列表。发送无效消息后，我们可以从无效表中删除条目，这样，我们将不再向这些客户端发送无效消息，直到它们不再读取该插槽的key为止。
请注意，客户端不必真正使用hash函数的所有24位。例如，他们可能只使用20位，然后也会转移Redis发送给他们的无效消息槽。不确定这样做是否有很多好的理由，但在内存受限的系统中可能是一个想法。
如果您严格按照我所说的进行操作，您会认为相同的连接同时接收到正常的客户端响应和无效消息。对于RESP3，这是可能的，因为无效消息是作为“推送”消息类型发送的。 但是，如果客户端是阻塞客户端，而不是事件驱动的客户端，则这将变得很复杂：应用程序需要某种方式不时读取新数据，并且看起来复杂而脆弱。 在这种情况下，最好使用另一个应用程序线程和另一个客户端连接，以便接收无效消息。 因此，您可以执行以下操作：</description></item><item><title>Redis Client Side Cache - Redis客户端缓存 - RedisConf18</title><link>https://icorer.com/icorer_blog/posts/redis-client-side-cache---redis-client-side-cache---redisconf18/</link><pubDate>Sun, 15 Mar 2020 16:22:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/redis-client-side-cache---redis-client-side-cache---redisconf18/</guid><description>一. 背景描述# 客户端缓存是一个有意思的话题，它不是空穴来风的技术，在最新的Redis RC版本已经正式开始着手CSC方案的设计，虽然目前版本的CSC还不能真正的商用，但是市面上也有一些其他公司开始着手试探CSC相关方案的设计与实现。
目标比较有名的模型是两种：
Ben Malec paylocity公司方案 Redis6 RC方案 这两种方案并不是独立的，他们各有各的优势，paylocity公司的方案被redis团队所赞赏，并吸收了一些思路进入Redis RC版本中，Redis RC版本主要是提供了一些server端的协助，但是本质上还是没有完整的CSC方案。
二. RedisConf2018大会 Ben Malec分享# 这里，我们将阐述RedisConf 2018年的经典分享，这个分享围绕CSC机制的相关设计与实现，并且方案已经被广泛使用在paylocity公司，有很高的的借鉴意义。 轻点放大 轻点放大 Ben Malec的分享主要围绕如何实现一个和Redis缓存同步的本地内存缓存。
首先，我们看一下简单的网站模型，模型图如下：
轻点放大 接着，Ben提出很重要的缓存象限，缓存象限图如下所示：
轻点放大 缓存最好的应用场景就是针对更改少、请求频繁的数据读写场景。
轻点放大 客户端缓存，首先需要面对的问题就是 “缓存数据滞后”
轻点放大 这部分演讲，Ben发散思维了所有Web服务器尝使用的“文件系统观察”功能。
随后，客户端缓存会出现“跨服务器缓存数据不一致”问题。
轻点放大 这种问题并不是只会在不同的机器间出现，还会在同一台机器不同进程中出现。
比如在两台机器针对缓存都设置了相同的TTL生命期，但是由于机器间时间可能不同步，从而造成缓存不一致情况。更坏的情况就是，数据已经更新了，但是客户端缓存没办法及时更新，造成用户请求到旧的数据，如果再多台机器负载的情况下，极有可能出现一会新值、一会旧值得问题，这种飘忽不定的缓存返回会造成用户较差的使用体验。
接下来，Ben提出一个很重要的时间观点，服务器间想在大约相同的时间内更新相关的key，这个大约相同的时间证明这个缓存方案并不一定能够满足分布式强一致，只是在合理的时间范围内数据一致。
接下来，Ben提出第三个缓存问题，“缓存踩踏”问题
轻点放大 这里所说的就是如果自己完全制作一个进程内缓存，有很多需要考虑，比如启动数据加载，数据池的备份，服务器扩容过程，等等问题。
轻点放大 Redis可以提供简单的缓存解决方案。
Redis缓存可以很好地解决缓存一致性问题，也可以解决缓存数据滞后问题，也不会有数据践踏。
轻点放大 但是redis也有一些其他问题，比如每次缓存获取都需要tcp往返通信，虽然redis已经很快了，但是本地内存的访问速度仍然比网络io速度高太多。
轻点放大 这里，Ben提出如果在redis基础上，再增加进程内缓存，效果就会更好了。
轻点放大 针对这种本地缓存方案，首先提出了三个需要做的事情：
解决数据一致性问题 解决数据滞后问题，主要围绕进程内缓存和远程redis之间的滞后问题 不要让网络爆炸，要控制合理的网络通信 轻点放大 借助redis，我们是不是可以更好的实现这个功能呢？
轻点放大 轻点放大 上面这部分讲述了一个问题，如果我们想让机器间的数据保证一致性，如果仅仅通过广播变更的key-value，这将是致命的，因为大量的key-value将引爆网络，还有一个原因就是你广播了key-value数据，并不是所有的节点以后都会使用，这就会造成效率问题，这些问题几乎都是围绕网络，但是还没考虑网络的质量问题，比如网络质量很差的情况下，节点可能收到多组不同的改动，这些改动可能会数据践踏，但是你不知道践踏的顺序，从而造成数据的不一致问题。
轻点放大 因此，我们并不是广播key-value，而是只广播key，但是你也知道redis支持key数据，最大可以达到512MB，就算不是512MB，就算是1kb的数据，我们的网络就能抗住吗，所以简单的广播key是不理智的。
轻点放大 redis集群中采用hash槽位来进行数据分片，那么我们是否可以借鉴这种思路呢？我们不再广播key，而是广播key所计算的hash值，这样如果key的数据多么大，我们都能控制在网络上传输的数据大小。
轻点放大 我们放弃了广播key，而选择同步16bit的key hash槽数据，这样操作的优势明显，首先广播数据的大小被控制了，并且解决了数据一致性问题，我们只是广播hash，并没有广播数据，当某个hash出现了脏数据，它将会在下次访问时被感知并被更新。这个也有一点缺陷需要注意，因为我们借助了hash槽位，所以一个hash slot上会包含很多key，这些key中的一个被更新，则这组hash slot都将失效。
计算遍历所有的 key 吗？命中脏 slots 的话，就删除这个key？但是这样的话相当于对每一个缓存更新操作，客户端都要遍历计算一遍自己所有 key 的 slot，显然是不可接受的。</description></item><item><title>Go的垃圾收集者之旅 [Getting to Go: The Journey of Go's Garbage Collector]</title><link>https://icorer.com/icorer_blog/posts/getting-to-go-the-journey-of-gos-garbage-collector/</link><pubDate>Thu, 12 Mar 2020 13:21:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/getting-to-go-the-journey-of-gos-garbage-collector/</guid><description>一 . 背景介绍# 这篇文章是一片演讲笔记，这是Richard L. Hudson于2018.06.18在国际内存管理研讨会(ISMM)上的演讲。
理查德·哈德森（Rick）因其在内存管理方面的工作而闻名，其中包括发明了Train，Sapphire和Mississippi Delta算法以及GC堆栈映射，这些算法能够以静态类型的语言（例如Modula-3，Java）进行垃圾收集 ，C＃和Go。 Rick目前是Google Go团队的成员，他致力于Go的垃圾回收和运行时问题。
Original URL : https://blog.golang.org/ismmkeynote 二. 演讲内容# 轻点放大 在我们正式研究这些东西之前，我们首先需要展示一下GC在Go中看着像什么？
轻点放大 首先，Go程序有成千上万个堆栈，他们被Go调度器管理着并且总是在GC安全点被抢占。Go调度器将Go协程多路复用到系统线程上，希望每一个物理线程运行一个系统线程。我们通过复制堆栈和修改栈指针来管理栈及其大小。因为这些是本地操作所以很容易扩展。
轻点放大 接下来，我们需要讨论一个重要的内容，和传统C系统语言类似、Go也是一种“值定向”语言，而不是类似众多runtime管理型语言的“参考导向”语言。正如上面的例子展示了tar包中某一个类型如何在内存中布局存储，所有的字段均直接内嵌在Reader变量中。这使程序员可以在需要的时候更好的控制内存布局。可以把有关联值的字段进行临近分配，这样的策略有利于提高缓存的存储位置。
以值为导向有助于使用外部功能接口(有助于不同语言之间通信)，Go语言和C/C++语言能够很快的FFI (语言交互接口 ) 操作，谷歌内部有大量可用的功能、但是他们使用C++编写的。Go语言迫不及待的实现这些功能，因此Go必须使用外部功能访问接口来实现这些功能。
基于这个设计上的决定导致Go运行时必须执行一些惊人的东西，这些可能是Go和其他带有GC的计算机语言最重要的不同之处。
轻点放大 Go语言当然会有指针的存在，但是事实上Go甚至可以有内部指针[ interior pointer ]。这些指针可以让数据的整体具有活性，而且他们很常见。
轻点放大 Go语言有一套完善的预编译系统，从而一个单独的二进制运行体文件就可以包含完整的运行时环境。
运行时也不需要JIT热点重新编译，这有优点也有缺点。首先，这种模式下程序执行的可重现性要容易很多，这使得编译器改进的步伐变得更快。
可悲的是，我们没有机会像使用JITed系统那样可以反馈优化。因此，静态预编译存在上述优缺点。
轻点放大 Go 提供了两个旋钮用来控制GC。第一个是GCPercent，这个旋钮基本上是用来调整要使用的CPU和内存的数量，默认值为100、代表一半的堆专用于活动内存、一半的堆用来分配。当然，你可以按照你需要的比例方向就行旋钮调整。
最大堆，这个属性目前尚未发布、但已经在内部使用和评估了，这个参数允许编程人员控制最大的堆使用空间。内存不足、内存溢出(OOM)、在Go语言上很难；暂时的内存使用高峰应该通过增加CPU成本来解决，不是通过终止程序。基本上，如果GC遇到了内存压力，它应该通知应用程序应该减轻负载。当一切恢复正常之后，GC会通知应用程序让其恢复到正常负载。最大堆特性还为调度提供更多的灵活性。运行时不必总是对可用的内存量有多大的幻想，而是可以将堆的大小调整为最大堆的大小。
这结束了我们对垃圾回收器很重要的Go片段的讨论。
轻点放大 现在让我们来谈谈Go语言运行时以及我们如何到达这里，如何达到自己所在的位置。这句话是演讲者想表达Go运行时GC是如何一路发展的。
轻点放大 2014年，毫无疑问、如果Go不能以某种方式解决GC延迟问题，则Go是不会成功的。
其他新语言也会遇到同样的问题。Rust之类的语言采用了不通的解决方式，但是这里我们将讲述Go所走的道路。
为什么延迟如此的重要？
轻点放大 延迟是个累积量，数学对此是不能完全解释的。
99%的隔离式GC延迟服务级别目标(SLO)，例如 99% 的GC周期小于10ms，只是根本无法扩展。重要的是整个会话期间的延迟或一天中多次使用程序的延迟（这里表达的含义是：单次GC看着不重，但是无论对于单次长会话、还是长期运行的程序体，这会产生累计损害）。假设浏览一个网页的会话在一个会话中最终发出100个服务器请求，或者发出20个请求，并且一天中您有5个会话。 在这种情况下，只有37％的用户将在整个会话中获得一致的10毫秒以下体验。
正如我们所建议的那样，如果您希望这些用户中有99％的用户具有10ms以下的体验，则数学计算表明您确实需要定位4个9s或99.99％ile。
所以是2014年，杰夫·迪恩（Jeff Dean）发表了他的论文《The Tail at Scale》(规模的尾巴)，进一步探讨了这一问题。 由于它对Google的向前发展和试图以Google规模扩展产生严重影响，因此在Google周围被广泛阅读。
我们称这个问题为9s暴政。
轻点放大 那么，我们是如何对抗这场“暴政”的呢？
我们在2014年做了不少事情。
如果您想要10个答案，请再输入几个，然后选择前10个，这些就是您在搜索页面上输入的答案。如果请求超过50％ile，则重新发出请求或将请求转发到另一台服务器。 如果GC将要运行，请拒绝新请求或将请求转发到另一台服务器，直到完成GC。 依此类推。这段文字讲述的是类似负载均衡模式降低系统整体的响应时间。
所有这些变通办法来自非常聪明的人，他们有非常实际的问题，但他们没有解决GC延迟的根本问题。 在Google规模上，我们必须解决根本问题。 为什么？</description></item><item><title>Linux内核-内存管理: Out Of Memory Management 源码分析</title><link>https://icorer.com/icorer_blog/posts/linux-kernel-memory-management-out-of-memory-management-source-code-analysis/</link><pubDate>Sun, 08 Mar 2020 11:45:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/linux-kernel-memory-management-out-of-memory-management-source-code-analysis/</guid><description>我们这篇文章 中描述了Linux内核对于 Out Of Memory Management 场景下的相关策略，接下来我们将进行Linux 5.0内核的OOM内核源码分析。
一. 关键数据结构# 针对源码部分，我们首先需要阐述oom_kill部分的核心数据结构。
文件路径：/linux/include/linux/oom.h
1.1 oom_control 结构体# 首先，我们给出具体的内核定义：
/* * Details of the page allocation that triggered the oom killer that are used to * determine what should be killed. */ struct oom_control { /* Used to determine cpuset */ struct zonelist *zonelist; /* Used to determine mempolicy */ nodemask_t *nodemask; /* Memory cgroup in which oom is invoked, or NULL for global oom */ struct mem_cgroup *memcg; /* Used to determine cpuset and node locality requirement */ const gfp_t gfp_mask; /* * order == -1 means the oom kill is required by sysrq, otherwise only * for display purposes.</description></item><item><title>Linux内核-内存管理: Out Of Memory Management - OOM</title><link>https://icorer.com/icorer_blog/posts/linux-kernel-memory-management-out-of-memory-management---oom/</link><pubDate>Sat, 07 Mar 2020 11:49:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/linux-kernel-memory-management-out-of-memory-management---oom/</guid><description>一. 引言# 这篇文章，我们将要讨论的是内存不足(OOM)管理器，OOM检查是否有足够的可用内存来满足系统运行需求，如果没有足够的可用内存则进行进程kill操作。这是Linux内核虚拟内存模块中一个有争议的部分，有人建议在很多情况下删除它。所以在使用OOM的时候，首先需要确认OOM是否在待操作的Linux内核中存在，还需要确定OOM在Linux内核中的开启与关闭选项。
二. 检查可用内存（Checking Available Memory）# 对于某些操作，例如使用brk()扩展堆或使用mremap()重新映射地址空间，系统将检查是否有足够的可用内存来满足请求。请注意，这与当前文章后面介绍的out_of_memory()是不同部分，Linux内核的内存分配机制和内存可用度检查用于尽可能避免系统处于OOM状态。
检查可用内存时，所需的页数作为参数传递给vm_enough_memory()。除非系统管理员指定系统应超量使用内存，否则将检查可用内存的装载。为了确定有多少页面是可用的，Linux总结了以下数据位：
Total page cache (总页面缓存)：页面缓存很容易回收。 Total free pages (总空闲页面)：总可用页面，它们已经可用。 Total free swap pages(总自由交换页) ：用户空间页面可能会被换出。 Total pages managed by swapper_space(由swapper_space管理的总页面)： 尽管这将重复计算空闲交换页面。这是平衡某些情况，此选项有时保留但不使用。 Total pages used by the dentry cache(dentry缓存使用的总页面)： 这部分内存很容易被回收，主要用于vfs Total pages used by the inode cache (inode缓存使用的总页面)： 这部分内存很容易被回收，主要用于vfs-inode索引 如果在此处添加的页面总数足以满足请求，则vm_enough_memory() 将true返回给调用方。 如果返回false，则调用者知道该内存不可用，通常决定将-ENOMEM返回给用户空间。
三. 确定OOM状态（Determining OOM Status）# 当机器内存不足时，将回收旧的页面框架，但是尽管回收了页面，但仍可能发现即使以最高优先级进行扫描，也无法释放足够的页面来满足请求。如果无法释放页帧，则会调用out_of_memory() 以查看系统是否内存不足，是否需要终止进程。 轻点放大 不幸的是，系统可能没有内存不足，只需要等待IO完成或页面交换到外部存储。不幸的是，这不是因为系统具有内存，而是因为这个函数被不必要地调用，导致不必要地关闭进程。在决定终止一个进程之前，它要经过以下检查表。
是否还有足够的交换空间(nr_swap_pages&amp;gt; 0) ？如果是，则不进行OOM 从上次失败到现在已经超过5秒了吗?如果是，则不进行OOM 我们在最后一秒失败了吗?如果没有，则不进行OOM 如果在过去5秒内没有10次失败，就不进行OOM 最近5秒钟内进程是否被杀死？ 如果是，则不进行OOM 四. 选择一个进程（Selecting a Process）# 函数select_bad_process()负责选择要终止的进程。它通过逐步执行每个正在运行的任务并计算使用badness()函数杀死它的适合程度来做出决定。坏度的计算方法如下，请注意，平方根是使用int_sqrt()计算的整数近似值。
badness_for_task = total_vm_for_task / (sqrt(cpu_time_in_seconds) * sqrt(sqrt(cpu_time_in_minutes))) 这个公式是为了选择一个使用大量内存但寿命不是很长的进程。已经运行了很长时间的进程不太可能是导致内存不足的原因，因此这个计算可能会选择一个使用了大量内存但没有运行很长时间的进程。如果该进程是根进程或具有CAP_SYS_ADMIN功能，则将坏度值除以4，因为假定根特权进程表现良好。类似地，如果它具有CAP_SYS_RAWIO功能(访问原始设备)特权，则坏度值进一步除以4，因为不希望杀死一个直接访问硬件的进程。</description></item><item><title>PHP-rdkafka 内核扩展相关源码分析</title><link>https://icorer.com/icorer_blog/posts/php-rdkafka-kernel-extension-related-source-code-analysis/</link><pubDate>Fri, 06 Mar 2020 12:41:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/php-rdkafka-kernel-extension-related-source-code-analysis/</guid><description>这篇文章主要针对PHP生态的的kafka组件 php-rdkafka 进行相关的内核源码分析，方便大家把握组件的相关使用，目前文章主要针对kafka生产者部分。
一. 样例PHP代码# public function __construct($config) { $conf = new \RdKafka\Conf(); $conf-&amp;gt;set(&amp;#39;metadata.broker.list&amp;#39;, $config[&amp;#39;brokerList&amp;#39;]); $conf-&amp;gt;set(&amp;#39;message.max.bytes&amp;#39;, $config[&amp;#39;messageMaxBytes&amp;#39;]); $conf-&amp;gt;set(&amp;#39;metadata.request.timeout.ms&amp;#39;, $config[&amp;#39;requestTimeout&amp;#39;]); $conf-&amp;gt;set(&amp;#39;session.timeout.ms&amp;#39;, $config[&amp;#39;sessionTimeout&amp;#39;]); $this-&amp;gt;producer = new \RdKafka\Producer($conf); $this-&amp;gt;producer-&amp;gt;addBrokers($config[&amp;#39;brokerList&amp;#39;]); } public function sendMessage($data){ $result = 1; $topic = $this-&amp;gt;producer-&amp;gt;newTopic($data[0][&amp;#39;topic&amp;#39;]); $topic-&amp;gt;produce(RD_KAFKA_PARTITION_UA, 0, $data[0][&amp;#39;value&amp;#39;]); $this-&amp;gt;producer-&amp;gt;poll(0); for ($flushRetries = 0; $flushRetries &amp;lt; 10; $flushRetries++) { $result = $this-&amp;gt;producer-&amp;gt;flush(10000); if (RD_KAFKA_RESP_ERR_NO_ERROR === $result) { break; } } if (RD_KAFKA_RESP_ERR_NO_ERROR !== $result) { throw new \RuntimeException(&amp;#39;Was unable to flush, messages might be lost!</description></item><item><title>Redis哨兵-官方文档翻译</title><link>https://icorer.com/icorer_blog/posts/redis-sentinel---official-document-translation/</link><pubDate>Mon, 24 Feb 2020 22:36:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/redis-sentinel---official-document-translation/</guid><description>Sentinel概述# Redis Sentinel为Redis提供高可用性。实际上，这意味着使用&amp;quot;哨兵&amp;quot;可以创建一个不需要人工干预就能抵抗某些类型失败的Redis部署。
Redis Sentinel还提供其他附属任务，如监控、通知和为客户提供配置。
这是宏观上（即全局）Sentinel功能的完整列表：
监视：Sentinel会不断检查你的主实例和副本实例是否按预期工作。 通知：Sentinel可以通过API通知系统管理员或其他计算机程序，其中一个被监控的Redis实例出了问题。 自动故障转移：如果一个主服务器没有按照预期工作，Sentinel可以启动一个故障转移过程，其中一个副本被提升到主服务器，其他附加的副本被重新配置以使用新的主服务器，使用Redis服务器的应用程序在连接时被告知要使用的新地址。 组态设定提供者：Sentinel充当客户端服务发现的授权来源：客户端连接到Sentinels，以询问负责给定服务的当前Redis主服务器的地址。 如果发生故障转移，Sentinels将报告新地址。 Sentinel的分布式性质# Redis Sentinel是一个分布式系统：
哨兵本身被设计成在一个有多个协作的哨兵进程的配置中运行。有多个哨兵进程协作的好处如下:
当多个哨兵一致认为某个主节点不再可用时，就会执行故障检测。这降低了误报的概率。 即使不是所有的哨兵进程都在工作，哨兵也能工作，这使得系统对故障具有健壮性。毕竟，拥有一个本身就是单点故障的故障转移系统是毫无乐趣的。 哨兵、Redis实例(主实例和副本实例)和连接到哨兵和Redis的客户机的所有组成部分是一个更大的具有特定属性的分布式系统。在本文档中，将逐步介绍概念，从为了理解Sentinel的基本属性所需的基本信息，到为了理解哨兵的工作原理的更复杂的信息（可选）。
快速入门# 获得哨兵# 当前版本的Sentinel称为Sentinel 2。它是对最初的哨兵实现的重写，使用了更强大、更简单的预测算法(在本文档中有解释)。
自Redis 2.8起已发布稳定版本的Redis Sentinel。
在不稳定分支中进行了新的开发，并且有时新功能一旦被认为是稳定的，便会立即移植回最新的稳定分支。
Redis Sentinel版本1(随Redis 2.6一起发布)是不推荐使用的。
运行哨兵# 如果您正在使用redis-sentinel可执行文件(或者如果您有一个与redis-server可执行文件同名的符号链接)，您可以使用以下命令行运行Sentinel：
redis-sentinel /path/to/sentinel.conf 否则，您可以直接使用redis-server可执行文件以Sentinel模式启动它：
redis-server /path/to/sentinel.conf --sentinel 这两种方法的工作方式相同。
但是，在运行Sentinel时必须使用一个配置文件，因为系统会使用这个文件来保存在重新启动时要重新载入的当前状态。如果没有配置文件，或者配置文件路径不可写，Sentinel将拒绝启动。
哨兵默认情况下会监听TCP端口26379的连接，因此，为了使哨兵正常工作，必须打开服务器的端口26379，以接收来自其他哨兵实例的IP地址的连接。 否则，哨兵无法讨论也不能就该做什么达成共识，因此将永远不会执行故障转移。
部署哨兵前需要了解的基本内容# 一个健壮的部署至少需要三个Sentinel实例。 应将三个哨兵实例放置到被认为以独立方式发生故障的计算机或虚拟机中。例如在不同的可用区域上执行的不同物理服务器或虚拟机。 Sentinel + Redis分布式系统不保证在故障期间保留已确认的写入，因为Redis使用异步复制。但是，有一些部署Sentinel的方法使窗口丢失写入仅限于某些时刻，而还有其他一些不太安全的方法来部署它。 您的客户需要Sentinel支持。 流行的客户端库具有Sentinel支持，但不是全部。 如果您不经常在开发环境中进行测试，那么就没有HA设置是安全的，如果您可以在生产环境中进行测试，如果它们能够工作，那就更好了。你可能有一个错误的配置，只有当它变得太晚(凌晨3点当master停止工作)才会变得明显。 Sentinel，Docker或其他形式的网络地址转换或端口映射应该小心混合：Docker执行端口重新映射，破坏了其他Sentinel进程的Sentinel自动发现以及主数据库的副本列表。有关更多信息，请参阅本文档后面有关Sentinel和Docker的部分。 配置哨兵# edis源发行版包含一个名为Sentinel .conf的文件，它是一个自文档化的示例配置文件，您可以使用它来配置Sentinel，但是典型的最小配置文件，如下所示：
sentinel monitor mymaster 127.0.0.1 6379 2 sentinel down-after-milliseconds mymaster 60000 sentinel failover-timeout mymaster 180000 sentinel parallel-syncs mymaster 1 sentinel monitor resque 192.</description></item><item><title>MKV-高性能分布式内存KV-开篇</title><link>https://icorer.com/icorer_blog/posts/mkv-high-performance-distributed-memory-kv-opening/</link><pubDate>Wed, 19 Feb 2020 11:43:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/mkv-high-performance-distributed-memory-kv-opening/</guid><description>一. 背景描述# 目前缓存环境中，使用较多的是Redis缓存，但是Redis单线程机制，在特高并发场景中还是能达到吞吐瓶颈，又由于很多大数据应用场景需要单次GET 1000或者更多的key，所以直接打到Redis服务器上，很容易让Redis主线程出现阻塞情况，产生吞吐大大下降的情况。
在这样的情况下，我们就设想架构设计一个分布式内存的缓存系统（MKV），主要设计目标包括一下：
多线程机制保障多核使用，提高云服务器的CPU使用率。 实现高性能、并发安全、存储具备数据完整性的内存缓存存储，支撑单次1000以上的key获取操作。 支持Redis-RESP应用层协议，由于大部分业务方使用redis缓存，尽量避免缓存切换带来的系统调整成本。 服务可用性达到99.99% 支持分布式场景不是和使用。 等等。。。 二. 模型试验# 由于团队一直在研究Redis内核及其通信协议，因此我们首先需要对多线程版本的缓存MKV 进行模型实验，证明猜想的有效性。
于是，我们分别针对官方Redis内核 和 我们目前的多线程版本缓存KV组件 - MKV进行性能测试对比。
2.1 测试环境# 我们的测试在下面的环境中进行：
Linux 5.0.0 Kernel Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz [4核] 16GB内存 单次请求 ：1000 个key 使用Redis官方 redis-benchmark 工具进行压测 2.2 Redis 官方版本压测【SET: 85w/s GET: 105w/s 】# redis-benchmark -p 6379 -t get -n 5000000 -P 1000 -c 10 压测结果如下：
====== SET ====== 10000000 requests completed in 11.75 seconds 10 parallel clients 3 bytes payload keep alive: 1 0.</description></item><item><title>LibCurl连接复用原理</title><link>https://icorer.com/icorer_blog/posts/libcurl-connection-multiplexing-principle/</link><pubDate>Fri, 14 Feb 2020 13:35:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/libcurl-connection-multiplexing-principle/</guid><description>一. 背景描述# Curl是计算机中使用最多的网络请求工具，很多开源项目在内核中对于HTTP、FTP的操作是通过libcurl库获得的技术支持。这篇文章主要调研libcurl库中的TCP连接复用部分。
二. 连接池# Libcurl针对tcp连接采用了连接池管理，一次传输完成后，它将在“连接池”（有时也称为连接缓存）中保持N个连接处于活动状态，以便恰好能够重用现有连接之一的后续传输可以使用它而不是创建一个新连接。
重用一个连接而不是创建一个新的连接在速度和所需资源方面提供了显著的好处。
当libcurl准备建立一个新的连接来进行传输时，它首先会检查池中是否有可以重用的现有连接。**连接重用检查是在使用任何DNS或其他名称解析机制之前完成的，因此它完全基于主机名。**如果已经存在到正确主机名的实时连接，则还将检查许多其他属性（端口号，协议等），以确保可以使用它。
三. 连接池场景# Libcurl 几乎在所有的实现场景中都自动加入了连接池支持，主要的场景包括以下三种：
Easy API pool Multi API pool Sharing the &amp;ldquo;connection cache&amp;rdquo; 3.1 Easy API pool# 当您使用easy API，或更具体地说，使用curl_easy_perform()时，libcurl将使该池与特定的easy句柄关联。 然后重用同一简单句柄将确保它可以重用其连接。
3.2 Multi API pool# 当您使用multi API时，连接池将与multi句柄相关联。这允许您自由地清理和重新创建easy句柄，而不会有丢失连接池的风险，并且允许一个easy句柄使用的连接在以后的传输中被另一个简单句柄重用。只需重用multi句柄。
3.3 Sharing the &amp;ldquo;connection cache&amp;rdquo;# 从libcurl 7.57.0开始，应用程序可以使用 share interface ，以使其他独立的传输共享同一连接池。
四. Curl-TCP长连接和DNS解析的关系# libcurl具有自己的内部DNS缓存，默认情况下它将在其中缓存解析的地址60秒（此选项可以更改） 。因此具有相同名称的后续解析将使用该时间范围内的缓存结果。
curl的连接缓存完全基于URL中使用的主机名，因此，如果缓存中已有与“ example.com”的可用连接，则该连接将用于对同一主机名的后续请求。 curl既不知道也不关心该名称的IP地址是什么，或者自连接启动以来它是否更改。 重用连接时，它将跳过整个dns解析阶段。
传输完成且连接仍然处于活动状态时，将把连接放回连接缓存中(或者，如果由于达到了限制而认为缓存已满，则关闭连接)。
由于连接重用是基于名称完成的，因此使用另一个名称解析为现有连接的相同IP不会使curl重复使用该连接。 它将解析名称并为此创建一个新的连接。
一个连接可以无限期地保留在连接缓存中，除非它被杀死以腾出空间或被重用。 如果它“死了”（由于它从另一端关闭），则当它被注意到时，它将最终从缓存中删除。
HTTP/2
可以通过HTTP/2发送的PING帧不会在连接缓存中处理(atm)连接，这将导致它们很快被服务器杀死。(libcurl 7.62.0添加了一个新的API，允许应用程序保持这样的连接，参见curl_easy_upkeep)
DoH
随着curl 7.62.0引入了DoH (dn -over- https)支持，DNS缓存将缓存TTL秒数的名称，而不仅仅是使用默认的60秒。
四. 重点总结# Libcurl连接重用检查是在使用任何DNS或其他名称解析机制之前完成的，因此它完全基于主机名。当libcurl的池中已经有了到主机名的活动连接时，它会跳过名称解析，而是直接进行重用。 libcurl长连接 和 dns请求没有相关关系，因此原生的libcurl库并不能对于dns解析变化有很好的的感知过程。 五.</description></item><item><title>LibCurl-DNS超时参数解析</title><link>https://icorer.com/icorer_blog/posts/libcurl-dns-timeout-parameter-analysis/</link><pubDate>Fri, 14 Feb 2020 12:07:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/libcurl-dns-timeout-parameter-analysis/</guid><description>一. 名称# CURLOPT_DNS_CACHE_TIMEOUT - 设置DNS缓存条目的生存时间
二. 摘要# #include &amp;lt;curl/curl.h&amp;gt; CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DNS_CACHE_TIMEOUT, long age); 三. 描述# 传递一个long类型参数，这会设置超时时间(以秒为单位)。名称解析将保存在内存中，并使用此秒数。设置为0将完全禁用缓存，或设置为-1使缓存的条目永远保持不变。默认情况下，libcurl缓存该信息60秒。
除非明确告知（例如，通过调用res_init（3）），否则各种libc实现的名称解析功能都不会重新读取名称服务器信息。这可能会导致libcurl继续使用旧的服务器，即使DHCP已经更新了服务器信息，对于一般的libcurl-app用户来说，这可能是一个DNS缓存问题。
请注意，DNS条目具有“ TTL”属性，但libcurl不使用该属性。 DNS缓存超时完全是推测性的，一个名称将在未来的一小段时间内解析为相同的地址。
默认值# 60
协议# ALL
样例# CURL *curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, &amp;#34;http://example.com/foo.bin&amp;#34;); /* only reuse addresses for a very short time */ curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, 2L); ret = curl_easy_perform(curl); /* in this second request, the cache will not be used if more than two seconds have passed since the previous name resolve */ ret = curl_easy_perform(curl); curl_easy_cleanup(curl); } 可用性# Always</description></item><item><title>Go 十年</title><link>https://icorer.com/icorer_blog/posts/ten-years-of-go/</link><pubDate>Tue, 24 Dec 2019 13:18:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/ten-years-of-go/</guid><description>Russ Cox，代表Go团队
2019年11月8日
Happy birthday, Go!
这个周末，我们庆祝Go发布10周年，庆祝Go作为一种开源编程语言和构建现代网络软件的生态系统的10周年。
为了纪念这一时刻，Go gopher的创始人蕾妮·弗兰奇描绘了这一令人愉快的场景:
轻点放大 庆祝Go十周年让我回想起2009年11月上旬，那时我们正准备与世界分享Go。 我们不知道会有什么样的反应，也不知道是否有人会关心这种小小的语言。我希望，即使没有人最终使用Go，我们至少也会注意到一些好的想法，特别是Go的并发性和接口方法，它们可能会影响后续语言。
当人们对Go感到兴奋的时候，我研究了流行语言的历史，比如C、C++、Perl、Python和Ruby，考察了它们被广泛采用所花的时间。例如，在我看来，Perl似乎在上世纪90年代中后期就已经完全成形了，有了CGI脚本和web，但它是在1987年首次发布的。这一模式几乎适用于我所研究的每一种语言:一种新的语言要真正起飞，似乎需要大约十年的安静、稳定的改进和传播。
我在想:十年后会是什么样子?
今天，我们可以回答这个问题:Go无处不在，全世界至少有一百万开发者在使用它。
Go最初的目标是网络系统基础设施，也就是我们现在所说的云软件。如今，每个主要的云提供商都使用用Go编写的核心云基础设施，如Docker、Etcd、Istio、Kubernetes、Prometheus和Terraform;云计算基金会的大多数项目都是用Go编写的。无数的公司也在使用Go将他们自己的工作转移到云上，从从无到有的创业公司到现代化软件栈的企业。Go的应用范围也远远超出了它最初的云目标，从使用GoBot和TinyGo来控制微型嵌入式系统，到使用GRAIL进行大规模的大数据分析和机器学习来检测癌症，以及两者之间的一切。
所有这一切都说明，Go的成功超乎我们的想象。Go的成功不仅仅在于语言。它是关于语言，生态系统，特别是社区的合作。
在2009年，该语言是一个不错的主意，并带有一个实现的工作草图。 go命令不存在：我们运行了诸如6g的命令进行编译，并运行了6l的命令来链接二进制文件，这些命令使用makefiles自动执行。 我们在语句末尾键入分号。 整个程序在垃圾回收期间停止，然后努力利用两个内核。 Go只能在Linux和Mac，32位和64位x86和32位ARM上运行。
在过去的十年里，在全球Go开发人员的帮助下，我们已经将这个想法和草图发展成为一种富有成效的语言，它具有出色的工具、高质量的产品实现、最先进的垃圾收集器以及12个操作系统和10个体系结构支持。
任何编程语言都需要蓬勃发展的生态系统的支持。 开源版本是该生态系统的种子，但是从那时起，许多人贡献了自己的时间和才干，用出色的教程，书籍，课程，博客文章，播客，工具，集成以及可重复使用的Go来填充Go生态系统。 可通过go get导入的软件包。 没有这个生态系统的支持，Go永远不可能成功。
当然，生态系统需要蓬勃发展的社区的支持。 在2019年，全球有数十个Go会议，以及超过90个成员超过150个Go会议团体。GoBridge和Going Who Go通过指导，培训和会议奖学金帮助将新的声音带入Go社区。仅今年一年，他们就在社区成员教授和指导新加入者的研讨会上，教育了数百名来自传统代表性不足群体的人。
全球有超过一百万的Go开发人员，全球各地的公司都在寻求雇用更多的人。 实际上，人们经常告诉我们，学习Go帮助他们获得了技术行业的第一份工作。 最后，我们为Go感到最自豪的不是设计完善的功能或巧妙的代码，而是Go在这么多人的生活中产生的积极影响。我们的目标是创造一种语言，帮助我们成为更好的开发人员，我们很高兴Go帮助了这么多人。
作为＃GoTurns10，我希望每个人都花一点时间来庆祝Go社区以及我们所取得的一切。 代表Google的整个Go团队，感谢过去十年来加入我们的每个人。 让下一个更不可思议！
Original URL : https://blog.golang.org/10years</description></item><item><title>Curl-VS-Guzzle 性能测试</title><link>https://icorer.com/icorer_blog/posts/curl-vs-guzzle-performance-test/</link><pubDate>Fri, 22 Feb 2019 13:40:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/curl-vs-guzzle-performance-test/</guid><description>Curl-VS-Guzzle 性能测试 这里项目围绕Curl 和 Guzzle这两个HTTP请求组件进行一些压力测试,看一下性能差距.我们围绕两个组件的连接复用情况来测试.(文章中会强调opcache的作用)
一. 测试阐述# 测试curl和guzzle在连接复用情况下的性能差别 (guzzle不开启opcache) 测试curl和guzzle在连接复用情况下的性能差别 (guzzle开启opcache) 二. 性能测试过程# 2.1 测试条件# 在相同的Nginx,PHP,LibCurl库环境 测试脚本包含curl对象的复用,每次测试请求执行10次外部http请求 2.2 Guzzle测试代码 # //GuzzleClient.php use \GuzzleHttp\Client; class GuzzleClient { protected static $guzzleClientConnection = null; public static function getGuzzleClient($baseUrl, $persistent = true) { if (!$persistent || !self::$guzzleClientConnection) { self::$guzzleClientConnection = new Client([&amp;#39;base_uri&amp;#39; =&amp;gt; $baseUrl]); } return self::$guzzleClientConnection; } } //get_loop_simple.php 内部循环调用多次 for ($i=0;$i&amp;lt;10;$i++){ try { //获取Client静态变量,复用curl单体 $client = GuzzleClient::getGuzzleClient(&amp;#34;http://127.0.0.1&amp;#34;); $response = $client-&amp;gt;request(&amp;#39;GET&amp;#39;, &amp;#39;/test.php&amp;#39;); // var_dump($response-&amp;gt;getBody()-&amp;gt;getContents()); } catch (\Exception $e) { $error = $e-&amp;gt;getMessage(); var_dump($error); } } 2.</description></item><item><title>PHP-CURL-Guzzle-HTTP-连接复用内核原理</title><link>https://icorer.com/icorer_blog/posts/php-curl-guzzle-http-connection-reuse-kernel-principle/</link><pubDate>Fri, 22 Feb 2019 13:16:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/php-curl-guzzle-http-connection-reuse-kernel-principle/</guid><description>PHP-CURL连接复用内核原理 0.写在前面# PHP是一个时代的产物,它的底层支持是C语言,因此它在CPU密集型计算或者系统内核调用上有天生的优势,Zend引擎把PHP执行生命期分成了五个阶段1,这五个阶段并不是全部都能常驻进程,这种模式下,对于很多使用场景会造成不好的影响,比如网络IO.
对于网络IO中的HTTP请求 , 很多工程师使用 php-curl 系列函数 . 所以这篇文章将从内核角度讲解php如何支持curl请求的连接复用(这里的连接复用也是指在一个RINIT2&amp;ndash;&amp;gt;RSHUTDOWN3周期内复用).
1. PHP引擎借力CURL库函数# PHP需要使用curl组件进行HTTP系列通信,因此它在底层需要curl有相关的支撑,所以curl首先需要在系统环境中被部署或者被编译,并对外部提供动态链接库文件,PHP通过调用curl相关的动态链接库函数来进行自己内核函数的实现过程.
轻点放大 多说一句,PHP并不一定需要curl才能完成http请求,因为php引擎中已经包含了socket完善的函数库,所以有些php扩展包支持curl和原生stream_socket(tcp)两种模式,例如:guzzle
2. PHP-CURL基础数据结构(php_curl结构体)# 147 typedef struct { 148 php_curl_write *write; 149 php_curl_write *write_header; 150 php_curl_read *read; 151 zval std_err; 152 php_curl_progress *progress; 153 #if LIBCURL_VERSION_NUM &amp;gt;= 0x071500 /* Available since 7.21.0 */ 154 php_curl_fnmatch *fnmatch; 155 #endif 156 } php_curl_handlers; 173 typedef struct { 174 CURL *cp; //curl库 实体结构体 175 php_curl_handlers *handlers; //header 头部 176 zend_resource *res; //引擎资源指针 177 struct _php_curl_free *to_free; 178 struct _php_curl_send_headers header; 179 struct _php_curl_error err; //错误码 180 zend_bool in_callback; 181 uint32_t* clone; 182 } php_curl; 3.</description></item><item><title>PHP内核函数: microtime</title><link>https://icorer.com/icorer_blog/posts/php-kernel-function-analysis-microtime/</link><pubDate>Fri, 22 Feb 2019 13:04:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/php-kernel-function-analysis-microtime/</guid><description>microtime Description ¶ microtime ([ bool $get_as_float = FALSE ] ) : mixed microtime() returns the current Unix timestamp with microseconds. This function is only available on operating systems that support the gettimeofday() system call.
source file:** /php-src/ext/standard/microtime.c**
Part-1 : 内核抛出定义# 1.1 源码# 85 /* {{{ proto mixed microtime([bool get_as_float]) 86 Returns either a string or a float containing the current time in seconds and microseconds */ 87 PHP_FUNCTION(microtime) 88 { 89 _php_gettimeofday(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 90 } 91 /* }}} */ Part-2 : 源码分析# 2.</description></item><item><title>基于CMake构建标准GoLang编译和打包框架</title><link>https://icorer.com/icorer_blog/posts/build-standard-go-compilation-and-packaging-framework-based-on-cmake/</link><pubDate>Tue, 19 Feb 2019 14:32:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/build-standard-go-compilation-and-packaging-framework-based-on-cmake/</guid><description>##一. 背景描述
为了简化团队内部中间件的编译及打包和方便运维伙伴的线上环境部署过程 , 我们开始尝试使用标准的rpm安装包来进行线上的环境部署,虽然制作rpm安装包可以采用很多途径 , 但是我们选择采用CMake方式 , 采用这种方式的优点如下:
利用CMake 可以构建出很强大的自动编译系统. CMake在编译周期结束后,支持rpm , zip等格式的自动打包. 下面的内容从两个方面来阐述: 利用CMake 构建Go语言的自动编译环境 , 利用CMake 进行rpm包制作
二. 实现Go语言的通用CMake编译框架# 2.1 文件结构# 这里将构建一个具有通用性的Go语言工程编译环境,旨在为后续Go语言开发工程师,提供团队内部统一的构建基础环境, 首先我们来查看一下文件结构,文件结构的树形图如下:
轻点放大 在这个文件结构中,我们先阐述一下相关文件的作用:
CMakeLists.txt : 构建系统的总入口 cmake目录 : 这个目录存储构建系统的子功能模块 cmd : 这个目录是一个功能单元的样例环境, 这里的CMakeLists.txt 被根CMakeList 加载. 2.2 重要文件描述# 上面的工程结构,保障了CMake工程的结构化清晰,这里将对几个重要文件做详细阐述
2.2.1 CMakeLists.txt# 这个文件是CMake工程的总入口 , 它负责的工作包括:
加载cmake子目录下的子功能单元 定义Go工程的相关工程属性: 工程名, 工程版本号 加载go语言编译器 加载各个子编译体的源码目录 加载rpm , zip 等打包模块 2.2.2 CMakeDetermineGoCompiler.cmake# 这个文件Go语言编译器的总入口 , 它负责的工作包括:
在操作系统环境中寻找Go语言编译器 加载Go编译器参数 拷贝必要的编译配置文件 ####　2.2.3 golang.cmake
这个文件是在CMakeDetermineGoCompiler.cmake文件基础上实现了必要的Go代码编译函数,主要功能函数包括:</description></item><item><title>IO读取缓冲器-BufReader</title><link>https://icorer.com/icorer_blog/posts/io-read-buffer---bufreader/</link><pubDate>Thu, 03 Jan 2019 16:59:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/io-read-buffer---bufreader/</guid><description>一. IO问题思考 IO读取缓冲器,顾名思义就是针对系统的IO读取操作添加一层缓冲层,有这层缓冲层到底有啥好处呢?针对这个问题,我先问大家以下几个问题.
对于IO读取操作,无论针对的是对象,还是针对网络,每次IO操作均需要陷入内核调用,频繁内核调用会严重影响性能,请问有没有什么办法优化这部分? 针对网络IO读取过程,网络时好时坏,如何让网络IO能够发挥最大的性能潜力,在网络好的时候抓紧多读,在网络差的时候适当少读? 对于文件读取,和网络短连接读取,我们可以很快的根据EOF来结束io连接,但是对于网络长连接,我们无法即使获取到IO的EOF事件,我们该如何避免数据包读取过程的最终状态判断造成的延时问题? 如何提高文件读取,网络读取的内存使用率? 针对上面三个问题,我们均可以使用IO读取缓冲器来解决.
二. 无IO缓冲器 IO无用户态缓冲器下,[数据源]和[数据接收端]这两方之间通过程序语言提供的IO API进行数据通信,这种通信模式图如下:
从上图可以看到
三. 缓冲器作用 缓冲器建立在传统IO对象上,在传统的IO操作基础上,我们不立刻把读取到的数据传达给调用层代码,而是放进内存缓冲区,并启动针对缓冲区的两个指针(写入指针,读取指针).
相关的模型图如下:
轻点放大</description></item><item><title>开源: 高性能网络监听库-NetHandle</title><link>https://icorer.com/icorer_blog/posts/open-source-high-performance-network-monitoring-library-nethandle/</link><pubDate>Wed, 02 Jan 2019 13:39:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/open-source-high-performance-network-monitoring-library-nethandle/</guid><description>NetHandle 这是一个库,方便构建高性能TCP服务端应用程序,站在Go语言的巨人肩膀上
项目地址: https://github.com/gitsrc/NetHandle 一. 特点# 高性能,低资源消耗 非常简单易用的开发接口 支持众多协议,TCP,UDP,UNIX 二. 安装# go get -u github.com/gitsrc/NetHandle
三. 性能测试:# 3.1 50*10000 (50线程 X 10000请求)# 轻点放大 轻点放大 3.2 50*20000 (50线程 X 20000请求)# 轻点放大 3.3 100*10000 (100线程 X 10000请求)# 轻点放大 四. 样例代码:# 使用这个库的时候,只需要自定义简单的回调函数,即可构造出性能强悍的网络监听.
package main import ( &amp;#34;fmt&amp;#34; &amp;#34;github.com/gitsrc/NetHandle&amp;#34; &amp;#34;log&amp;#34; &amp;#34;sync&amp;#34; ) var addrTcp = &amp;#34;127.0.0.1:10000&amp;#34; func main() { log.SetFlags(log.Lshortfile | log.LstdFlags) var mu sync.RWMutex count := 0 go log.Printf(&amp;#34;started server at %s&amp;#34;, addrTcp) err := NetHandle.</description></item><item><title>源码阅读：YAF框架系列文章(3) - (yaf_application.c)</title><link>https://icorer.com/icorer_blog/posts/source-code-reading-yaf-framework-series-articles-3---yaf_application.c/</link><pubDate>Thu, 22 Nov 2018 15:33:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/source-code-reading-yaf-framework-series-articles-3---yaf_application.c/</guid><description>这个文件主要围绕Yaf_Application类的注册，这里，按照倒叙的方式来进行讲解。
一、注册yaf_application类
YAF_STARTUP_FUNCTION(application) { //定义一个zend_class_entry实例变量 zend_class_entry ce; /* 初始化一个CLASS ENTRY #define YAF_INIT_CLASS_ENTRY(ce, name, name_ns, methods) \ if(YAF_G(use_namespace)) { \ INIT_CLASS_ENTRY(ce, name_ns, methods); \ } else { \ INIT_CLASS_ENTRY(ce, name, methods); \ } */ YAF_INIT_CLASS_ENTRY(ce, &amp;#34;Yaf_Application&amp;#34;, &amp;#34;Yaf\\Application&amp;#34;, yaf_application_methods); // https://src.icorer.com/xref/php-src/Zend/zend_API.c#2752 //注册一个类到内核类表中 yaf_application_ce = zend_register_internal_class_ex(&amp;amp;ce, NULL); //修改类属性为终极类 yaf_application_ce-&amp;gt;ce_flags |= ZEND_ACC_FINAL; //声明一个属性定义，为Protected类型 zend_declare_property_null(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_CONFIG), ZEND_ACC_PROTECTED); zend_declare_property_null(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_DISPATCHER), ZEND_ACC_PROTECTED); //声明一个NULL元素，为static protected类型 zend_declare_property_null(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_APP), ZEND_ACC_STATIC | ZEND_ACC_PROTECTED); zend_declare_property_null(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_MODULES), ZEND_ACC_PROTECTED); //声明一个布尔类型的元素，为protected类型 zend_declare_property_bool(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_RUN), 0, ZEND_ACC_PROTECTED); //声明一个字符串类型的元素 ， 为protected类型 zend_declare_property_string(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_ENV), YAF_G(environ_name), ZEND_ACC_PROTECTED); //声明一个长整数类型的元素，为protected类型 zend_declare_property_long(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_ERRNO), 0, ZEND_ACC_PROTECTED); zend_declare_property_string(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_ERRMSG), &amp;#34;&amp;#34;, ZEND_ACC_PROTECTED); return SUCCESS; } 二、添加类方法 上面讲解了创建一个类的过程，但是类中还有很多方法，通过yaf_application_methods方法集进行管理，具体对于函数的添加代码如下。</description></item><item><title>源码阅读：YAF框架系列文章(2) - (yaf.c)</title><link>https://icorer.com/icorer_blog/posts/source-code-reading-yaf-framework-series-articles-2---yaf.c/</link><pubDate>Thu, 22 Nov 2018 10:04:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/source-code-reading-yaf-framework-series-articles-2---yaf.c/</guid><description>这个文件是yaf框架的整体组成框架文件，因为yaf的设计思路是模块化的，因此在这个文件中进行了总体整合。整合的思路分为以下几个部分。
INI配置文件的解析 注册系统使用的常量 注册各个模块 对扩展模块的各个生命期做拦截监控 注册扩展模块 一、INI配置文件解析功能
在php_yaf.h文件中对于全局变量进行了定义工作，随后在yaf.c中进行了声明工作，声明操作 ZEND_DECLARE_MODULE_GLOBALS(yaf); ，声明操作之后，并在PHP_GINIT_FUNCTION钩子函数期进行了全局变量的初始化工作，框架进行了配置文件的加载过程，配置文件的操作定义如下：
/** {{{ PHP_INI_MH(OnUpdateSeparator) */ PHP_INI_MH(OnUpdateSeparator) { YAF_G(name_separator) = ZSTR_VAL(new_value); YAF_G(name_separator_len) = ZSTR_LEN(new_value); return SUCCESS; } /* }}} */ /** {{{ PHP_INI */ PHP_INI_BEGIN() STD_PHP_INI_ENTRY(&amp;#34;yaf.library&amp;#34;, &amp;#34;&amp;#34;, PHP_INI_ALL, OnUpdateString, global_library, zend_yaf_globals, yaf_globals) STD_PHP_INI_BOOLEAN(&amp;#34;yaf.action_prefer&amp;#34;, &amp;#34;0&amp;#34;, PHP_INI_ALL, OnUpdateBool, action_prefer, zend_yaf_globals, yaf_globals) STD_PHP_INI_BOOLEAN(&amp;#34;yaf.lowcase_path&amp;#34;, &amp;#34;0&amp;#34;, PHP_INI_ALL, OnUpdateBool, lowcase_path, zend_yaf_globals, yaf_globals) STD_PHP_INI_BOOLEAN(&amp;#34;yaf.use_spl_autoload&amp;#34;, &amp;#34;0&amp;#34;, PHP_INI_ALL, OnUpdateBool, use_spl_autoload, zend_yaf_globals, yaf_globals) STD_PHP_INI_ENTRY(&amp;#34;yaf.forward_limit&amp;#34;, &amp;#34;5&amp;#34;, PHP_INI_ALL, OnUpdateLongGEZero, forward_limit, zend_yaf_globals, yaf_globals) STD_PHP_INI_BOOLEAN(&amp;#34;yaf.name_suffix&amp;#34;, &amp;#34;1&amp;#34;, PHP_INI_ALL, OnUpdateBool, name_suffix, zend_yaf_globals, yaf_globals) PHP_INI_ENTRY(&amp;#34;yaf.</description></item><item><title>源码阅读：YAF框架系列文章(1) - (php_yaf.h)</title><link>https://icorer.com/icorer_blog/posts/source-code-reading-yaf-framework-series-articles-1---php_yaf.h/</link><pubDate>Wed, 21 Nov 2018 14:30:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/source-code-reading-yaf-framework-series-articles-1---php_yaf.h/</guid><description>这个文件的核心使命是构建yaf基础定义，这部分定义主要包括
对于内核函数的宏定义 对于框架变量类型的宏定义 对于框架所使用的全局变量进行定义 一、对于内核函数进行宏定义
#define YAF_STARTUP_FUNCTION(module) ZEND_MINIT_FUNCTION(yaf_##module) #define YAF_RINIT_FUNCTION(module)	ZEND_RINIT_FUNCTION(yaf_##module) #define YAF_STARTUP(module)	ZEND_MODULE_STARTUP_N(yaf_##module)(INIT_FUNC_ARGS_PASSTHRU) #define YAF_SHUTDOWN_FUNCTION(module) ZEND_MSHUTDOWN_FUNCTION(yaf_##module) #define YAF_SHUTDOWN(module)	ZEND_MODULE_SHUTDOWN_N(yaf_##module)(INIT_FUNC_ARGS_PASSTHRU) 这个部分表现了yaf框架的模块化设计，yaf通过宏定义对于模块相关ZEND函数进行了封装，每个模块都将有自己的模块加载、关闭函数。例如YAF_STARTUP_FUNCTION(module) 的宏定义展开形式就是 zm_startup_yaf_module(int type, int module_number)
二、对于框架自定义变量类型进行定义
#define yaf_application_t	zval #define yaf_view_t zval #define yaf_controller_t	zval #define yaf_request_t	zval #define yaf_router_t	zval #define yaf_route_t	zval #define yaf_dispatcher_t	zval #define yaf_action_t	zval #define yaf_loader_t	zval #define yaf_response_t	zval #define yaf_config_t	zval #define yaf_registry_t	zval #define yaf_plugin_t	zval #define yaf_session_t	zval #define yaf_exception_t	zval 三、对内核中将用到的函数做声明</description></item><item><title>检测并分析PHP扩展的内存泄露</title><link>https://icorer.com/icorer_blog/posts/detect-and-analyze-memory-leaks-in-php-extensions/</link><pubDate>Tue, 31 Jul 2018 09:11:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/detect-and-analyze-memory-leaks-in-php-extensions/</guid><description>1. 背景描述 基于C/C++开发的程序，内存管理是很大程度上的工作，我们在这篇文章里来给大家讲解一下如何监控程序体可能存在的内存泄露。
工欲善其事必先利其器，这里选择使用 Valgrind 工作来进行内存监控。http://valgrind.org/
2. Valgrind工具安装 git clone git://sourceware.org/git/valgrind.git ./autogen.sh ./configure --prefix=/usr/local/valgrind make make install 3. 测试命令样例 valgrind --tool=memcheck --leak-check=full --show-reachable=yes --trace-children=yes php PulseFlow.php 4. 一次针对PHP扩展的内存泄露检测过程 针对已经开源的 PulseFLow 插件，今天我们将进行相关的内存泄露检测，由于我们是对PHP扩展进行泄露检查，所以：
第一步，需要给PHP打开debug 编译参数，相关的编译参数如 ./configure --enable-debug 。
第二步，我们需要关闭zend 内存管理 ，添加相关的环境变量 export USE_ZEND_ALLOC=0 export ZEND_DONT_UNLOAD_MODULES=1 第三步，我们执行相关命令
ZEND_DONT_UNLOAD_MODULES=1 USE_ZEND_ALLOC=0 valgrind --tool=memcheck --leak-check=full --show-reachable=yes --trace-children=yes php PulseFlow.php 第四步，查看报告，获得总体报告如下
==20296== LEAK SUMMARY: ==20296== definitely lost: 0 bytes in 0 blocks ==20296== indirectly lost: 0 bytes in 0 blocks ==20296== possibly lost: 0 bytes in 0 blocks ==20296== still reachable: 75,936 bytes in 29 blocks ==20296== suppressed: 0 bytes in 0 blocks 5.</description></item><item><title>编程笔记：C动态连接库编程</title><link>https://icorer.com/icorer_blog/posts/programming-notes-c-dynamic-link-library-programming/</link><pubDate>Tue, 24 Jul 2018 09:15:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/programming-notes-c-dynamic-link-library-programming/</guid><description>动态链接库，可以方便程序体扩展功能、更新组件，相对于编译时连接，具有更大的灵活性，下面我们从三个方面来讲解一个案例。
库函数定义 在这里，我们首先定义一个简单的加法函数。
#include &amp;lt;stdio.h&amp;gt; int add(int a,int b){ return a+b; } 动态链接库编译 我们通过编译命令对于源码文件进行编译，在linux系统中编译为so文件。
gcc -shared -fPIC ./io.c -o add.so 编译参数解析# -shared该选项指定生成动态连接库（让连接器生成T类型的导出符号表，有时候也生成弱连接W类型的导出符号），不用该标志外部程序无法连接，相当于一个可执行文件。
-fPIC：表示编译为位置独立的代码，不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要，而不能达到真正代码段共享的目的。
测试动态链接库是否可用 编写测试代码
#include &amp;lt;stdio.h&amp;gt; #include &amp;lt;dlfcn.h&amp;gt; int main() { void *handle = dlopen(&amp;#34;./add.so&amp;#34;, RTLD_LAZY); //打开动态链接库文件 char *dlerr = dlerror(); //跟踪动态链接库错误 if (handle == NULL || dlerr != NULL) { printf(&amp;#34;%s\n&amp;#34;, dlerr); return -1; } int (*add)(int, int) = dlsym(handle, &amp;#34;add&amp;#34;); //加载动态链接库函数 转换为函数指针 printf(&amp;#34;%d\n&amp;#34;, add(1, 2)); //根据函数指针调用动态链接库函数 return 0; } 编译测试代码时，需要链接dl库 ，编译命令如下：</description></item><item><title>阅读笔记：动态内存分配 + 指针小结</title><link>https://icorer.com/icorer_blog/posts/reading-notes-dynamic-memory-allocation-+-pointer-summary/</link><pubDate>Mon, 23 Jul 2018 17:36:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/reading-notes-dynamic-memory-allocation-+-pointer-summary/</guid><description>1.什么是内存的动态分配 轻点放大 2.怎样建立内存分配 轻点放大 轻点放大 轻点放大 轻点放大 3. 指针小结 轻点放大 轻点放大 轻点放大</description></item><item><title>阅读笔记：指针数组和多重指针</title><link>https://icorer.com/icorer_blog/posts/reading-notes-pointer-arrays-and-multiple-pointers/</link><pubDate>Mon, 23 Jul 2018 15:58:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/reading-notes-pointer-arrays-and-multiple-pointers/</guid><description>1. 什么是指针数组 一个数组，其元素均为指针类型的数据，被成为指针数组。也就是说，指针数组中的每一个元素都存放一个地址，相当于一个指针变量。下面定义一个指针数组。 轻点放大 ##1.1 样例分析 轻点放大 轻点放大 轻点放大 轻点放大 2. 指向指针的指针 轻点放大 轻点放大 轻点放大 轻点放大 轻点放大 轻点放大 轻点放大</description></item><item><title>阅读笔记：指针数组和多重指针</title><link>https://icorer.com/icorer_blog/posts/reading-notes-c-language-function-pointer/</link><pubDate>Mon, 23 Jul 2018 13:51:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/reading-notes-c-language-function-pointer/</guid><description>1.指向函数的指针 1.1什么是指针函数# 轻点放大 1.2 怎样定义指向函数的指针变量# 定义指向函数的指针变量一般形式为： 轻点放大 例如 int (*p)(int a, int b); 这里的 “类型名” 是指函数返回值的类型。
1.2.1说明# 定义指向函数的指针变量，并不意味着这个指针变量可以指向任何函数，它只能指向在定义时指定的类型的函数。在同一个程序中，一个指针变量可以先后指向同类型的不同函数。
在给指针变量赋值时，只需给出函数名，而不需要给出参数，如果带上参数，会让编译器误认为正在调用函数。
对指向函数的指针变量不能进行加减运算、因为这些云端是没有意义的。
通过函数名，只能调用一个函数，而通过函数指针变量，便可以实现动态调用不同的函数。
1.3 使用函数指针调用函数# 如果想调用一个函数，除了使用函数名进行调用之外，还可以使用指向此函数的函数指针变量进行调用，简单样例如下。
#include &amp;lt;stdio.h&amp;gt; int main() { int (*p)(int a, int b); int add(int a, int b); //函数声明 p = add; //函数指针变量赋值 or p = &amp;amp;add; int a = 100, b = 200; int c = (*p)(a, b); //函数指针调用 printf(&amp;#34;%d\n&amp;#34;, c); return 0; } int add(int a, int b) { return a + b; } 1.</description></item><item><title>环境搭建：CLion 搭建 PHP 扩展开发环境</title><link>https://icorer.com/icorer_blog/posts/clion-builds-a-php-extension-development-environment/</link><pubDate>Tue, 10 Jul 2018 10:06:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/clion-builds-a-php-extension-development-environment/</guid><description>#1. PHP扩展代码框架搭建 此处，可以参考本博客原来的文章进行框架代码搭建。 【PHP扩展开发1：代码框架搭建】 2. 从源文件导入CLion工程 点击clion菜单栏File -&amp;gt; Import Project 选择扩展目录 -&amp;gt; 选择项目所要的文件 -&amp;gt; 点击确认 因为clion是由CMakeList.txt文件进行，所以当导入后clion会自动生成基本的配置文件。
#3. 修改CMakeList.txt 加入库文件索引等，样例配置如下。
cmake_minimum_required(VERSION 3.10) project(PulseFlow C) set(CMAKE_C_STANDARD 11) set(SOURCE_FILES php_PulseFlow.h PulseFlow.c) add_executable(PulseFlow ${SOURCE_FILES}) add_custom_target(makefile COMMAND make &amp;amp;&amp;amp; sudo make install WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) include_directories(.) set(PHP_SOURCE /usr/local/php/include/php) include_directories(${PHP_SOURCE}/main) include_directories(${PHP_SOURCE}/Zend) include_directories(${PHP_SOURCE}/sapi) include_directories(${PHP_SOURCE}/pear) include_directories(${PHP_SOURCE}) #4. 调试代码
4.1 在CMakeList.txt文件中添加编译命令# add_custom_target(makefile COMMAND make &amp;amp;&amp;amp; sudo make install WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 4.2 添加运行配置 (很重要 一定要选择 makefile编译)#</description></item><item><title>编程笔记：C语言回调函数</title><link>https://icorer.com/icorer_blog/posts/programming-notes-c-language-callback-function/</link><pubDate>Mon, 09 Jul 2018 16:56:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/programming-notes-c-language-callback-function/</guid><description>在计算机程序设计中，回调函数，或简称回调（Callback 即call then back 被主函数调用运算后会返回主函数），是指通过函数参数传递到其它代码的，某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。 轻点放大 假设我们要使用一个排序函数来对数组进行排序，那么在主程序(Main program)中，我们先通过库，选择一个库排序函数(Library function)。但排序算法有很多，有冒泡排序，选择排序，快速排序，归并排序。同时，我们也可能需要对特殊的对象进行排序，比如特定的结构体等。库函数会根据我们的需要选择一种排序算法，然后调用实现该算法的函数来完成排序工作。这个被调用的排序函数就是回调函数(Callback function)。
结合这幅图和上面对回调函数的解释，我们可以发现，要实现回调函数，最关键的一点就是要将函数的指针传递给一个函数(上图中是库函数)，然后这个函数就可以通过这个指针来调用回调函数了。注意，回调函数并不是C语言特有的，几乎任何语言都有回调函数。在C语言中，我们通过使用函数指针来实现回调函数。那函数指针是什么？不着急，下面我们就先来看看什么是函数指针。
什么是函数指针 函数指针也是一种指针，只是它指向的不是整型，字符型而是函数。在C中，每个函数在编译后都是存储在内存中，并且每个函数都有一个入口地址，根据这个地址，我们便可以访问并使用这个函数。函数指针就是通过指向这个函数的入口，从而调用这个函数。
函数指针的使用 函数指针的定义# 函数指针虽然也是指针，但它的定义方式却和其他指针看上去很不一样，我们来看看它是如何定义的：
/* 方法1 */ void (*p_func)(int, int, float) = NULL; /* 方法2 */ typedef void (*tp_func)(int, int, float); tp_func p_func = NULL; 这两种方式都是定义了一个指向返回值为 void 类型，参数为 (int, int, float) 的函数指针。第二种方法是为了让函数指针更容易理解，尤其是在复杂的环境下；而对于一般的函数指针，直接用第一种方法就行了。 如果之前没见过函数指针，可能会觉得函数指针的定义比较怪，为什么不是 void ()(int, int, float)*p_func 而是 void (*p_func)(int, int, float) 这种形式？这个问题我也不知道，也没必要纠结，花点时间理解下它与普通指针的区别，实在不行就先记住它的形式。
函数指针的赋值# 在定义完函数指针后，我们就需要给它赋值了我们有两种方式对函数指针进行赋值：
void (*p_func)(int, int, float) = NULL; p_func = &amp;amp;func1; p_func = func2; 上面两种方法都是合法的，对于第二种方法，编译器会隐式地将 func_2 由 void ()(int, int, float) 类型转换成 void (*)(int, int, float) 类型，因此，这两种方法都行。</description></item><item><title>源码阅读：PHP TSRM 线程安全管理器</title><link>https://icorer.com/icorer_blog/posts/source-code-reading-php-tsrm-thread-safety-manager/</link><pubDate>Sun, 08 Jul 2018 23:49:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/source-code-reading-php-tsrm-thread-safety-manager/</guid><description>TSRM 简介 在查看php源代码或开发php扩展的时候，会出现大量 TSRMLS_ 宏字样在函数参数的位置，这些宏就是Zend为线程安全机制所提供的（Zend Thread Safety，简称ZTS）用于保证线程的安全 , 是防止多线程环境下以模块的形式加载并执行PHP解释器，导致内部一些公共资源读取错误，而提供的一种解决方法。
什么时候需要用 TSRM 只要服务器是多线程环境并且PHP以模块的形式提供，那么就需要TSRM启用，例如apache下的 worker 模式(多进程多线程)环境，这种情况就必须要使用线程安全版本的PHP，也就是要启用TSRM , 在Linux下是编译PHP的时候指定是否开启TSRM、windows下是提供线程安全版本和非线程安全版本的PHP。
PHP 如何实现 TSRM 正常多线程环境下操作公共的资源都是加上互斥锁，而PHP没有选择加锁，因为加锁可能多少会有些性能损耗，PHP的解决方法是为每一个线程都copy一份当前PHP内核所有的公共资源过来，每个线程指向自己的公共资源区，互不影响，各操作各的公共资源。
公共资源是什么 就是各种各样的 struct 结构体 定义。
#TSRM数据结构
tsrm_tls_entry结构体# tsrm_tls_entry 线程结构体、每个线程都有一份该结构体。
typedef struct _tsrm_tls_entry tsrm_tls_entry; struct _tsrm_tls_entry { void **storage; int count; THREAD_T thread_id; tsrm_tls_entry *next; } static tsrm_tls_entry **tsrm_tls_table = NULL //线程指针表头指针 static int tsrm_tls_table_size; //当前线程结构体数量 ###字段说明
void **storage ：资源指针、就是指向自己的公共资源内存区 int count : 资源数、就是 PHP内核 + 扩展模块 共注册了多少公共资源 THREAD_T thread_id ： 线程id tsrm_tls_entry *next：指向下一个线程指针，因为当前每一个线程指针都存在一个线程指针表里（类似于hash表），这个next可以理解成是hash冲突链式解决法.</description></item><item><title>PHP扩展开发2.2：线程安全</title><link>https://icorer.com/icorer_blog/posts/php-extension-development-2.2-thread-safety/</link><pubDate>Fri, 06 Jul 2018 17:26:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/php-extension-development-2.2-thread-safety/</guid><description>背景介绍 线程安全是编程中的术语，指某个函数、函数库在多线程环境中被调用时，能够正确地处理多个线程之间的共享变量，使程序功能正确完成。
一般来说，线程安全的函数应该为每个调用它的线程分配专门的空间，来储存需要单独保存的状态（如果需要的话），不依赖于“线程惯性”，把多个线程共享的变量正确对待（如，通知编译器该变量为“易失（volatile）”型，阻止其进行一些不恰当的优化），而且，线程安全的函数一般不应该修改全局对象。
很多C库代码（比如某些strtok的实现，它将“多次调用中需要保持不变的状态”储存在静态变量中，导致不恰当的共享）不是线程安全的，在多线程环境中调用这些函数时，要进行特别的预防措施，或者寻找别的替代方案。 更多线程安全信息请浏览维基百科：链接地址 在PHP初期，是作为单进程的CGI来运行的，所以并没有考虑线程安全问题。我们可以随意的在全局作用域中设置变量并在程序中对他进行修改、访问，内核申请的资源如果没有正确的释放，也会在CGI进程结束后自动地被清理干净。
后来，php被作为apache多进程模式下的一个模块运行，但是这仍然把php局限在一个进程里，我们设置的全局变量，只要在每个请求之前将其正确的初始化，并在每个请求之后正确的清理干净，便不会带来什么麻烦。由于对于一个进程来说，同一个时间只能处理一个请求，所以这是内核中加入了针对每个请求的内存管理功能，来防止服务器资源利用出现错误。
随着使用在多线程模式的软件系统越来越多，php内核中亟需一种新的资源管理方式，并最终在php内核中形成了一个新的抽象层：TSRM(Thread Safe Resource Management)。
线程安全与非线程安全 在一个没有线程的程序中，我们往往倾向于把全局变量声明在源文件的顶部，编译器会自动的为它分配资源供我们在声明语句之下的程序逻辑中使用。（即使通过fork()出一个子进程，它也会重新申请一段内存，父子进程中的变量从此没有了任何联系）
但是在一个多线程的程序中，如果我们需要每个线程都拥有自己独立的资源的话，便需要为每个线程独立开辟出一个区域来存放它们各自的资源，在使用资源的时候，每个线程便会只在自己的那一亩三分地里找，而不会拔了别人的庄稼。
线程安全资源池（Thread-SafeDataPools）# 在扩展的ModuleInit里，扩展可以调用ts_allocate_id()函数来告诉 TRSM 自己需要多少资源。TRSM 接收后更新系统使用的资源，并得到一个指向刚分配的那份资源的id。
typedef struct { int sampleint; char *samplestring; } php_sample_globals; int sample_globals_id; PHP_MINIT_FUNCTION(sample) { ts_allocate_id(&amp;amp;sample_globals_id, sizeof(php_sample_globals), (ts_allocate_ctor) php_sample_globals_ctor, (ts_allocate_dtor) php_sample_globals_dtor); return SUCCESS; } 当一个请求需要访问数据段的时候，扩展从TSRM层请求当前线程的资源池，以ts_allocate_id()返回的资源ID来获取偏移量。换句话说，在代码流中，你可能会在前面所说的MINIT语句中碰到SAMPLE_G(sampleint)=5;这样的语句。在线程安全的构建下，这个语句通过一些宏扩展如下：
(((php_sample_globals*)(*((void ***)tsrm_ls))[sample_globals_id-1])-&amp;gt;sampleint = 5; 如果你看不懂上面的转换也不用沮丧，它已经很好的封装在PHPAPI中了，以至于许多开发者都不需要知道它怎样工作的。
当不在线程环境时# 因为在PHP的线程安全构建中访问全局资源涉及到在线程数据池查找对应的偏移量，这是一些额外的负载，结果就是它比对应的非线程方式（直接从编译期已经计算好的真实的全局变量地址中取出数据）慢一些。 考虑上面的例子，这一次在非线程构建下：
typedef struct { int sampleint; char *samplestring; } php_sample_globals; php_sample_globals sample_globals; PHP_MINIT_FUNCTION(sample) { php_sample_globals_ctor(&amp;amp;sample_globals TSRMLS_CC); return SUCCESS; } 首先注意到的是这里并没有定义一个int型的标识去引用全局的结构定义， 只是简单的在进程的全局空间定义了一个结构体。 也就是说SAMPLE_G(sampleint) = 5;展开后就是sample_globals.</description></item><item><title>PHP扩展开发2.1：PHP生命周期</title><link>https://icorer.com/icorer_blog/posts/php-extension-development-2.1-php-lifecycle/</link><pubDate>Fri, 06 Jul 2018 16:14:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/php-extension-development-2.1-php-lifecycle/</guid><description>#1. PHP SAPI 无论是Web模式、FastCgi模式、CLI模式，PHP的工作原理都是一样的，都是作为一种SAPI在运行（Server Application Programming Interface : the API sed by PHP to interface with Web Servers）。当我们在终端敲入php这个命令时候，它使用的是&amp;quot;”command lines api！它就像一个mini的web服务器一样来支持php完成这个请求，请求完成后再重新把控制权交给终端。简单来说,SAPI就是PHP和外部环境的代理器。它把外部环境抽象后,为内部的PHP提供一套固定的,统一的接口,使得PHP自身实现能够不受错综复杂的外部环境影响，保持一定的独立性
#2. PHP的启动与终止 PHP的启动和终止有两层含义，第一层是基于宿主进程、第二层是基于用户请求，前者被称为模块、后者成为请求。
在最初的初始化时候，就是PHP随着Apache的启动而诞生在内存里的时候，它会把自己所有已加载扩展的MINIT方法(全称Module Initialization，是由每个模块自己定义的函数。)都执行一遍。在这个时间里，扩展可以定义一些自己的常量、类、资源等所有会被用户端的PHP脚本用到的东西。但你要记住，这里定义的元素都会随着Apache常驻内存，可以被所有请求使用，直到Apache卸载掉PHP模块！
内核中预置了PHP_MINIT_FUNCTION()宏函数，来帮助我们实现这个功能：
int minit_startTime = 0 ; PHP_MINT_FUNCTION(extension_name){ minit_startTime = time(NULL); php_printf(&amp;#34;%d\n&amp;#34;,minit_startTime); return SUCCESS; } 当一个页面请求到来时候，PHP会迅速的开辟一个新的环境，并重新扫描自己的各个扩展，遍历执行它们各自的RINIT方法(俗称Request Initialization)，这时候一个扩展可能会初始化在本次请求中会使用到的变量等，还会初始化等会儿用户端（即PHP脚本）中的变量之类的，内核预置了PHP_RINIT_FUNCTION()这个宏函数来帮我们实现这个功能：
int rinit_startTime = 0 ; PHP_RINIT_FUNCTION(extension_name){ rinit_startTime = time(NULL); php_printf(&amp;#34;%d\n&amp;#34;,rinit_startTime); return SUCCESS; } 好了，现在这个页面请求执行的差不多了，可能是顺利的走到了自己文件的最后，也可能是出师未捷，半道被用户给die或者exit了，这时候PHP便会启动回收程序，收拾这个请求留下的烂摊子。它这次会执行所有已加载扩展的RSHUTDOWN（俗称RequestShutdown）方法，这时候扩展可以抓紧利用内核中的变量表之类的做一些事情，因为一旦PHP把所有扩展的RSHUTDOWN方法执行完，便会释放掉这次请求使用过的所有东西，包括变量表的所有变量、所有在这次请求中申请的内存等等。
内核预置了PHP_RSHUTDOWN_FUNCTION宏函数来帮助我们实现这个功能
PHP_RSHUTDOWN_FUNCTION(extension_name){ FILE*fp=fopen(&amp;#34;time_rshutdown.txt&amp;#34;,&amp;#34;a+&amp;#34;); fprintf(fp,&amp;#34;%ld\n&amp;#34;,time(NULL)); fclose(fp); return SUCCESS; } 前面该启动的也启动了，该结束的也结束了，现在该Apache老人家歇歇的时候，当Apache通知PHP自己要Stop的时候，PHP便进入MSHUTDOWN（俗称ModuleShutdown）阶段。这时候PHP便会给所有扩展下最后通牒，如果哪个扩展还有未了的心愿，就放在自MSHUTDOWN方法里，这可是最后的机会了，一旦PHP把扩展的MSHUTDOWN执行完，便会进入自毁程序，这里一定要把自己擅自申请的内存给释放掉，否则就杯具了。
内核中预置了PHP_MSHUTDOWN_FUNCTION宏函数来帮助我们实现这个功能：
PHP_MSHUTDOWN_FUNCTION(extension_name){ FILE*fp=fopen(&amp;#34;time_mshutdown.txt&amp;#34;,&amp;#34;a+&amp;#34;); fprintf(fp,&amp;#34;%ld\n&amp;#34;,time(NULL)); fclose(fp); return SUCCESS; } 这四个宏都是在extension_name.</description></item><item><title>研究报告：JAVA 与 Golang 在 UDP服务器上的性能对比</title><link>https://icorer.com/icorer_blog/posts/performance-comparison-between-java-and-golang-on-udp-server/</link><pubDate>Tue, 03 Jul 2018 15:43:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/performance-comparison-between-java-and-golang-on-udp-server/</guid><description>背景介绍 因工作需求，目前需要采用UDP协议来存储用户日志信息，目前采用了JAVA 和 Golang 两种途径。
#Linux内核优化（非常重要） 可以使用netstat -su 查看UDP是否有错包，如果查看到有UDP receive errors，可以调整UDP缓冲区的大小以应对大规模请求，主要参数如下
net.core.rmem_max=26214400 net.core.rmem_default=26214400 #客户端情况介绍 客户端采用PHP语言进行编写，由于PHP底层采用C实现，所以UDP客户端的性能应该算是最佳了，相关代码如下：
&amp;lt;?php $islocalUdp = true; $server_ip = &amp;#39;127.0.0.1&amp;#39;; $server_port = 10000; $message = &amp;#39;loginfo&amp;#39;; if($islocalUdp){ $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); $ret = socket_sendto($socket, $message, strlen($message), 0, $server_ip, $server_port); }else{ $message = &amp;#34;$server_ip**$server_port**$message&amp;#34;; $ret = sendDataUds ($message,3,&amp;#39;/dev/shm/unix_udp_socks.sock&amp;#39;); } ?&amp;gt; #JAVA服务端介绍 JAVA使用名声很大的Netty 网络包。
#Golang 服务端介绍 Golang服务端采用Net包中的ListenUDP进行程序编写，由于目前没有对大日志进行测试，所以不进行缓冲区中转编程，相关代码如下：
package main import ( &amp;#34;fmt&amp;#34; &amp;#34;log&amp;#34; &amp;#34;net&amp;#34; ) const ( BUF_SIZE = 1024 ) func main() { udp_addr, err := net.</description></item><item><title>Nginx FAST-CGI缓存优化</title><link>https://icorer.com/icorer_blog/posts/nginx-fast-cgi-cache-optimization/</link><pubDate>Sun, 24 Jun 2018 20:42:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/nginx-fast-cgi-cache-optimization/</guid><description>背景描述 传统的LNMP架构中，PHP-FPM对于PHP脚本进行解析工作，Nginx反向代理的时候，会把PHP请求转达给PHP-FPM。对于一个PHP站点，PHP-FPM的工作压力很巨大，所以，如果我们在Nginx层面上做一个FAST-CGI缓存，则会大大缓解解析器的压力，达到更好的响应效果。
NGINX 缓存配置 1. HTTP层配置# fastcgi_cache_path /tmp/cache/fastcgi_cache levels=1:2 keys_zone=fastcgi-cache:10m inactive=2d max_size=512m; fastcgi_cache_key $scheme$request_method$host$request_uri;; proxy_buffering on; proxy_cache_valid any 10m; proxy_temp_path /tmp/cache/tmp; proxy_buffer_size 4k; proxy_buffers 100 8k; fastcgi_cache_lock on; fastcgi_cache_use_stale error timeout invalid_header updating http_500; fastcgi_ignore_headers Cache-Control Expires Set-Cookie; 这里的key_zone = fastcgi-cache, 就是在server层需要用到的代理zone
2. Server层配置# location ~ [^/]\.php(/|$) { try_files $uri =404; fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_index index.php; include fastcgi.conf; add_header PHP-Cache $upstream_cache_status; //添加响应头部 fastcgi_cache fastcgi-cache; //设置缓存zone fastcgi_cache_valid 200 60m; } 测试总结 经过测试，对于实时性要求不是很高的系统，启用了缓存机制后，能够大大提高系统的访问速度，下图是本博客的全国测试结果。</description></item><item><title>解析 Go 中的函数调用</title><link>https://icorer.com/icorer_blog/posts/parsing-function-calls-in-go/</link><pubDate>Fri, 08 Jun 2018 10:17:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/parsing-function-calls-in-go/</guid><description>让我们来看一些简单的 Go 的函数，然后看看我们能否明白函数调用是怎么回事。我们将通过分析 Go 编译器根据函数生成的汇编来完成这件事。对于一个小小的博客来讲，这样的目标可能有点不切实际，但是别担心，汇编语言很简单。哪怕是 CPU 都能读懂。
这是我们的第一个函数。对，我们只是让两个数相加。 func add(a, b int) int { return a + b } 我们编译的时候需要关闭优化，这样方便我们去理解生成的汇编代码。我们用 go build -gcflags 'N -l' 这个命令来完成上述操作。然后我们可以用 go tool objdump -s main.add func 输出我们函数的具体细节（这里的 func 是我们的包名，也就是我们刚刚用 go build 编译出的可执行文件）。
如果你之前没有学过汇编，那么恭喜你，你将接触到一个全新的事物。另外我会在 Mac 上完成这篇博客的代码，因此所生成的是 Intel 64-bit 汇编。
main.go:20 0x22c0 48c744241800000000 MOVQ $0x0, 0x18(SP) main.go:21 0x22c9 488b442408 MOVQ 0x8(SP), AX main.go:21 0x22ce 488b4c2410 MOVQ 0x10(SP), CX main.go:21 0x22d3 4801c8 ADDQ CX, AX main.go:21 0x22d6 4889442418 MOVQ AX, 0x18(SP) main.</description></item><item><title>微服务：请求熔断原理</title><link>https://icorer.com/icorer_blog/posts/microservices-principles-of-request-fusing/</link><pubDate>Wed, 06 Jun 2018 13:27:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/microservices-principles-of-request-fusing/</guid><description>伴随微服务，出现了很多新鲜的名词，其实剥去外衣并没有那么高大上。
今天要谈到的，叫做”熔断”，一个典型的开源实现是Hystrix（JAVA实现）。
背景 一个分布式系统中，服务间互相调用错综复杂，假设某个基础服务宕机，那么就会导致若干上游调用方出现访问超时，进而引起上游重试，导致宕机的基础服务遭受到数倍的流量放大，更加无法恢复服务。
这种恶劣的情况并不会就此结束，上游因为调用基础服务超时而变慢，导致上游的上游超时…异常向上蔓延，最终导致整个分布式系统”雪崩”。
“熔断”就是为了避免”雪崩”而生的，它的思路是在调用方增加一种”避让”机制，当下游出现异常时能够停止（熔断）对下游的继续请求，当等待一段时间后缓慢放行部分的调用流量，并当这部分流量依旧正常的情况下，彻底解除”熔断”状态。
听起来，流程不算复杂吧？整个流程图如下，看不懂没关系，继续往下阅读吧。
轻点放大 #健康统计
判断下游正常的前提是统计最近一段时间内，下游的调用成功率，因此需要一个健康统计模块，记录最近N秒内的总请求数，成功请求数，失败请求数，是由业务调用后将结果打点到健康统计模块中。
下游健康的标志，是最近N秒的成功率大于某个阀值，那么代表下游健康。
因为时间不停的前进，要统计最近N秒内的成功率，显然仅仅维护3个数字是不足以表达的，因此这里一般会使用”时间窗口”来实现。
如最上面的图片所示，整个时间窗口由10个槽位（bucket）构成，每个槽位代表1秒钟，整个时间窗口表达了最近10秒的健康统计，最右侧的bucket记录了最近1秒的成功/失败请求数量，仅此而已。
随着时间每过去1秒，整个窗口会向右滑动1格，最左侧的1个槽位被淘汰，最右侧加入当前1秒的新槽位，这就是时间窗口的实现原理。
当然，我们在实现的时候不会写一个定时器每秒去更新时间窗口，而是当打点接口被调用的时候进行计算和窗口滑动。为了更清晰的帮助你理解，我写了一个简短的PHP实现：
&amp;lt;?php // 时间窗口10个桶 define(&amp;#34;BUCKET_NUM&amp;#34;, 10); // 成功率大于该值为健康 define(&amp;#34;HEALTHY_RATE&amp;#34;, 0.8); // 健康统计 class HealthStats { private $service = &amp;#39;&amp;#39;; private $buckets = []; private $curTime = 0; public function __construct($service) { $this-&amp;gt;service = $service; $this-&amp;gt;buckets = array_fill(0, BUCKET_NUM, [&amp;#39;success&amp;#39; =&amp;gt; 0, &amp;#39;fail&amp;#39; =&amp;gt; 0,]); } private function shiftBuckets() { $now = time(); $timeDiff = $now - $this-&amp;gt;curTime; if (!</description></item><item><title>Pecl_Http 与 unix domain socket 客户端封装</title><link>https://icorer.com/icorer_blog/posts/pecl_http-and-unix-domain-socket-client-package/</link><pubDate>Tue, 05 Jun 2018 09:44:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/pecl_http-and-unix-domain-socket-client-package/</guid><description>1. 背景描述# Pecl/HTTP是一个PHP扩展，历史非常悠久了，从2005年至2018年不断完善其功能，它主要帮助PHP对于HTTP请求的相关操作。不同于CURL，其具有更丰富的扩展接口，既包括平常的请求，也包括对于HTTP数据的封包或拆包操作。
对于PHP和HTTP，大部分程序员关心的如何完成一个请求。但是更深一步，我们会发现HTTP数据包的文件格式也很重要，比如传统的HTTP请求性能很弱，对于请求密集型业务，传统的HTTP并不能达到很好的RPS，就算是开启了Keep-Alive，性能还是很弱。对于这种情况，我们失望的是HTTP请求，而不是HTTP的数据包格式，所以我们可以在数据封包拆包上继续使用HTTP协议，但是对于数据传输这层，我们可以采用性能更高的一些通路，比如Unix domain socket。
2. 研究难点# HTTP的通信协议数据包格式总体来说并不复杂，但是为了便于系统研发及维护，一般都站在巨人的肩膀上进行研发，目前针对PHP进行数据拆包与封包的库很少。一方面我们可以从网上比较火的一些Http Client库中抽取相关的调用层，另一方面我们可以从pecl中找寻一些扩展库，基于pecl的扩展库都是基于C语言进行的研发，性能更强，而且安装也很方便。
在本文中，我们主要围绕Pecl/HTTP库进行相关阐述，在接下来的文章中，我们也会专门围绕Guzzle或者更合适的PHP库来讲解数据包的装包和拆包。
3. HTTP数据包：封包-拆包# 3.1	扩展类设计思路# 本文主要讲解HTTP数据包的封包和拆包操作，我们首先封装一个HTTP数据包相关接口，接口主要包括对于Get、Post的封包；对于数据包的解包操作。
&amp;lt;?php interface HttpPack{ public function encodeGetPack($url,$header); public function encodePostPack($url,$header,$body); public function decodePack($packStr); } ?&amp;gt; 随后，我们定义了一个SimpleTun类来实现这个接口，具体函数实现在各节详细描述，此处为框架代码。 &amp;lt;?php class SimpleTun implements HttpPack { public function encodeGetPack($url, $header) { // TODO: Implement encodeGetPack() method. } public function encodePostPack($url, $header, $body) { // TODO: Implement encodePostPack() method. } public function decodePack($packStr) { // TODO: Implement decodePack() method. } } ?</description></item><item><title>测试报告：HTTP Post 与 Unix Domain Socket 通信性能对比</title><link>https://icorer.com/icorer_blog/posts/test-report-comparison-of-communication-performance-between-http-post-and-unix-domain-socket/</link><pubDate>Mon, 28 May 2018 09:35:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/test-report-comparison-of-communication-performance-between-http-post-and-unix-domain-socket/</guid><description>&lt;h2 id="背景描述">背景描述&lt;a class="anchor" href="#%e8%83%8c%e6%99%af%e6%8f%8f%e8%bf%b0" aria-label="链接到此节">#&lt;/a>&lt;/h2>
&lt;p>因工作需求，项目需要在不同的程序语言框架中进行通信，目前对于进程通信的方式，互联网上主要有HTTP请求、IPC通信、Socket通信、共享内存通信，虽然共享内存效率最高，但是对于内存结构的设计与队列维持需要很高的系统实现能力，所以目前我测试了HTTP与Unix Socket这两种通信方案。&lt;/p>
&lt;h2 id="测试环境搭建">测试环境搭建&lt;a class="anchor" href="#%e6%b5%8b%e8%af%95%e7%8e%af%e5%a2%83%e6%90%ad%e5%bb%ba" aria-label="链接到此节">#&lt;/a>&lt;/h2>
&lt;p>目前分为HTTP和Unix Socket通信两种测试环境，为了保持测试环境尽量统一，我们请求端用PHP语言、接受信息端用Go语言。
测试软件使用 Jmeter 4.0
操作系统：Centos 7
硬件条件：I5 CPU、8GB内存&lt;/p></description></item><item><title>Jmeter测试报表相关参数说明</title><link>https://icorer.com/icorer_blog/posts/jmeter-test-report-related-parameter-description/</link><pubDate>Fri, 18 May 2018 11:26:18 +0800</pubDate><guid>https://icorer.com/icorer_blog/posts/jmeter-test-report-related-parameter-description/</guid><description>背景介绍# 采用Jmeter测试工具对web系统作的负载测试，得出的响应报表，数据比较难懂，现作一具体说明。
以下是在一次具体负载测试中得出的具体数值，测试线程设置情况为：线程数：200，等待时间（ramp-up）：0秒，循环次数为永远，另：
线程组——这些元件用于指定运行的线程数和等候周期。每个线程模拟一个用户，而等候周期用于指定创建全部线程的时间。例如，线程数为5，等候时间为10秒，则创建每个线程之间的时间间隔为2秒。循环数定义了线程的运行时间。使用调度器，还可以设置运行的起始时间。 取样器——对于服务器HTTP、FTP或LDAP请求，这些元件是可配置请求。该教程仅侧重于Web Services请求。 监听器——这些元件用于请求数据的后期处理。例如，可以将数据保存到文件或用图表来说明结果。此时JMeter图表并没有提供许多配置选项；然而它是可扩展的，它始终可以添加额外的可视化效果或数据处理模块。 一、图形报表# 轻点放大 图表底部参数的含义如下： 样本数目是总共发送到服务器的请求数。 最新样本是代表时间的数字,是服务器响应最后一个请求的时间。 吞吐量是服务器每分钟处理的请求数。 平均值是总运行时间除以发送到服务器的请求数。 中间值是代表时间的数字，有一半的服务器响应时间低于该值而另一半高于该值。 偏离表示服务器响应时间变化、离散程度测量值的大小，或者，换句话说，就是数据的分布。 二、 聚合报告# 轻点放大 图表含义说明如下：
Label：说明是请求类型，如Http，FTP等请求。 Samples：也就是图形报表中的样本数目，总共发送到服务器的样本数目。 Average：也就是图形报表中的平均值，是总运行时间除以发送到服务器的请求数。 Median：也就是图形报表中的中间值，是代表时间的数字，有一半的服务器响应时间低于该值而另一半高于该值。 90%line：是指90%请求的响应时间比所得数值还要小。 Min：是代表时间的数字,是服务器响应的最短时间。 Max: 是代表时间的数字,是服务器响应的最长时间。 Error%:请求的错误百分比。 Throughput:也就是图形报表中的吞吐量，这里是服务器每单位时间处理的请求数，注意查看是秒或是分钟。 KB/sec:是每秒钟请求的字节数。 三、 使用分析# 在测试过程中，平均响应时间是我们性能测试的一个重要衡量指标，但是在测试中，特别是在聚合报告中，得出的90%Line,我这里参考《《LoadRunner 没有告诉你的》之一——描述性统计与性能结果分析》，我认为90%Line等同于该文作者提出的90%响应时间,这个数值对我们性能测试分析也很有参考价值。90%响应时间是说在发送的请求中，90%的用户响应时间都比得到的数值上要短，同时说明，一个系统在应用时，90%的用户响应时间都能达到这个数值，那么就为系统性能分析提供了很好的参考价值。
原文链接： https://blog.csdn.net/zwc2xm/article/details/78895165 #</description></item></channel></rss>