Go语言实现简单分布式系统(笔记)

news2024/7/6 18:38:30

视频:

Go语言编写简单分布式系统(完结)_哔哩哔哩_bilibili,作者:杨旭,非常感谢,大佬真牛批

参考笔记及代码:

Go语言实现简单分布式系统 - N3ptune - 博客园 (cnblogs.com)

 

整体框图:

061f562150aa42e78389f854cadb72ce.png

log服务、grading服务、以及portal服务需要注册到服务注册中心Registry。grading服务依赖于log服务,portal服务依赖于log服务和grading服务,因此注册中心Registry需要将服务所依赖服务通知给该服务。

 

数据结构:

注册中心需要有一个列表(切片)保存已经注册的服务信息,实际应用中可使用数据库持久化保存数据。这些服务信息当前为一个结构体,包括服务名称、服务地址ServiceURL、所依赖服务列表(可以理解为订阅的服务),当依赖服务更新时所通知地址ServiceUpdateURL,以及健康检查地址HeartbeatURL。

 

服务注册:

        Registry设置一个handler,当接收到post请求时,将待注册服务的信息保存起来,当收到delete请求时,将服务信息删除。

        在其它服务启动时,首先设置三个handler,对应ServiceURL、ServiceUpdateURL、HeartbeatURL三个地址,并启动监听,之后便可以进行服务注册,即向Registry发送一个post请求;而当服务结束运行前,向Registry发送delete请求,取消注册。

服务发现:

        Registry在接收到一个注册请求时(假设待注册服务为A),做两件事:一、找到当前已经注册服务中,哪些服务是A所需要的,将这些服务的信息通过A的ServiceUpdateURL告诉A;二、找到已经注册的服务中,哪些服务是依赖于A的,将A的信息通过这些服务的ServiceUpdateURL进行通知。而在收到delete请求时,只做一件事,就是对依赖这个服务的服务进行通知。

        其它服务收到通知后,即在ServiceUpdateURL对应的handler里面,保存或者删除所依赖服务的信息,视频里称其为provider,为一个map数据结构,key为依赖的服务名,value为服务的地址列表(一般依赖的服务不止一个地址)。使用依赖的服务时,从map里取出地址即可。

健康检查:

        Registry里面每隔一段时间,对已经注册服务的健康度进行检查,即向服务的HeartbeatURL发送一个get请求。

        而在其它服务的HeartbeatURL对应的handler里面,只需要简单返回一个OK即可。

 

各个服务/组件及其代码实现:

注册中心的服务代码:

Registry是注册中心,包含一个已注册服务的数组,由于会有并发访问问题,将其与mutex绑定为一个结构体。根据method执行不同的函数,包括add函数和delete函数。

当接收到post请求时,执行add函数,将服务名和地址添加进数组里(服务注册),找到已经注册的服务中被当前服务所依赖的服务,将这些服务的信息告诉当前服务,同时找到依赖当前服务的服务,依次进行通知(服务发现)

当接收到delete请求时,执行remove函数,根据传入的url在数组里找到该服务并删除(取消注册),通知找到依赖当前取消注册的服务的服务,依次通知该服务已经取消注册。

 

注册中心的客户使用代码:

为了方便其它服务使用注册中心,设置了一个client.go文件,里面提供了一个注册服务函数、一个取消注册函数、以及一个getProviders函数供其它服务使用。也就是说,其它服务使用Registry是通过调用这三个函数实现的。

注册服务函数RegisterService:由于每个服务的ServiceUpdateURL和HeartbeatURL对应的handler要做的事情是一样的,因此将这些handler函数及其注册(http.Handle)都放到注册服务函数里了,然后向Registry发送post请求完成服务注册。

取消注册函数UnregisterService:即向Registry发送删除的delete请求,取消注册服务

getProviders函数:在ServiceUpdateURL对应的handler里会对Provider进行更新(这是一个map结构,保存了服务发现的结果),当客户需要使用所依赖服务时,传入服务名即可获得服务地址。注意这是客户代码,每个客户的Provider都是不一样的。这里的get并不是使用时去发送网络请求问注册中心,而是注册中心知道当前服务需要依赖什么服务并发现可用时主动告诉当前服务的(类似发布订阅模式),也就是说这里的Provider是缓存在当前服务本地的。

 

services通用包:

