Elixir基础概念讲解

每日分享最新,最流行的软件开发知识与最新行业趋势,希望大家能够一键三连,多多支持,跪求关注,点赞,留言。

elixir内存 Elixir基础概念讲解

在我开始写这篇博客之前,我认为用一个简短的声明作为开头是明智的。作为一个处于 JavaScript 学习旅程早期阶段的人,冒险进入未知领域似乎有点为时过早。该领域特别是另一种编程语言,我可能没有业务探索。但我相信这将是有益的。了解另一种语言的内部工作原理并理解它的语法和数据类型(即使是在基本层面上)可能会对如何以及在何处解决我的 JavaScript 和一般编码的弱点有所了解。

elixir内存 Elixir基础概念讲解

Elixir 是 Jose Valim 在 2012 年发布的一种函数式编程语言。从那时起,它已经获得了相当多的粉丝群,并被摩托罗拉、Pinterest 和 Discord (以及许多其他公司)等公司使用。它运行在 Erlang Beam 虚拟机之上,该虚拟机实际上是在 80 年代开发的,用于扩展不断增长的电话切换需求。Elixir 的创建本质上是为了让日常开发人员可以使用 Erlang 技术。Elixir 具有受 Ruby 启发的最小且动态类型的语法,这使得它比其他语言更容易上手。此外,它的 Phoenix Web 框架负责创建数以千计的全栈 Web 应用程序。

在您的机器上安装 Elixir 轻而易举。只需访问 Elixir 安装页面并在安装列表中找到您的操作系统。对于 MacOS,您只需在终端中运行命令,或者对于 Windows,遵循一系列快速安装提示,瞧,您已经安装了 Elixir。不需要路径配置或类似的东西,只需直接安装。要仔细检查安装过程是否成功,请返回您的终端并确保使用以下命令安装了正确的版本:elixir -v. 在撰写本文时,Elixir 目前的版本为 1.14.0。要开始一个新项目,请将您的终端设置为所需的目录,然后使用命令mix new "project name",并且必要的文件将被加载到您的项目文件夹中,包括自述文件、gitignore、库和其他基础知识。

现在我们已经建立了一个项目,让我们开始看看构成 Elixir 的数据类型。

elixir内存 Elixir基础概念讲解

我们将研究的前两种数据类型是整数和浮点数。这些都是数字数据类型,但它们永远不能严格相等。任何整数都被认为是一个整数,而浮点数是在该数字后面具有任何给定小数位数的数字。这里快速演示了这两种数据类型如何在操作中一起使用,但最终还是不同的。

iex(1)> 1 + 12 iex(2)> 1.5 + 1.53.0 iex(3)> 1 + 1.52.5 iex(4)> 4 * 416 iex(5)> 3 === 3.0false

elixir内存 Elixir基础概念讲解

下一个数据类型是布尔值。这将是您的标准布尔数据类型,为您提供真假值。

iex(6)> truetrue iex(7)> true === falsefalse

我们甚至可以将值包装在 is_boolean 函数中,以评估该值是否实际上是布尔数据类型。

iex(8)> is_boolean(true)trueiex(9)> is_boolean("a")false

elixir内存 Elixir基础概念讲解

Elixir 中的字符串必须使用双引号分隔。(请参阅后面的单引号。)除此之外,Elixir 中的字符串的行为与 JavaScript 中的字符串非常相似。它们可以与+or<>运算符连接在一起,并且 Elixir 还通过将字符串值插入插值语法来支持字符串插值:#{string value}. 要打印字符串值,只需将您的值包装在IO.puts(string value)函数中。其他字符串函数包括String.length(string value)和String.upcase(string value)。

iex(10)> string = "dog""dog"iex(11)> "The #{string} ran fast""The dog ran fast"iex(12)> "The " <> "#{string} " <> "ran fast" "The dog ran fast"iex(13)> IO.puts("Hello World!")Hello World!iex(14)> String.length("hello")5iex(15)> String.upcase("hello")"HELLO"

elixir内存 Elixir基础概念讲解

