MIX OTP——监督动态子进程

现在,我们已经成功定义了我们的监督器,它将作为应用程序生命周期的一部分自动启动(和停止)。

但请记住,我们的 KV.Registry 在 handle_cast/2 回调中同时链接(通过 start_link)和监控(通过 monitor)存储容器进程:

链接是双向的,这意味着存储容器崩溃会导致注册表崩溃。虽然我们现在有了监督进程,可以保证注册表恢复正常运行,但注册表崩溃仍然意味着我们会丢失将存储容器名称与其各自进程相关联的所有数据。

换句话说,我们希望即使存储容器崩溃,注册表也能继续运行。让我们编写一个新的注册表测试:

该测试类似于“退出时删除存储容器”,只是我们发送 :shutdown 作为退出原因而不是 :normal,这要更严格一些。如果进程因 :normal 以外的原因终止,则所有链接进程都会收到 EXIT 信号,导致链接进程也终止,除非它正在捕获退出。

由于存储容器终止,注册表也停止了,并且当我们尝试 GenServer.call/3 时我们的测试失败:

  1) test removes bucket on crash (KV.RegistryTest)
     test/kv/registry_test.exs:26
     ** (exit) exited in: GenServer.call(#PID<0.148.0>, {:lookup, "shopping"}, 5000)
         ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
     code: assert KV.Registry.lookup(registry, "shopping") == :error
     stacktrace:
       (elixir) lib/gen_server.ex:770: GenServer.call/3
       test/kv/registry_test.exs:33: (test)

我们将通过定义一个新的监管者来解决这个问题,该监管者将生成并监督所有存储容器。与我们之前定义的监管者相反,子节点并不是预先知道的,而是动态启动的。对于这些情况,我们使用一个针对此类用例优化的监管者,称为 DynamicSupervisor。DynamicSupervisor 在初始化期间不需要子节点列表;而是通过 DynamicSupervisor.start_child/2 手动启动每个子节点。

存储容器监管者

由于 DynamicSupervisor 在初始化期间不定义任何子项,因此 DynamicSupervisor 还允许我们跳过使用通常的 start_link 函数和 init 回调定义整个单独模块的工作。相反,我们可以直接在监控树中定义 DynamicSupervisor,为其指定名称和策略。

打开 lib/kv/supervisor.ex 并将动态监控器添加为子项,如下所示:

请记住,进程的名称可以是任何原子。到目前为止,我们已经将进程命名为与定义其实现的模块相同的名称。例如,由 KV.Registry 定义的进程被赋予了 KV.Registry 的进程名称。这只是一个惯例:如果稍后您的系统中出现错误,提示“名为 KV.Registry 的进程因原因而崩溃”,我们确切地知道要调查的位置。

在这种情况下,没有模块,所以我们选择了 KV.BucketSupervisor 这个名字。它可能是任何其他名字。我们还选择了 :one_for_one 策略,这是目前动态监管者唯一可用的策略。

运行 iex -S mix,这样我们就可以尝试我们的动态监管者:

DynamicSupervisor.start_child/2 需要监管者的名称和要启动的子项的子规范。

最后一步是更改注册表以使用动态监管者:

这足以让我们的测试通过,但是我们的应用程序中存在资源泄漏。当一个 bucket 终止时,supervisor 将在其位置启动一个新的 bucket。毕竟,这是 supervisor 的角色!

但是,当 supervisor 重新启动新的 bucket 时,注册表并不知道这一点。因此,supervisor 中将有一个空的 bucket,没有人可以访问!为了解决这个问题,我们想说 bucket 实际上是临时的。如果它们崩溃,无论出于何种原因,都不应重新启动它们。

我们可以通过在 KV.Bucket 中传递 restart: :temporary 选项来使用 Agent 来实现这一点:

我们还将一个测试添加到 test/kv/bucket_test.exs,以确保 bucket 是临时的:

我们的测试使用 Supervisor.child_spec/2 函数从模块中检索子规范,然后断言其重新启动值为 :temporary。此时,您可能想知道如果 supervisor 永远不会重新启动其子节点,为什么要使用它。有时,监督器提供的不仅仅是重启,它们还负责保证正确启动和关闭,特别是在监督树崩溃的情况下。

监督树

当我们将 KV.BucketSupervisor 添加为 KV.Supervisor 的子进程时,我们开始拥有监管其他监管者的监管者,形成所谓的“监管树”。

每次向监管者添加新子进程时,评估监管者策略是否正确以及子进程的顺序非常重要。在本例中,我们使用 :one_for_one,并且 KV.Registry 在 KV.BucketSupervisor 之前启动。

立即出现的一个缺陷是排序问题。由于 KV.Registry 调用 KV.BucketSupervisor,因此 KV.BucketSupervisor 必须在 KV.Registry 之前启动。否则,注册表可能会在启动之前尝试访问 bucket 监管者。

第二个缺陷与监管策略有关。如果 KV.Registry 死亡,则将 KV.Bucket 名称与 bucket 进程联系起来的所有信息都会丢失。因此 KV.BucketSupervisor 和所有子进程也必须终止 - 否则我们将拥有孤儿进程。

鉴于这一观察,我们应该考虑转向另一种监管策略。另外两个候选者是 :one_for_all 和 :rest_for_one。使用 :rest_for_one 策略的监管者将杀死并重新启动在崩溃的子进程之后启动的子进程。在这种情况下,我们希望 KV.BucketSupervisor 在 KV.Registry 终止时终止。这将要求将 bucket 监管者置于注册表之后,这违反了我们在上面两段中建立的排序约束。

因此,我们的最后一个选择是全力以赴并选择 :one_for_all 策略:只要其中任何一个子进程死亡,监管者就会杀死并重新启动其所有子进程。对于我们的应用程序来说,这是一种完全合理的方法,因为注册表在没有 bucket 监管者的情况下无法工作,而 bucket 监管者应该在没有注册表的情况下终止。让我们在 KV.Supervisor 中重新实现 init/1 来编码这些属性:

在进入下一章之前,还有两个主题。

测试中的共享状态

到目前为止,我们已为每个测试启动一个注册表,以确保它们是隔离的:

由于我们已将注册表更改为使用 KV.BucketSupervisor,因此我们的测试现在依赖于此共享监管者,即使每个测试都有自己的注册表。问题是:我们应该吗?

视情况而定。只要我们仅依赖此状态的非共享分区,就可以依赖共享状态。尽管多个注册表可能会在共享存储容器监管者上启动存储容器,但这些存储容器和注册表彼此隔离。如果我们使用 DynamicSupervisor.count_children(KV.BucketSupervisor) 之类的函数来计算所有注册表中的所有存储容器,我们只会遇到并发问题,当测试同时运行时可能会产生不同的结果。

由于到目前为止我们只依赖存储容器监管者的非共享分区,因此我们不必担心测试套件中的并发问题。如果出现问题,我们可以为每个测试启动一个监管者,并将其作为参数传递给注册表 start_link 函数。

观察者

现在我们已经定义了监督树,这是介绍 Erlang 附带的 Observer 工具的绝佳机会。使用 iex -S mix 启动您的应用程序并输入以下内容:

缺少依赖项

当使用 iex -S mix 在项目中运行 iex 时,观察者将无法作为依赖项使用。为此,您需要先调用以下函数:

如果上述任何调用失败,则可能发生以下情况:某些包管理器默认安装最小化的 Erlang,不带 WX 绑定以提供 GUI 支持。在某些包管理器中,您可能能够用更完整的包替换无头 Erlang(在 Debian/Ubuntu/Arch 上查找名为 erlang vs erlang-nox 的包)。在其他管理器中,您可能需要安装单独的 erlang-wx(或类似名称)包。

有对话可以在未来的版本中改善这种体验。

应会弹出一个 GUI,其中包含有关我们系统的各种信息,从一般统计数据到负载图表,以及所有正在运行的进程和应用程序的列表。

在“应用程序”选项卡中,您将看到系统中当前正在运行的所有应用程序及其监督树。您可以选择 kv 应用程序以进一步探索它:

不仅如此,当您在终端上创建新存储容器时,您应该会看到 Observer 中显示的监督树中生成的新进程:

我们将让您进一步探索 Observer 提供的功能。请注意,您可以双击监督树中的任何进程以检索有关它的更多信息,也可以右键单击进程以发送“终止信号”,这是一种模拟故障并查看您的监督者是否按预期做出反应的完美方式。

归根结底,像 Observer 这样的工具是您希望始终在监督树内启动进程的原因之一,即使它们是临时的,也可以确保它们始终可访问和可自省。

现在我们的存储容器已正确链接和监督,让我们看看如何加快速度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/36001.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分享一个导出数据到 Excel 的解决方案

前言 许多业务场景下需要处理和分析大量的数据&#xff0c;而 Excel 是广泛使用的文件格式&#xff0c;几乎所有人都能打开和查看 Excel 文件&#xff0c;因此将数据库中的原始数据处理后&#xff0c;导出到 Excel 是一个很常见的功能&#xff0c;对于数据管理、分析、备份、展…

侯捷C++面向对象高级编程(上)-2-构造函数

1.inline函数 2.访问级别 3.构造函数 4.重载

《UDS协议从入门到精通》系列——图解0x38:请求上传

《UDS协议从入门到精通》系列——图解0x38&#xff1a;请求上传 一、简介二、数据包格式2.1 服务请求格式2.2 服务响应格式2.2.1 肯定响应2.2.2 否定响应 三、通信示例 Tip&#x1f4cc;&#xff1a;本文描述中但凡涉及到其他UDS服务的&#xff0c;将陆续提供链接跳转方式以便快…

新学期必备,录取情况统计如何制作?

暑假即将开始&#xff0c;新学期离我们又近了一步&#xff0c;老师们是不是在为如何高效统计录取情况而头疼呢&#xff1f;别担心&#xff0c;分享一个超实用的小技巧——使用易查分小程序的新建填表功能&#xff0c;让你的录取统计工作变得简单又高效&#xff01; 打开易查分小…

G882磁力仪拖鱼位置是如何计算的?

根据参考文献&#xff0c;磁力仪拖鱼位置计算有两种方法&#xff1a; 1、直线法 直线计算法是假设不考虑海流、船摆等动态因素的影响&#xff0c;拖鱼与拖点始终和航向相同&#xff0c;即整个拖拽系统与船舶是刚性连接。 2、曲线法 实际海洋磁力测量中&#xff0c;在海风、海…

Windows宝塔面板部署ThinkPHP8.0创建Vue项目案例

安装ThinkPHP8.0 登录宝塔面板&#xff0c;创建一个站点。 输入composer代码&#xff0c;执行完成后自动创建TP目录 composer create-project topthink/think tp 网站目录设置为tp&#xff0c;运行目录设置为public 设置PHP版本为8.0以上&#xff0c;不然会出现下面的报错代…

软考 有向图 数据库之关系模式范式

假设有一个关系 R(A, B, C, D)&#xff0c;并且已知以下函数依赖&#xff1a; A → B B → C BC → D 求候选键? 求候选码? 候选键/候选码 是同一个概念. 数据库范式也分为1NF,2NF,3NF,BCNF,4NF,5NF。 https://cloud.tencent.com/developer/article/2055118 2NF在1NF的基础…

visual studio 2022配置和使用protobuf

上图证明&#xff0c;我真的测了好多遍&#xff0c;测了好多版本的protobuf&#xff0c;花了很多时间。不过好在最后在vs2022上测通了。 下载protobuf 这里是protobuf下载的地址。 Releases protocolbuffers/protobuf GitHub 个人使用的3.21.9这个版本才跑通的。 1、首先…

第6章_libmodbus使用

文章目录 第6章 libmodbus使用6.1 libmodbus开发库6.1.1 功能概要6.1.2 源码获取6.1.3 源码阅读1. 新建工程2. 同步文件3.打开工程4. 操作示例5. 快捷键 6.1.4 libmodbus与应用程序的关系 6.2 libmodbus源代码解析6.2.1 核心函数6.2.2 框架分析与数据结构6.2.3 情景分析1. 初始…

OOXML入门学习

进入-飞入 <par> <!-- 这是一个并行动画序列的开始。"par"代表并行&#xff0c;意味着在这个标签内的所有动画将同时开始。 --><cTn id"5" presetID"2" presetClass"entr" presetSubtype"4" fill"hold&…

C语言指针速成下篇

c语言的指针下篇终于迎来了收尾&#xff0c;那么废话不多说&#xff0c;我们直接进入正题 指针访问数组 # include <stdio.h> int main () { int arr[ 10 ] { 0 }; // 输⼊ int i 0 ; int sz sizeof (arr)/ sizeof (arr[ 0 ]); // 输⼊ int * p arr //这…

在Tomcat中部署war包

1、准备war包 确保已经有一个有效的war包&#xff0c;该war包包含了web应用程序的所有内容&#xff1b; 2、停止tomcat服务器 在部署之前&#xff0c;确保tomcat服务器已经停止&#xff0c;进入tomcat的配置目录执行命令&#xff1a;[路径]/tomcat/conf&#xff1b; 在Linux…

Socket——向FTP服务器发送消息并获得响应

1、简介 Socket&#xff08;套接字&#xff09;是网络编程中用于描述IP地址和端口的一个抽象概念&#xff0c;通过它可以实现不同主机间的通信。套接字可以分为几种不同的类型&#xff0c;每种类型对应不同的协议和传输模式。 1.1、基本概念 IP地址&#xff1a;用于标识网络…

【管理咨询宝藏137】RB大型卡车集团供应链体系优化设计方案中期汇报

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏137】RB大型卡车集团供应链体系优化设计方案中期汇报 【格式】PDF版本 【关键词】罗兰贝格、供应链管理、运营提升 【核心观点】 - 甲方采取销售…

CBSD创建和管理bhyve容器Ubuntu@FreeBSD

bhyve介绍&#xff1a;bhyve&#xff1a;FreeBSD下的原生虚拟机管理器_freebsd 虚拟化平台bhyve-CSDN博客 两个bhyve的管理软件&#xff1a;使用bvm管理bhyve虚拟机管理系统FreeBSD-CSDN博客 vm-bhyve&#xff1a;bhyve虚拟机的管理系统FreeBSD-CSDN博客 现在&#xff0c;我…

从零开始做题:LSB

1 题目 2 解题 2.1 使用stegsolve工具 ┌──(holyeyes㉿kali2023)-[~/Misc/tool-misc] └─$ java -jar Stegsolve.jar 2.1.1 发现R、G、B的plane0有隐藏信息 2.1.2 提取隐藏信息 2.1.3 save bin后得到二维码 2.1.4 QR Research得到flag 3 flag cumtctf{1sb_i4_s0_Ea4y}

9种慢慢被淘汰的编程语言...【送源码】

技术不断进步&#xff0c;我们使用的编程语言也不例外。 随着人工智能的兴起以及对编程语言使用的影响&#xff0c;我们更加关注哪些语言将在未来继续流行&#xff0c;哪些会被淘汰。 Python、Java 和 JavaScript 等多功能编程语言正在主导市场&#xff0c;而其他一些语言则逐…

kubernetes给指定用户分配调用k8s的api权限

文章目录 概要利用RBAC添加角色权限使用shell命令创建角色权限使用配置文件创建角色权限 调用k8s的api获取k8s账户的token 小结 概要 使用kubernetes部署项目时&#xff0c;有些特殊场景&#xff0c;我们需要在自己创建的pod里面调用k8s的api来管理k8s&#xff0c;但是需要使用…

某山词霸翻译js逆向分析

一、基础知识 1、post的几种发包的方式 2、query string和form data的区别 Query String Parameters&#xff1a; GET请求时&#xff0c;参数会以url string 的形式进行传递&#xff0c;即?后的字符串则为其请求参数&#xff0c;并以&作为分隔符。&#xff08;有时候pos…

修改 app id - 鸿蒙 HarmonyOS Next

修改项目 app id 后通过真机 build run 的时候抛出了如下异常; 项目中更改后的配置与真机的不匹配; {app: {bundleName: "com.xxxxxx.xxx_harmony",vendor: "xxxxxx",versionCode: 1,versionName: "3.5.00",icon: "$media:app_icon",…