↓ Skip to main content
  1. Categories/

工程

2026

从倒排索引到 BPE:高性能系统为什么总在避免扫描全集

·2540 words·6 mins
最近在系统学习 Search 和 Information Retrieval 的知识。在看倒排索引(Inverted Index)的时候,我越看越觉得这个结构非常眼熟。直到我想起前段时间写 CS336 作业里 BPE(Byte-Pair Encoding)分词算法的优化逻辑,我才突然意识到:原来这些看似完全不同领域的系统,底层其实都在共享同一种 pattern。

模型压缩之后,为什么推理反而变慢了:一次 CPU Serving 的性能优化实践

·2830 words·6 mins
之前我负责过一个推荐系统深度学习 Serving 框架的功能开发与性能优化。 我们的系统主要跑在 CPU 上,以 TensorFlow 为主力 inference engine。随着模型迭代,尤其是 Embedding 层越来越大,模型导出、传输和上线变得非常慢,Serving 节点的内存成本也眼看着往上飙。

开公司 VPN 后 ChatGPT 无法访问:一场 DNS 归属与透明代理的冲突

·1871 words·4 mins
起因 # 最近在家办公,需要连公司 VPN(UniVPN)进内网。但一连上 VPN,浏览器里的 chatgpt.com 就直接打不开了。 看起来很像「VPN 把网络搞坏了」。以前遇到这种情况,可能就忍忍,查资料时关掉,进内网时再打开。但来回切实在太难受了,于是决定查一查到底哪里冲突了。

为什么一个 Python Library 既要锁依赖,又不能锁依赖

·5605 words·12 mins
起因 # 最近在团队内部重新整理 Python 项目的打包、发布和依赖管理规范,逐渐把各个工程统一收敛到: 1pyproject.toml 2uv 3uv.lock 4wheel 5src layout 6internal package registry 在这个过程中,大家交流最多的往往是一些具体的工具用法:私有源怎么配、build backend 选哪一个、uv 的命令参数怎么写。但我越梳理越发现,这些工程细节很容易盖住一个更基础的问题:

从进程视角重新理解 Docker

·3809 words·8 mins
起因 # 第一次接触 Docker 是 2017 年,在深圳网警机房驻场做审核项目。机房完全没有外网,模型、依赖、运行环境全靠 U 盘拷贝 docker image 来传输。后来做模型转换系统,再到量化行业负责机器学习平台,和 Docker、K8s 打了不少交道。但距离上一次系统梳理 namespace、cgroup 这些底层机制,已经过去好几年了。

2022

浅谈 Cpp Value Categories

·925 words·2 mins
背景 # 每一个cpp expression都有一个type 和 value category 属性 前者大家都比较了解,但是后者却常常被忽视 Value Categories in the c language # cpp是由c语言发展而来,因此这里先介绍c 语言中的value category

redis学习笔记

·1304 words·3 mins
最近在做一个智能算力的项目,其中需要用到redis维护某个全局的时间窗口 资料 # https://redis.io/docs/about/ 极客时间Redis核心技术与实战 复杂数据结构的表示方式 # 学习过程中唯一让我迷惑的是一个嵌套的数据结构要如何表示。比如我想表示一个key为string, value为List的Hash 按照c++的语法,也就是一个

[施工中] levelDB 代码阅读笔记 06 iterator

·1164 words·3 mins
接口 # 一个ABC,后面会继承这个类做各种实现 clean up function # 代码比较好懂,唯一让我感到疑惑的是 clean up function 这部分 1 2 // FIXME: 不太理解为什么需要很多个clean up function 3 // Cleanup functions are stored in a single-linked list. 4 // The list's head node is inlined in the iterator. 5 struct CleanupNode { 6 // True if the node is not used. Only head nodes might be unused. 7 bool IsEmpty() const { return function == nullptr; } 8 // Invokes the cleanup function. 9 void Run() { 10 assert(function != nullptr); 11 (*function)(arg1, arg2); 12 } 13 14 // The head node is used if the function pointer is not null. 15 CleanupFunction function; 16 void* arg1; 17 void* arg2; 18 CleanupNode* next; 19 }; 20 CleanupNode cleanup_head_; 21}; 从 table/iterator.cc 的析构函数中,可以看到在iterator析构的时候会依次调用多个clean up function

levelDB 代码阅读笔记 05 arena

·1286 words·3 mins
arena是levelDB中的内存池实现 接口 # 没有太多好说的,都非常直观。补了些注释 1 2class Arena { 3 public: 4 Arena(); 5 6 Arena(const Arena&) = delete; 7 Arena& operator=(const Arena&) = delete; 8 9 ~Arena(); 10 11 // Return a pointer to a newly allocated memory block of "bytes" bytes. 12 char* Allocate(size_t bytes); 13 14 // Allocate memory with the normal alignment guarantees provided by malloc. 15 char* AllocateAligned(size_t bytes); 16 17 // Returns an estimate of the total memory usage of data allocated 18 // by the arena. 19 size_t MemoryUsage() const { 20 return memory_usage_.load(std::memory_order_relaxed); 21 } 22 23 private: 24 char* AllocateFallback(size_t bytes); 25 char* AllocateNewBlock(size_t block_bytes); 26 27 // Allocation state 28 // alloc_ptr_ 表示下一个可用的位置 29 char* alloc_ptr_; 30 size_t alloc_bytes_remaining_; 31 32 // Array of new[] allocated memory blocks 33 // 需要注意,vector中每一个元素都是一段内存块(memory, block) 34 std::vector<char*> blocks_; 35 36 // Total memory usage of the arena. 37 // 38 // TODO(costan): This member is accessed via atomics, but the others are 39 // accessed without any locking. Is this OK? 40 std::atomic<size_t> memory_usage_; 41}; 分配策略 # 代码可说的不多,主要想讲讲分配策略

