OPT(erlang)打造一套缓存系统(一)

2024-01-16 01:52

本文主要是介绍OPT(erlang)打造一套缓存系统(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

缓存的设计

这个简易缓存存储的是键/值对,其中键与键之间不得重复,并且每个键只能映射到一个值。这个设计背后的核心思想是为写人缓存的每一个值都分配一个独立的存储进程再将对应的键映射至该进程。你可能会对这种为每个值分配一个进程的设计感到惊讶,甚至觉得不可思议;但对缓存这类服务而言,这个设计是合理的,因为缓存中的值相互独立,各有各的生命周期。同时,Erlang本身对大量轻量级进程提供了良好的支持,使得这种设计成为可能。
为了搭建这个缓存,我们得先建立一些基本的子系统,其中每个子系统都是一个独立的模块。

我们一共需要创建5个模块,
用户只能通过simple_cache API模块与缓存服务交互。该模块直接与sc_store模块和sc_element模块通信,前者负责维护键和进程间的映射关系,后者负责存储进程的创建、更新和删除。所有存储进程都受sc_sup监督进程监督,除此之外,还有一个负责整个缓存系统的启动和停止的应用行为模式模块sc_app。让我们从进程和数据流的角度展示了该架构。

在处理运行时的键/值对插入操作时,监督进程会按需派生sc_element进程。派生出来的进程会记住与给定的键相关联的值,随后,sc_store会记录下该键与该进程ID间的映射关系。键/值之间的映射关系就这样建立起来了。要获取与指定的键相关联的值,首先应该查找与键相关联的存储进程的D,然后再向该进程查询当前持有的值便可。
 

创建OTP应用的基本骨架

1.应用目录结构的布局

首先新建一个名为simple_cache的顶层应用目录。在该目录下,新建doc、ebin、include、priv和src等子目录。

2.创建应用元数据

在启动应用或在执行运行时代码热升级时,OTP需要了解一些用于描述应用自身的元数据。存放元数据的.app文件的文件名应该与应用名相匹配(但无须采用特定模块的名字),在这个例子中,该文件就是ebin/simple_cache.app。

.app文件当前内容如下

{application,simple_cache,
[fdescription,"A simple caching system"},
{vsn, "0.1.0"},
{modules,[sc_app,sc_sup]},{registered,[sc_sup] } ,
{applications,[kernel, stdlib]},
{mod, {sc_app. []}}
]}.

3.实现应用行为模式

应用行为模式的实现位于文件src/sc_app.erl内,需要注意的是,.app文件中的mod元组给出了应用行为模式模块的模块名,系统就是从这里得知应该从何处启动和停止应用的。

-module(sc_app) .
-behaviour(application).
-export ([start/2, stop/1] ) .
start(_StartType, _StartArgs)->case sc_sup:start_link()of{ ok, Pid} ->{ ok,Pid};other ->{error, other}
end.
stop(_state) ->ok.

sc_app模块唯一的任务就是在应用启动时启动根监督者,在应用停止时则什么也不用做。

4.实现监督者

根监督者在文件src/sc_sup.erl中实。我们没有给这个监督者静态指派任何永久子进程,但却可以给它动态添加任意多个同类型的临时子进程。

-module(sc_sup) .
-behaviour(supervisor) .
-export([start_link /0,start_child/2]).
-export([init/1] ).
-define(SERVER,?MODULE).
start_link()->supervisor:start_link({local,?SERVER},?MODULE,[]).
start_child (Value,LeaseTime) ->supervisor:start_child ( ?SERVER,[Value,LeaseTime]).
init([])->Element = {sc__element,{sc_element,start_link,[]},temporary, brutal_kill, worker, [sc_element]},Children = [Element] ,Restartstrategy = { simple_one_for_one,0, 1},{ok,{Restartstrategy,Children }} .
1.简易一对一监督

该监督者的监督策略被设定为simple_one_for_one(简易一对一监督)。采用one_for_one等其他重启策略时,监督者一般需要同时管理多个与自己同时启动的子进程,通常这些子进程的生命周期也与监督者相同。simple_one_for_one型监督者只能启动一种子进程,但却可以启动任意多个。它所有的子进程都是运行时动态添加的,监督者本身在启动时不会启动任何子进程。
观察代码中的监督者模块,现在却只能有一个: simple_.one_for_one型监督者的init/1必须指定一种且仅一种子进程,但子进程并不会随监督者一同启动。不过,你随时可以通过调用简化版supervisor:start_child/2函数,令监督者启动新的子进程。其他类型的监督者在动态添加子进程时,必须将完整的子进程规范传递给start_child/2。但对于simple_one_for_one型监督者而言,由于所有子进程都遵循同一套已知的子进程规范,我们只需要说一声“再来一份”就可以了。这套机制恰恰可以满足我们当前的需求。

