elixir 高可用系列(二) GenServer
程序员文章站
2022-06-16 23:49:11
概述 如果我们需要管理多个进程,那么,就需要一个专门的 server 来集中监控和控制这些进程的状态,启停等。 OTP 平台中的 GenServer 就是对这个 server 通用部分的抽象。 利用 GenServer 中已经提供的通用操作, 可以很方便的开发出可靠,健壮的程序。 下面首先通过一个示 ......
概述
如果我们需要管理多个进程,那么,就需要一个专门的 server 来集中监控和控制这些进程的状态,启停等。
OTP 平台中的 GenServer 就是对这个 server 通用部分的抽象。
利用 GenServer 中已经提供的通用操作, 可以很方便的开发出可靠,健壮的程序。
下面首先通过一个示例演示 GenServer 的方便和强大之处,然后再对其进行介绍。
这是一个 GenServer 管理多个进程的示例,模拟控制各个进程的启动,停止,以及状态查询。
defmodule ProcessMonitor do use GenServer #==================================================== # api for clients #==================================================== # start GenServer def start(data, opt \\ []) do GenServer.start_link(__MODULE__, data, opt) end # add process which is controled by this GenServer def process_add(server, name) do GenServer.call(server, {:add, name}) end # get process status def process_status(server, name) do GenServer.call(server, {:status, name}) end # start a process by name def process_start(server, name) do GenServer.cast(server, {:start, name}) end # stop a process by name def process_stop(server, name) do GenServer.cast(server, {:stop, name}) end #==================================================== # callbacks for server #==================================================== def init(data) do {:ok, data} end # handle status message synchronization def handle_call({:status, name}, _from, data) do val = Map.get(data, name, nil) {:reply, val, data} end # handle add message synchronization def handle_call({:add, name}, _from, data) do data = Map.put(data, name, "stopped") {:reply, name, data} end # handle start message asynchronization def handle_cast({:start, name}, data) do data = Map.put(data, name, "running") {:noreply, data} end # handle stop message asynchronization def handle_cast({:stop, name}, data) do data = Map.put(data, name, "stopped") {:noreply, data} end end
上面代码测试方法如下:
$ iex -S mix Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace] Interactive Elixir (1.2.4) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> {:ok, server} = ProcessMonitor.start(Map.new) # 创建 GenServer,并初始化一个 map 用于存储此server管理的 process 信息 {:ok, #PID<0.87.0>} iex(2)> ProcessMonitor.process_status(server, "process01") # 创建 GenServer 后,默认没有管理任何进程,所以没有 process01 的信息 nil iex(3)> ProcessMonitor.process_add(server, "process01") # 给 GenServer 增加一个被管理进程 process01 "process01" iex(4)> ProcessMonitor.process_status(server, "process01") # 新加入的进程默认状态是 stopped,示例代码默认这么实现 "stopped" iex(5)> ProcessMonitor.process_start(server, "process01") # 启动 process01 :ok iex(6)> ProcessMonitor.process_status(server, "process01") # process01 状态变为 running "running" iex(7)> ProcessMonitor.process_stop(server, "process01") # 停止 process01 :ok iex(8)> ProcessMonitor.process_status(server, "process01") # process01 状态变为 stopped "stopped" iex(9)> ProcessMonitor.process_add(server, "process02") # 再增加一个被管理进程 process02 "process02" iex(10)> ProcessMonitor.process_start(server, "process02") # 启动 process02 :ok iex(11)> ProcessMonitor.process_status(server, "process02") # process02 状态变为 running "running" iex(12)> ProcessMonitor.process_status(server, "process01") # process01 状态仍然是 stopped,不受 process02 的影响 "stopped" iex(13)> ProcessMonitor.stop(server) # 停止 GenServer
注 上面的代码是用 mix 创建工程来运行的,mix 的使用方法可以参见 blog:mix 构建工具
GenServer 通用抽象简介示例代码使用了 GenServer 中的几个关键函数: init handle_call handle_case
init: 这个函数在 GenServer.start_link 时执行,对 start_link 中的参数进行处理 handle_call: 这个函数接受同步消息并处理 handle_cast: 这个函数接受异步消息并处理处理这3个常用的函数之外,GenServer 中的函数也不是很多,其他的函数,属性以及每个函数返回的值说明请参见:http://elixir-lang.org/docs/stable/elixir/GenServer.html
在上面的示例中,其实 client 也可以直接调用 GenServer 的 handle_call/handle_cast 来发送同步/异步消息,
我之所以封装了一些 api 给 client 调用,一方面,是为了简化客户端的调用(client 的 api 中参数更加简洁直观),
另一方面,将处理消息的代码和 发送消息的代码分开,便于以后扩展(因为,可能存在多个发送消息的处理都对应同一个消息处理)。
来源:http://blog.iotalabs.io/
推荐阅读
-
[原创]分布式系统之缓存的微观应用经验谈(二) 【主从和主备高可用篇】
-
Spark快速入门系列(6) | Spark环境搭建—standalone(3) 配置HA高可用模式
-
【高可用架构】借助Envoy工具发布项目到多台服务器(二)
-
[Security系列一]拿什么保障企业对外网络服务的高可用性?
-
013.Kubernetes二进制部署worker节点Nginx实现高可用
-
redis 系列26 Cluster高可用 (1)
-
《从零开始学架构》笔记——第二部分:高性能和高可用架构模式
-
redis 系列27 Cluster高可用 (2)
-
Redis集群方案(高可用)之哨兵模式(一主二从三哨兵)
-
Redis高可用哨兵模式搭建 一主一从二哨兵模式