面对实际交付,我看thousand_island的重点不在星标,而在这项能力:千岛是一个纯粹的 Elixir 套接字服务器。在部署与运行环境场景里,常见问题是权限、依赖和环境差异会放大维护成本,这正是评估时需要盯住的地方。试跑可以从在非生产环境复现一次安装与运行开始,并把依赖锁定、权限边界、日志、回滚和资源消耗写进验收记录。整体来看,它适合愿意维护环境并重视故障恢复的工程团队拿来做对照测试,最终决定仍应回到真实结果和维护状态。
千岛是一个现代的、纯粹的 Elixir 套接字服务器,其灵感很大程度上来自于 牧场。它的目的是易于理解 并进行推理,同时至少与替代方案一样稳定和高性能。 非正式测试将牧场和千岛的水平大致相同 性能和开销;在最繁忙的服务器上缺少合成场景, 他们在所有意图和目的上表现都是平等的。
千岛完全是用 Elixir 编写的,几乎没有依赖( 唯一使用的库是 遥测)。 该应用程序强烈拥护 OTP 设计原则,并强调可读性、 简单的代码。希望千岛有能力支持 作为要求最高的服务,它也作为一种简单平易近人的方式很有用 惯用的 OTP 设计模式的参考。
用途
千岛作为监督树实施,旨在托管
在主机应用程序内部,通常作为嵌入到更高级别的依赖项
协议库如Bandit。除了
监督千岛进程树,应用程序与千岛交互
岛屿主要通过
ThousandIsland.Handler 行为。
处理程序
ThousandIsland.Handler 行为定义了千岛群岛的接口
用于将 ThousandIsland.Sockets 传递到应用程序级别;他们在一起
构成大多数应用程序与千岛群岛的主要界面。
千岛提供了一些简单的协议处理程序作为示例;
这些可以在 示例 中找到
该项目的文件夹。一个简单的实现如下所示:
defmodule Echo do
use ThousandIsland.Handler
@impl ThousandIsland.Handler
def handle_data(data, socket, state) do
ThousandIsland.Socket.send(socket, data)
{:continue, state}
end
end
{:ok, pid} = ThousandIsland.start_link(port: 1234, handler_module: Echo)
有关更多信息,请参阅 ThousandIsland.Handler 文档。
启动千岛服务器
千岛服务器以监督树的形式存在,由调用启动
到
ThousandIsland.start_link/1.
支持多种选项;有关完整的说明,请参阅
【千岛
docs.
连接耗尽和关闭
ThousandIsland.Server进程只是一个标准的Supervisor,所以所有的
适用有关关闭和关闭超时的通常规则。紧接着
开始关闭序列 ThousandIsland.ShutdownListener 将导致
套接字关闭,这又会导致所有的Acceptor
进程也会关闭。至此,只剩下监督了
树是几层主管,无论 Handler 进程是什么
启动关闭时正在进行。此时,标准Supervisor关闭
超时语义为现有连接提供了完成任务的机会。 Handler
进程陷阱退出,因此它们在关闭后继续运行,直到它们
完成或在关闭超时到期后为 :brutal_killed。
shutdown_timeout 配置选项允许对
关闭超时值。默认为 15000 毫秒。
记录和遥测
作为一个底层库,千岛故意不做任何内联
任何类型的日志记录。 ThousandIsland.Logger 模块定义了许多
帮助跟踪各种日志级别的连接的功能,以及此类日志记录
可以针对已运行的服务器动态启用和禁用。这个
日志记录由内部遥测事件支持。
千岛群岛发出一组丰富的遥测事件,包括每个事件的跨度
服务器、接受者进程和单个客户端连接。这些遥测
事件记录在 ThousandIsland.Telemetry 模块中。
实施说明
在顶层,Server 协调涉及响应的流程
套接字上的连接。 Server 管理两个顶级进程: Listener
它负责实际绑定到端口并管理结果
侦听器套接字,以及负责管理的 AcceptorPoolSupervisor
AcceptorSupervisor 进程池。
每个 AcceptorSupervisor 进程(默认有 100 个)管理两个进程:
一个 Acceptor 接受与服务器侦听器套接字建立的连接,
以及一个 DynamicSupervisor,用于监督支持个人的流程
客户端连接。每次客户端连接到服务器的端口时,其中之一
Acceptors 以套接字的形式接收连接。然后它创建
基于配置的处理程序的新进程来管理此连接,以及
立即等待另一个连接。值得注意的是Acceptor
进程是长期存在的,并且通常在该进程的整个时期内都存在
Server 正在运行。
处理程序进程与客户端连接的生命周期相关联,并且是 仅在客户端连接时启动。其寿命长于 底层连接取决于配置的处理程序模块的行为。 在典型情况下,其生命周期与底层连接的生命周期直接相关。
这种分层方法减少了连接等待被接受所花费的时间,
并且还减少了创建新内容时对 DynamicSupervisor 访问的争用
Handler 进程。每个AcceptorSupervisor子树的功能几乎
自主地提高可扩展性和崩溃弹性。
从图形上看,这就像这样:
graph TD;
Server(Server: supervisor, rest_for_one)-->Listener;
Server-->AcceptorPoolSupervisor(AcceptorPoolSupervisor: dynamic supervisor);
AcceptorPoolSupervisor--1...n-->AcceptorSupervisor(AcceptorSupervisor: supervisor, rest_for_one)
AcceptorSupervisor-->DynamicSupervisor
AcceptorSupervisor-->Acceptor(Acceptor: task)
DynamicSupervisor--1...n-->Handler(Handler: gen_server)
Server-->ShutdownListener;
千岛内部不使用命名进程或其他“全局”状态
(遥测事件名称除外)。完全支持单节点
托管任意数量的 Server 进程,每个进程不同的端口。
安装
千岛是 ,可用十六进制 表示。套餐
可以通过将 thousand_island 添加到 mix.exs 中的依赖项列表来安装:
def deps do
[
{:thousand_island, "~> 1.0"}
]
end
文档可以在 https://thousand-island.hexdocs.pm 中找到。