Elixir 中的列表类似于其他语言中的数组,但它们并不完全相同。从美学上讲,它们是相同的,但 Elixir 中的列表的行为更类似于链表数据结构。列表的第一个元素被认为是“头”,其余元素被认为是“尾”。可以使用hd(list)andtl(list)函数访问列表中的第一个和剩余的值。列表也是不可变的,这意味着无法编辑或更改原始列表。

iex(16)> list = [2, 4, 6, 8][2, 4, 6, 8]iex(17)> hd(list)2iex(18)> tl(list)[4, 6, 8]

elixir内存 Elixir基础概念讲解

元组有点类似于列表。但是,它们用大括号而不是方括号来表示。然而,它们也是不可变的。真正的区别在于列表在内存中作为链表进行排序。这意味着访问列表末尾是一个线性操作,因此我们需要遍历整个列表来确定其长度或大小。另一方面,元组连续存储在内存中。所以访问一个元素可以是一个非常快速的操作。但是,向元组添加或更新元素可能会占用大量内存,因为它需要创建一个新元组。

iex(19)> {"hello", "world!"}{"hello", "world!"}iex(20)> tuple = {"hello", "world!"}{"hello", "world!"}iex(21)> tuple_size(tuple)2iex(22)> elem(tuple, 0)"hello"iex(23)> elem(tuple, 1)"world!"

elixir内存 Elixir基础概念讲解

最后我们到达了原子!原子类似于 Ruby 中的符号,有点类似于在 JavaScript 中使用 const 关键字定义变量。原子是常量,其名称也是它们的值。换句话说,他们将永远代表他们所代表的东西。原子也可以表示布尔值,如下所示。

iex(24)> :hello === :hellotrueiex(25)> :hello === :worldfalseiex(26)> true === :truetrueiex(27)> is_atom(false)true

如果您想知道我的代码前面的“iex”是什么,那就是 Elixir 交互式 Shell。它是内置的 shell,允许您编写语句并执行它们,从而产生输出。

因此,有一些基本的基础知识可以让您的脚趾浸入 Elixir!我希望继续进一步探索 Elixir,并希望将来使用这种语言构建一些项目。

利用Elixir作为轻量级工具来存储实时指标数据

对性能瓶颈的可见性是Wallaroo监控中心和度量UI设计背后的驱动力。我们希望为用户提供工具,使他们能够在实时执行时观察他们的应用程序,并为他们提供足够的内省,以便根据他们所看到的内容对他们的应用程序进行调整; 是否添加额外的工作人员来分配高工作负载或重写计算以提高效率。能够预防潜在的瓶颈将使我们的用户能够利用Wallaroo提供的一些功能。

在设计监控中心和度量标准UI时,我们设想了一个轻量级工具,用户可以在开发或生产环境中与其应用程序一起运行。在选择用于创建监控中心和度量用户界面的工具时,Elixir具有许多功能,使其成为可行的选择。凤凰频道是软实时发送和接收消息的抽象,是决策背后的动机,我们希望尽可能多地利用Elixir生态系统作为该项目的一部分。

elixir内存 Elixir基础概念讲解

在过去,我们谈到“选择Elixir的凤凰为实时Web UI提供动力” ,这深入探讨了为什么我们选择Phoenix来为Wallaroo的监控中心和Metrics UI提供支持。在这篇文章中,我们将更深入地介绍我们如何利用Elixir存储,汇总和广播Wallaroo的最终用户消费指标消息。

在我们深入研究如何使用Elixir管理Wallaroo的监控中心和Metrics UI之前,我们想先介绍一下Wallaroo的度量信息以及我们想要传达的信息。

打破Wallaroo的度量信息

Wallaroo为正在运行的应用程序的以下类别发出度量标准消息:

管道统计: 为应用程序中的每个管道报告。计算为Wallaroo收到消息到管道定义完成的时间。管道的总统计数据是每个工作人员报告所述管道的统计数据的集合。工作人员统计数据: 报告给作为申请一部分的每个工人。计算为工作人员收到消息至完成或传递给其他工作人员的时间。报告每个管道上运行的管道。工作人员的总统计数据是针对所有管道在此工作人员上传递的每条消息的聚合。计算统计: 报告应用程序中的每个计算运行。计算为给定消息的所述计算完成所花费的时间。由每个运行所述计算的工人报告。计算的总统计数据是针对给定计算报告的每个工作人员的聚合。