对于其它服务,每个服务的生命流程是类似的,即设置handler,启动监听、服务注册,当服务挂掉时取消注册。因此抽象出了这么一个包,里面仅包含一个start函数,它调用了服务传进来的RegisterHandlers函数设置服务的handlers并启动监听,然后调用注册中心的客户函数RegisterService对服务进行注册,然后设置一个go协程用于服务结束时调用注册中心的客户函数UnregisterService。

对于Registry,启动流程也是类似的,但不用自己注册自己,因此不能使用services通用包。

 

log服务:

服务端首先重定向了log的输出位置为一个文件;然后设置一个handler,收到post请求时直接调用log.pritnf,这时候由于重定向了log的输出,实际上就写到了文件里面了。其实个人感觉不做重定向也可以,就操作文件就好了。该服务的启动只需设置好5个服务信息,然后调用services通用包的start函数即可。

另外,为了方便其它服务使用log服务,同样也提供了client.go文件,实现了SetClientLogger函数,里面将log进行重定向。log的重定向输出是通过重写Write函数实现的,这里实现的Write函数就是向log服务发送post请求。在重定向后,使用者每次log.printf()就会自动向log服务发送post请求,提高了使用的便利性。

需要注意这里的两个重定向,一个发生在服务端(重定向至文件),一个发生在服务调用者处(自动向log服务发送http请求)。

 

grading服务:

业务内容略去。该服务也是通过services通用包启动的。由于其依赖log服务,在启动后(services通用包的start函数返回后),调用getproviders函数获得log服务的地址,然后调用SetClientLogger函数设置使用log服务。

 

文章结束。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1700088.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nvidia 如何成为 AI 训练的超级强国

周三,英伟达公布了第一季度的财务业绩,再次超出了分析师的预期。在截至 4 月 28 日的季度中,该公司的利润同比飙升 262%,股价一度创下 1000 美元以上的新高。 目前,英伟达的市值超过 2.3 万亿美元,是全球第…

React自定义Componment和State深层次理解-07

本节主要从底层原理上分析下React开发相关的内容和注意事项,本节会围绕使用展开,而非源码讲解。 Componment详解 什么是组件 在 MVVM架构出现之前,组件主要分为两种。 狭义上的组件,又称为 UI 组件,比如 Tabs 组件、…

shell脚本开发基础

shell脚本开发基础 什么是linux内置命令?什么是外置命令 内置命令:在系统启动时就加载入内存,常驻内存,执行效率更高,但是占用资源,cd 外置命令:系统需要从硬盘中读取程序文件,再读…

C语言对一阶指针 二阶指针的本质理解

代码&#xff1a; #include <stdio.h>char a 2; char* p &a; char** d &p;int main(){printf("a -> %d, &a -> %p\n", a, &a);printf("*p -> %d, p -> %p, &p -> %p\n", *p, p, &p);printf(&qu…

数据库(8)——DML数据操作

