Service Implementation Patterns for Microservice

Hexagonal architectures for microservices 微服务的六边形架构 六边形架构 Hexagonal Architecture 也被称为接口与适配器架构 Prots and Adapters Architecture, 是一种软件架构模式, 旨在实现高内聚、低耦合和可测试性的应用程序设计. 该架构由 Alistair Cockburn 发明, 他是敏捷宣言的签署者之一. 该架构是说, 在任何应用程序中, 都有一个核心逻辑实现服务, 并且在该服务周围"附加"上一些接口, 用于核心与外部组件的交互. 例如, 一个 web API 就是一个适配器 adapter, 帮助核心逻辑与互联网上的 web 客户端交流. 对于数据库也是一样的, 其也是一个外部组件, 帮助服务维护数据. 如果我们需要, 应该要能迁移到其他的数据库, 并且服务仍然是相同的. 因此, 数据库也是一个适配器 adapter. 上述架构可通过在核心业务逻辑层与适配器之间构建接口 ports 来实现. 在处理核心业务逻辑与适配器之间的关系时, 应用依赖反转原则 dependency inversion principle: 高层模块不应该依赖底层细节. 相反, 两者都应该依赖抽象. 以数据存储为例, 我们应当通过统一的接口进行操作, 无需理解数据库的具体实现细节. 无论是 SQL 数据库、NoSQL 数据库还是缓存存储系统, 都应该使用相同的接口规范. 抽象不应依赖于具体实现, 而具体实现应依赖于抽象. 以业务层与数据层之间的接口设计为例, 必须确保接口不会因数据库实现细节的变动而修改, 相反地, 我们通过调整数据层实现来适配接口规范.这意味着数据层依赖于接口定义, 而非接口依赖于数据层实现. 依赖反转的概念经常同控制反转与依赖注入的概念一同出现, 这些是相关但是不同的概念. ...

September 10, 2025 · 1 min · 76 words · Starslayerx

Dealing With Grabage in Python