levelDB 代码阅读笔记 04 filter

·2552 words·6 mins
FilterPolicy接口 # 1 2class LEVELDB_EXPORT FilterPolicy { 3 public: 4 virtual ~FilterPolicy(); 5 6 // Return the name of this policy. Note that if the filter encoding 7 // changes in an incompatible way, the name returned by this method 8 // must be changed. Otherwise, old incompatible filters may be 9 // passed to methods of this type. 10 virtual const char* Name() const = 0; 11 12 // keys[0,n-1] contains a list of keys (potentially with duplicates) 13 // that are ordered according to the user supplied comparator. 14 // Append a filter that summarizes keys[0,n-1] to *dst. 15 // 16 // Warning: do not change the initial contents of *dst. Instead, 17 // append the newly constructed filter to *dst. 18 virtual void CreateFilter(const Slice* keys, int n, 19 std::string* dst) const = 0; 20 21 // "filter" contains the data appended by a preceding call to 22 // CreateFilter() on this class. This method must return true if 23 // the key was in the list of keys passed to CreateFilter(). 24 // This method may return true or false if the key was not on the 25 // list, but it should aim to return false with a high probability. 26 virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0; 27}; 其中CreateFilter的含义是从n个key生成一个 std::string. 生成的std::string可以包含n个key的信息(类似于生成了一个全集) 从而后续判断某个key是否在其中。

[c++17] std::any 笔记

·1400 words·3 mins
背景 # 一种很常见的背景是,需要表示未知类型的数据。比如可能是用户提供的数据,也可能是一个 Cache 的实现,其 value 想支持任意类型的数据 对于这种场景,c 语言出身的开发者通常会使用 void* 来实现

levelDB 代码阅读笔记 02 comparator

·3968 words·8 mins
levelDB是一个有序的KV存储,因此key的顺序是十分关键的 levelDB提供用户自己定义key顺序的能力 先看下comparator的接口 接口 include/leveldb/comparator.h # 1 2// A Comparator object provides a total order across slices that are 3// used as keys in an sstable or a database. A Comparator implementation 4// must be thread-safe since leveldb may invoke its methods concurrently 5// from multiple threads. 6class LEVELDB_EXPORT Comparator { 7 public: 8 virtual ~Comparator(); 9 10 // Three-way comparison. Returns value: 11 // < 0 iff "a" < "b", 12 // == 0 iff "a" == "b", 13 // > 0 iff "a" > "b" 14 virtual int Compare(const Slice& a, const Slice& b) const = 0; 15 16 // The name of the comparator. Used to check for comparator 17 // mismatches (i.e., a DB created with one comparator is 18 // accessed using a different comparator. 19 // 20 // The client of this package should switch to a new name whenever 21 // the comparator implementation changes in a way that will cause 22 // the relative ordering of any two keys to change. 23 // 24 // Names starting with "leveldb." are reserved and should not be used 25 // by any clients of this package. 26 virtual const char* Name() const = 0; 27 28 // Advanced functions: these are used to reduce the space requirements 29 // for internal data structures like index blocks. 30 31 // If *start < limit, changes *start to a short string in [start,limit). 32 // Simple comparator implementations may return with *start unchanged, 33 // i.e., an implementation of this method that does nothing is correct. 34 virtual void FindShortestSeparator(std::string* start, 35 const Slice& limit) const = 0; 36 37 // Changes *key to a short string >= *key. 38 // Simple comparator implementations may return with *key unchanged, 39 // i.e., an implementation of this method that does nothing is correct. 40 virtual void FindShortSuccessor(std::string* key) const = 0; 41}; 比较让人迷惑的应该是 FindShortestSeparator 和 FindShortSuccessor 函数。 其实可以简单理解成为了节省存储,而对key做了一定修改。 这个实现是不确定的,甚至完全什么都不做也是合法的。

levelDB 代码阅读笔记 01 db.h

·1551 words·4 mins
背景 # 最近在做一个智能算力相关的项目,类似美团外卖广告智能算力的探索与实践 其中实现控制系统需要与数据库交互。虽然最后技术选型并没有使用到levelDB,但是想趁机把代码读了吧。

博客除草

·469 words·1 min
博客要长草了。。趁着过年时间多,打理一下。。 添加google analytics # hugo本身已经集成了这个功能 要点是集成的是旧版本的universal analytics (对应的是UA-ID) 而目前google主推得其实是新版本google analytics 4(对应的是GA4-ID)