首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Claude Code 在大型代码库中的工作原理:最佳实践与入门指南

Claude Code 正在生产环境中运行,覆盖数百万行代码的单体仓库、数十年的遗留系统、跨越数十个仓库的分布式架构,以及拥有数千名开发者的组织。这些环境带来了小型简单代码库不会遇到的挑战——无论是每个子目录中不同的构建命令,还是分布在没有共享根目录的文件夹中的遗留代码。 Anthropic 观察到最成功的 Claude Code 部署共享一组可识别的模式,涵盖配置、工具和组织结构。本文是 "规模化 Claude Code" 系列的一部分,涵盖了企业规模化使用 Claude Code 的最佳实践。 Agentic Search 避免传统 RAG 的失败模式 传统的 AI 编程工具依赖基于 RAG 的检索,通过嵌入整个代码库并在查询时检索相关块。但在大型规模下,这些系统可能失败,因为嵌入管道无法跟上活跃的工程团队。当开发者查询索引时,它反映的是几天、几周甚至几小时前存在的代码库。检索然后返回团队两周前重命名的函数,或者引用上一个 sprint 中删除的模块,而没有任何指示两者已过时。 Agentic search 避免了这些失败模式。没有嵌入管道或需要维护的集中索引,因为数千名工程师提交新代码时,每个开发者的实例都从实时代码库工作。但这种方法有权衡:它最适合 Claude 有足够的起始上下文知道在哪里查找。这意味着 Claude 的导航质量取决于代码库的设置方式——用 CLAUDE.md 文件和技能分层上下文。如果你要求它在十亿行代码库中找到所有模糊模式的实例,你会在工作开始前就达到上下文窗口限制。投资于代码库设置的团队会看到更好的结果。 扩展层决定性能而非模型本身 关于 Claude Code 最常见的误解之一是其能力完全由使用的模型定义。团队关注模型的基准测试及其在测试任务上的表现。在实践中,围绕模型构建的生态系统——即 "harness"——比单独的模型更能决定 Claude Code 的性能。 Harness 由五个扩展点构建:CLAUDE.md 文件、hooks、skills、plugins 和 MCP 服务器,每个都有不同的功能。团队构建它们的顺序很重要,因为每一层都建立在前一层之上。LSP 集成和子代理这两个额外能力完成了设置。 CLAUDE.md 文件首先出现。这些是 Claude 在每个会话开始时自动读取的上下文文件:根文件用于全局视图,子目录文件用于本地约定。它们给予 Claude 所需的代码库知识来做好任何事情。由于它们在每个会话中加载,无论任务如何,保持它们专注于广泛适用的内容将防止它们成为性能的拖累。 Hooks 使设置自我改进。大多数团队认为 hooks 是阻止 Claude 做某事的脚本,但它们更有价值的用途是持续改进。stop hook 可以反思会话期间发生的事情,并在上下文新鲜时提出 CLAUDE.md 更新。start hook 可以动态加载特定于团队的上下文,这样每个开发者都为其模块获得正确的设置,而无需手动配置。对于 linting 和格式化等自动检查,hooks 确定性地执行规则,比依赖 Claude 记住指令产生更一致的结果。 Skills 保持正确的专业知识按需可用,而不会膨胀每个会话。在具有数十种任务类型的大型代码库中,并非所有专业知识都需要出现在每个会话中。Skills 通过渐进式披露解决这一问题,将专业工作流和领域知识卸载,否则这些会竞争上下文空间,并且仅在任务需要时才加载。例如,安全审查 skill 在 Claude 评估代码漏洞时加载,而文档处理 skill 在代码更改并需要更新文档时加载。Skills 也可以绑定到特定路径,因此它们仅在代码库的相关部分激活。 Plugins 分发有效的设置。一个挑战是有效的设置可能保持部落化。一个 plugin 将 skills、hooks 和 MCP 配置捆绑到单个可安装包中,因此当新工程师在第一天安装该 plugin 时,他们将立即拥有与已经使用 Claude 的人相同的上下文和能力。Plugin 更新可以通过托管市场跨组织分发。 LSP 集成赋予 Claude 与开发者在 IDE 中相同的导航能力。大多数大型代码库 IDE 已经运行 LSP,为 "转到定义" 和 "查找所有引用" 提供支持。向 Claude 展示这一点给了它符号级精度:它可以跟踪函数调用到其定义,跨文件追踪引用,并区分不同语言中同名的函数。没有它,Claude 在文本上模式匹配,可能落在错误的符号上。一家企业软件公司在 Claude Code 推广之前就在整个组织部署了 LSP 集成,专门是为了在规模上使 C 和 C++ 导航可靠。对于多语言代码库,这是最高价值的投资之一。 MCP 服务器扩展一切。MCP 服务器是 Claude 连接到无法到达的内部工具、数据源和 API 的方式。最复杂的团队构建 MCP 服务器,将结构化搜索作为 Claude 可以直接调用的工具暴露。其他人连接 Claude 到内部文档、票务系统或分析平台。 Subagents 将探索与编辑分离。子代理是一个孤立的 Claude 实例,有自己的上下文窗口,接受任务,执行工作,只将最终结果返回给父级。一旦 harness 就位,一些团队启动只读子代理来映射子系统并将发现写入文件,然后让主代理根据完整情况编辑。 三大配置模式 如何为大型代码库配置 Claude Code 很大程度上取决于该代码库的结构。但三种模式在观察到的部署中始终如一地出现。 保持 CLAUDE.md 文件精简和分层。Claude 在代码库中移动时_ADDITIVELY_加载它们:根文件用于全局视图,子目录文件用于本地约定。根文件应该只是指针和关键的注意事项;其他一切都会漂移到噪音中。 在子目录中初始化,而不是在 repo 根目录。Claude 在与任务实际相关的代码库部分范围内工作时效果最好。在单体仓库中,这可能感觉违反直觉,因为工具通常假设根访问,但 Claude 自动向上遍历目录树并加载沿途找到的每个 CLAUDE.md 文件,因此根级上下文永远不会丢失。 每个子目录的测试和 lint 命令范围。当 Claude 更改一个服务时运行完整套件会导致超时并在不相关的输出上浪费上下文。子目录级别的 CLAUDE.md 文件应该指定适用于该部分代码库的命令。这对于面向服务的代码库工作得很好,其中每个目录都有自己的测试和构建命令。在具有深度跨目录依赖的编译语言单体仓库中,每个子目录的范围更难实现,可能需要特定于项目的构建配置。 使用 .claudeignore 文件排除生成的文件、构建工件和第三方代码。在 .claude/settings.json 中提交 permissions.deny 规则意味着排除是版本控制的,因此团队中的每个开发者都获得相同的噪音减少,而无需自己配置。在某些代码库中,生成的文件本身就是开发工作的主题。从事代码生成器工作的开发者可以在本地设置中覆盖项目级别的排除,而不影响团队的其他人。 构建代码库地图当目录结构不能完成工作时。对于代码不在传统目录结构中整合的组织,在 repo 根目录的轻量级 markdown 文件列出每个顶级文件夹及其内容的单行描述,给 Claude 一个可以扫描的目录表,然后再打开文件。对于有数百个顶级文件夹的代码库,这最适合作为分层方法:根文件只描述最高级别的结构,子目录 CLAUDE.md 文件提供下一级细节,在 Claude 通过树移动时按需加载。对于更简单的情况,@-mention 特定文件或目录可以让 Claude 参考相同的工作。 运行 LSP 服务器以便 Claude 按符号而非字符串搜索。在大型代码库中 grep 常见函数名会返回数千个匹配项,Claude 会燃烧上下文打开文件以找出哪个重要。LSP 只返回指向相同符号的引用,因此过滤在 Claude 读取任何内容之前发生。 主动维护 CLAUDE.md 文件 随着模型的发展,为当前模型编写的指令可能会与未来的模型产生负面影响。指导 Claude 度过曾经挣扎模式的 CLAUDE.md 文件可能在下一个模型发布时变得不必要或主动限制。例如,一个告诉 Claude 将每个重构分解为单文件更改的 CLAUDE.md 规则可能帮助更早的模型保持正轨,但会阻止更新模型进行其处理良好的协调跨文件编辑。 为补偿特定模型限制而构建的 skills 和 hooks,无论是模型的推理还是 Claude Code 自己的工具,一旦这些限制不再存在就会成为开销。一旦 Claude Code 添加了原生 Perforce 模式,一个拦截文件写入以在 Perforce 代码库中强制执行 p4 编辑的 hook 就变得冗余了。 团队应该期望每三到六个月进行一次有意义的配置审查,但在重大模型发布后性能感觉停滞时也值得进行一次。 分配 Claude Code 管理和采用的所有权 技术配置 alone 不能推动采用。正确的组织也在组织层投入。推广传播最快的公司在广泛访问之前有专门的基础设施投资。一个小团队,有时甚至只是一两个人,连接工具以便在开发者第一次接触时 Claude 已经适合开发者工作流程。在一家公司,几位工程师构建了一套 plugin 和 MCP,在第一天就可用。在另一家,一整个专注于管理 AI 编程工具的团队在推广开始之前就准备好了基础设施。在这两种情况下,开发者的第一次体验是高效的而不是沮丧的,采用从这里传播。 今天做这项工作的团队往往位于开发者体验或开发者生产力之下,这通常是负责新工程师入职和构建开发者工具的职能。在几个组织中,一个新兴角色是 agent manager:一个专门的 PM/工程师职能,致力于管理 Claude Code 生态系统。对于没有专门团队的组织,最低可行版本是 DRI:一个人拥有 Claude Code 配置的所有权,做出设置的权限、权限策略、plugin 市场和 CLAUDE.md 约定的权威,以及保持它们最新的责任。 自下而上的采用会产生热情,但如果没有某人集中化有效的工作,可能会分散。你需要一个人或一个团队组装和推广正确的 Claude Code 约定(例如标准化的 CLAUDE.md 层次结构或精选的 skills 和 plugins 集)。没有这项工作,知识将保持部落化,采用将停滞。 在大型组织中,特别是在受监管行业中,治理问题很早就出现,例如:谁控制哪些 skills 和 plugins 可用,如何防止数千名工程师独立重建相同的东西,如何确保 AI 生成的代码经过与人类生成代码相同的审查过程?为了尽早解决这些问题,我们建议从一组已批准的 skills、必需的代码审查流程和有限的初始访问开始,随着信心的建立而扩展。 来源:Anthropic (https://claude.com/blog/how-claude-code-works-in-large-codebases-best-practices-and-where-to-start)

优秀的个人博客,低调大师

DolphinScheduler+Sqoop 入门避坑:一文搞定数据同步常见异常

在DolphinScheduler中假如遇到创建租户时,报错,错误日志显示权限不足: 可以使用下面的语句去开启权限: hdfs dfs -chmod 777 / 遇见下面的错误 检查 DolphinScheduler 如何整合 Sqoop 呢? 按照上边的图片里的路径和文档在最后边添加下边的代码: export SQOOP_HOME=/opt/installs/sqoop export PATH=$SQOOP_HOME/bin:$HADOOP_HOME/bin:$SPARK_HOME1/bin:$SPARK_HOME2/bin:$PYTHON_HOME/bin:$JAVA_HOME/bin:$HIVE_HOME/bin:$FLINK_HOME/bin:$DATAX_HOME/bin:$SEATUNNEL_HOME/bin:$CHUNJUN_HOME/bin:$PATH 然后重启一下DolphinScheduler: 查看ds状态:bash ./bin/dolphinscheduler-daemon.sh status standalone-server 关闭ds:bash ./bin/dolphinscheduler-daemon.sh stop standalone-server 开启ds:bash ./bin/dolphinscheduler-daemon.sh start standalone-server 若出现下边的错误 Caused by: java.lang.ClassNotFoundException: Class QueryResult not found at org.apache.hadoop.conf.Configuration.getClassByName(Configuration.java:2571) at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2665) ... 12 more 解决方案就是:拷贝一个 QueryResult.jar 到 sqoop 的 lib 下 【临时解决方案】 [INFO] 2024-09-25 06:19:16.083 +0000 - -> 注: /tmp/sqoop-root/compile/46c0c4b3def5aba0c202ae9664234de6/QueryResult.java使用或覆盖了已过时的 API。 注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。 通过日志看到一个位置: cd /tmp/sqoop-root/compile/46c0c4b3def5aba0c202ae9664234de6 将此jar包拷贝 cp /tmp/sqoop-root/compile/46c0c4b3def5aba0c202ae9664234de6/QueryResult.jar /opt/installs/sqoop/lib/ 永久解决方案: 在 DolphinScheduler的配置文件中添加一句话: 在文档的最下边添加下边的代码 export HADOOP_CONF_DIR=/opt/installs/hadoop/etc/hadoop 配置完成后,重启 DolphinScheduler。 查看ds状态:bash ./bin/dolphinscheduler-daemon.sh status standalone-server 关闭ds:bash ./bin/dolphinscheduler-daemon.sh stop standalone-server 开启ds:bash ./bin/dolphinscheduler-daemon.sh start standalone-server 报错如下: [INFO] 2024-09-25 06:27:53.628 +0000 - -> 2024-09-25 14:27:52,757 INFO [main] sqoop.Sqoop (Sqoop.java:<init>(96)) - Running Sqoop version: 1.4.7 2024-09-25 14:27:52,824 ERROR [main] tool.BaseSqoopTool (BaseSqoopTool.java:hasUnrecognizedArgs(333)) - Error parsing arguments for import: 2024-09-25 14:27:52,825 ERROR [main] tool.BaseSqoopTool (BaseSqoopTool.java:hasUnrecognizedArgs(336)) - Unrecognized argument: dt 2024-09-25 14:27:52,829 ERROR [main] tool.BaseSqoopTool (BaseSqoopTool.java:hasUnrecognizedArgs(336)) - Unrecognized argument: 2024-09-24 2024-09-25 14:27:52,829 ERROR [main] tool.BaseSqoopTool (BaseSqoopTool.java:hasUnrecognizedArgs(336)) - Unrecognized argument: -m 2024-09-25 14:27:52,829 ERROR [main] tool.BaseSqoopTool (BaseSqoopTool.java:hasUnrecognizedArgs(336)) - Unrecognized argument: 1 2024-09-25 14:27:52,829 ERROR [main] tool.BaseSqoopTool (BaseSqoopTool.java:hasUnrecognizedArgs(336)) - Unrecognized argument: --connect 2024-09-25 14:27:52,829 ERROR [main] tool.BaseSqoopTool (BaseSqoopTool.java:hasUnrecognizedArgs(336)) - Unrecognized argument: jdbc:mysql://192.168.233.131:3306/jrxd?allowLoadLocalInfile=false&autoDeserialize=false&allowLocalInfile=false&allowUrlInLocalInfile=false 2024-09-25 14:27:52,830 ERROR [main] tool.BaseSqoopTool (BaseSqoopTool.java:hasUnrecognizedArgs(336)) - Unrecognized argument: --username 2024-09-25 14:27:52,830 ERROR [main] tool.BaseSqoopTool (BaseSqoopTool.java:hasUnrecognizedArgs(336)) - Unrecognized argument: root 2024-09-25 14:27:52,830 ERROR [main] tool.BaseSqoopTool (BaseSqoopTool.java:hasUnrecognizedArgs(336)) - Unrecognized argument: --password 通过以上可以大概猜到,是 sqoop 命令写错了。 出现这个错误说明是 DolphinScheduler 工作流中的sqoop 语句出错了。 [INFO] 2024-09-25 06:34:34.639 +0000 - -> 2024-09-25 14:34:33,636 INFO [main] sqoop.Sqoop (Sqoop.java:<init>(96)) - Running Sqoop version: 1.4.7 2024-09-25 14:34:33,674 WARN [main] tool.BaseSqoopTool (BaseSqoopTool.java:applyCredentialsOptions(1120)) - Setting your password on the command-line is insecure. Consider using -P instead. Must specify destination with --target-dir. Try --help for usage instructions. [INFO] 2024-09-25 06:34:34.640 +0000 - FINALIZE_SESSION 再出现错误,则按照下边的格式进行修改 : 如果出现以下语法错误: 2024-09-25 14:36:53,044 ERROR [main] manager.SqlManager (LoggingUtils.java:logAll(43)) - Error executing statement: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%Y-%m-%d) = 2024-09-24 AND (1 = 0)' at line 1 java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%Y-%m-%d) = 2024-09-24 AND (1 = 0)' at line 1 at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120) 则应该将双引号变单引号。 如果出现以下错误: Caused by: org.apache.hive.service.cli.HiveSQLException: Error while compiling statement: FAILED: ParseException line 45:21 cannot recognize input near ';' '<EOF>' '<EOF>' in expression specification at org.apache.hive.service.cli.operation.Operation.toSQLException(Operation.java:335) at org.apache.hive.service.cli.operation.SQLOperation.prepare(SQLOperation.java:199) 解决方式:使用 sql 模块,不要添加分号;。 原文链接:https://blog.csdn.net/m0_51350088/article/details/148723463 本文由 白鲸开源科技 提供发布支持!

