mcc:一个简单易理解的 C 编译器
mcc (minimal c compiler) 是一个小型的 C 编译器,仅支持有限的 C 语言特性,思路来源于 C4。 C4 仅用了少量代码和有限特性实现了自举(1个文件4个函数),非常精巧但却晦涩难懂。 正所谓:编译过程一遍过,递归调用循环调,全局变量随处变,类型转换强制转。 mcc 则走的是相反的路,完全以简单可理解为目标。当然,不可避免地,代码量会大许多,大概有1700多行。 如果你刚刚开始学习编译原理,希望真切地了解编译器前端和虚拟机运行,而不只是书上的文法和期末的试卷,那么可以考虑先看看 mcc,然后再回去看 C4,相信会豁然开朗。 项目地址:https://github.com/patricklaux/mcc 注:C4 是500多行代码。 1. 编译运行 # 下载源码 git clone git@github.com:patricklaux/mcc.git # 编译 mcc gcc -o mcc ./src/mcc/lexer.c ./src/mcc/parser.c ./src/mcc/vm.c ./src/mcc/mcc.c # 使用 mcc 运行测试代码 ./mcc [-s] [-d] ./src/test/test1.c 提示: 除了直接用 gcc 编译,也可以用 cmake,这里不再赘述。 -s 和 -d 为可选参数: -s 打印生成的指令,但不执行;-d 运行并打印整个运行过程执行的指令。 Windows 10 (MinGW_w64 11.0) 和 Ubuntu 22.04 (gcc 11.4.0) 均可正常编译运行。 2. 概要介绍 2.1. 流程 为了便于理解,特意画了几张流程图,按图索骥,相信更容易理解。 ...
Clion远程调试Redis源码
官方 Redis 不支持 Windows 环境下构建运行,如希望在 Windows 环境下跟踪调试 Redis 源码,可使用 CLion 的远程开发模式。 1. 概述 CLion 的远程调试有两种模式: Remote GDB Server:仅支持 cmake 项目,CLion 可自动构建二进制文件并上传到远程服务器,并自动调用 gdbserver 执行程序。 Remote Debug:可支持非 cmake 项目,需手动在远程服务器端完成首次构建,并将可执行文件和符号表下载到本地环境。 由于 Redis 通过 makefile 进行构建,并非 cmake 项目,所以需采用 Remote Debug 模式。 Remote Debug Remote GDB Server Project format Any CMake Toolchain Not specified Default on macOS/Linux; MinGW, Cygwin, WSL on Windows; Remote and Docker toolchains also available Path mappings Not created automatically, should be set up in run/debug configuration Not created automatically,should be set up in run/debug configuration 2. 环境准备 本地系统: Windows(Windows 10) ...
Xcache:多级缓存框架介绍
多年前,我造过一个轮子,也是多级缓存框架,名字也叫做 Xcache。 多年后,本着重复造轮子的精神,我又造了个新轮子:https://github.com/patricklaux/xcache 因为是新造的轮子,所以看起来似乎更圆了一些,跑起来似乎也更顺滑了一些。 非要自夸一下的话,那就是这么些年的编程生涯,在踩过许多坑之后,编码质量更好了点,架构设计更合理了些。 1. 整体架构 说明: Cache API:缓存接口。 Cache Annotation:缓存注解。 Cache:缓存对象。 Store:缓存数据存储,每个缓存对象实例最多可支持三级缓存数据存储。 Codec:数据编解码(序列化与反序列化)。 Compressor:数据压缩。 CacheLoader:数据加载,用于从数据源读取数据。 CacheRefresh:缓存数据刷新,定时通过 CacheLoader 加载并刷新缓存数据。 CacheSync:缓存数据同步,用于维护各实例间私有缓存数据的一致性。 CacheMetrics:缓存指标采集,用于记录缓存调用次数及命中率等指标。 MetricsSystem:缓存指标信息的存储、计算与展示。 MQ:消息队列,用于转发数据同步消息(已有实现采用 Redis Stream)。 DataSource:数据源。 Redis or Other……:缓存数据存储仓库。 2. 框架特性 支持多级缓存:一级缓存采用 Caffeine,二级缓存采用 Redis,最多可支持三级缓存。 缓存数据同步:通过缓存事件广播,多个应用实例的缓存数据保持一致。 缓存指标统计:支持调用次数、命中次数等指标,数据呈现可自由扩展。 缓存数据刷新:定时自动刷新缓存数据,避免慢查询导致应用响应缓慢。 随机存活时间:可选择使用随机存活时间,避免大量数据集中过期,导致数据源压力过大。 数据回源加锁:同一个键同一时刻仅允许一个线程回源查询,减轻数据源压力。 数据存在断言:可选择实现数据存在断言接口,譬如 Bloom Filter,减少无效回源查询。 支持缓存空值:可选择缓存空值,减少无效回源查询。 缓存数据压缩:可选择数据压缩,降低内存(磁盘)消耗。 支持缓存注解:Cacheable,CacheableAll,CachePut,CachePutAll,…… ,CacheClear 适配 Spring Cache 注解:如希望使用 Spring Cache 注解,可依赖 Xcache 适配项目,即可解锁更多功能。 3. 缓存流程 原则:数据查询顺序从一级缓存到三级缓存,数据写入、删除顺序从三级缓存到一级缓存。 实际应用中,可能只有一级缓存或两级缓存,并不一定有全部三级缓存,这是可配置的。 3.1. 数据查询 流程:按照一级缓存 → 二级缓存 → 三级缓存的顺序依次查询。 图示: 3.2. 数据写入 流程:按照三级缓存 → 二级缓存 → 一级缓存的顺序依次写入。 图示: 3.3. 数据删除 流程:按照三级缓存 → 二级缓存 → 一级缓存的顺序依次删除。 ...
二叉树06:从2-3-4树到红黑树
1. 前言 红黑树是一种自平衡二叉查找树(Self-balancing binary search tree)。 如前文所述,根据红黑树的定义去理解其设计思想是非常困难的,但借助 B 树我们却可以更好地理解它,因为红黑树本就是由4阶B树推导而来。 全文较长,但为了完整的阅读体验,所以没有拆分为多篇文章,读者可以根据导图挑选阅读感兴趣的章节。 代码仓库:https://github.com/patricklaux/perfect-code 2. 由来 了解红黑树的由来和变体,有助于更好地理解。 (1) 1972 年,Rudolf Bayer 提出了 “symmetric binary B-tree”,这是B 树的 4 阶情形,也就是 2-3-4树(或称为 2-4 树)1。 (2) 1978 年,Leonidas J. Guibas 和 Robert Sedgewick 从 “symmetric binary B-tree” 推导出红黑树2。 (3) 1993 年,Arne Andersson 引入 “right leaning tree(右倾树)” 的概念来简化插入和删除操作3。 (4) 1999 年,Chris Okasaki 展示了如何使插入操作成为纯函数,只需处理 4 种失衡类型和 1 种默认平衡类型4。 (5) 2001 年,Cormen 等人将原算法的 8 个失衡类型减少为 6 个失衡类型5。 (6) 2008 年,Sedgewick 根据 Andersson 的思想,提出了 “Left leaning red black tree(左倾红黑树)”,这是 2-3 树的等价转换6。 ...
二叉树05:B树详解与实现
1. 前言 红黑树的实现并不困难,但仅根据其定义去理解背后的设计思想却是相当不容易的。 相比较而言,B树是非常直观且容易理解的,了解B树之后,再去看红黑树,就会发现红黑树其实是4阶B树的一种等价实现,红黑树的查找、插入、删除、着色和旋转都可以在4阶B树中一一找到对应关系。 另外,B树及其变体也广泛地运用于数据库系统,譬如 MySQL、MongoDB……等。 这篇文章中,我会先介绍 B树的由来,接着介绍其定义和概念,然后通过图例和流程图来说明相关操作,最后会给出其代码实现。 代码仓库:https://github.com/patricklaux/perfect-code 2. 由来 B 树是由 Rudolf Bayer 和 Edward McCreight 在波音实验室工作期间提出的,论文 “Organization and maintenance of large ordered indices1” 发表于1972年。 B 树是多叉查找树的一种实现,而多叉查找树是二叉查找树的推广。 与内存相比,磁盘具有持久性、大容量和单位存储价格便宜等优点。 但磁盘相对于内存而言是非常缓慢的,二叉树这种内存数据结构并不能很好地应用于磁盘存储。 磁盘读写以页为单位,分页大小为 4KB 时,读取 1B 数据与 4KB 数据均需一次磁盘I/O,耗时几乎相等。 另外,磁盘顺序读写比随机读写的性能要好得多,当读写连续的数据页时,通常都会有不错的性能表现。 因此,根据磁盘数据读写的这些特点,为减少磁盘I/O,很自然的一个想法就是将多个数据项合并存入到一个节点,节点大小恰好是页大小的整数倍。 如下图所示,多个二叉树节点合并成一个节点,这样二叉查找树就变成了多叉查找树 (M-ary search tree)。 图2.1:节点合并(图片来源于参考资料[2]) 一棵完全二叉树 (complete binary tree) 的层数大约为 \( log_2n \),一棵完全多叉树 (complete M-ary tree) 的层数大约为 \( log_mn \),n 为数据记录数。 这意味着,如果有 100万条数据记录,当以二叉树的形式存储到磁盘,搜索一条数据记录约需 20次磁盘I/O: \( log_21000000≈20 \); 如图2.1 所示,通过将 7个节点合并成一个数据页存储到磁盘,变成一棵 8叉搜索树,那么搜索一条数据记录仅需约 7次磁盘I/O: ...
二叉树04:AVL树实现与优化
时隔多年又重新实现了一遍 AVL树,并且进行了深度优化,所以有些心得。 首先,我会介绍6种失衡类型和4种旋转; 然后,重点描述插入和删除的优化实现,并将给出严谨的分析和证明,解释为什么可以这么优化; 最后,我会用 AVL 树与 Java 的 TreeMap (红黑树)进行性能对比,以验证优化结果。 代码仓库:https://github.com/patricklaux/perfect-code 1. 简介 AVL 树是一种自平衡二叉查找树(Self-balancing binary search tree),得名于其两位作者的首字母1: Georgy Adelson-Velsky 和 Evgenii Landis。 相比于二叉查找树最坏情况下时间复杂度为 \( O(n) \),AVL树查找、插入和删除的平均时间复杂度和最坏时间复杂度均为 \( O(log_2n) \),其中 n 为树的节点数。 2. 高度与平衡因子 AVL树的平衡性质:其任意节点的左子树和右子树的高度差的绝对值小于等于1。 2.1. AVL节点 private class AvlNode<K, V> { K key; // 键 V val; // 值 byte height; // 高度 AvlNode<K, V> left; // 左孩子 AvlNode<K, V> right; //右孩子 } 2.2. 获取高度 // 空树的高度定义为 -1。 private byte height(AvlNode<K, V> node) { return (node == null) ? -1 : node.height; } 2.3. 更新高度 // 取左右子树的高度的大者再加1,即为父节点的高度 private void updateHeight(AvlNode<K, V> parent) { parent.height = (byte) (Math.max(height(parent.left), height(parent.right)) + 1); } 2.4. 平衡因子 二叉查找树的平衡因子 BF (Balance Factor) 的定义为两棵子树的高度之差。 ...
二叉树03:无需队列的层序遍历算法IDDFS
1. 概述 IDDFS (Iterative deepening depth-first search):迭代加深搜索,是一种状态空间/图的搜索策略。 其空间复杂度仅为 \( O(d) \),相比用队列实现层序遍历所需的 \( O(b^d) \) 空间复杂度,极大地节约了空间开销,b 为分支因子,d 为深度。 从三个维度来分析,空间开销、时间性能和求解路径的代价,IDDFS 都接近最优,是一个非常优秀的算法。 本文主要介绍用 IDDFS 算法实现二叉树的层序遍历,如对其它方面的搜索运用感兴趣,可阅读参考资料1。 代码仓库:https://github.com/patricklaux/perfect-code 2. 使用队列实现层序遍历 层序遍历:即为按层顺序访问,所有深度为 d 的节点在深度为 d+1 的节点之前访问——(d, b, f, a, c, e, g)。 使用队列实现层序遍历并不复杂,代码如下: public void levelOrderTraversal(List<Tuple2<K, V>> kvs) { if (root == null) { return; } ArrayDeque<Node<K, V>> queue = new ArrayDeque<>(size.get() / 2); queue.push(root); while (!queue.isEmpty()) { Node<K, V> p = queue.poll(); kvs.add(Tuples.of(p.key, p.val)); if (p.left != null) { queue.offer(p.left); } if (p.right != null) { queue.offer(p.right); } } } 常见的算法书在介绍层序遍历时都采用队列来实现,这种算法被称为标准 BFS。 ...
二叉树02:深度优先遍历之Morris遍历
1. 概述 前一篇文章介绍了深度优先遍历的递归实现和迭代实现,这两种方式的时间复杂度都是 \( O(n) \),空间复杂度都是 \( O(h) \),本文将要介绍的 Morris 遍历的时间复杂度依然为 \( O(n) \),但空间复杂度仅为 \( O(1) \),其中 n 为节点数,h 为树的高度。 算法来历 1968年,《计算机程序设计艺术》的作者 Knuth 提出了一个问题:设计一个无需堆栈和额外标志域的非递归的中序遍历算法,且当遍历结束时树结构不变。此后,诞生了许多解决方案,而Morris 遍历是其中最优雅的一种(见参考资料1)1。 此算法由 Joseph M. MORRIS 在1979年的论文 “Traversing Binary Trees Simply and Cheaply2” 中首次提出。顺便再说一句,这个 MORRIS 正是大名鼎鼎的 KMP 算法的作者之一。 代码仓库:https://github.com/patricklaux/perfect-code 2. 算法解析 线索二叉树 如果了解线索二叉树的话,肯定对前驱和后继非常熟悉。 通过在二叉树节点增加前驱和后继指针,可以非常方便地进行向前查找、向后查找和遍历等线性化操作,相当于是二叉树和链表的结合。这其中指向前驱和后继的指针称之为线索,而包含线索的二叉树则称之为线索二叉树(Threaded Binary Tree)3。 譬如 Java 的 HashMap 中的 红黑树节点,就增加了 prev 和 next 指针,其节点结构类似如下: class TreeNode<K,V> { TreeNode<K,V> parent; // 父节点 TreeNode<K,V> left; // 左孩子 TreeNode<K,V> right; // 右孩子 TreeNode<K,V> prev; // 前驱 TreeNode<K,V> next; // 后继 boolean red; // 颜色 } 这种方式需要额外内存来保存前驱和后继指针,那么是不是有一些其它方式来避免这个问题呢? ...
二叉树01:深度优先遍历
1. 概述 图1:二叉树遍历 遍历二叉树,即按照某条搜索路径巡访树中的每个结点,使得每个节点均被访问一次,而且仅被访问一次1。 深度优先遍历,常见的有递归方式和用栈实现的迭代方式, Morris 遍历虽然空间复杂度很好,但因需在遍历期间改变树结构而不常用。 广度优先遍历,常见的是用队列实现的迭代方式,但需耗费大量内存,而 IDDFS 算法则更节省内存空间。 本文将主要讲述深度优先遍历的递归和迭代的实现方式,其它见后续文章。 代码仓库:https://github.com/patricklaux/perfect-code 2. 递归 先序遍历、中序遍历和后序遍历的过程完全相同,都是从根到左子树再到右子树,差别仅在于何时访问值。 看后面的代码实现,会发现三段递归程序几乎完全相同,仅仅是调整了访问值的次序。 2.1. 先序遍历 先序遍历 (pre-order traversal):根,左,右 图2:先序遍历 代码实现 private void preorderTraversalR(List<Tuple2<K, V>> kvs, Node<K, V> p) { // visit,添加到结果集 kvs.add(Tuples.of(p.key, p.val)); if (p.left != null) { preorderTraversalR(kvs, p.left); } if (p.right != null) { preorderTraversalR(kvs, p.right); } } 2.2. 中序遍历 中序遍历(in-order traversal):左,根,右 中序遍历正好是按键的大小排序。 图3:中序遍历 ...
字典树之旅04:Patricia Trie(二)
前文实现了 Patricia Trie,但用的是字符比较,而原论文则采用的是二进制位比较。 然后,我们心里可能会有疑问:二进制位比较是如何推广到字符比较的呢?二进制位比较相比于字符比较,又有哪些优点或缺点呢? 相关代码:https://github.com/patricklaux/perfect-code 1. 基数 让我们先从基数说起吧。 1.1. 基数(radix) 基数(radix),在定位数系(positional numeral system) 中表示不重复编码(digit) 的数量。 譬如在10进制中,有 {0, 1, 2, … ,8, 9} 共 10 个编码,那么基数就是 10; 譬如在16进制中,有 {0, 1, 2, … ,e, f} 共 16 个编码,那么基数就是 16; ………… 如果我们用 EASCII 字符编码来作为集合,那么其基数就是 256; 如果我们用 UTF-16 字符编码来作为集合,那么其基数就是 65536; ………… 如果我们用小写英文字母 {a, b, c, … , y, z} 来作为集合,那么其基数就是26。 也就是说,我们可以根据需要定义一套编码集,而基数就是这套编码集的元素数量。 注:基数(radix) 也可以看作是集合论中的基数(cardinal),而编码集是有限良序集。 1.2. 基数树(radix tree) 基数概念推广到树中,那么这个基数就是 R 的大小。 我们在前两篇文章的节点定义就有一个 R,用来指定数组容量。类似于如下定义: class RadixNode{ // 值 V val; // 子节点数组 RadixNode<V>[] table; // R为数组容量 public RadixNode(int R) { this.table = new RadixNode[R]; } } 这棵树会有 R 个分支,又因为编码集是有限良序集,所以可将数组索引映射为唯一编码。 ...
字典树之旅03:Patricia Trie(一)
这篇文章我将介绍 StandardTrie 的简单变体: PatriciaTrie1。 PatriciaTrie 或 PatriciaTree, 在一些论文中又被称为 CompactTrie(紧凑 trie)或 CompressedTrie(压缩 trie)。 相关代码:https://github.com/patricklaux/perfect-code 1. 导引 PatriciaTrie 的显著优化是合并单路分支:如果一个非根无值节点有且仅有一个子节点,则将其子节点与该节点合并。 文字描述稍有点抽象,还是看图: 节点合并 图1:节点合并 节点分裂 如果需要添加键 “da”,该如何来处理哪?我们需要将 “dad” 分裂成两个节点,效果见下图: 图2:节点分裂 相信,这两张图已足以说明一切😀 同时,我们也可以看到合并后节点数变少,因此减少了可能的内存消耗。 2. 代码实现 依照惯例,还是写代码来实现它。 2.1. 节点定义 package com.igeeksky.perfect.nlp.trie; private static class PatriciaNode<V> { // key 的子串 String subKey; // 值(支持泛型,可以是非字符串) V val; // 子节点 PatriciaNode<V>[] table; public PatriciaNode(int R) { this.table = new PatriciaNode[R]; } public PatriciaNode(int R, String subKey) { this.subKey = subKey; this.table = new PatriciaNode[R]; } public PatriciaNode(String subKey, V value) { this.subKey = subKey; this.val = value; } public PatriciaNode(int R, String subKey, V value) { this.subKey = subKey; this.val = value; this.table = new PatriciaNode[R]; } } 对比前文的 StandardNode,多了一个 String 类型的 subKey 字段,该字段用于存储节点合并之后的字符串,其它无变化。 ...
字典树之旅02:Trie 的标准实现
这篇文章将介绍最简单的 Trie 结构,即 StandardTrie,常被称为 标准 Trie,或朴素 Trie。 相关代码:https://github.com/patricklaux/perfect-code 1. 导引 假设有一个关键词集,其中有 6 个单词:bad, bade, bed, ca, cad, dad。 当输入 “b” 时,输出以 “b” 为前缀的所有单词; 输入一段文本,输出文本中存在这六个单词的哪几个,以及单词出现的起止位置…… 我们可以建立如下图所示的树形结构。 图1:字典树示例 每个字符一个节点,节点之间用边相连; 有特殊标记(有值)则代表一个完整的关键词。 2. 基本性质与操作 通过观察 ”图1:字典树示例“,我们可以发现一些性质和规律。 基本性质 根节点无字符; 兄弟节点的字符互异; 非根节点有且仅有一个字符; 非根节点有且仅有一个父节点; 根节点到其它节点的每条路径代表一个唯一的字符串。 根据以上性质,我们又可以得到一个有意思的推论:6. 兄弟节点都具有同一前缀; 键查找 从根节点沿着序列路径递归查找子节点,最后一个字符对应节点如果有特殊标记,则命中。 譬如要查找 bad,root → b → a → d,命中,返回 bad;譬如查找 cup,root → c → NULL,未命中,返回空。 前缀匹配 先找到前缀节点,然后遍历其子节点。 譬如查找以 b 为前缀的关键词:1. 先找到 b 对应的节点,root → b,找到 b 节点;2. 遍历 b 节点的所有子节点。 ...
字典树之旅01:开篇
Trie1 通常被称为字典树(或前缀树、单词搜索树),是一种用于存储和检索字符串的树型数据结构。 Trie 是英文单词 retrieval 的一部分,名称最早由 E. Fredkin2 提出,发音同 “try”。 图1:关键词推荐列表 典型的应用场景是搜索引擎的输入框:譬如当输入 “trie” 时,会列出以 “trie” 为前缀的关键词推荐列表。 此外,还有诸如拼写检查、词典分词、词频统计、数据压缩、倒排索引、字符串排序、关键词过滤……等等众多应用场景。 技术演化 由于字典树相关算法的应用广泛,所以演化出大量的数据结构和优化技术,其进化史就是一个脑洞大开的过程。 我之前画过一张复杂的演进图,现在看来并无必要,事实上只要了解关键脉络即可。删繁就简,最终留下了这张比较简单的图。 图2:技术演化 文章目录 字典树之旅01:开篇(本文) 字典树之旅02:Trie 的标准实现 字典树之旅03:Patricia Trie(一) 字典树之旅04:Patricia Trie(二) 未完待续…… 参考资料 https://en.wikipedia.org/wiki/Trie ↩︎ Fredkin, E. . “Trie memory.” Communications of the Acm 3(1960). ↩︎
智能会话机器人:SaaS平台设计与思考
1. 前言 随着自然语言处理和智能语音识别技术的发展,智能会话机器人开始部分替代人工客服。 网上关于 NLP 算法的文章有很多,但关于 Chatbot 架构的却很少,关于 Chatbot SaaS 平台架构的则更少。我是一名对机器学习感兴趣的程序员,更关注如何设计实现一个架构良好的 Chatbot SaaS 平台,因此写下了这篇文章。 2. Chatbot架构 2.1. 智能会话机器人的分类 智能会话机器人按照对话轮次来划分,可以分为单轮对话机器人和多轮对话机器人;按照知识领域来划分,可以分为限定域机器人和开放域机器人;按照任务类型来划分,可以分为任务型机器人、问答型机器人、闲聊型机器人和融合型机器人。 任务型:根据用户给出的信息完成指定的任务。一般限定于某个垂直领域,常采用多轮对话的形式。如订餐、订票等服务。 问答型:为用户提出的事实型、布尔型、计算型、推理型等类型的问题自动给出答案,进一步还可以再划分为常见问题解答(FAQ)和知识图谱问答(KBQA),一般限定于某个特定知识领域。 闲聊型:与用户进行开放式聊天,满足用户的情感陪护需求。一般不限定话题范围,但有可能偏向于某个领域。 融合型:一般以任务型或问答型为主,融合闲聊功能。如对于电商客服机器人来说,能完成商品推荐购买任务,能回答保修政策问题,还能陪客户闲聊天,融合型是应用场景越来越复杂的产物。 从应用的发展趋势来看:单轮对话——>多轮对话,以获得更多更完整的信息;单领域——>多领域,以满足用户更多层面的需求。 2.2. 任务型机器人交互模型 企业应用中最常见的需求是任务型机器人,上图是任务型机器人经典的交互模型。其中红色框为文字语音转换部分,这里暂不作讨论。 2.2.1. 自然语言理解(NLU) 领域识别(Domain Identification) 检测用户输入内容所涉及的领域概念。 意图识别(Intent Detection) 检测用户在特定领域下表述内容所代表的意图。 词槽填充(Slots Filling) 收集用户在对话过程中任务所必需的关键信息。 2.2.2. 对话管理(DM) 对话状态追踪(Dialogue State Tracking,DST) 记录和判断当前会话处于任务的何种状态。 对话策略(Dialogue Policy,DP) 根据对话状态决定下一步的系统行为。 2.2.3. 自然语言生成(NLG) 自然语言生成主要有两种方法:基于模板生成和基于模型生成。 基于模板生成:调用设计人员预先设计的回复模板,根据前置阶段获取到的状态和关键信息生成自然语言回复给用户。优点是响应速度较快,缺点是语言表达不够丰富,需要人工定义模板规则。因此比较适合在响应动作较少时使用,或是在系统冷启动时使用。 基于模型生成:通常使用seq2seq模型学习大量交互语料数据,根据用户输入直接生成相关自然语言回复给用户。优点是不需要人工定义模板规则,语言表达较为丰富;缺点是回复结果不太可控,响应速度较慢,需要学习大量的交互语料数据。因此比较适合系统资源充足且有大量交互数据时采用。 2.3. 组件集成(pipeline) 任务型机器人的系统设计中,通常采用pipeline方式来集成各个组件。 pipeline的组件构成根据采用的方法不同而不同。有可能整个pipeline由三个组件构成,NLU、DM、NLG分别为一个模型;也可能整个pipeline由两个组件构成,NLU + DM 为一个模型,NLG 是一个模型;也有可能整体仅有一个组件,NLU + DM + NLG 是一个整体的模型(end2end)。 某些情况下,为了提高响应速度,还可能是一个并行流(如下图所示)。 ...
kubernetes:ingress-nginx安装与配置
1. 快速安装 1.1. 使用 Helm 安装 在线安装 helm upgrade --install ingress-nginx ingress-nginx \ --repo https://kubernetes.github.io/ingress-nginx \ --namespace ingress-nginx --create-namespace 离线安装 wget https://github.com/kubernetes/ingress-nginx/releases/download/helm-chart-4.13.3/ingress-nginx-4.13.3.tgz helm install ingress-nginx ingress-nginx-4.13.3.tgz --version 4.13.3 --namespace ingress-nginx --create-namespace 1.2. 使用 yaml 安装 wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.13.3/deploy/static/provider/cloud/deploy.yaml kubectl apply -f deploy.yaml 1.3. 安装日志 NAME: ingress-nginx LAST DEPLOYED: Mon Oct 6 13:55:42 2025 NAMESPACE: ingress-nginx STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: The ingress-nginx controller has been installed. It may take a few minutes for the load balancer IP to be available. You can watch the status by running 'kubectl get service --namespace ingress-nginx ingress-nginx-controller --output wide --watch' # 省略 …… 1.4. 查看服务 $ kubectl get svc ingress-nginx-controller -n ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) ingress-nginx-controller LoadBalancer 10.99.75.212 <pending> 80:31647/TCP,443:32648/TCP ingress-nginx-controller 对外曝露了 2 个端口:http 为 31647;https 为 32648。 ...
Kubernetes:Dashboard 安装
Kubernetes Dashboard 是官方开发的仪表盘,可以方便地查看集群信息和管理集群资源。 对于初学者来说,还是很好的学习途径,可以直观地感受 Kubernetes 的各种概念,很多管理操作也都会直接给出相应命令。 这篇文章将介绍如何安装 Dashboard,与及如何创建相关的 ServiceAccount 和登录令牌。 1. 安装 Helm Kubernetes Dashboard 官方仅提供了 Helm 安装方式,因此需先安装 Helm。 Helm 的安装非常简单:直接将执行文件 helm 移动到 /usr/local/bin/ 目录即可。 # 下载安装包 wget https://get.helm.sh/helm-v3.19.0-linux-amd64.tar.gz # 解压 tar -zxvf helm-v3.19.0-linux-amd64.tar.gz # 移动执行文件到 bin 目录 sudo mv linux-amd64/helm /usr/local/bin/helm Helm: install Helm: releases 2. 安装 Dashboard 1.1. 准备镜像(可选) 为了避免网络影响,我们可以预先拉取(导入)镜像到主节点。 所需镜像及版本:Dashboard: releases #!/bin/bash # # 拉取 kubernetes-dashboard-7.13.0 所需镜像 set -euxo pipefail # 镜像列表 images=( docker.io/kubernetesui/dashboard-api:1.12.0 docker.io/kubernetesui/dashboard-auth:1.3.0 docker.io/kubernetesui/dashboard-metrics-scraper:1.2.2 docker.io/kubernetesui/dashboard-web:1.7.0 docker.io/library/kong:3.8 ) # 拉取镜像 for imageName in ${images[@]} ; do sudo crictl pull $imageName done # 创建导出目录 mkdir -p docker.io/kubernetesui/ mkdir -p docker.io/library/ # 导出镜像 for imageName in ${images[@]} ; do sudo ctr -n=k8s.io images export ${imageName}.tar $imageName done # 导入镜像 for imageName in ${images[@]} ; do sudo ctr -n=k8s.io images import ${imageName}.tar done 1.2. 在线安装 # 添加仓库 helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/ # 创建命名空间,安装 dashboard-7.13.0 版本 helm install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard --version 7.13.0 --create-namespace --namespace kubernetes-dashboard # 或:创建命名空间,升级(或安装)最新版本 dashboard # 注意:安装最新版本,预导入镜像的版本需与最新版本相匹配 helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard --create-namespace --namespace kubernetes-dashboard 1.3. 离线安装 我们也可以先将 chart 下载到本地,然后执行离线安装。 ...
Kubernetes:Metrics Server 通信安全
Metrics Server 并非 Kubernetes 核心 API,而是以聚合层方式提供的扩展 API 服务。 因此,为了使其与 Kubernetes 核心 API 之间实现通信安全,需要额外进行一些稍显复杂的配置。 1. 快速安装 # 获取资源配置 wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml 如为测试环境,仅需添加一行配置:--kubelet-insecure-tls,然后 kubectl apply -f components.yaml 即可完成安装。 # 省略 …… apiVersion: apps/v1 kind: Deployment # 省略 …… spec: # 省略 …… template: spec: containers: - args: - --cert-dir=/tmp - --secure-port=10250 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port - --metric-resolution=15s # 1.仅需添加下面这行:不验证 Kubelet 的服务证书的 CA(仅用于测试环境) - --kubelet-insecure-tls # 省略 …… --- apiVersion: apiregistration.k8s.io/v1 kind: APIService # 省略 …… spec: group: metrics.k8s.io groupPriorityMinimum: 100 # 2. 跳过 TLS 校验 insecureSkipTLSVerify: true # 省略 …… 示例配置如上,这里我们需特别关注两项配置: ...
自动化脚本快速搭建 Kubernetes 集群
Kubernetes 集群搭建好之后,一般来说一年半载都不会再操作一次。 但每次重新搭建都得折腾半天,是一件相当繁杂的事,所以我把搭建过程写成了脚本: GitHub :https://github.com/patricklaux/kube-install 这篇文章只是介绍配置项、执行命令和软件安装包,可与自动化脚本相互印证参考。 GitHub 中则包含完整的自动化脚本和软件安装包,如果一切顺利的话,大概十分钟就可完成全部过程。 0. 环境说明 集群搭建工具为 Kubeadm ,示例集群共有 3 个节点:1 个主节点和 2 个工作节点。 操作系统均为 Ubuntu 24.04.3,硬件配置为 4核-8G-200G 虚拟机,详细节点信息如下: IP 主机名 角色 192.168.50.130 k8s-control-1 控制平面 192.168.50.135 k8s-worker-1 工作节点1 192.168.50.136 k8s-worker-2 工作节点2 部署的软件版本为 Kubernetes 1.34.1 + Containerd 2.1.4 + Calico 3.30.3。 另,这次部署将尝试 Kubernetes 正式支持的新特性:nftables,此特性在 Calico 的当前版本仅处于技术预览阶段,因此勿用于生产环境。】 另,这些系统均无需提前安装 Docker。 1. 安装要求 每台机器均需安装 Linux 兼容系统。 集群所有节点能通过网络相互连接。 主节点应至少具有 2 个 vCPU 和 2GB RAM。 工作节点应至少具有 1 个 vCPU 和 2GB RAM。 ...
IDEA 远程部署 Docker 容器
为了便于自测或他测,我们可能会有这样的需求: 本机写完代码后,可以一键发布到远程服务器构建镜像并启动运行。 我试了几种方式,发现最方便的还是使用 IDEA 的 Docker 插件,而且本机无需安装任何其它 Docker 程序。 1. 环境说明 本机:Windows 10 系统,IDEA 2023.2.8 旗舰版,未安装 Docker Desktop。 远程:Ubuntu 24.04,已安装 Docker Engine。 2. 监听方式 交互模式: 客户端 (Docker cli) <——-> 守护程序 (Docker daemon) 监听本地请求: 守护程序默认通过 Unix Socket 来监听来自本地客户端请求。 Linux 下默认监听 /var/run/docker.sock,Windows 下默认监听 npipe:////./pipe/docker_engine 。 监听远程请求: 守护程序如要监听远程客户端请求,可通过 docker.service 或 daemon.json 配置为监听 IP 地址和端口。 其中 2375 默认为 HTTP 端口, 2376 默认为 HTTPS 端口。 详情见:https://docs.docker.com/engine/daemon/remote-access/ 3. 插件配置 如下图所示,IDEA 的 Docker 插件与守护程序的交互有三种方式: ① Docker for Windows;② TCP socket;③ SSH。 ...
Harbor 安装
Harbor 是一个开源的 企业级容器镜像仓库管理平台,由 VMware 中国团队开发并捐赠给 CNCF 托管。 其在 Docker Registry 的基础上提供了丰富的管理策略、基于角色的访问控制、多租户支持……等企业所需功能,几乎是私有云和本地容器镜像管理的首选解决方案。 1. 安装准备 1.1. 环境需求 硬件准备: 准备两台 Linux 服务器,具体分工如下: 名称 地址 角色 备注 仓库服务器 192.168.50.75 服务端 用于部署 Harbor 演示服务器 192.168.50.92 客户端 演示使用 Harbor 硬件要求: 仓库服务器 需运行多个不同类型的容器,因此需要较高的性能,官方建议如下: Resource Minimum Recommended CPU 2 CPU 4 CPU Mem 4 GB 8 GB Disk 40 GB 160 GB 软件要求: Software Version Description Docker Engine Version > 20.10 Docker Engine Installation Docker Compose Docker compose > 2.3 Docker Compose is part of Docker Engine OpenSSL Latest (optional) Used to generate certificate and keys for Harbor 两台服务器分别需预安装以下软件: ...