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 FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用

Linux系统之dns域名解析全过程

《Linux系统之dns域名解析全过程》:本文主要介绍Linux系统之dns域名解析全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、dns域名解析介绍1、DNS核心概念1.1 区域 zone1.2 记录 record二、DNS服务的配置1、正向解析的配置

Linux修改pip和conda缓存路径的几种方法

《Linux修改pip和conda缓存路径的几种方法》在Python生态中,pip和conda是两种常见的软件包管理工具,它们在安装、更新和卸载软件包时都会使用缓存来提高效率,适当地修改它们的缓存路径... 目录一、pip 和 conda 的缓存机制1. pip 的缓存机制默认缓存路径2. conda 的缓

Redis解决缓存击穿问题的两种方法

《Redis解决缓存击穿问题的两种方法》缓存击穿问题也叫热点Key问题,就是⼀个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击,本文给大家介绍了Re... 目录引言解决办法互斥锁(强一致,性能差)逻辑过期(高可用,性能优)设计逻辑过期时间引言缓存击穿:给

Linux系统中配置静态IP地址的详细步骤

《Linux系统中配置静态IP地址的详细步骤》本文详细介绍了在Linux系统中配置静态IP地址的五个步骤,包括打开终端、编辑网络配置文件、配置IP地址、保存并重启网络服务,这对于系统管理员和新手都极具... 目录步骤一:打开终端步骤二:编辑网络配置文件步骤三:配置静态IP地址步骤四:保存并关闭文件步骤五:重

Windows系统下如何查找JDK的安装路径

《Windows系统下如何查找JDK的安装路径》:本文主要介绍Windows系统下如何查找JDK的安装路径,文中介绍了三种方法,分别是通过命令行检查、使用verbose选项查找jre目录、以及查看... 目录一、确认是否安装了JDK二、查找路径三、另外一种方式如果很久之前安装了JDK,或者在别人的电脑上,想

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

Linux系统之authconfig命令的使用解读

《Linux系统之authconfig命令的使用解读》authconfig是一个用于配置Linux系统身份验证和账户管理设置的命令行工具,主要用于RedHat系列的Linux发行版,它提供了一系列选项... 目录linux authconfig命令的使用基本语法常用选项示例总结Linux authconfi