<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by JetSquirrel on Medium]]></title>
        <description><![CDATA[Stories by JetSquirrel on Medium]]></description>
        <link>https://medium.com/@jetdeng?source=rss-bdff15df02b6------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*21la4a15ZPQJv8t47KO_og.png</url>
            <title>Stories by JetSquirrel on Medium</title>
            <link>https://medium.com/@jetdeng?source=rss-bdff15df02b6------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 26 Jun 2026 03:35:32 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@jetdeng/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[豌豆的记忆]]></title>
            <link>https://medium.com/@jetdeng/%E8%B1%8C%E8%B1%86%E7%9A%84%E8%AE%B0%E5%BF%86-0389b245519b?source=rss-bdff15df02b6------2</link>
            <guid isPermaLink="false">https://medium.com/p/0389b245519b</guid>
            <dc:creator><![CDATA[JetSquirrel]]></dc:creator>
            <pubDate>Sun, 15 Mar 2026 16:19:00 GMT</pubDate>
            <atom:updated>2026-03-15T16:19:00.485Z</atom:updated>
            <content:encoded><![CDATA[<p>在大学的时候，我选修了一门课叫《中国近现代文化》。</p><p>有堂课讲到了我们大学所在城市的特色食物凉粉，关于它的文化以及制作原料 — — 豌豆。</p><p>豌豆为什么要叫豌豆？为什么在川渝地区非常流行而其它地方很少见？安徒生童话中的豌豆公主、豌豆花与碗杂面、豌豆尖汤有什么关联？</p><p>我当时没有深究。但这些问题留在了脑子里，像一颗种子，等着某一天发芽。<br>豌豆为什么要叫豌豆？在那堂课上，老师提到了豌豆的「豌」指的是西域国家「大宛」。</p><p>大宛，古国名，在今中亚费尔干纳盆地，张骞出使西域时，带回了葡萄、苜蓿，也带回了豌豆。</p><p>从地理分布上来看，四川重庆地区吃豌豆比较多，而西方的故事中也有豌豆身影 — — 安徒生的《豌豆公主》，英国的豌豆泥。</p><h4>安徒生写过两篇关于豌豆的童话。</h4><p>一篇是《豌豆公主》。王子要找真正的公主，怎么也找不到。一个雨夜，一个女孩敲开了城门，说自己是公主。皇后在她的床上放了一颗豌豆，压了二十层床垫和二十层鸭绒被。第二天早上，女孩说她睡得不舒服，有什么东西硌着她了。于是所有人都相信，她是真正的公主 — — 因为只有真正的公主，皮肤才会那么敏感。</p><p>一篇是《五粒豌豆》。一个豆荚里有五粒豌豆，它们都想飞到远方去。前四粒豌豆各有各的愿望，但都被鸟吃掉了或者烂在沟里。只有最后一粒豌豆，飞到了一个贫苦病弱的小女孩窗前，生根发芽，开出紫红色的花朵。小女孩看着它，一天天好起来。</p><p>小时候读这些故事，只觉得有趣。现在想想，豌豆在安徒生笔下，好像总是和「敏感」有关。</p><p>豌豆公主敏感，因为她能感受到别人感受不到的东西。窗前的豌豆敏感，因为它能在一个病弱女孩的生命里，开出花来。</p><h4>豌豆最主要的作用还是吃。</h4><p>嫩豌豆是甜的。</p><p>小时候我会去菜地里摘下来吃，连皮带豆塞进嘴里，甜丝丝的。</p><p>作为川渝人，豌豆在我们的饭桌上出现频率很高。</p><p>人类饮食的一大特色，是对鲜味的追求。西方选择了奶基：牛奶、奶酪、黄油。东方选择了豆基：黄豆、酱油、豆腐、豆豉。</p><p>而作为丝绸之路的起点 — — 川渝地区，发展出了另一种鲜味：以豌豆为基的料理。</p><p>豌豆尖汤。冬天的时候，豌豆尖刚长出来，嫩得掐得出水。烫一下就捞出来，翠绿翠绿的，带着一股清甜。豌豆尖是最不需要厨艺的菜 — — 因为它本身就是最好的。</p><p>凉粉。黄豌豆磨成浆，沉淀，煮成糊，冷却凝固。切块，浇上红油辣椒、蒜水、醋，撒一把葱花。夏天的凉粉摊，总是围满了人。</p><p>锅盔夹凉粉。南充的特产。锅盔是酥的，凉粉是软的，咬一口，酥脆和绵软在嘴里交织。我大学时候的食堂，三块钱一个，每次排队都要等十分钟。</p><p>碗杂面。豌豆煮得软烂，和杂酱拌在一起。豌豆的甜和杂酱的咸，是绝配。</p><p>豆汤面。宜宾的早餐，一碗豆汤面，配一个叶儿粑。豆汤是金黄色的，豌豆煮到开花，汤浓而不腻。</p><h4>为什么会想到豌豆？</h4><p>这篇文章构思了很久。我也不知道为什么，只是我的大脑中有很多件与豌豆相关的事情，在某一瞬间突然关联起来。</p><p>最近都忙于做 AI 相关的东西，似乎已经脱离太多人文的东西。我想要我的记忆，我的经历留下来。</p><p>在某天买锅盔凉粉的时候，看着老板拿勺子刮过凉粉表面，我想起凉粉似乎是豌豆做的。于是问了老板凉粉是什么做的，果然是豌豆。</p><p>在这一瞬间，我大脑中关于豌豆的记忆被激活。</p><p>豌豆从西域来，在川渝落了脚。 豌豆在童话里，是敏感的象征。 豌豆在生物学里，是遗传定律的起点。 豌豆在我的饭桌上，是童年的甜、少年的粉、成年的鲜。</p><p>这些看起来毫不相关的事情，被一颗豌豆串在了一起。</p><p>最近过年假期，终于有时间把这些记下来。</p><p>大宛已经没有了。孟德尔已经不在了。安徒生已经写完了。我也已经从大学毕业了好多年。</p><p>我吃着它，想起这一切，记忆中的一件件往事慢慢浮现。</p><p>旧事已去，只可追忆，但豌豆还在。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0389b245519b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[日本 JAWS 之旅]]></title>
            <link>https://medium.com/@jetdeng/%E6%97%A5%E6%9C%AC-jaws-%E4%B9%8B%E6%97%85-6f33c3117497?source=rss-bdff15df02b6------2</link>
            <guid isPermaLink="false">https://medium.com/p/6f33c3117497</guid>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[JetSquirrel]]></dc:creator>
            <pubDate>Sun, 15 Mar 2026 15:58:29 GMT</pubDate>
            <atom:updated>2026-03-20T12:10:57.874Z</atom:updated>
            <content:encoded><![CDATA[<p>有幸入选 AWS 社区交流项目，3月6–8日在东京度过了三天充实的旅程。这也是我第一次出国，亲身感受了不同的文化。</p><p>那作为一个老二次元，JAWS Days 就拿着明日香玩偶去各个摊位打卡，与各个工作人员进行了深入的交流（其实互相都不怎么听得懂对方的英语)。在这里，我想向大家分享一下 JAWS Days 各个展台的情况</p><p>JAWS（大白鲨）是日本 AWS UG 的吉祥物，与明日香都是橙色系，这是日本 AWS UG 官方展台，左边的展示了各个支部，分为是42个地域支部与26个领域支部。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6m6oWvnAJxiX8Phi" /><figcaption>日本 AWS UG 的支部</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*8FxEd5qTvxMXaFlj" /><figcaption>与 JAWS 的吉祥物合影</figcaption></figure><p>日本的活动一大特色就是展台上充斥着各种各样的萌物</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*4Qg5c6rtbDOTE3_9" /><figcaption>一只可爱的小狗</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ZVlK-6N2V1ousH6t" /><figcaption>一个博客网站，吉祥物是猫</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*W0J7dh5ox5zrGp8a" /><figcaption>AI 配对婚恋网站，吉祥物是两只鱼</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6h7L2EXXt0R88G55" /><figcaption>云朵</figcaption></figure><p>吧唧（badge）也是一大特色，一个展台的小礼品</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*dy3RTTZnrlJUDb03" /><figcaption>吧唧上面的意思是「我现在很幸福」</figcaption></figure><p>和阿尼亚 Coser 志愿者的合照</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*jX7hFQf-O4agr6Eo" /></figure><p>我们大中华/韩国展台的合影</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*xBaWVGVDrCFOS4on" /></figure><p>在一个用 AI 来生成贴纸展台，我们大中华区 User Group 生成了自己的贴纸。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qeUS_b_QWygDaJ-Y" /></figure><p>最后，很感激亚马逊云社区给了我们这一次机会，在 Jaws Days 上见识到日本的商业现状，以及与不同国家工程师、架构师、AI 从业者进行了沟通交流。对于「出海选 AWS」这句话有了更深的认知。</p><p>顺带一提，展位的小狗到了我的背包上</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jVK7LOFgCdix0NTXq2V1ng.jpeg" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6f33c3117497" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[如何注册 MD 域名]]></title>
            <link>https://medium.com/@jetdeng/%E5%A6%82%E4%BD%95%E6%B3%A8%E5%86%8C-md-%E5%9F%9F%E5%90%8D-c92e5a4327d6?source=rss-bdff15df02b6------2</link>
            <guid isPermaLink="false">https://medium.com/p/c92e5a4327d6</guid>
            <dc:creator><![CDATA[JetSquirrel]]></dc:creator>
            <pubDate>Mon, 16 Feb 2026 15:17:32 GMT</pubDate>
            <atom:updated>2026-02-16T15:17:32.602Z</atom:updated>
            <content:encoded><![CDATA[<p>最近 MD 域名火起来了，一大批以 MD 结尾的域名涌现出来，SOUL.md、AGENTS.md、CLUADE.md。最近我在听一期播客，给我的建议也是去注册 .md 域名，我果断购入了一批。</p><p>在推上我看到有些朋友在问如何注册域名，那么我分享一下。长话短说，</p><p><a href="http://nic.md"><strong>到 http://nic.md</strong></a><strong> 进行注册，184.17元（450 摩尔多瓦列伊，26.69美元）一个域名/年，支持万事达和 Visa 支付。</strong></p><p><a href="https://zh.wikipedia.org/zh-hans/.md">.md</a> 原本为摩尔多瓦和德涅斯特河沿岸的国家及地区顶级域的域名，而刚好跟 Markdown 的缩写重合。MD 格式天然适合 GenAI，无论是训练数据集，还是行业生态，都是 Markdown 格式。最近 Claudflare 更是推出在网站源头将内容转成 MD 的功能。所以未来写给 AI 的看的网址很有可能是以 md 结尾。</p><p>最后，我也购买力一批，比如我将 AI Agent SOUL.md 放到了 <a href="http://ASUKA.md">ASUKA.md</a>。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*je7WtF8Pye6p0WvF" /><figcaption><a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">嘴巴塞满坚果的松鼠</a></figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c92e5a4327d6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[来吧，AI 的狂欢]]></title>
            <link>https://medium.com/@jetdeng/%E6%9D%A5%E5%90%A7-ai-%E7%9A%84%E7%8B%82%E6%AC%A2-0af712c86d73?source=rss-bdff15df02b6------2</link>
            <guid isPermaLink="false">https://medium.com/p/0af712c86d73</guid>
            <category><![CDATA[随笔]]></category>
            <dc:creator><![CDATA[JetSquirrel]]></dc:creator>
            <pubDate>Mon, 16 Feb 2026 14:04:25 GMT</pubDate>
            <atom:updated>2026-02-16T14:59:14.545Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*HDFP2m47hhow9mSL" /><figcaption>Photo by <a href="https://unsplash.com/@pearseoh?utm_source=medium&amp;utm_medium=referral">Pearse O&#39;Halloran</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>又到了一年的春节，总结我个人过去的一年工作上经历很是坎坷。年初从 DevOps 转化角色到做内部业务的 AI 转型，再到后来公司发生变故无法继续推进 AI 项目，最后我看到前司衡量 AI 的单位居然是「工时」，毅然决定离开去开启一段更多机会接触 AI 的工作。</p><p>同样，在 AI 圈里也是发生在的翻天覆地。业界总在提「奇点」已来，过去的炒作更多，或者从我的角度看至少在有生之年不会看到。但是，自从 ChatGPT 发布后，这种感觉随着各个 AI 模型或工具的发布进一步加深了我的感觉。特别是在去年，整个时间都被加速了：</p><ul><li>如果说 Claude Code 的出现改变了整个编程的方式，那么 OpenClaw 对于我来说已经是接近认知中的 AGI</li><li>如果说 Sora 对于传统的内容产出是巨大的打击，那么 Seeddance 制作的内容更是让人惊艳，比如 「<a href="https://www.bilibili.com/video/BV15HcbzREPc">新鸳鸯蝴蝶梦</a>」无论是从画面音乐都无可挑剔</li><li>如果说「星际之门」计划只是一场资本的泡沫，那么 Minimax 和智谱的上市是让普通人也可以参与到这次 AI 的狂欢中，看到暴涨的股票我拍断腿后悔为啥不开港股</li></ul><p>去年年初 DeepSeek 不仅仅只是改变了业界，对我来说，让我花更多的心思在 AI 上，年底的 OpenClaw 发布后更是颠覆整个我对 AI Agent 的认知。<br>我很庆幸，我拿到了 AI 的入场券，我也很焦虑，爆炸信息量不断涌入我的大脑。</p><p>但总的来说，我乐在其中，数不尽的新玩具冒出，可以供我挑选和玩耍，我喜欢新技术更享受把自己筹码 All in AI 的感觉。</p><p>来吧一起加入 AI 的狂欢。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0af712c86d73" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[「无盘」化新趋势？从实践到理论探索 S3]]></title>
            <link>https://medium.com/@jetdeng/%E6%97%A0%E7%9B%98-%E5%8C%96%E6%96%B0%E8%B6%8B%E5%8A%BF-%E4%BB%8E%E5%AE%9E%E8%B7%B5%E5%88%B0%E7%90%86%E8%AE%BA%E6%8E%A2%E7%B4%A2-s3-721317b83f6c?source=rss-bdff15df02b6------2</link>
            <guid isPermaLink="false">https://medium.com/p/721317b83f6c</guid>
            <category><![CDATA[database]]></category>
            <category><![CDATA[s3]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[JetSquirrel]]></dc:creator>
            <pubDate>Wed, 17 Dec 2025 18:04:02 GMT</pubDate>
            <atom:updated>2025-12-17T18:05:52.585Z</atom:updated>
            <content:encoded><![CDATA[<p>在今年六月份上海的亚马逊云的 Summit，ScopeDB 的创始人 tison 向我分享了 ScopeDB 的「无盘」设计方案 — 即<strong>直接将数据库数据到 S3 </strong>。而最近我也注意到 Kafka 和 Clickhouse Cloud 的「无盘」趋势。</p><p>借此，我们想聊一聊 重新审视一下 Amazon S3， 如何在这个很慢的服务上构建数据库。</p><h3>什么是「无盘」？</h3><p>首先需要澄清的是：</p><blockquote><strong><em>「无盘」并不是没有存储，而是跳过本地块设备，直接把数据写入对象存储（S3）。</em></strong></blockquote><p>在这种架构中，S3 不再只是备份层或归档层，而是<strong>主存储层</strong>。</p><p>作为对比，在传统架构中（例如 Prometheus + Thanos 的 sidecar 模式）：</p><ul><li>Prometheus 先将数据写入本地磁盘（WAL / head block）</li><li>定期压缩为 block</li><li>再由 Thanos Sidecar 上传到对象存储</li></ul><p>这种模式本质上仍然是<strong>磁盘优先</strong>。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iZDBlza8o2ub5p4iTfTcrw.png" /><figcaption>thanos sidecar</figcaption></figure><p>而我们今天讨论的这些系统，正在尝试反过来。</p><h3>走向「无盘」的项目</h3><h4>ScopeDB</h4><p>ScopeDB[3] 是一个面向<strong>可观测性数据</strong>的数据库。日志、指标、追踪数据天然是 <strong>append-only</strong> 的，查询也大多是<strong>时间范围扫描</strong>。</p><p>ScopeDB 通过精心设计的分片与索引结构，将写入和查询映射为 <strong>S3 上的对象操作</strong>，从而绕开了 S3 在低延迟随机 IO 场景下的短板。</p><h4>Kafka</h4><p>Kafka 的「无盘化」并不是完全取消本地存储，而是：</p><ul><li>将<strong>历史数据与副本负担</strong>转移到 S3（或 S3 兼容对象存储）</li><li>让 broker 节点更接近<strong>无状态</strong></li></ul><p>Confluent 推动的 <strong>Tiered Storage</strong>，其核心思想正是：</p><blockquote><strong><em>热数据留在本地，冷数据卸载到对象存储。</em></strong></blockquote><p>这样一来，扩缩容、故障恢复都会显著简化。</p><h4>Clickhouse Cloud</h4><p>ClickHouse Cloud [4] 近几年逐步演进出一套 「<strong>无盘 / 无状态计算</strong>」 的架构，其目标在于：</p><ul><li>计算节点不再依赖本地磁盘</li><li>节点可以快速启动和销毁</li><li>存储与计算彻底解耦</li></ul><p>通过将数据和元数据统一放入共享存储系统，ClickHouse Cloud 实现了真正意义上的 <strong>stateless compute</strong>。</p><p>ScopeDB、Kafka、ClickHouse Cloud 虽然面向的场景完全不同，但它们正在走向同一个方向：<strong>让对象存储承担原本属于本地磁盘的职责。</strong></p><h3>为什么要「无盘」</h3><p>我们在学习计算机体系过程中会了解到，计算机存储是分层的，从 CPU 缓存到内存，再到磁盘以及网络存储设备，速度从快到慢，同时价格由贵到便宜。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9mui_zJgToWSsk6W1Qcb5g.png" /><figcaption>配图来源于《深入理解计算机系统》，由 ChatGPT 重绘</figcaption></figure><p>而在 AWS 上的存储服务，也对应有着不同的层级：</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GeZeMfrNj_Yu2i1LndnvOg.png" /></figure><p>在 AWS 上，存储分层大致如下：</p><ul><li><strong>EC2（计算实例内存）</strong>：速度最快，适合临时数据和高性能需求，但数据不持久。</li><li><strong>EBS（弹性块存储）</strong>：块级存储，适合数据库、持久化磁盘，支持快照和高可用，但成本较高。</li><li><strong>S3（对象存储）</strong>：高可用、低成本、弹性扩展，适合大规模数据、日志、备份、数据湖等场景。</li><li>此外，S3 还提供了多种存储类别（如<strong>S3 Glacier，</strong> S3 Standard-IA, S3 One Zone-IA 等）</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/952/1*jBe1hY3959qRfaNv2zZuPQ.png" /></figure><p>我们知道，越接近计算的越贵，从 CPU 到硬盘是读写速度减慢同时价格逐渐变低的过程<a href="https://www.scopedb.io/blog/manage-observability-data-in-petabytes"><em>[1]</em></a>。这个规律同样也适用于 AWS 上的存储服务</p><p>根据 S3 的特点，我们可以看到两个方面的推动因素。</p><ol><li><strong>成本驱动：</strong></li></ol><p>而云上唯一可用的商品块设备只有 EBS 类型，这在存储 PB 级数据时非常昂贵。</p><ul><li>EBS ：$80,000 — $125,000/1 PB/月</li><li>S3 ：$21,550/1 PB/月</li></ul><p>即使是 1 PB 的 EBS 存储，每月的成本也为 80,000 至 125,000 美元，相比之下，在 S3 上存储 1 PB 的数据每月费用为 21,550 美元[1]。<strong>成本差距接近 4–6 倍</strong>。</p><p>2. <strong>简化运维：</strong></p><p>直接写入 S3 可以简化运维工作。无需管理和维护底层存储设备，减少了故障排查和数据恢复的复杂性。S3 提供了高可用性和持久性，用户可以专注于应用逻辑而非存储管理。</p><h3>为什么可以直接写入到 S3</h3><p>我们知道数据库由于有大量读写操作，使用块存储是更合适的方式。直接写入 S3 会由于时延不满足要求，以及大量读写操作造成高额请求开销。</p><p>那为什么 ScopeDB 和 Kafka 可以做到呢？</p><p>我们来回顾这两个项目，有一个共同的特点，那就是「<strong>顺序</strong>」：</p><ul><li><strong>ScopeDB</strong>：应用于可观测数据，有大量的写入并且查询会有时间范围</li><li><strong>Kafka</strong>：采用队列的方式顺序写，而读的时候会顺序读</li></ul><p>这类场景下，数据的写入和读取都可以批量、顺序地进行，极大地减少了对低延迟和高并发的需求，S3 的高吞吐和低成本优势就能被最大化利用。</p><p>S3 的对象存储模型决定了它非常适合 append-only、immutable 的数据模式。每个对象都可以看作是一个 chunk，写入时只需要追加新对象，读取时批量拉取对象即可。</p><p>S3 可能不太适合于需要频繁更新的场景，但对于日志、事件流、归档等场景，具有天然的优势。</p><h3>深入剖析 S3</h3><p>从何说起 S3 的天然优势？ 更进一步，我们想要分析 S3 的架构，来了解为什么可以这么做</p><p><strong>1. 存储机制</strong></p><p>S3 的底层构建于海量的 HDD，由于<strong>物理原因[2]</strong>，HDD 速度很慢，又容易物理的损坏。那 S3 是如何做到以下特性的？</p><ul><li><strong>高可用</strong>：11 个 9 的持久性（99.999999999%）</li><li><strong>高扩展</strong>：可以存储几乎无限量的数据</li><li><strong>低成本</strong>：远低于块存储的价格</li></ul><p>而实现这些背后靠的是</p><ul><li><strong>分片</strong>：每个对象被拆分成多个数据块</li><li><strong>纠删码（Reed-Solomon EC）</strong>：生成校验块，允许部分丢失后恢复</li><li><strong>多副本冗余</strong>：数据块分布在不同的存储节点和机架上</li><li><strong>自动自愈机制</strong>：系统持续自我检测和修复</li><li><strong>规模化带来的平滑负载</strong>：海量节点分摊故障概率</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*2ClS0xckN7_CO2tz.png" /><figcaption><a href="https://bigdata.2minutestreaming.com/p/how-aws-s3-scales-with-tens-of-millions-of-hard-drives">How AWS S3 serves 1 petabyte per second on top of slow HDDs</a></figcaption></figure><p>每个对象会被拆分成多个数据块和校验块，分布在不同的存储节点和机架上，哪怕坏掉几个硬盘、甚至整个机架挂了，数据都能无损恢复。系统持续自我检测和修复，持久性是动态评估、持续保障的。</p><p><strong>2. 架构分层</strong></p><p>S3 架构分为三层[5]：</p><ul><li><strong>API 层</strong>：负责接收请求、做负载均衡。</li><li><strong>命名空间服务</strong>：负责对象元数据和一致性。</li><li><strong>存储管理层</strong>：负责实际的数据存储、复制、分层和后台维护。</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f8CntrwvQl1tBQrCOFLplA.png" /><figcaption><a href="https://highscalability.com/behind-aws-s3s-massive-scale/">Behind AWS S3’s Massive Scale</a></figcaption></figure><p>底层存储后端采用 LSM（Log-Structured Merge Tree）结构，顺序写入磁盘，充分利用 HDD 的吞吐能力。新数据块天然更「热」，老数据会自动冷却、迁移、均衡。</p><p><strong>3. 为什么顺序写入很关键</strong></p><p>底层存储后端采用 LSM（Log-Structured Merge Tree）结构，顺序写入磁盘，充分利用 HDD 的物理特性。新数据块天然更”热”，老数据会自动冷却、迁移、均衡。</p><p><strong>S3 底层特性</strong></p><ul><li>LSM 顺序写入</li><li>分层存储</li><li>前缀索引</li></ul><p><strong>无盘数据库的利用方式</strong></p><ul><li>append-only 模式，只追加不修改</li><li>冷热分离，老数据自动降级</li><li>按时间分片，支持范围扫描</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*c0199x6EUQZP8B1lGvLnJQ.jpeg" /></figure><h3>实践</h3><p>我们用命令行工具来演示最简单的 S3 时间序列数据的写入和查询。</p><pre># 写入<br>echo &#39;{&quot;ts&quot;:&quot;2025-12-15T10:30:00&quot;,&quot;value&quot;:&quot;hello&quot;}&#39; | \<br>  aws s3 cp - s3://bucket/data/2025/12/15/103000_abc.json<br><br># 查询某天所有数据<br>aws s3 cp s3://bucket/data/2025/12/15/ - --recursive | jq -s &#39;.&#39;<br><br># 列出对象（前缀扫描）<br>aws s3 ls s3://bucket/data/2025/12/15/</pre><p>从这里例子我们可以看到，我们只会通过追加的方式添加新的数据，并且按照查询语句可以按照时间顺序读取，最后根据前缀扫描接口做到批量列出数据。</p><pre># sh顺序写入数据<br>$ echo &#39;{&quot;ts&quot;:&quot;2025-12-15T10:30:00&quot;,&quot;value&quot;:&quot;hello&quot;}&#39; | \<br>    aws s3 cp - s3://bucket/data/2025/12/15/103000_abc.json</pre><p>成功写入到 S3 中</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s7LBR0IO3Xex7IsaNTQ5ew.png" /><figcaption>S3 以日期为存储路径</figcaption></figure><p>执行根据前缀扫描命令</p><pre># 列出对象（前缀扫描）<br>$ aws s3api list-objects-v2 \<br>  --bucket s3-diskless-database-demo \<br>  --prefix data/2025/12/18/<br><br>{<br>    &quot;Contents&quot;: [<br>        {<br>            &quot;Key&quot;: &quot;data/2025/12/18/103000_abc.json&quot;,<br>            &quot;LastModified&quot;: &quot;2025-12-17T17:46:36.000Z&quot;,<br>            &quot;ETag&quot;: &quot;\&quot;3760ca4d8f2d4546910fc32b74b0db79\&quot;&quot;,<br>            &quot;ChecksumAlgorithm&quot;: [<br>                &quot;CRC32&quot;<br>            ],<br>            &quot;ChecksumType&quot;: &quot;FULL_OBJECT&quot;,<br>            &quot;Size&quot;: 45,<br>            &quot;StorageClass&quot;: &quot;STANDARD&quot;<br>        }<br>    ],<br>    &quot;RequestCharged&quot;: null,<br>    &quot;Prefix&quot;: &quot;data/2025/12/18/&quot;</pre><p>在上面的 demo 中，我们实现了一个 shell 命令就实现了无盘顺序写入以及批量读。当然，这离真正的工程实现还有很远的距离，但我们可以由此窥见「无盘」架构设计的精妙之处，以及 S3 的强大。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*MUf8yKnHFRwi8kvaOEglhA.jpeg" /><figcaption>S3 笑话</figcaption></figure><h3><strong>总结</strong></h3><p>「无盘」不是一个噱头，而是一种在特定场景下非常务实的架构选择。实践证明，只要设计得当，S3 完全可以作为数据库的主存储层。</p><p>当然，「无盘」并非银弹。对于随机读写，频繁更新、高 QPS 点查的场景，本地块存储依然不可替代。</p><h3>参考</h3><p>[1]<a href="https://www.confluent.io/blog/kafka-tiered-storage-cloud-native-architecture/"> 岔路口：决定卡夫卡的无盘未来 — 杰克·范莱特利</a></p><p>[2]<a href="https://www.cs.cmu.edu/~213/">《深入理解计算机系统》（Computer Systems: A Programmer’s Perspective）</a></p><p>[3] <a href="https://www.scopedb.io/blog/manage-observability-data-in-petabytes">ScopeDB</a></p><p>[4] <a href="https://clickhouse.com/blog/clickhouse-cloud-stateless-compute">No more disks: the architecture behind stateless compute in ClickHouse Cloud</a></p><p>[4]. <a href="https://bigdata.2minutestreaming.com/p/how-aws-s3-scales-with-tens-of-millions-of-hard-drives">How AWS S3 serves 1 petabyte per second on top of slow HDDs 5. Hard disk drive (HDD) — Physical Mechanism</a></p><p>[5]: <a href="https://en.wikipedia.org/wiki/Hard_disk_drive">https://en.wikipedia.org/wiki/Hard_disk_drive</a> “Hard disk drive (HDD ) — Physical Mechanism”</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=721317b83f6c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[再谈 P95 — 原理]]></title>
            <link>https://medium.com/@jetdeng/%E5%86%8D%E8%B0%88-p95-%E5%8E%9F%E7%90%86-20d0c651a9f7?source=rss-bdff15df02b6------2</link>
            <guid isPermaLink="false">https://medium.com/p/20d0c651a9f7</guid>
            <dc:creator><![CDATA[JetSquirrel]]></dc:creator>
            <pubDate>Tue, 16 Dec 2025 18:14:33 GMT</pubDate>
            <atom:updated>2025-12-16T18:14:33.893Z</atom:updated>
            <content:encoded><![CDATA[<h3>再谈 P95 — 原理</h3><h3>P95 是什么？</h3><p>假设有个班的学生，让他们按照身高从低往高排列，那么</p><ul><li>P0 = 最小值 → 最矮的同学</li><li>P50 = 中位数 → 中间高度的同学</li><li>P100 = 最大值 → 最高的同学</li></ul><p>由此，P95 既是第 95 高位置的同学。</p><p>在 IT 系统的时间中，P95 通常用于衡量系统的时延。使用最大值来衡量的一个问题是，很容易被一些极端值所影响。我们在实际业务系统中，需要关注受时延影响最大的一批用户，而不是最大的一个用户。</p><h3>P95 怎么算？</h3><p>以时延来看看，我们该如何计算时延的 P95？</p><h4>a. 排序</h4><p>最容易想到的时候，把所有的数据进行排序，然后从低往高找第 95% 位置的数据。当然这个方案在真实业务是不可能用的，排序带来的开销很高，在实际应用没什么价值</p><h4><strong>b. 桶</strong></h4><p>以 Prometheus 为例，其 Histogram 通过桶的数据结构来实现。会设计不同时延的桶，</p><p>例如 [(0,1),(1,2),…..]，统计到的时延数据会被放到</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gHfIe0ErvhOOqgEFqlsTkA.png" /><figcaption>用桶计算 P95</figcaption></figure><h4>c. 堆</h4><p>在学习堆这个数据结构的时候，了解到其也可以用于排序，而且其可以做到部分排序，</p><p>那么不妨脑洞一下堆是否可以用于 P95 的计算。</p><p>当然可以！但前提是是知道所有的数据，才可以使用堆来计算，而流式的数据就无法做到。</p><p><strong>d. CKMS</strong></p><p>既然聊到了 Histogram，那么不得不提 Summary ，这两个的概念应该差不多吧，他们的实现也应该是同样的逻辑吧？然而当我问了一下我的 AI 助手，Amazing 呀！它们俩采用了完全不同的算法。</p><p>Summary 使用了叫 <strong>CKMS</strong> 的算法，总而言之就是把「相近的多个点用一个点来代表」。</p><p>还是回到最开始的例子，站了一排同学，几个差不多高的同学可以用一个来占位，比如 3 位同学身高相差不过 1 厘米，那就可以用一位同学来作为代表占位，另外两位同学就不用排队而去休息了</p><p>核心逻辑是：</p><p>1) 插入数据（Insert）</p><p>把数据插入到有序链表中。</p><p>2) 合并节点（Compress）</p><p>如果两个节点合并后误差仍可接受 → 把它们压缩成一个。</p><p>3) 误差限制（Invariant）</p><p>始终守住设置的最大错误率（如 0.01）</p><p>g + δ 决定了两个节点之间能代表多少真实数据。<br> 扫描累加，达到 95% 的位置，就是 P95。</p><p><strong>关键数字节点 = 满足 CKMS 误差不等式（g + δ ≤ 2εN）的有序节点集。</strong></p><p>最终，扫描这些节点就能估算出 P95/P99 的值。</p><h3>总结一下</h3><p>总之，这几类算法的核心就在于「压缩」，<strong><em>只保存对理解数据最关键的部分，其他能压就压。都在大量数据中，只保留能代表整体的信息，<br> 其余部分通过数学规则压缩掉。</em></strong></p><p>其核心哲学是：</p><p><strong>删不重要的点，保留最关键的点</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=20d0c651a9f7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[YACE 源码解读（一）]]></title>
            <link>https://medium.com/@jetdeng/yace-%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB-%E4%B8%80-6f651d918b0b?source=rss-bdff15df02b6------2</link>
            <guid isPermaLink="false">https://medium.com/p/6f651d918b0b</guid>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[prometheus]]></category>
            <category><![CDATA[cloudwatch]]></category>
            <category><![CDATA[observability]]></category>
            <dc:creator><![CDATA[JetSquirrel]]></dc:creator>
            <pubDate>Fri, 31 Oct 2025 05:07:43 GMT</pubDate>
            <atom:updated>2025-10-31T05:08:49.318Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*avE5005cVHao-UF0Ihp0rQ.jpeg" /><figcaption>CloudWatch 和 Prometheus 3D 打印小饼干</figcaption></figure><h3><strong>概述</strong></h3><p><a href="https://github.com/prometheus-community/yet-another-cloudwatch-exporter"><strong>YACE</strong></a>（<strong>Y</strong>et-<strong>A</strong>nother-<strong>C</strong>loudwatch-<strong>E</strong>xporter) 是一个基于 Golang 编写，开源的 AWS CloudWatch 的指标（metrics）导出器（exporter）。其可以将 CloudWatch 的指标导出为 Prometheus 格式的指标，通过 Prometheus 抓取后可以通过 PromQL 来进行查询对应的指标，例如 aws_ec2_cpu_utilization。</p><p>本文将通过学习 yace 的代码，来了解如 AWS CloudWach 指标的 API 接口，以及熟悉 Metrics 的机制。我们将从两个部分进行解读：</p><ul><li>配置读取与 CloudWatch 客户端初始化</li><li>从 AWS API 获取指标并转换为 Prometheus Exporter 的格式</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xvhsez7mx8gWudI9YZzFQg.png" /><figcaption>YACE 代码结构（通过 <a href="https://gitdiagram.com/prometheus-community/yet-another-cloudwatch-exporter">GitDiagram</a> 生成）</figcaption></figure><p>由于篇幅有限，本文主要关注配置和 CloudWatch 的客户端逻辑。</p><h3>配置读取</h3><p>在开始主流程的解读前，我们将会关注如何配置文件从 AWS 获取指标，客户端</p><ul><li>配置层</li><li>客户端层</li></ul><h4>配置层</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*vBj4pp0ex-uu1EGHQaY5zg.png" /></figure><p>YACE 通过读取 YAML 来进行配置，其配置文件示例如下：</p><pre>apiVersion: v1alpha1<br>discovery:<br>  jobs:<br>    - type: AWS/EC2<br>      regions:<br>        - us-east-1<br>      period: 300<br>      length: 300<br>      metrics:<br>        - name: CPUUtilization<br>          statistics: [Average]</pre><p>在上述的文件中， YACE 配置 discover 来抓取指标，discover 可以通过 tag 自动发现服务。</p><p>每个 job 控制着抓取不同 AWS 服务的指标，例如 EC2, Lambda, ECS。</p><ul><li><strong>type</strong>： CloudWatch Metrics 的 namepsace</li><li><strong>region</strong>：从特定的 region 获取指标（注，部分指标只在特定的region，如cloudfront）</li><li><strong>period</strong>：进行数据聚合的间隔</li><li><strong>length</strong>：最久可获取到的时长</li><li><strong>metrics</strong>：要从该服务拉取的指标类型，可以通过在CloudWatch中的指标名字定位，同时可以指定聚合的类型。</li></ul><p>对应着以上的配置文件，在 YACE 的代码中，将 config.yaml 中的配置读取：</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/40189efd5c8865a6dc1b8b26864bf02c/href">https://medium.com/media/40189efd5c8865a6dc1b8b26864bf02c/href</a></iframe><p>上述代码摘抄于 <a href="https://github.com/prometheus-community/yet-another-cloudwatch-exporter/blob/master/pkg/config/config.go">config.go</a>，该部分的代码定义了结构体以及从 YAML 文件读取配置和进行验证的方法。ScrapeConf 的 Load() 方法中实现了 YAML 读取并写入到结构体中的细节。</p><p>以 Metric 结构体为例，其可以定义了之前中配置文件中的 Name 和 Statistics ，还有一些之前没有列出的配置项，如 Delay、NilToZero、AddCloudwatchTimestamp等配置选项参数，关于这些配置的内容可以参考官方配置的文档：<a href="https://github.com/prometheus-community/yet-another-cloudwatch-exporter/blob/master/docs/configuration.md">yet-another-cloudwatch-exporter/docs/configuration.md</a></p><p>另外，在 <a href="https://github.com/prometheus-community/yet-another-cloudwatch-exporter/blob/master/pkg/config/services.go">services.go </a>中，服务的名称和别名做了定义，也针对某些服务做了特殊处理，这些内容会被存放到 ServiceConfig 中</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0ee88c25ca98b7092aba5571ab0bda0f/href">https://medium.com/media/0ee88c25ca98b7092aba5571ab0bda0f/href</a></iframe><p>例如,「AWS/Usage」和「AWS/EC2」, 其中 Namspace 为「AWS/EC2」的做了一些特殊的处理，</p><ul><li>Namespace： 对应着 CloudWatch Metrics 的命名空间</li><li>Alias：一些支持在配置文件中设置的别名，例如 <em>AWS/EC2</em> namespace 的别名可以设置为 <em>ec2</em></li><li>ResourceFilters：这是一个字符串列表，用作 resourcegroupstaggingapi.GetResources 请求中的过滤器。它用于在资源组标记 API 请求中指定要过滤的资源类型在 AWS/EC2 中，ResourceFilters 被设置为 ec2:instance，这意味着过滤器将专门针对 EC2 实例进行。</li><li>DimensionRegexps：可选的正则表达式列表，用于从资源 ARN 中提取维度名称。 AWS/EC2 的表达式regexp.MustCompile(&quot;instance/(?P&lt;InstanceId&gt;[^/]+)&quot;)将从 ARN 中提取 InstanceId 维度</li></ul><p>上述的参数被定义在 ServiceConfig。我们来看一下 config 的定义部分，在 ServiceConfig 中。</p><p>而抓取的类型在 YACE 中被分成了三种：</p><ul><li>Job：通过 tag 自动发现服务资源，并自动抓取</li><li>Static：手动配置要抓取的资源</li><li>CustomerNamespace：自定义的指标，如 CloudWatch Agent 采集的指标，使用 SDK 上传的自定义指标</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/08b8764096f7314e90aac4408b0c5ce8/href">https://medium.com/media/08b8764096f7314e90aac4408b0c5ce8/href</a></iframe><p>通过上面的代码即可将 YACE 的配置读取到 Golang 的结构体。带给我们的启发在于如何定义配置文件以对接 AWS 的 SDK 和 API，以获取所需的数据。</p><h3>CloudWatch 客户端初始化</h3><p>YACE 项目使用了 AWS 的 Golang SDK，其中涉及到 v1/v2 的 AWS Golang SDK。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tGJMwRXGfWTMDXxAVIGnQg.png" /></figure><p>而 AWS SDK 中会涉及到不同服务的客户端，yace 主要使用了 3 类客户端：</p><ul><li>Account Client 完成认证</li><li>CloudWatch Client 负责获取数据</li><li>Tagging Client 负责服务发现和过滤</li></ul><h4><strong>1. 认证</strong></h4><p>我们首先先找到与AWS进行认证的逻辑，与 AWS 进行认证的部分在factory.go文件中，通过createStsOptions方法和awsConfigForRegion函数实现。这些方法设置了AWS STS（安全令牌服务）选项和区域配置。</p><pre>func awsConfigForRegion(r model.Role, c *aws.Config, region awsRegion, stsOptions func(*sts.Options)) *aws.Config {<br> regionalConfig := c.Copy()<br> regionalConfig.Region = region<br><br> if r == defaultRole {<br>  return &amp;regionalConfig<br> }<br><br> // based on https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/stscreds#hdr-Assume_Role<br> // found via https://github.com/aws/aws-sdk-go-v2/issues/1382<br> regionalSts := sts.NewFromConfig(*c, stsOptions)<br> credentials := stscreds.NewAssumeRoleProvider(regionalSts, r.RoleArn, func(options *stscreds.AssumeRoleOptions) {<br>  if r.ExternalID != &quot;&quot; {<br>   options.ExternalID = aws.String(r.ExternalID)<br>  }<br> })<br> regionalConfig.Credentials = aws.NewCredentialsCache(credentials)<br><br> return &amp;regionalConfig<br>}</pre><ul><li>创建基础 AWS 配置的区域副本。</li><li>如果角色是默认角色（AK/SK），直接返回区域配置。</li><li>对于非默认角色，使用 AWS STS 进行角色假设，并通过stscreds.NewAssumeRoleProvider设置配置中的凭证。</li></ul><p>而这些认证 credentals 将会被存储到 cachedClients，</p><p>数据结构如下</p><pre>type cachedClients struct {<br> awsConfig *aws.Config<br><br> onlyStatic bool<br> cloudwatch cloudwatch_client.Client<br> tagging    tagging.Client<br> account    account.Client<br>}</pre><p>其中，将会根据 role 和 region 来区分 client，并将其存放到 cache 中</p><pre>cache := map[model.Role]map[awsRegion]*cachedClients{}<br>  // 按照job的类型进行区分，比如ec2,s3<br> for _, discoveryJob := range jobsCfg.DiscoveryJobs {<br>  // 按照role区分，一般来说一个role对应着一个aws account<br>  for _, role := range discoveryJob.Roles {<br>   if _, ok := cache[role]; !ok {<br>    cache[role] = map[awsRegion]*cachedClients{}<br>   }<br>    // 按照 region 进行区分<br>   for _, region := range discoveryJob.Regions {<br>    // 获取区域的客户端和认证的逻辑<br>    regionConfig := awsConfigForRegion(role, &amp;c, region, stsOptions)<br>    cache[role][region] = &amp;cachedClients{<br>     awsConfig:  regionConfig,<br>     onlyStatic: false,<br>    }<br>   }<br>  }<br> } </pre><p>我们从 README 找到了rolearn 配置文件的示例</p><pre>apiVersion: v1alpha1<br>sts-region: eu-west-1<br>discovery:<br>  jobs:<br>    - type: AWS/ECS<br>      regions:<br>        - eu-north-1<br>      roles:<br>        - roleArn: &quot;arn:aws:iam::1111111111111:role/prometheus&quot; # newspaper<br>        - roleArn: &quot;arn:aws:iam::2222222222222:role/prometheus&quot; # radio<br>        - roleArn: &quot;arn:aws:iam::3333333333333:role/prometheus&quot; # television<br>      metrics:<br>        - name: MemoryReservation<br>          statistics:<br>            - Average<br>            - Minimum<br>            - Maximum<br>          period: 600<br>          length: 600</pre><p>可以看到其分层关系 jobs -&gt; regions -&gt; roles 与 cache 的代码是对应的</p><p><a href="https://github.com/prometheus-community/yet-another-cloudwatch-exporter/blob/master/pkg/clients/v2/factory.go">yet-another-cloudwatch-exporter/pkg/clients/v2/factory.go</a></p><p>而 cachedClients 的作用，是为了生成要拉取数据所用 CloudWatch 客户端，</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qDFGpL4OrNYDwUXWQDH_TA.png" /></figure><p>上述的代码会获取 CloudWatch、Tagging 和 Account 的客户端。</p><h4>2.<strong> CloudWatch 客户端</strong></h4><p>对与 cachedClients 生成的三个我们接下来将重点理解 CloudWatch client的逻辑</p><p><a href="https://github.com/prometheus-community/yet-another-cloudwatch-exporter/blob/master/pkg/clients/cloudwatch/client.go">yet-another-cloudwatch-exporter/pkg/clients/cloudwatch/client.go</a></p><p>中定义了一个接口，主要是 Client 的接口</p><pre>type Client interface {<br> // ListMetrics returns the list of metrics and dimensions for a given namespace<br> // and metric name. Results pagination is handled automatically: the caller can<br> // optionally pass a non-nil func in order to handle results pages.<br> ListMetrics(ctx context.Context, namespace string, metric *model.MetricConfig, recentlyActiveOnly bool, fn func(page []*model.Metric)) error<br><br> // GetMetricData returns the output of the GetMetricData CloudWatch API.<br> // Results pagination is handled automatically.<br> GetMetricData(ctx context.Context, getMetricData []*model.CloudwatchData, namespace string, startTime time.Time, endTime time.Time) []MetricDataResult<br><br> // GetMetricStatistics returns the output of the GetMetricStatistics CloudWatch API.<br> GetMetricStatistics(ctx context.Context, logger *slog.Logger, dimensions []model.Dimension, namespace string, metric *model.MetricConfig) []*model.Datapoint<br>}</pre><p>其中，其实现了三个 CloudWatch 相关的接口，这三个为我们提供了获取指标的核心能力</p><ul><li>ListMetrics：查看当前的 CloudWatch 命名空间中有什么指标</li><li>GetMetricData： 获取 CloudWatch 服务中的数据，并通过 MetricDataResult 的结构体存储</li><li>GetMetricStatistics：返回统计后的数据，相比 GetMetricData 会有更少的开销</li></ul><p>以上的数据以 MetricDataResult 存储</p><pre>type MetricDataResult struct {<br> ID string<br> // A nil datapoint is a marker for no datapoint being found<br> Datapoint *float64<br> Timestamp time.Time<br>}</pre><p>为了解决 AWS API 限流的问题，yace 对 CloudWatch的客户端包装成了limitedConcurrencyClient，其</p><p>由于 AWS Golang Client 存在着不同的版本，CloudWatch 客户端同样区分了 v1 和 v2 ，我们后续主要通过 v2 的代码进行解读</p><p><a href="https://github.com/prometheus-community/yet-another-cloudwatch-exporter/blob/master/pkg/clients/cloudwatch/v2/client.go">yet-another-cloudwatch-exporter/pkg/clients/cloudwatch/v2/client.go</a></p><p>a) ListMetrics 用于列出符合条件的 CloudWatch 指标，并支持分页获取数据</p><p>参数：</p><ul><li>namespace：AWS服务命名空间</li><li>metric：指标配置</li><li>recentlyActiveOnly：是否只获取最近活跃的指标</li><li>使用分页器逐页获取数据并通过回调函数处理结果</li></ul><p>b) GetMetricData 可以批量获取指标数据</p><p>其支持：</p><ul><li>多个指标同时查询</li><li>自定义时间范围</li><li>自定义统计周期和统计方法</li><li>使用分页器处理大量数据</li><li>包含性能计数和错误监控</li></ul><p>c) GetMetricStatistics</p><ul><li>更少的数据开销</li><li>获取单个指标的详细统计信息</li><li>支持多种维度的数据查询</li><li>提供错误处理和日志记录</li></ul><p>在代码中提供了一些数据转换工具函数，主要目的是将 AWS 格式的数据统一为 Prometheus exporter 的数据格式</p><p>a) toModelMetric (74-85行)</p><ul><li>将 AWS CloudWatch 的指标数据转换为内部模型格式</li></ul><p>b) toModelDimensions (87-97行)</p><ul><li>将 AWS 维度数据转换为内部模型格式</li></ul><p>c) toMetricDataResult (149-160行)</p><ul><li>将 API 响应转换为标准化的指标数据结果</li></ul><p>d) toModelDatapoints (187-206行)</p><ul><li>将 CloudWatch 数据点转换为内部模型格式</li><li>处理扩展统计信息</li></ul><h4><strong>CloudWatch Client 初始化逻辑</strong></h4><p>a. 客户端被初始化入口，YACE 定义了一个 NewClient 函数：</p><pre>// pkg/clients/cloudwatch/v2/client.go<br>func NewClient(logger *slog.Logger, cloudwatchAPI *cloudwatch.Client) cloudwatch_client.Client {<br>    return &amp;client{<br>        logger:        logger,<br>        cloudwatchAPI: cloudwatchAPI,<br>    }<br>}</pre><p>这个函数将一个已经按照 AWS SDK 配置好的 cloudwatch.Client 实例和日志器传入，封装成 YACE 内部使用的 cloudwatch_client.Client 接口类型。</p><p>b. 客户端创建过程：</p><p>在 pkg/clients/v2/factory.go 文件中，YACE 的工厂（CachingFactory）负责根据 AWS 区域（region）和角色（role）配置来创建基础的 cloudwatch.Client</p><pre>// 创建基础的 CloudWatch 客户端<br>func (c *CachingFactory) createCloudwatchClient(regionConfig *aws.Config) *cloudwatch.Client {<br>    return cloudwatch.NewFromConfig(*regionConfig, func(options *cloudwatch.Options) {<br>        // 1. 设置日志级别<br>        if c.logger != nil &amp;&amp; c.logger.Enabled(context.Background(), slog.LevelDebug) {<br>            options.ClientLogMode = aws.LogRequestWithBody | aws.LogResponseWithBody<br>        }<br>        <br>        // 2. 设置自定义端点（如果有）<br>        if c.endpointURLOverride != &quot;&quot; {<br>            options.BaseEndpoint = aws.String(c.endpointURLOverride)<br>        }<br><br>        // 3. 配置重试策略<br>        options.Retryer = retry.NewStandard(func(options *retry.StandardOptions) {<br>            options.MaxAttempts = 5<br>            options.MaxBackoff = 3 * time.Second<br>        })<br><br>        // 4. 配置 FIPS 端点（如果启用）<br>        if c.fipsEnabled {<br>            options.EndpointOptions.UseFIPSEndpoint = aws.FIPSEndpointStateEnabled<br>        }<br>    })<br>}</pre><p>c. YACE 使用 CachingFactory 将每个（角色，region）组合对应的客户端存入缓存，以避免重复创建。其核心方法如下：</p><pre>func (c *CachingFactory) GetCloudwatchClient(region string, role model.Role, concurrency cloudwatch_client.ConcurrencyConfig) cloudwatch_client.Client {<br>    // 1. 检查是否需要刷新<br>    if !c.refreshed {<br>        c.mu.Lock()<br>        defer c.mu.Unlock()<br>    }<br>    <br>    // 2. 检查缓存中是否存在客户端<br>    if client := c.clients[role][region].cloudwatch; client != nil {<br>        return cloudwatch_client.NewLimitedConcurrencyClient(client, concurrency.NewLimiter())<br>    }<br>    <br>    // 3. 创建新的客户端并缓存<br>    c.clients[role][region].cloudwatch = cloudwatch_v2.NewClient(<br>        c.logger, <br>        c.createCloudwatchClient(c.clients[role][region].awsConfig)<br>    )<br>    <br>    // 4. 返回带并发限制的客户端<br>    return cloudwatch_client.NewLimitedConcurrencyClient(<br>        c.clients[role][region].cloudwatch, <br>        concurrency.NewLimiter()<br>    )<br>}</pre><p>工厂类将实例化的客户端放入到缓存中，由于客户端有时间限制，所以会定期的进行检查是否过期，如果过期需要进行刷新连接。同时在进行返回的时候为避免客户端请求 API 超过限流，在返回的其实是带并发限制的客户端。</p><h3>总结</h3><p>本文对 YACE 的源码进行了分析。主要借此来学习如何构造并使用适配 CloudWatch 指标（Metrics）的配置文件，以及探索 YACE 如何与 AWS API（如 CloudWatch、Tagging API）进行交互，实现指标拉取、资源发现与数据转换。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6f651d918b0b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[在 10 分钟内使用 GreptimeDB 和 OTel 构建 LLM 可观测性]]></title>
            <link>https://medium.com/@jetdeng/%E5%9C%A8-10-%E5%88%86%E9%92%9F%E5%86%85%E4%BD%BF%E7%94%A8-greptimedb-%E5%92%8C-otel-%E6%9E%84%E5%BB%BA-llm-%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7-0c665262efc7?source=rss-bdff15df02b6------2</link>
            <guid isPermaLink="false">https://medium.com/p/0c665262efc7</guid>
            <category><![CDATA[opentelemetry]]></category>
            <category><![CDATA[greptime]]></category>
            <category><![CDATA[llm-observability]]></category>
            <dc:creator><![CDATA[JetSquirrel]]></dc:creator>
            <pubDate>Sun, 06 Jul 2025 04:45:54 GMT</pubDate>
            <atom:updated>2025-07-06T05:15:10.629Z</atom:updated>
            <content:encoded><![CDATA[<h3>前言</h3><p>随着 LLM 应用变得广泛，各种 AI 应用和 Agent 迎来了大爆发。而 LLM 作为一个基于概率的模型，以及其是一个黑盒，我们很难搞清楚里面发生了什么。在实际开发中进行调试时，<strong>构建良好的可观测性体系</strong>变得尤为重要。</p><p>过去我们常说 「Talk is cheap show me the code」，而现在，在与 LLM 交互的场景下，更像是 「Code is cheap show me the talk」</p><p>虽然是句玩笑话，但在 LLM 应用中，<strong>记录上下文、输入输出、模型行为等信息，是实现可观测性的基础。</strong>‍</p><p>目前主流的 LLM 可观测性方案有 LangSmith 和 LangFuse，本篇文章将介绍如何基于 <strong>OpenTelemetry（OTel）与 GreptimeDB</strong> 构建一个简单的 LLM 可观测性系统。</p><p>下面我们将一步步实现这一过程。</p><h3>操作步骤</h3><p>我们将会用到 OpenLLMetry 来收集链路追踪（Trace）和指标（Metric)[1]。</p><p>这是一个使用 OpenAI SDK 与 DeepSeek 接口进行调用的简单示例</p><pre>import os<br>from openai import OpenAI<br><br>openai_client = OpenAI(api_key=&quot;sk-xxxxxxxxxxxxxxxxxxx&quot;, base_url=&quot;https://api.deepseek.com&quot;)<br> <br>chat_completion = openai_client.chat.completions.create(<br>    messages=[<br>        {<br>          &quot;role&quot;: &quot;user&quot;,<br>          &quot;content&quot;: &quot;What is LLM Observability?&quot;,<br>        }<br>    ],<br>    model=&quot;deepseek-chat&quot;,<br>)<br> <br>print(chat_completion)</pre><p>只需在 LLM 应用中添加如下代码，即可自动采集链路数据：</p><pre>from traceloop.sdk import Trpytaceloop<br><br>Traceloop.init(disable_batch=True,<br>               api_endpoint=OTEL_EXPORTER_OTLP_ENDPOINT,<br>               )</pre><p>该代码会对 OpenAI sdk, langchain 进行自动埋点</p><p>完整的代码如下:</p><pre>import os<br>from openai import OpenAI<br>from traceloop.sdk import Traceloop<br><br>OTEL_EXPORTER_OTLP_ENDPOINT = &quot;http://127.0.0.1:4000/v1/otlp&quot; <br>Traceloop.init(disable_batch = True,<br>               api_endpoint = OTEL_EXPORTER_OTLP_ENDPOINT,<br>)<br>openai_client = OpenAI(api_key=&quot;sk-xxxxxxxxxxxxxxxxxxx&quot;, base_url=&quot;https://api.deepseek.com&quot;)<br> <br>chat_completion = openai_client.chat.completions.create(<br>    messages=[<br>        {<br>          &quot;role&quot;: &quot;user&quot;,<br>          &quot;content&quot;: &quot;What is LLM Observability?&quot;,<br>        }<br>    ],<br>    model=&quot;deepseek-chat&quot;,<br>)<br> <br>print(chat_completion.choices[0].message.content)‍</pre><p>注意 OTEL_EXPORTER_OTLP_ENDPOINT 是 OTLP（OpenTelemetry Protocol） 的数据接收地址。<br>常见接收端包括 otel-collector、Vector、Grafana Alloy 等，这里为了简化流程，我们使用 GreptimeDB 来接收数据 [2]</p><h3>运行项目</h3><ol><li>在本地下载和安装 GreptimeDB，并且运行（standalone 模式）[3]</li></ol><pre>$ ./greptime standalone start</pre><p>2. 随后运行自动埋点后的代码，即可将 OTEL 采集的数据写入到 GreptimeDB</p><h3>可视化数据</h3><p>我们可以使用 GreptimeDB Dashboard [4]查看</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UukWj2W7tYmYFdd6r-tS0A.png" /><figcaption>Grafana Dashboard</figcaption></figure><h3>在 Gafana 中添加数据源</h3><p>​也可以通过 Grafana 构建更完善的可观测性视图。在 Grafana 上创建两个连接，分别是 Prometheus 和 Jaeger</p><ol><li>新建 Prometheus 类型的连接，并填入 URL: <em>http://localhost:4000/v1/prometheus/​</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wCwqb_n2en9mkfga0BT1hw.png" /><figcaption>GreptimeDB Prometheus Datasource</figcaption></figure><p>2. 新建 Jaeger 类型的连接，并填入 URL: <em>http://localhost:4000/v1/jaeger​</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dSgOalw1OD_7VAuDNHXWRg.png" /><figcaption>GreptimeDB Jaeger Datasource</figcaption></figure><p>添加成功后，即可在 Grafana 中查看链路追踪与指标信息：</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hsnbie_pTVXYfWXuhynB0Q.png" /></figure><p>你也可以导入这份导入示例 Dashboard [5] 来快速体验完整效果。‍</p><h3>总结</h3><p>本文基于 OpenTelemetry 与 GreptimeDB 搭建了一个简单的 LLM 可观测性系统：</p><ul><li><strong>OpenLLMetry</strong> 提供了便捷的自动埋点能力；</li><li><strong>GreptimeDB</strong> 作为新一代可观测性数据库，简化了部署流程，支持多协议数据接入；</li><li><strong>Grafana</strong> 帮助我们实现全面的可视化展示。</li></ul><p>这套方案兼具灵活性与低门槛，本文只是做了一个简单的尝试，以快速构建简单版本的 LLM 可观测性。‍</p><p>[1] <a href="https://www.traceloop.com/docs/openllmetry/getting-started-python">https://www.traceloop.com/docs/openllmetry/getting-started-python</a><br>[2] <a href="https://docs.greptime.com/user-guide/ingest-data/for-observability/opentelemetry">https://docs.greptime.com/user-guide/ingest-data/for-observability/opentelemetry</a><br>[3] <a href="https://docs.greptime.com/getting-started/installation/greptimedb-standalone">https://docs.greptime.com/getting-started/installation/greptimedb-standalone</a><br>[4] <a href="https://docs.greptime.com/getting-started/installation/greptimedb-dashboard/">https://docs.greptime.com/getting-started/installation/greptimedb-dashboard/</a><br>[5] <a href="https://gist.github.com/JetSquirrel/d8fbc1a589aae7f62c117601262eb66c">https://gist.github.com/JetSquirrel/d8fbc1a589aae7f62c117601262eb66c</a></p><p>‍</p><p>‍</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0c665262efc7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[使用 GreptimeDB MCP 审计 AWS CloudTrail日志]]></title>
            <link>https://medium.com/@jetdeng/%E4%BD%BF%E7%94%A8-greptimedb-mcp-%E5%AE%A1%E8%AE%A1-aws-cloudtrail%E6%97%A5%E5%BF%97-5d6f563b586f?source=rss-bdff15df02b6------2</link>
            <guid isPermaLink="false">https://medium.com/p/5d6f563b586f</guid>
            <category><![CDATA[mcps]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[greptimedb]]></category>
            <dc:creator><![CDATA[JetSquirrel]]></dc:creator>
            <pubDate>Sun, 04 May 2025 08:08:13 GMT</pubDate>
            <atom:updated>2025-05-07T16:06:17.906Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>GreptimeDB</strong> 是一个高性能时序数据库，Greptime 团队提供了支持 MCP 协议的开源项目 <a href="https://github.com/GreptimeTeam/greptimedb-mcp-server">greptimedb-mcp-server</a>。</p><p><strong>AWS CloudTrail </strong>用于记录 AWS 上的操作，例如创建资源、权限授予等。</p><p>本文将 AWS CloudTrail 的日志导入到 GreptimeDB 中，并使用 GreptimeDB MCP Server，让大模型对 CloudTrail 日志进行分析，发现云安全威胁和恶意操作。</p><p>以下是一个聊天的效果，我们查询到「155.63.17.217」这一个IP 地址的异常操作：</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kXt2Sid73ENXm2cOuhLDSQ.png" /></figure><h3>一、环境准备</h3><h4>GreptimeDB 下载和安装</h4><p>a. <a href="https://greptime.com/download">下载 GreptimeDB</a> 二进制文件，解压后并进入对应的目录，使用以下的命令运行</p><pre>./greptime standalone start</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*le0UXIi5VJUb1uUatRpMdw.png" /><figcaption>启动 GreptimeDB</figcaption></figure><p>b. (可选) 使用 GreptimeDB Dashboard 查询数据</p><p>在连接到 GreptimeDB 兼容 MySQL 和 PostgrepSQL 可以用 Navicat、DBeaver 等工具连接，也可以使用 Greptime 提供的 <a href="https://github.com/GreptimeTeam/dashboard">GreptimeDB dashboard.</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*duU9aPYQUpRMDRXF0QKQHQ.png" /><figcaption>greptime dashboard</figcaption></figure><h4>GreptimeDB MCP 服务器</h4><p><a href="https://github.com/GreptimeTeam/greptimedb-mcp-server">GreptimeTeam/greptimedb-mcp-server</a> 基于 Python 开发，可以</p><p>使用Git 克隆到本地：</p><pre>git clone https://github.com/GreptimeTeam/greptimedb-mcp-server.git</pre><p>确保本地已经安装 Python 的包 管理工具 uv，用于运行该项目，安装步骤可以查看<a href="https://docs.astral.sh/uv/getting-started/installation/">这里</a>。</p><h4>MCP 客户端</h4><p>使用 MCP 的客户端来连接MPC服务器，例如 Claude Desktop、Cline、Cherry Studio、ChatWise。</p><p>本文以 ChatWise 为例，将下面的 JSON 修改 MCP Server 的路径后，复制导入 MCP 客户端</p><pre>{<br>  &quot;mcpServers&quot;: {<br>    &quot;greptimedb&quot;: {<br>      &quot;command&quot;: &quot;uv&quot;,<br>      &quot;args&quot;: [<br>        &quot;--directory&quot;,<br>        &quot;/path/to/greptimedb-mcp-server&quot;,<br>        &quot;run&quot;,<br>        &quot;-m&quot;,<br>        &quot;greptimedb_mcp_server.server&quot;<br>      ],<br>      &quot;env&quot;: {<br>        &quot;GREPTIMEDB_HOST&quot;: &quot;localhost&quot;,<br>        &quot;GREPTIMEDB_PORT&quot;: &quot;4002&quot;,<br>        &quot;GREPTIMEDB_USER&quot;: &quot;root&quot;,<br>        &quot;GREPTIMEDB_PASSWORD&quot;: &quot;&quot;,<br>        &quot;GREPTIMEDB_DATABASE&quot;: &quot;public&quot;<br>      }<br>    }<br>  }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JlpW02SUFmm5KndVCuyIZg.png" /></figure><p>在 ChatWise 中配置模型，</p><h3>二、数据导入</h3><h4>下载数据集</h4><p>从 <a href="https://summitroute.com/downloads/flaws_cloudtrail_logs.tar"><strong>这里</strong></a><strong> </strong>下载 CloudTrail 的数据集用来做测试。</p><p>关于此数据集可参考：</p><ul><li><a href="https://summitroute.com/blog/2020/10/09/public_dataset_of_cloudtrail_logs_from_flaws_cloud/">Summit Route — 来自 flaws.cloud 的 Cloudtrail 日志的公共数据集</a></li><li><a href="https://goodycyb.hashnode.dev/threat-detection-in-aws-using-amazon-athena-to-analyze-cloudtrail-logs-from-flawscloud">Threat detection🕵️‍♂️ in AWS using Amazon Athena Service</a></li></ul><p>下载到本地后，对文此件进行解压，如果是 Windows 可以采用 7z 进行解压，如果是 Unix/Linux 系统可以使用以下命令</p><pre>find . -type f -exec gunzip {} \;</pre><h4>导入数据到 GreptimDB</h4><p>我们利用 Python 脚本将 JSON 格式的 CloudTrail 日志导入到 GreptimeDB，将该脚本存于下载数据集的<strong>同一目录</strong>下并运行</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2f8757729d1331f1d3fd154007098d24/href">https://medium.com/media/2f8757729d1331f1d3fd154007098d24/href</a></iframe><p>上述代码的作用是：</p><ul><li>创建 CloudTrail 的表</li><li>导入原始的 JSON 数据到 GreptimeDB 中</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DWONJ7xtpEyLs8P9HpdnsA.png" /></figure><p>在 GreptimeDB Dashboard 上查询数据，验证是否导入成功：</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*g7AkAQ0Pb-tauLozReyPDQ.png" /></figure><h3>三、大模型问答</h3><p>参考 Promtp</p><pre><br>Promtp:<br># 监控指标分析模板<br>你是一安全日志分析助手，致力于帮助用户查询和分析 GreptimeDB 中的数据。您的任务是分析用户的数据需求，并提供 SQL 查询语句，从 GreptimeDB 中提取相关信息。<br><br><br>## 1. 概述<br>GreptimeDB 是一个统一指标、日志和事件的时间序列数据库。<br>1. 提示：此服务器提供提示，帮助您构建与 GreptimeDB 的交互。<br>2. 资源：您可以在资源中找到格式为&quot;greptime://&lt;table_name&gt;/data&quot;的表。<br>3. 工具：<br>- &quot;execute_sql&quot;：执行 SQL 命令（MySQL 语法）。<br><br>## 2. 指导原则<br>1. 时间范围至关重要 - 请务必在查询中指定时间范围。<br>2. 要探索可用数据，请使用 SQL 命令，例如 (`DESCRIBE`、`SELECT`、`SHOW TABLES`)<br>3. 遵循 SQL 最佳实践：<br>- 使用适当的筛选条件来限制结果集<br>- 考虑对时间序列数据使用聚合函数<br>- 利用 GreptimeDB 的内置时间函数<br>4. 服务器将阻止危险操作。除非需要修改数据，否则请专注于读取操作<br>5. 使用简洁的 Markdown 格式，并添加适当的标题和项目符号。<br><br>## 3. 示例用例和查询<br>- 尝试通过特定用户 ARN 启动 EC2 实例<br>- 谁可以通过控制台访问<br>- 搜寻 AWS 控制台的登录失败<br>- 通过 AWS 管理控制台调查创建的事件（IAM、S3 和 EC2）资源。<br>- 通过 AWS 管理控制台、AWS CLI、SDK 或直接 API 调用调查创建的事件（IAM、S3 和 EC2）资源<br>- 搜寻 CloudTrail 中断<br>- 搜寻未经授权的呼叫<br>- 寻找 “whoami” 身份<br>- 通过创建 IAM 用户来入侵账户的努力<br>- 在 Secrets Manager 中搜寻访问密钥<br>- 搜寻 xlarge EC2 实例<br>- 搜寻 S3 存储桶暴力破解尝试<br>- 搜寻可疑用户代理（Kali、Parrot、PowerShell）<br>- 搜寻永久密钥创建<br>- 创建公有 S3 存储桶<br>- 暴力破解尝试代入角色<br>- 尝试对账户执行对帐作<br><br>```sql<br>-- 获取表结构<br>DESCRIBE ${table};<br>-- 获取近期数据样本<br>SELECT * FROM ${table}<br>${sample_queries} ORDER BY ${time_column} DESC LIMIT 100<br><br>-- 尝试启动 EC2实例由特定用户 ARN<br>SELECT <br>  eventname, <br>  count(*) AS eventcount <br>FROM cloudtrail_logs WHERE <br>  user_identity.arn = &#39;${arn}&#39; <br>  AND source_ip=&#39;${ip}&#39;<br>GROUP BY eventname ORDER BY eventcount DESC;<br><br>-- 日志配置变更的高风险操作<br>SELECT event_time, error_message, user_identity, source_ip, event_name, user_agent, aws_region FROM cloudtrail_events WHERE event_name IN (&#39;StopLogging&#39;, &#39;DeleteTrail&#39;, &#39;UpdateTrail&#39;) AND event_time BETWEEN TIMESTAMP &#39;2018-01-01T00:00:00Z&#39; AND TIMESTAMP &#39;2020-12-31T23:59:59Z&#39; ORDER BY event_time DESC LIMIT 100<br>```<br><br>## 4. 补充说明<br>1. 如果您不知道如何回答特定问题，建议先探索模式以了解可用的数据结构。<br>2. 以清晰、翔实的方式解释查询结果。<br>3. 帮助他们有效地分析云安全日志数据。</pre><p><strong>例1</strong>： 分析 cloudtrail_events 表中在2018年4月存在的高危操作，注意这个表很大，请谨慎使用SQL</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UV4cwd7YkNPUzJ-BzIwsdA.png" /></figure><p><strong>例2：</strong>分析 AKIA01U43UX3RBRDXF4Q 用户的操作是否存在高危，注意这个表很大，请谨慎使用SQL</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iMUv2Z2wTL2s_OUduc-g3A.png" /></figure><p>对上述的内容进行验证，确实是存在恶意的操作。<a href="https://gist.github.com/goodycy3?direction=asc&amp;sort=created">goodycy3’s gists</a> 的博客中分享了对这个数据集的分析，可以多尝试一下更多的 case。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5d6f563b586f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[这是对ADHD最坏的时代，也是最好的时代]]></title>
            <link>https://medium.com/@jetdeng/%E7%8E%B0%E5%9C%A8%E6%98%AF%E5%AF%B9adhd%E6%9C%80%E5%9D%8F%E7%9A%84%E6%97%B6%E4%BB%A3-%E4%B9%9F%E6%98%AF%E6%9C%80%E5%A5%BD%E7%9A%84%E6%97%B6%E4%BB%A3-820526ab42c0?source=rss-bdff15df02b6------2</link>
            <guid isPermaLink="false">https://medium.com/p/820526ab42c0</guid>
            <dc:creator><![CDATA[JetSquirrel]]></dc:creator>
            <pubDate>Wed, 18 Dec 2024 15:48:03 GMT</pubDate>
            <atom:updated>2024-12-18T15:49:07.565Z</atom:updated>
            <content:encoded><![CDATA[<p>ADHD 就像是猎人，警觉、敏锐、爆发里强。但是社会的大部分人都是农民一样的生活方式，朝九晚五，有条有理。我们大部分的模式都是按照「农民」的方式进行设计。</p><p>ADHD 儿童很难适应坐在教室里的方式学习，上课不会专心听讲，而且还可能会打扰到其他同学，甚至被老师打 上「坏学生」和「笨小孩」。</p><p>而成人面临着更严峻的挑战，随着现代社会工业化和信息化的发展，社会结构化、流程化、成瘾物质泛滥和运动空间缩小，这些问题会在 ADHD 的身上放大，最终又会成为 ADHD 身上糟糕的标签：懒、蠢、缺乏自控。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xJIk81mD2ch3RYl1JpCHJg.jpeg" /></figure><p>近年 ADHD 慢慢的被大众所了解，也有许多人确诊了 ADHD。</p><p>当然不少人为了维持日常的生活、工作和学习，选择了吃药。我也正在吃药，这确实让我日常生活和工作更有条理，也解决了我拖延、注意力不集中和冲动的问题。</p><p>当然，若不是生活所迫，我也不想通过吃药来维持正常的工作和生活。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*b7HZInC3qNRKbT4xYQGN9Q.jpeg" /></figure><p>另一方面，ADHD 天生就是要去追求新鲜的事情，天生就充满好奇，大脑中时刻都有火花在闪耀。而恰恰工业化和信息化的社会给 ADHD 提供了非常多的舞台，交通工具的发展使我们能到世界每一个角落，信息化能让我们在几秒内将自己的想法传达出去。我们能到更多的地方，见更多的人，做更多的事。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/216/1*oiIR8NmXo_6cS_jM5D9WmQ.jpeg" /></figure><p>ADHD 的人蠢、无礼、鲁莽、冲动吗？我想我们身上确实会多多少少有这些问题，这是我们特质带来的影响。另一方面 ADHD 有着充沛的激情、生命力和好奇心，会驱动着我们去追求感兴趣的事情。</p><p>我给不出什么 ADHD 该如何生活的建议，因为我还在寻找。</p><p>我正在做的，写作，也许对我们是一种救赎。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=820526ab42c0" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>