Grabage Collection In Python 本篇文章介绍 Python 中的 Grabage Collection (GC) 机制介绍 What’s Python Object? Python 对象中有三样东西: 类型(Type)、值(value)和引用计数(reference count), 当给变量命名时, Python 会自动检测其类型, 值在定义对象时声明, 引用计数是指该对象名称的数量. 首先来看一个类 class Person: def __init__(self, name, unique_id, spouse): self.name = name self.unique_id = unique_id self.spouse = spouse def __del__(self): print( # !r: 调用 repr() 来获取该对象的字符串表达式 # !s: str() # !a: ascii() f"Object {self.unique_id!r} is about to be removed from memory. Goodbye!" ) 该 Person 类有以下3个属性: name: 人名 unique_id: 唯一性 id spouse: 将为 None 或者将存储另一个 Person 对象 有一个特殊方法 __del__(), 这个特殊方法有一定的误导性. 该方法并不像 __len__() 与 len() 或者 __iter__() 与 iter() 那样与 del 关键字相关联. __del__() 特殊方法并不定义当对对象引用时 del 会发送什么, 相反, __del__() 是一个终结器 finaliser: 它在对象被消毁之前从内存中移除之间被调用. 因此, __del__() 中 print() 调用的字符串仅在 Python 即将从内存中移除对象时显示. ...

September 8, 2025 · 2 min · 241 words · Starslayerx

Docker - Images

每个 Linux 容器都基于一个镜像, 镜像重新构建运行中容器的底层定义. 要启动一个容器, 需要下载公共镜像或者创建自己的镜像. 每个镜像由一个或多个相互关联的文件系统层 layer 组成, 这些层通常与创建镜像的每个构建步骤大致一一对应. 由于镜像由独立的层构建而成, 这就对 Linux 内核提出了特殊要求: 内核必须提供 Docker 所需的驱动, 以便运行存储后端. 在镜像管理, Docker 高度依赖这个存储后端, 该后端通过与底层 Linux 文件系统通信, 用来构建并管理多个层并将它们组合成一个可用的镜像. 主要支持的后端存储有以下类型: Overlay2 B-Tree File System Device Mapper 每一个后端都提供一个快速的 copy-on-write (CoW) 系统用于镜像管理. 包含: Building images Uploading (pushing) images to an image registry Downloading (pulling) images from an image registry Creating and running containers from an image Anatomy of a Dockerfile | 剖析 Dockerfile 这个文件描述了所有构建一个容器所需的步骤, 并且通常存储在项目源码的根目录里. 一个典型的 Dockerfile 看起来像下面这样, 这里是创建一个 Node.js 的应用镜像: ...

September 7, 2025 · 18 min · 3803 words · Starslayerx

Docker - Workflow

The Docker Workflow 这篇文章介绍 Docker 工作流 Revision Control 版本控制 Docker 有两种版本控制方式. 一个是用来跟踪文件系统层 layers (每个镜像的组成), 另一个是 tagging 标签系统. Filesystem layers 文件系统层 Linux 容器由堆叠文件系统层组成, 每一层由一个唯一的哈希标记, 每次 build 都在之前的修改之上. 这意味着, 每次 build 只需要重新构建修改过的层. 这节省了时间和网络带宽. Image Tags 镜像标签 第二种版本控制回答了一个问题: 之前部署的应用版本是? 非容器化应用的解决方案有很多种, 从 Git 发布标签到部署日志. Docker 有一个内置的处理机制: 每次 build 都有一个镜像标签. latest 经常被用来表示最新版本, 但由于这是一个浮动的标签, 因此在生产中使用并不好. 正确的做法应该是使用一个特定的版本. Building 构建镜像 Docker 的命令行工具包含一个 build 标志, 它会读取 Dockerfile 并产生一个 Docker 镜像. Dockerfile 中的每一条指令都会在镜像中生成一个新的层, 因此仅通过查看 Dockerfile 就能比较容易的推断出构建会做什么. 这样标准化的好处是, 任何熟悉 Dockerfile 的工程师都可以直接上手并修改任何其他应用的构建. Dockerfile 通常会提交到版本控制系统, 这也简化了对构建变更的追踪, 现代的多阶段构建还运行将构建环境与最终镜像分离, 为构建环境提供了像生产容器那样强大的可配置性. ...

September 6, 2025 · 2 min · 368 words · Starslayerx

Docker - Images and Registeries

The Docker Images | Docker 镜像 Image、OCI Image、Docker Image、Container Image 都是指同一个概念镜像的不容叫法. 镜像是一个轻量、只读且不可变的蓝图, 指定了应用运行所谁要的一切, 以及在 Docker 系统上如何运行. 就像是一份配方, 包括所有必要的原料, 诸如依赖、配置、环境设置和你的应用代码, 以及确保应用每次都能稳定运行的详细指令. 可以把镜像类比为面向对象编程中的类: 定义结构和行为, 但不能直接与类交互, 需要创建实例. Pulling and Inspecting an Image 拉取并查看镜像 镜像其实就是一个 JSON 对象, 可以这样拉取一个镜像 % docker pull celery:latest latest: Pulling from library/celery ef0380f84d05: Pull complete ada810c79ed7: Pull complete 4608a1c4fe47: Pull complete 58086cbb21fb: Pull complete a7bccb4a3faa: Pull complete 9de06a08ec25: Pull complete ad6feb8c6a6b: Pull complete 7568ca85d492: Pull complete 2d6f458f7411: Pull complete Digest: sha256:5c236059192a0389a2be21fc42d8db59411d953b7af5457faf501d4eec32dc31 Status: Downloaded newer image for celery:latest docker.io/library/celery:latest What's next: View a summary of image vulnerabilities and recommendations → docker scout quickview celery:latest 现在查看镜像信息 ...

September 5, 2025 · 5 min · 890 words · Starslayerx

Docker - Engine and Netowrking

Docker 引擎(Docker Engine), 顾名思意,是 Docker 的核心. 它为 Docker 提供动力, 并承担所有繁重的工作. 本文将深入探讨这一关键组件的内部运作, 以便了解 Docker 在内核下是如何工作的. The Evolution of the Docker Engine | Docker 引擎的演进 Docker 最初是一个巨大的单体(monolith), 所有代码都塞在同一个项目里. 对于 dotCloud来说, 这种方式一开始是可行的. 实际上, 这个方向运作得非常好, 以至于他们放弃了其他服务、把所有赌注都押在 Docker 上, 甚至把公司重命名为 Docker, Inc. 一开始, Docker 是一个又大又混乱的单体应用. 随着时间推移, Docker, Inc. 发现这种做法不可持续, 他们需要把系统拆分出来: 各个部分可以独立成长 更容易升级某些部分 - 可以替换旧组件而不影响整体 让社区更容易参与贡献 - 更小的组件意味着更多人能参与进来 更易跨平台 - 他们想要 Docker 在每个平台上运行, 而不只是 Linux 拆分的第一步是把客户端 client 剥离出来. 把客户端从大应用中抽出, 赋予它新职责: 把用户命令翻译成 Docker 引擎能理解的指令(也就是原来单体里"内核部分"的接口) 此时, Docker 引擎主要有两部分: ...

September 4, 2025 · 4 min · 653 words · Starslayerx

Docker - History

The Docker Story - Part1: Docker History docCloud - 也就是开发 Docker 的公司, 最初是一家 PaaS(平台即服务)公司, 他们在 PaaS 领域并没有太大的成功, 但他们构建了一个可以无缝管理客户系统与架构的工具: Docker. 2013 年, 他们决定放弃 PaaS 服务, 将全部精力投入到 Docker 这款产品上. Containers 容器 Docker 公司并没有发明容器这个概念. 实际上, 容器的概念已经演进了十多年, 很多参与者都做出了贡献, Linux 基金会和 Google 是推动整个生态走向成熟的重要力量. 假如你在运营一家公司, 希望将应用上线, 以前需要做的事大概是: 购买一台服务器 安装所有必要的应用和依赖 配置环境以匹配你的开发设置 部署应用 把服务器对外开放 看起来很简单, 但实际操作会很复杂: 要手动跟踪并更新每个依赖和配置 如果出问题, 需要手动去修复 基础设施团队需要估算服务器规格(内存、CPU 等) — 为了防止流量高峰崩溃, 通常会配置更高的规格(过度配置) 那台高配服务器大多数时间只是闲置着, 做最少量的工作 不能轻易扩展或在同一服务器上运行多个应用, 因为每个应用都需要独立的运行环境 总之, 非常混乱 后来出现了虚拟机(VM), 情况有了改善. 使用 VM 可以: 在同一台服务器上运行多个隔离的环境 为 VM 做快照并在不同服务器间复用 不再重复重复地搭建环境,这是一个很大的进步 但 VM 也有缺点: ...

September 3, 2025 · 2 min · 289 words · Starslayerx

How AI Assistants Make Precise Edits to Your Files

之前的文章介绍了如何制作一个基本的 AI 编程助手, 今天更近一步, 探讨 AI 助手如何对文件进行精确的修改. 实际的 AI Agent 不会读取所有的项目代码, 一般只会读取当前文件的代码, 当需要时才会去读取相关的代码文件. 然而, 输出也不会输出要修改的整个文件的代码, 因为这样输出不仅很慢, 同时成本也很高, 会有大量重复代码导致浪费(以 deepseek 为例, 输出 token 的价格是输入 token 价格的3倍, 是缓存命中输入 token 价格的24倍!), 因此一般是让模型输出要修改的代码和修改后的代码. 既然不能一次输出文件的所有代码, 这就引出了一个问题: 如何精确的修改代码文件? 首先要确定一种让模型准确地描述修改的格式, 并且提供健壮的格式匹配与错误重试机制(模型输出代码可能少个空格或者Tab), 这篇文章对这个问题做了探讨. 将 AI agent 生成的代码直接修改到文件中是一项核心能力, 然而实际上这常常出乎意料的困难, agent 可能会提出一个代码修改方案, 但实际修改却失败, 例如"找不到匹配的上下文"之类的错误, 需要手动干预. 许多 AI 编程助手的开发者都遇到过这种情况, 虽然 AI 理解代码的意图, 但将这种理解转化为精确的文件修改却带来了重大的技术挑战. Why Precise File Editing Matters 为什么精确的文件编辑至关重要 有效的文件编辑是编程助手的价值核心, 如果其不能可靠的修改文件, 需要人为手动修改, 就退化成了 AI 聊天引擎, 相比之下, 一个能够可靠自动化编辑的助手可以为开发者节省大量时间和认知负担. 根本的挑战在于, LLM 缺乏直接的文件系统访问权限, 他们必须通过专门的工具来描述预期的修改, 然后这些工具或 API 解释指令并尝试执行, LLM 的描述与文件系统状态之间的这种交接是常见的问题来源. 使用 GitHub Coplit、Aider、RooCode 或 Cursor 等工具的用户可能已经观察到这些问题: 编辑器无法找到正确的插入点、缩进不正确, 或者工具最终请求手动应用. ...

September 2, 2025 · 7 min · 1373 words · Starslayerx

Make an AI Coding Agent in python

这篇文件介绍如何使用 Python 制作一个基础的 AI 编程助手 Minimal AI Coding Agent 下面是一个 AI Coding Agent 至少需要的功能 Chat loop 对话循环 Call an LLM 调用大语言模型 Add tools to call 增加工具调用 Handle tool request 处理工具调用请求 Step 1: Chat Loop 首先, 聊天循环一直循环等待用户输入, Python 的 “input” 方法可以获取用户输入 print("Type q to quit") while True: user_message = input("You: ") if user_message == "q": break ai_message = f"You said {user_message}... so insightful" print(ai_message) 目前主流的 LLM 都是无状态的, 所以需要我们手动的去管理对话上下文, 这里使用一个 fake_ai 函数模拟真实的 LLM 调用, 并包含 role 和 content 内容 ...

September 1, 2025 · 11 min · 2265 words · Starslayerx

KMP Algorithm

KMP 算法 思想 KMP 算法, 全程 Knuth-Morris-Pratt 算法, 是一种高效的字符串匹配算法. 它的核心思想是: 在匹配过程中, 当发生文本串(text)与模式串(pattern)不匹配时, 能够利用已匹配过的部分信息, 智能地移动模式串, 从而避免从头开始匹配, 达到提高匹配效率的目的. KMP算法的巧妙之处在于: 它认为, 当发生不匹配时, 将模式串仅仅右移一位是"愚蠢"的. 当某个地方不匹配时, 表明前面实际上有部分内容已经匹配了. 如果直接从头开始匹配, 就浪费了这些信息. 有时前面已经匹配部分会有"重复"的性质, 可以利用这种性质, 让子串一次多移动几步, 从而加速匹配速度. 举例 主串S和模式串P S = BBC ABCDAB ABCDABCDABDE P = ABCDABD 当匹配到下面这种情况时: S = BBC ABCDAB ABCDABCDABDE P = ABCDABD 这里的 D 和上面空格不匹配, 此时保理匹配就直接向右移动一位, 但是通过观察已经匹配的部分 “ABCDAB” 可以发现, 该部分有相同的前后缀 “AB”, 因此可以直接将子串的 “A” 对准主串中后缀 “AB” 里面的 “A”: S = BBC ABCDAB ABCDABCDABDE P = ABCDABD 此时, S 的指针不用改变, 将 P 的指针回到 “C” 的位置就行了. 通过这种方法, 大大提升了效率. ...

August 31, 2025 · 6 min · 1133 words · Starslayerx