每个度量消息属于上述类别之一,并且还包含关于哪个工作者及其属于哪个管道的附加信息。此信息非常有用,因为它允许我们以更细的粒度细分统计信息,例如对特定工作人员进行计算的统计信息。

我们选择固定的bin直方图作为将度量消息从Wallaroo传输到监控中心的方式。每个bin表示bin的索引的2纳秒的功率,从0到64.每个bin的值是bin在给定时段内表示的时间范围内的消息数量。如果你想了解更多关于这种格式背后的决定,Nisan写了一篇很棒的博客文章, “Wallaroo Performance Metrics中的Latency Histograms和Percentile Distributions”就是这样的。

由于我们设计Wallaroo的度量捕获系统,Wallaroo的指标是从Wallaroo系统的不同步骤收集和发送的。这意味着接收系统需要将这些消息组合在一起,以便全面了解给定Wallaroo组件的指标。

信息我们希望Wallaroo的指标消息传达

尽管可以从Wallaroo提供的直方图中提取相当数量的信息,但我们不希望我们的最终用户提取该信息。相反,我们决定了一些我们认为在发现潜在瓶颈方面有价值的核心统计数据。

延迟: 处理单个事件所需的时间量,以事件样本的延迟百分比来衡量。吞吐量: 每秒处理的事件计数(由其类别定义)。

延迟统计

延迟指标统计计算为我们的最后5分钟的时间窗口,并表示50th Percentile Bin,90th Percentile Bin,95th Percentile Bin,99th Percentile Bin,和99.9th Percentile Bin。每个Percentile Bin表示计算的延迟的x%落入的箱的上限。我们还提供了一个Percentage by Bin图表。此图表将直方图值组合在一组关键区域中,以快速概述与我们认为对用户有意义的区间相关的性能。

吞吐量统计

吞吐量指标统计计算为我们的最后5分钟的时间窗口,而我们提供的minimum,median和maximum吞吐量观察。我们还提供了Throughput per Second最后5分钟的中位数图表,可用于快速查看性能是否出现峰值。

如果您想更深入地了解Wallaroo方面的度量收集系统背后的设计决策,请查看我们的“为高性能系统构建低开销度量标准集”博客文章。

既然我们已经介绍了如何接收数据以及我们希望如何向最终用户表示数据,那么让我们来看看我们如何使用Elixir来实现这一目标。

存储Wallaroo的度量消息

在ETS表中存储度量标准消息

由于我们为短期监控设计了Metrics UI,因此我们并不认为投资时间序列数据库是有意义的。团队中有一些以前有过使用Erlang经验的成员建议使用Erlang Term Storage(ETS)表,这是Erlang虚拟机中包含的高效内存数据库,因为他们觉得这些数据符合我们存储Wallaroo度量标准消息的需求。

ETS背后的设计理念在“了解你的一些Erlang”的“ ETS的概念”部分中有很好的描述:

“ETS的主要设计目标是提供一种在Erlang中存储大量数据的方法,并且具有持续的访问时间,并使这种存储看起来好像是作为进程实现的,以保持其使用简单和惯用。”

正在运行的Wallaroo应用程序的每个组件都有一个ETS表来存储其延迟指标,另一个用于存储其吞吐量指标。我们选择对两种类型的指标使用多个表,以避免对数据的访问争用。

实现滑动时间窗口数据存储

Wallaroo的Metrics UI旨在显示应用程序指标的滚动5分钟窗口。因此,我们不希望在某个时间点之前保留Wallaroo的度量标准消息,并且在我们不再需要它们时决定丢弃旧消息。我们利用ordered_setETS表的类型来做到这一点。通过使用时间戳作为键并让它们按升序自动排序,我们实现了一个函数,每次我们添加或读取ETS表中的数据时都会删除陈旧的消息,以使它们保持最新。实际上,将我们的ETS表转换为滑动时间窗口数据存储。

虽然与ordered_set其他表类型相比,类型提供了较慢的访问时间(O(log N),其中N是存储的对象数),但通过对每个ETS表存储的消息设置限制,我们知道访问时间永远不会增长到了影响性能的程度。