2.监督者模块

sc_sup模块有两个API函数,启动一个新的子进程,并将value和LeaseTime参数传给子进程的人口函数(因为每个子进程的这两个参数各不相同)。将这些逻辑组织成一个API函数将更有利于模块中实现细节的封装。

调用start_child/2 API函数时,当前进程会向监督进程发送一条消息,令它以value和LeaseTime为参数调用sc_element模块的start_link函数,进而启动一个新的子进程。子进程规范中的元组

{sc_element, start_link,[]}

给定了模块名、函数名和子进程启动函数的参数,调用start_link之前,列表[value,LeaseTime]将被并人参数列表[],从而形成最终的函数调用sc_element:start_link(value,LeaseTime)。

每调用一次sc_sup:start_child/2,就会新启动一个带有自己的值和淘汰时间的sc_element进程。这就形成了一棵动态生成的监督树。

至此,一个可运行的应用骨架就搭建完毕了。你可以从Erlang shell中启动它并观察它的运作情况。当然,目前除了启动和停止应用以外你还什么都做不了,因为应用的实际功能和用户接口都还没有实现。由于采用了simple_one_for_one型监督策略,监督者在启动时不会启动任何子进程;此外,由于sc_element尚未实现,调用sc_sup:start_child/2会触发运行时错误。
 

这篇关于OPT(erlang)打造一套缓存系统(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/610949

相关文章

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

CentOS系统Maven安装教程分享

《CentOS系统Maven安装教程分享》本文介绍了如何在CentOS系统中安装Maven,并提供了一个简单的实际应用案例,安装Maven需要先安装Java和设置环境变量,Maven可以自动管理项目的... 目录准备工作下载并安装Maven常见问题及解决方法实际应用案例总结Maven是一个流行的项目管理工具

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查

C#实现系统信息监控与获取功能

《C#实现系统信息监控与获取功能》在C#开发的众多应用场景中,获取系统信息以及监控用户操作有着广泛的用途,比如在系统性能优化工具中,需要实时读取CPU、GPU资源信息,本文将详细介绍如何使用C#来实现... 目录前言一、C# 监控键盘1. 原理与实现思路2. 代码实现二、读取 CPU、GPU 资源信息1.

在C#中获取端口号与系统信息的高效实践

《在C#中获取端口号与系统信息的高效实践》在现代软件开发中,尤其是系统管理、运维、监控和性能优化等场景中,了解计算机硬件和网络的状态至关重要,C#作为一种广泛应用的编程语言,提供了丰富的API来帮助开... 目录引言1. 获取端口号信息1.1 获取活动的 TCP 和 UDP 连接说明:应用场景:2. 获取硬

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

2.1/5.1和7.1声道系统有什么区别? 音频声道的专业知识科普

《2.1/5.1和7.1声道系统有什么区别?音频声道的专业知识科普》当设置环绕声系统时,会遇到2.1、5.1、7.1、7.1.2、9.1等数字,当一遍又一遍地看到它们时,可能想知道它们是什... 想要把智能电视自带的音响升级成专业级的家庭影院系统吗?那么你将面临一个重要的选择——使用 2.1、5.1 还是

高效管理你的Linux系统: Debian操作系统常用命令指南

《高效管理你的Linux系统:Debian操作系统常用命令指南》在Debian操作系统中,了解和掌握常用命令对于提高工作效率和系统管理至关重要,本文将详细介绍Debian的常用命令,帮助读者更好地使... Debian是一个流行的linux发行版,它以其稳定性、强大的软件包管理和丰富的社区资源而闻名。在使用

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

Ubuntu系统怎么安装Warp? 新一代AI 终端神器安装使用方法

《Ubuntu系统怎么安装Warp?新一代AI终端神器安装使用方法》Warp是一款使用Rust开发的现代化AI终端工具,该怎么再Ubuntu系统中安装使用呢?下面我们就来看看详细教程... Warp Terminal 是一款使用 Rust 开发的现代化「AI 终端」工具。最初它只支持 MACOS,但在 20