增添数据 给指定字段添加数据 INSERT INTO 表名 (字段名1&#xff0c;字段名2,...)VALUES(值1,值2...); 没有的添加的字段默认为NULL。 给全部字段添加数据 INSERT INTO 表名 VALUE (值1,值2,....值n); 此时值的顺序对应表中字段的顺序 批量添加数据 INSERT INTO 表名(字段1,…

【docker】仓库harbor的部署

harbor介绍 Harbor 是一个用于存储和管理 Docker 镜像的开源仓库。它提供了一系列的功能&#xff0c;比如用户管理、访问控制、镜像管理、日志审计和安全扫描等。Harbor 可以作为私有仓库来使用&#xff0c;也可以与公有仓库&#xff08;如 Docker Hub&#xff09;集成使用。 …

云启未来——移动云为未来开发助力

目录 前言 移动云-启未来 原生技术支持 资源和生态 智能化融合创新 移动云-安全可控 移动云如何推动未来行业变革&#xff1f; 移动云产品0元上云系列 文章总结 前言 未来的软件开发形式呈现出更加智能化、自动化和可持续化的趋势。开发工具和流程将更加注重提高开发效…

MySQL从入门到高级 --- 10.索引

文章目录 第十章&#xff1a;10.索引10.1 分类10.2 创建索引10.2.1 单列索引 - 普通索引10.2.2 查看索引10.2.3 删除索引10.2.4 单列索引 - 唯一索引10.2.5 单列索引 - 主键索引10.2.6 组合索引 10.3 全文索引10.3.1 概述10.3.2 使用 10.4 空间索引10.4.1 操作 10.5 原理10.5.1…

Java进阶:详解与实战Java Stream API

Java进阶&#xff1a;详解与实战Java Stream API &#x1f31f; Java进阶&#xff1a;详解与实战Java Stream API &#x1f31f;摘要引言一、Java Stream API介绍&#x1f4da;1. 什么是Java Stream API&#xff1f;2. Java Stream API支持的功能3. 使用Java Stream API的优势…

视频播放器-Kodi

一、前言 Kodi 是一款开源免费的多媒体播放软件。Kodi 是由非营利性技术联盟 Kodi 基金会开发的免费开源媒体播放器应用程序。 Kodi是一款免费和开源&#xff08;遵循GPL协议&#xff09;的多媒体播放器和娱乐中心软件&#xff0c;由XBMC基金会开发。Kodi的主要功能是管理和播…

mac brew 命令详解

brew 是 macOS 系统中 Homebrew 的命令行工具&#xff0c;用于在 macOS 上安装、更新和管理各种软件包。以下是对 brew 命令的详细介绍&#xff0c;按照功能和使用频率进行分点和归纳&#xff1a; 1. 安装和卸载软件包 安装软件包&#xff1a;使用 install 命令&#xff0c;后…

Golang | Leetcode Golang题解之第113题路径总和II

题目&#xff1a; 题解&#xff1a; type pair struct {node *TreeNodeleft int }func pathSum(root *TreeNode, targetSum int) (ans [][]int) {if root nil {return}parent : map[*TreeNode]*TreeNode{}getPath : func(node *TreeNode) (path []int) {for ; node ! nil; no…

五分钟”手撕“异常

目录 一、什么是异常 二、异常的体系和分类 三、异常的处理 1.抛出异常 2.异常的捕获 异常声明throws&#xff1a; try-catch处理 四、finally finally一定会被执行吗&#xff1f; 五、throw和throws区别 六、异常处理的流程 七、自定义异常 一、什么是异常 顾名…

每日练习——同余方程以及格雷码

同余方程 题目描述 运行代码 #include<iostream> #define ll long long using namespace std; ll exgcd(ll a, ll b, ll& x, ll& y) {if (!b)return x 1, y 0, a;ll d exgcd(b, a % b, y, x);y - a / b * x;return d; } int main() {ll a, b, x, y;cin >…

nodeJs上

文章目录 使用node执行js脚本文件流程示例读文件写文件 node构建web服务器流程根据不同请求路径返回不同数据核心模块模块系统ip地址和端口号的概念响应内容类型Content-type 初步实现Apache功能第三方模块 使用node执行js脚本文件 流程 1.创建js脚本文件 2.打开终端&#xf…

5月21号作业

思维导图 代码实现 TCP域套接字服务器 #include <header.h> #include <math.h>int main(int argc, const char *argv[]) {//为通信创建一个端点int sfdsocket(AF_UNIX,SOCK_STREAM,0);//参数1&#xff1a;说明使用的三ipv4通信域//参数2&#xff1a;说明使用的三…

你真的了解HTTPS协议吗

前言 在 HTTP 协议中有可能存在信息窃听或身份伪装等安全问题。使用 HTTPS 通信机制可以有效地防止这些问题。本文即将带大家来了解这些。 任何事物都有两面性&#xff0c;为了满足HTTP协议的快&#xff0c;但导致了它有如下的不足&#xff1a; 通信采用明文&#xff08;不加…

【Linux-INPUT输入的子系统】

Linux-INPUT输入的子系统 ■ input 子系统简介■ input 驱动编写流程■ ■ input 子系统简介 input 子系统就是管理输入的子系统&#xff0c; input 子系统分为 input 驱动层、 input 核心层、 input 事件处理层&#xff0c;最终给用户空间提供可访问的设备节点 ■ input 驱…

模仿高效网络进行目标检测——知识蒸馏

摘要 链接&#xff1a;https://openaccess.thecvf.com/content_cvpr_2017/papers/Li_Mimicking_Very_Efficient_CVPR_2017_paper.pdf 当前的基于卷积神经网络&#xff08;CNN&#xff09;的目标检测器需要从预训练的ImageNet分类模型中初始化&#xff0c;这通常非常耗时。在本…

【除自身以外数组的乘积】python

目录 思路&#xff1a; 代码&#xff1a; 思路&#xff1a; 直接计算前缀乘积&#xff0c;后缀乘积&#xff0c;然后相乘即可 开始我还在想&#xff0c;遍历一次i&#xff0c;怎么能同时计算前缀乘积和后缀乘积&#xff0c;事实上分开计算比较方便。。 代码&#xff1a; cl…