使用GenServers管理我们的ETS表

我们决定使用Elixir的GenServer,一个用于实现客户端 - 服务器关系服务器的行为模块,作为我们的ETS客户端代码的服务器。这个决定的好处是它抽象了对我们的ETS表的访问,并允许我们在整个代码库中使用通用访问代码。如果由于某种原因我们决定为另一个数据存储切换出ETS表,那么面向公众的GenServer代码很少或根本不会改变。

如果您想全面了解我们如何从ETS表存储和检索度量标准消息,请查看我们的MonitoringHubUtils.MessageLog。

汇总Wallaroo的度量标准

由于我们希望显示最近5分钟的指标统计信息,因此我们需要一种方法来聚合我们为该时间窗口存储的指标。我们为每个Wallaroo组件的每个统计数据实施了一个流程,该流程会定期从给定组件的ETS表中提取最新统计数据并对其进行特定计算。

聚合延迟统计

我们创建了一个LatencyStatsCalculator聚合和计算特定延迟统计数据。这个计算器的最终目标是利用直方图的列表有5分钟的窗口和计算50th Percentile Bin,90th Percentile Bin,95th Percentile Bin,99th Percentile Bin,并99.9th Percentile Bin为一组特定的,我们觉得是对用户有意义的箱。

汇总吞吐量统计

我们创建了一个ThroughputStatsCalculator汇总和计算min,med以及max吞吐量为5分钟的窗口,对于一个给定的组成部分。另外,我们发送最后5分钟窗口中每个组件的每秒吞吐量。

利用统计聚合的多个进程,我们可以利用Elixir的并发性和并行性,使我们能够同时接收和广播消息。

现在我们已经为最终用户消费配置了度量信息,我们需要一种方法来实时获取它们。

广播Wallaroo的指标

我们利用Elixir Phoenix的频道功能,将我们新创建的度量标准消息从监控中心广播到Metrics UI。计算Wallaroo的度量统计数据的过程都在一个时间间隔内运行,一旦计算出每个统计数据,它就会被广播到适当的信道。进行广播的好处是,监听该频道的任何应用程序或进程都可以接收度量标准消息。

虽然目前只有Metrics UI正在监听这些消息,但是还有机会通过其他工具对这些消息进行其他令人兴奋的事情,例如:

如果吞吐量达到特定阈值,则监视工作者的吞吐量并添加或删除工作者。监视延迟并在超出特定SLA时发送警报。

Wallaroo的度量消息流

下图全面概述了Wallaroo的度量标准消息如何通过Elixir流入我们的Celsius示例应用程序:

elixir内存 Elixir基础概念讲解

Wallaroo的度量标准消息通过度量标准信道到达。然后,消息按组件划分,并通过消息日志过程将延迟和吞吐量消息存储到ETS表中。在给定组件的初始消息上,创建延迟统计信息,吞吐量和吞吐量统计信息聚合器/广播器进程,它将以一定间隔读取最后5分钟的数据,并通过特定于该组件和度量标准统计类型的信道进行广播。

Wallaroo的行动指标

现在您已经了解了我们如何使用Elixir存储,聚合和广播Wallaroo的度量标准消息,请随时启动Wallaroo应用程序和我们的Metrics UI以查看它们的全部内容!

给Wallaroo一个尝试

我们希望这篇文章引起您对Wallaroo的兴趣!

如果您刚入门,我们建议您尝试我们的Docker映像,这样您就可以在几分钟内启动并运行Wallaroo。

相关问答

笔记本升级存储空间现在有一条南亚易胜(elixir)DDR31333...

一半4G内存够用了最好不要插不同型号大小的内存卡可能会蓝屏不过也不一定有的系统、主板就能,大部分情况会出现兼容问题,你可以根据现有的型号买一个2G的...

KVR1333D3S8N9/2G和Elixir南亚易胜DDR316002G一起用兼用吗?

可以的,南亚内存现在做的不错,兼容性也可以,建议带着笔记本去实验,避免兼容性问题可以的,南亚内存现在做的不错,兼容性也可以,建议带着笔记本去实验,避免兼容...