优秀的个人博客,低调大师

1.3 Go语言从入门到精通:编写第一个Go程序

在开始Go语言的基本语法、函数和高级特性等之前,让我们先编写第一个Go程序”Hello World!“开始,来了解Go语言最简单程序的结构吧,看看Go程序应该包括哪些部分,每部分都位于什么位置,Go语言究竟是如何执行的。 我们依然从永恒的“hello,world”程序开始,hello.go源代码如下: package main import "fmt" func main() { // "Hello World!" Go语言程序 fmt.Println("Hello World!") } 让我们来看下以上程序的各个部分: 第一行代码package main定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。 下一行import fmt告诉 Go 编译器这个程序需要使用fmt包中的函数或其他元素,fmt包实现了格式化 IO(输入/输出)的函数。 下一行func main()是程序开始执行的函数(入口函数)。main函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数),等同于Java中的public static void main(String[] agrs)。 下一行 //是注释,在程序执行时将被忽略。单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。(与其他语言相同) 下一行fmt.Println(...)可以将字符串输出到控制台,并在最后自动增加换行字符 \n换行。使用 fmt.Print("hello, world\n")可以得到相同的结果。Print和Println这两个函数也支持使用变量,如:fmt.Println(arr)。如果没有特别指定,它们会以默认的打印格式将变量 arr 输出到控制台,后续会单独讲解fmt包相关的内容。 1、Go语言结构 从上面的hello world程序可以看出,一个完整Go语言的程序结构由以下几部分组成: 包声明 引入包 函数 变量 语句 & 表达式 注释 2、执行流程 Go程序源文件是以.go作为后缀的文件,有两种执行流程: 1、将源文件先编译成可执行的二进制文件,再运行。 编译源代码:go build <xx.go>命令,生成可执行文件。 运行可执行文件:直接运行可执行程序文件。 常用于在Go编译环境上编译生成可执行的二进制文件,并将可执行的二进制文件部署在任何没有Go编译环境的机器上。 2、直接对源文件执行go run <xx.go>命令。 常用于开发环境测试使用。(go run必须依赖go开发编译环境) 3、开发注意事项 Go 源文件以 “go” 为扩展名,如:hello.go。 Go 应用程序的执行入口是 main()函数。 Go 语言严格区分大小写。 Go 方法是由一条条语句构成,每个语句后不需要分号;结束(实际上Go语言会自动在每行后加分号),这也体现了Go语言的简洁性。 Go 编译器是一行行编译的,因此我们一行就写一条语句,不能把多条语句写在同一行,否则报错。 Go 语言定义变量或者import的包如果没有使用到,则代码不能编译通过。 大括号都是成对出现的。 大括号{不能单独放在一行。如: package main import "fmt" func main() { // 错误,{不能单独成行 fmt.Println("Hello World!") } Go 语言有内置gofmt工具,能够自动整理代码多余的空白、变量名称对齐、并将对齐空格转换成Tab。

优秀的个人博客,低调大师

从零开始入门 K8s:理解容器运行时接口 CRI

云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! CRI 是 Kubernetes 体系中跟容器打交道的一个非常重要的部分。本文作者主要分为三个部分来进行:首先会为大家介绍 CRI 接口的一个由来和它的设计;其次会和大家分享目前有哪些 CRI 的实现;最后会给大家介绍一下相关的工具有哪些。 一、CRI 介绍 在 CRI 出现之前(也就是 Kubernetes v1.5 之前),Docker 作为第一个容器运行时,Kubelet 通过内嵌的 dockershim 操作 Docker API 来操作容器,进而达到一个面向终态的效果。在这之后,又出现了一种新的容器运行时 - rkt,它也想要成为 Kubernetes 支持的一个容器运行时,当时它也合到了 Kubelet 的代码之中。这两个容器运行时的加入使得 Kubernetes 的代码越来越复杂、难以维护。之后 hyber.sh 加入社区,也想成为第三个容器运行时。 此时就有人站出来说,我们能不能对容器运行时的操作抽象出一个接口,将 Kubelet 代码与具体的容器运行时的实现代码解耦开,只要实现了这样一套接口,就能接入到 Kubernetes 的体系中,这就是我们后来见到的 Container Runtime Interface (CRI)。 有一句话说得很好,「软件问题都可以通过加一层来解决」,我们的 CRI 就是加了这样一层。CRI 接口的通信协议是 gRPC,这里的一个时代背景就是当时的 gRPC 刚刚开源,此外它的性能也是优于 http/REST 模式的。gRPC 不需要手写客户端代码和服务端代码,能够自动生成通信协议代码。 接下来我们介绍一下 CRI 接口的设计。 二、CRI 实现 CRI 接口 在引入了 CRI 接口之后,Kubelet 的架构如上图所示。 跟容器最相关的一个 Manager 是 Generic Runtime Manager,就是一个通用的运行时管理器。我们可以看到目前 dockershim 还是存在于 Kubelet 的代码中的,它是当前性能最稳定的一个容器运行时的实现。remote 指的就是 CRI 接口。CRI 接口主要包含两个部分: 一个是 CRI Server,即通用的比如说创建、删除容器这样的接口; 另外一个是流式数据的接口 Streaming Server,比如 exec、port-forward 这些流式数据的接口。 这里需要注意的是,我们的 CNI(容器网络接口)也是在 CRI 进行操作的,因为我们在创建 Pod 的时候需要同时创建网络资源然后注入到 Pod 中。接下来就是我们的容器和镜像。我们通过具体的容器创建引擎来创建一个具体的容器。 给大家介绍一下 CRI 接口的设计。我们知道 Kubernetes 的一个运作的机制是面向终态的,在每一次调协的循环中,Kubelet 会向 apiserver 获取调度到本 Node 的 Pod 的数据,再做一个面向终态的处理,以达到我们预期的状态。 循环的第一步,首先通过 List 接口拿到容器的状态,再通过 Sandbox 和 Container 接口来创建容器,另外还有镜像接口用来拉取容器镜像。CRI 描述了 Kubelet 期望的容器运行时行为,主要就是我们刚刚所说的 3 个部分。 通过 CRI 操作容器的生命周期 比方说我们通过 kubectl 命令来运行一个 Pod,那么 Kubelet 就会通过 CRI 执行以下操作: 首先调用 RunPodSandbox 接口来创建一个 Pod 容器,Pod 容器是用来持有容器的相关资源的,比如说网络空间、PID 空间、进程空间等资源; 然后调用 CreatContainer 接口在 Pod 容器的空间创建业务容器; 再调用 StartContainer 接口启动容器,相对应的销毁容器的接口为 StopContainer 与 RemoveContainer。 CRI streaming 接口 这里给大家介绍一下 CRI 的流式接口 exec。它可以用来在容器内部执行一个命令,又或者说可以 attach 到容器的 IO 流中做各种交互式的命令。它的特别之处在于,一个是节省资源,另一个是连接的可靠性。 首先 exec 操作会发送到 apiserver,经过鉴权,apiserver 将对 Kubelet Server 发起 exec 的请求,然后 Kubelet 会调用 CRI 的 exec 接口将具体的请求发至容器的运行时。这个时候,容器运行时不是直接地在 exec 接口上来服务这次请求,而是通过我们的 streaming server 来异步地返回每一次执行的结果。也就是说 apiserver 其实实际上是跟 streaming server 交互来获取我们的流式数据的。这样一来让我们的整个 CRI Server 接口更轻量、更可靠。 CRI 的一些实现目前 CRI 的一些实现: CRI-containerd CRI-O PouchContainer @alibaba … CRI-containerd 是目前社区中比较主流的新一代 CRI 的实现,CRI-O 来自于红帽公司,PouchContainer 是由 alibaba 实现的 CRI,其它的 CRI 实现,这里就不一一介绍了。 CRI-containerd下图是 CRI-containerd 的架构。 这套 CRI 接口是基于 containerd 实现的。在早期的实现中,CRI 其实是作为一个独立进程的,再跟 containerd 进行交互。这样一来又多了一层进程跟进程之间的开销,因此在后来的版本中 CRI 的是直接以插件的形式实现到 containerd 中的,成为了 containerd 的一部分,从而能够可插拔地使用 CRI 接口。 整个架构看起来非常直观。这里的 Meta services、Runtime service 与 Storage service 都是 containerd 提供的接口。它们是通用的容器相关的接口,包括镜像管理、容器运行时管理等。CRI 在这之上包装了一个 gRPC 的服务。右侧就是具体的容器的实现,比如说,创建容器时就要创建具体的 runtime 和它的 shim,它们和 Container 一起组成了一个 Pod Sandbox。 CRI-containerd 的一个好处是,containerd 还额外实现了更丰富的容器接口,所以它可以用 containerd 提供的 ctr 工具来调用这些丰富的容器运行时接口,而不只是 CRI 接口。 CRI-O下图是 CRI-O 的实现思路。 它是通过直接在 OCI 上包装容器接口来实现的一个 CRI 服务。它对外提供的只有具体的 CRI 接口,没有我们前面所提到的 containerd 提供的更丰富的接口。它主要包含两个部分,首先是对容器 runtime 的管理,另一个是对镜像的管理。 三、相关工具 下面给大家介绍一下 CRI 相关的工具。这几个工具都在特别兴趣小组的一个项目里面。 crictl 它是一个类似 docker 的命令行工具,用来操作 CRI 接口。它能够帮助用户和开发者调试容器问题,而不是通过 apply 一个 yaml 到 apiserver、再通过 Kubelet 操作的方式来调试。这样的链路太长,而这个命令行工具可以直接操作 CRI。 critest 用于验证 CRI 接口行为是否是符合预期的。 性能工具 还有一些性能工具用来测试接口性能。 四、思考时间 1.目前 CRI 接口处于 v1 alpha2 版本,CRI 规范能不能更完善? CRI 标准的制定是至上而下的,通过 Kubernetes 的一些 feature 反向地要求 CRI 提供这样的功能,进而完善 CRI 规范。 2.如何通过 annotation 方式自定义 runtime 行为? 我们目前的 CRI 肯定不能满足所有用户的需求,很多公司可能会对 CRI 接口做一些增强、定制,比如说 alibaba。最简单的方式是通过 annotation 来自定义 runtime 的行为。在每个接口都设置一个 annotation 的字段,容器运行时通过理解这些字段来去自定义 runtime 的行为。同学们可以尝试去在各个 CRI 接口中通过识别 annotation 的方式来达到自定义 runtime 行为的目的。 五、本节总结 本节课的主要内容就到此为止了,这里为大家简单总结一下: CRI 介绍:CRI 的出现是为了将容器运行时与 Kubernetes 解耦开; CRI 实现:CRI-O 与 CRI-containerd; CRI 工具:CRI 调试工具 cri-tools, CRI 测试工具 critest。 【云栖号在线课堂】每天都有产品技术专家分享!课程地址:https://yqh.aliyun.com/zhibo 立即加入社群,与专家面对面,及时了解课程最新动态!【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK 原文发布时间:2020-03-29本文作者:知谨本文来自:“InfoQ”,了解相关信息可以关注“InfoQ ”

优秀的个人博客,低调大师

Apache Flink 零基础入门(四):客户端操作的 5 种模式

作者:周凯波 1.环境说明 在前面几期的课程里面讲过了 Flink 开发环境的搭建和应用的部署以及运行,今天的课程主要是讲 Flink 的客户端操作。本次讲解以实际操作为主。这次课程是基于社区的 Flink 1.7.2 版本,操作系统是 Mac 系统,浏览器是 Google Chrome 浏览器。有关开发环境的准备和集群的部署,请参考「开发环境搭建和应用的配置、部署及运行」的内容。 2.课程概要 如下图所示,Flink 提供了丰富的客户端操作来提交任务和与任务进行交互,包括 Flink 命令行,Scala Shell,SQL Client,Restful API 和 Web。Flink 首先提供的最重要的是命令行,其次是 SQL Client 用于提交 SQL 任务的运行,还有就是 Scala Shell 提交 Table API 的任务

优秀的个人博客,低调大师

spring-boot整合hazelcast实现高频交易撮合引擎缓存部分入门

简介:官网:https://hazelcast.com/一.可用性Hazelcast的分布式架构为连续群集正常运行时间提供冗余,并始终提供可用数据,以满足最苛刻的应用需求。容量随着需求弹性增长,而不会影响性能或可用性。二.速度Hazelcast In-Memory解决方案可以更快地补充数据库和数量级。时间就是金钱; 为您的新应用提供推动业务发展所需的微秒响应时间。将数据保留保留在数据库中,并利用Hazelcast以数字速度进行数据处理。三.用户体验在数字时代,用户不会等待。无论是复杂的电子商务交易还是机器学习驱动的客户自助服务门户,速度都是一切。Hazelcast客户实际上利用我们的速度在其微小的处理窗口中创造更多时间,以便在更多更深层次的服务中分层,创造卓越的商业价值,同时提供业界最佳的用户体验。四.风险缓解有足够的速度和规模,

优秀的个人博客,低调大师

Python爬虫入门教程 36-100 酷安网全站应用爬虫 scrapy

爬前叨叨 2018年就要结束了,还有4天,就要开始写2019年的教程了,没啥感动的,一年就这么过去了,今天要爬取一个网站叫做酷安,是一个应用商店,大家可以尝试从手机APP爬取,不过爬取APP的博客,我打算在50篇博客之后在写,所以现在就放一放啦~~~ 酷安网站打开首页之后是一个广告页面,点击头部的应用即可 页面分析 分页地址找到,这样就可以构建全部页面信息 我们想要保存的数据找到,用来后续的数据分析 上述信息都是我们需要的信息,接下来,只需要爬取即可,本篇文章使用的还是scrapy,所有的代码都会在文章中出现,阅读全文之后,你就拥有完整的代码啦 import scrapy from apps.items import AppsItem # 导入item类 import re # 导入正则表达式类 class AppsSpider(scr

优秀的个人博客,低调大师

Python爬虫入门教程 35-100 知乎网全站用户爬虫 scrapy

爬前叨叨 全站爬虫有时候做起来其实比较容易,因为规则相对容易建立起来,只需要做好反爬就可以了,今天咱们爬取知乎。继续使用scrapy当然对于这个小需求来说,使用scrapy确实用了牛刀,不过毕竟本博客这个系列到这个阶段需要不断使用scrapy进行过度,so,我写了一会就写完了。 你第一步找一个爬取种子,算作爬虫入口 https://www.zhihu.com/people/zhang-jia-wei/following 我们需要的信息如下,所有的框图都是我们需要的信息。 获取用户关注名单 通过如下代码获取网页返回数据,会发现数据是由HTML+JSON拼接而成,增加了很多解析成本 class ZhihuSpider(scrapy.Spider): name = 'Zhihu' allowed_domains = ['www.zhi

优秀的个人博客,低调大师

Python爬虫入门教程 28-100 虎嗅网文章数据抓取 pyspider

1. 虎嗅网文章数据----写在前面 今天继续使用pyspider爬取数据,很不幸,虎嗅资讯网被我选中了,网址为 https://www.huxiu.com/ 爬的就是它的资讯频道,本文章仅供学习交流使用,切勿用作其他用途。 常规操作,分析待爬取的页面 拖拽页面到最底部,会发现一个加载更多按钮,点击之后,抓取一下请求,得到如下地址 2. 虎嗅网文章数据----分析请求 查阅该请求的方式和地址,包括参数,如下图所示 得到以下信息 页面请求地址为:https://www.huxiu.com/v2_action/article_list 请求方式:POST 请求参数比较重要的是一个叫做page的参数 我们只需要按照上面的内容,把pyspider代码部分编写完毕即可。on_start 函数内部编写循环事件,注意到有个数字2025这个数字,是我从刚才那个请求中

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册