【启程Golang之旅】从零开始构建可扩展的微服务架构

news2024/11/23 13:50:31

欢迎来到Golang的世界!在当今快节奏的软件开发领域,选择一种高效、简洁的编程语言至关重要。而在这方面,Golang(又称Go)无疑是一个备受瞩目的选择。在本文中,带领您探索Golang的世界,一步步地了解这门语言的基础知识和实用技巧。

近几年微服这个词闯入我们的视线,那么什么是微服务?微服务的概念是怎么产生的?接下来我们开始正式了解一下Go语言与微服务的千丝万缕与来龙去脉!

目录

初识微服务

初识RPC协议

初识ProtoBuf

初识GRPC


初识微服务

        微服务是一种软件架构风格,旨在将大型应用程序拆分为一组小的、独立的服务。这些服务围绕特定的业务功能组织,每个服务可以独立开发、测试、部署和扩展。微服务之间通过轻量级的通信机制(如 HTTP/REST 或消息队列)进行交互。

什么是微服务:在介绍微服务时,首先得先理解什么是微服务,顾名思义,微服务得从两个方面去理解,什么是"微"、什么是"服务"?(micro)狭义来讲就是体积小,著名的"2pizza团队"很好的诠释了这一解释(2pizza团队最早是亚马逊CEOBezos提出来的,意思是说单个服务的设计,所有参与人从设计、开发、测试、运维所有人加起来只需要2个披萨就够了)。服务(service)一定要区别于系统,服务一个或者一组相对较小且独立的功能单元,是用户可以感知最小功能集。那么广义上来讲,微服务是一种分布式系统解决方案,推动细粒度服务的使用,这些服务协同工作。

微服务和单体式架构区别:微服务架构将应用拆分为多个独立的服务,关注特定功能,便于独立部署和扩展;而单体式架构则将所有功能打包在一个应用中,整体开发和部署,扩展和维护较为复杂,具体如下所示:

新功能开发传统单体架构分布式微服务架构
部署不经常而且容易部署经常发布,部署复杂
隔离性故障影响范围大故障影响范围小
架构设计初期技术选型难度大设计逻辑难度大
系统性能相对时间快,吞吐量小相对时间慢,吞吐量大
系统运维运维难度简单运维难度复杂
新人上手学习曲线大(应用逻辑)学习曲线大(架构逻辑)
技术技术单一而且封闭技术多样而且容易开发
测试和差错简单复杂(每个服务都要进行单独测试,还需要集群测试)
系统扩展性扩展性差扩展性好
系统管理重点在于开发成本重点在于服务治理和调度

初识RPC协议

简单了解了微服务定义和优缺点之后,在我们正式学习微服务框架之前,需要首先了解一下RPC协议,为什么要了解RPC协议?RPC协议具体是什么呢?

RPC协议概念:RPC(Remote Procedure Call Protocol)也叫 “远程过程调用协议”,是一种使程序能够在网络上调用远程服务器上的函数或服务的通信协议,它允许客户端发送请求到远程服务器并接收执行结果,就像调用本地函数一样,其常用于微服务架构中支持服务之间的高效交互,RPC协议通常包括以下几个主要特点:

1)透明性:调用远程服务看起来就像调用本地服务,隐藏了网络通信的复杂性。

2)协议支持:可以通过多种协议(如 HTTP、TCP、UDP)进行通信。

3)语言无关性:支持不同编程语言之间的交互,常通过序列化格式(如 JSON、Protocol Buffers)传输数据。

RPC协议具体是什么:是一种允许程序在网络中调用另一台计算机上的函数或服务的协议。它使得开发者能够像调用本地函数一样,轻松地请求远程服务。

为什么微服务需要使用RPC:微服务使用RPC的好处就是不限定服务的提供方使用什么技术选型,能够实现公司跨团队的技术解耦,如下图所示:

RPC的使用步骤: 接下来开始简述一下RPC的使用步骤:

----服务端:

1)注册rpc服务对象,给对象绑定方法(1. 定义类、2. 绑定类方法)

rpc.RegisterName("服务名", 回调对象)

2)创建监听器:listener, err := net.Listen()

3)建立连接:conn, err := listener.Accept()

4)将连接绑定rpc服务:rpc.ServeConn(conn)

----客户端:

1)用rpc连接服务器:conn, err := rpc.Dial()

2)调用远程函数:conn.Call("服务名.方法名", 传入参数, 传出参数)

RPC相关函数:接下来开始讲解一下使用RPC函数所涉及到的一些函数:

1)注册rpc服务:

// 参数1:服务名,字符串类型
// 参数2:对应rpc对象,该对象绑定方法需要满足如下条件:
/*
    1)方法必须是导出的 —— 包外可见,首字母大写。
    2)方法必须有两个参数,都是导出类型、内建类型。
    3)方法的第二个参数必须是 “指针”(传出参数)
    4)方法只有一个 error 接口类型的 返回值。
*/
func (server *Server) RegisterName(name string, rcvr interface{}) error

// 举例:
type World struct {}
func (this *World) HelloWorld(name string, resp *string) error {}
rpc.RegisterName("服务名", new(World))

2)绑定rpc服务:

// conn: 成功建立好连接的 socket -- conn
func (server *Server) ServeConn(conn io.ReadWriteCloser)

3)调用远程函数:

// serviceMethod: “服务名.方法名”
// args: 传入参数,方法需要数据
// reply: 传出参数,定义 var 变量,&变量名 完成传参
func (client *Client) Call (serviceMethod string, args interface{}, reply interface{}) error

这里我们开始做一个演示,这里我们写一个服务器端:

package main

import (
	"fmt"
	"net"
	"net/rpc"
)

// World 定义类对象
type World struct {
}

// HelloWorld 绑定类方法
func (this *World) HelloWorld(name string, resp *string) error {
	*resp = name + "你好!"
	return nil
}

func main() {
	// 01注册RPC服务,绑定对象方法
	err := rpc.RegisterName("hello", new(World))
	if err != nil {
		fmt.Println("注册 rpc 服务失败", err)
		return
	}
	// 02设置监听
	listener, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println("监听失败", err)
		return
	}
	defer listener.Close()
	fmt.Println("开始监听...")
	// 03建立连接
	conn, err := listener.Accept()
	if err != nil {
		fmt.Println("绑定服务失败", err)
		return
	}
	defer conn.Close()
	fmt.Println("连接成功...")
	// 04绑定服务
	rpc.ServeConn(conn)
}

然后客户端这里我们写通过rpc连接服务器然后调用远程方法:

package main

import (
	"fmt"
	"net/rpc"
)

func main() {
	// 01 用rpc链接服务器 --Dial()
	conn, err := rpc.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println("Dial error", err)
		return
	}
	defer conn.Close()
	// 02 调用远程函数方法
	var reply string // 接受返回值 --- 传出参数
	err = conn.Call("hello.HelloWorld", "zhangsan", &reply)
	if err != nil {
		fmt.Println("call error", err)
		return
	}
	fmt.Println(reply)
}

最终达到的效果如下所示:

jsonrpc使用:因为rpc使用了go语言特有的数据序列化gob,其他编程语言不能解析,所以这里我们还需要使用通用的能实现序列化和反序列化的json操作,这里我们使用nc充当服务器,如下:

初识ProtoBuf

        Protobuf是ProtocolBuffers的简称,它是Google公司开发的一种数据描述语言,是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化或者说序列化,它很适合做数据存储或RPC数据交换格式,可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式,目前提供了C++、Java、Python三种语言的APl,需要了解的两点是:

1)protobuf是类似与json一样的数据描述语言(数据格式)

2)protobuf非常适合于RPC数据交换格式

protobuf的优势与劣势

---优点---

1)序列化后体积相比Json和XML很小,适合网络传输

2)支持跨平台语言

3)消息格式升级和兼容性还不错

4)序列化反序列化速度很快,快于json的处理速度

---劣势---

1)应用不够广(相比xml和json)

2)二进制格式导致可读性差

3)缺乏自描述

Protobuf的具体安装可以参考我之前的文章:地址 这里不再赘述,如下我们简单的讲解一下在日常编写protobuf过程中的注意事项有哪些,如下所示:

1)message成员编号可以不从1开始,但是不能重复,不能使用 19000 - 19999

2)可以使用message嵌套

3)可以使用定义数组、切片使用 repeated 关键字

4)可以使用枚举enum

5)可以使用联合体:oneof关键字,成员编号依然不能重复

syntax = "proto3";
// 指定所在包名
package pd;
option go_package = "./";

// 定义枚举类型
enum  Week {
  Monday = 0; // 枚举值,必须从0开始
  Tuesday = 1;
}
// 定义消息体
message  Student {
  int32 age = 1; // 可以不从1开始,但是不能重复,不能使用19000-20000的数字
  string name = 2;
  People p = 3;
  repeated int32 score = 4; // 定义数组
  Week w = 5; // 定义枚举类型
  oneof data {
    string  teacher = 6;
    string  class = 7;
  }
}
// 消息体可以嵌套
message People {
  int32  weight = 1;
}

然后我们终端执行如下命令可以看到我们生成了对应的go文件:

protoc --go_out=./ *proto

注意:protobuf编译期间默认不编译服务,例如如下的rpc服务是不会被protobuf编译的:

// 添加rpc服务
service  bj38 {
  rpc Say(People) returns (Student) {}
}

想要编译服务的话需要使用gRPC,其编译指令可以参考如下的内容:

protoc --go_out=plugins=grpc:./ *.proto

初识GRPC

        如果从Protobuf的角度看,GRPC只不过是一个针对service接口生成代码的生成器,如果想详细了解gRPC,可以参考我之前的文章:地址 ,接着我们来学习一下GRPC的用法,这里我们创建一个简单的proto文件,定义一个HelloService接口:

syntax = "proto3";

package pd;

// 消息体 --一个package中,不允许定义同名的消息体
message Teacher {
  int32  age = 1;
  string name = 2;
}
// 定义服务
service SayName {
  rpc SayHello (Teacher) returns (Teacher);
}

然后我们终端执行如下命令进行执行proto文件:

protoc --go-grpc_out=. *.proto

执行完命令之后,我们的文件已经生成出来了:

创建grpc服务端:接下来我们开始创建grpc的服务端,来调用我们proto文件生成的go文件:

package main

import (
	pd "chat-simple/src/pd"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"net"
)

// Children 定义类
type Children struct {
	pd.UnimplementedSayNameServer // 嵌入未实现部分
}

// SayHello 按接口绑定类方法
func (this *Children) SayHello(ctx context.Context, t *pd.Teacher) (*pd.Teacher, error) {
	t.Name += "is Sleeping"
	return t, nil
}
func main() {
	// 01 初始一个grpc对象
	grpcServer := grpc.NewServer()
	// 02 注册服务
	pd.RegisterSayNameServer(grpcServer, new(Children))
	// 03 设置监听
	listener, err := net.Listen("tcp", ":8800")
	if err != nil {
		fmt.Println("Listen err", err)
		return
	}
	defer listener.Close()
	// 04 启动grpc服务
	err = grpcServer.Serve(listener)
	if err != nil {
		return
	}
}

创建客户端:接下来创建客户端,调用服务端的一个函数并把数据进行显示,两者通信的桥梁就是我们proto生成的go文件里面的函数:

package main

import (
	pd "chat-simple/src/pd"
	"context"
	"fmt"
	"google.golang.org/grpc"
)

func main() {
	// 01连接服务
	grpcConn, err := grpc.Dial("localhost:8800", grpc.WithInsecure())
	if err != nil {
		fmt.Println("grpc连接失败", err)
		return
	}
	defer grpcConn.Close()
	// 02初始化grpc客户端
	grpcClient := pd.NewSayNameClient(grpcConn)
	// 03调用grpc服务
	t, err := grpcClient.SayHello(context.TODO(), &pd.Teacher{Name: "张三", Age: 18})
	fmt.Println(t, err)
}

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

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

相关文章

多个NVR同时管理EasyNVR多品牌NVR管理工具/设备:IP常见问题解决方案

随着视频监控技术的不断发展,NVR(网络视频录像机)已经成为现代安防系统的重要组成部分。而为了更高效地管理多个品牌的NVR设备,EasyNVR这一多品牌NVR管理工具应运而生。然而,在实际使用过程中,尤其是在多个…

GS-Blur数据集:首个基于3D场景合成的156,209对多样化真实感模糊图像数据集。

2024-10-31,由韩国首尔国立大学的研究团队创建的GS-Blur数据集,通过3D场景重建和相机视角移动合成了多样化的真实感模糊图像,为图像去模糊领域提供了一个大规模、高覆盖度的新工具,显著提升了去模糊算法在真实世界场景中的泛化能力…

一文熟悉新版llama.cpp使用并本地部署LLAMA

0. 简介 最近是快到双十一了再给大家上点干货。去年我们写了一个大模型的系列,经过一年,大模型的发展已经日新月异。这一次我们来看一下使用llama.cpp这个项目,其主要解决的是推理过程中的性能问题。主要有两点优化: llama.cpp …

VMWareTools安装及文件无法拖拽解决方案

文章目录 1 安装VMWare Tools2 安装vmware tools之后还是无法拖拽文件解决方案2.1 确认vmware tools安装2.2 客户机隔离2.3 修改自定义配置文件2.4 安装open-vm-tools-desktop软件 1 安装VMWare Tools 打开虚拟机VMware Workstation,启动Ubuntu系统,菜单…

Maven的依赖管理、传递、冲突、父子工程的继承和聚合

目录 一、基于IDEA 进行Maven依赖管理 (一)依赖管理概念 (二)Maven工程核心信息配置和解读(GAVP) (三)Maven工程依赖管理配置 1.依赖管理和依赖添加 2.依赖版本统一提取和维护 (四)依赖范围 (五)Maven工程依赖下载失败错误解决(重点…

华为云计算知识总结——及案例分享

目录 一、华为云计算基础知识二、华为云计算相关案例实战案例一:搭建弹性云服务器(ECS)并部署Web应用案例二:构建基于OBS的图片存储和分发系统案例三:基于RDS的高可用数据库应用案例四:使用华为云DDoS防护保…

证件照尺寸168宽240高,如何手机自拍更换蓝底

在提供学籍照片及一些社会化考试报名时,会要求我们提供尺寸为168*240像素的电子版证件照,本文将介绍如何使用“报名电子照助手”,借助手机拍照功能完成证件照的拍摄和背景更换,特别是如何将照片尺寸调整为168像素宽和240像素高&am…

智能出行助手:SpringBoot共享汽车管理平台

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理共享汽车管理系统的相关信息成为必然。开发…

cell队列监控

1.cell队列监控 基于Windows定时计划任务,通过Windows bat脚本监控Cell队列,当Source Cell队列有告警没有传递至Destination Cell时,能够及时发出告警。 Cell_Queue_Monitoring.bat ::关闭命令回显 echo off::日志目录创建 if not exist &…

基于java+SpringBoot+Vue的师生共评作业管理系统设计与实现

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: Springboot mybatis Maven mysql5.7或8.0等等组成&#x…

Leetcode刷题Python之540.有序数组中的单一元素

提示:使用二分查找降低时间复杂度。 文章目录 一、问题描述示例 二、解题思路三、代码实现代码解析 总结 一、问题描述 给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。请你找出并返回只出现一次的那个数…

基于SpringBoot和Vue的公司文档管理系统设计与开发(源码+定制+开发)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

如何保证kafka生产者数据可靠性

ack参数的设置: 0:生产者发送过来的数据,不需要等数据落盘应答 假如发送了Hello 和 World两个信息,Leader直接挂掉,数据就会丢失 生产者 ---> Kafka集群 一放进去就跑 数据可靠性分析:丢数 1&#…

python画图|text()和dict()初探

【1】引言 在进行hist()函数的学习进程中,了解到了subplot_mosaic()函数,在学习subplot_mosaic()函数的时候,又发现了text()和dict()函数。 经探究,text()和dict()函数有很多一起使用的场景,为此,我们就一…

网线类别线芯含义和传输距离以及水晶头制作标准

网线八芯每根的含义: 网线的八根线芯,也被称为RJ45网线中的8芯,网线采用8根线芯,这八根线芯各自承担着特定的功能。这8根线芯被分为4对,每对以特定的方式绞合在一起,8芯网线主要是为了减少电磁信号的相互干…

每天五分钟深度学习PyTorch:基于全连接神经网络完成手写字体识别

本文重点 上一节我们学习了搭建普通的全连接神经网络,我们现在用它来解决一个实际问题,我们用它跑一下手写字体识别的数据,然后看看它的效果如何。 网络模型 class ThreeNet(nn.Module) : def __init__ (self,in_dim,n_hidden_1,n_hidden_2,out_dim): super(ThreeNet, self…

【R78/G15 开发板测评】串口打印 DHT11 温湿度传感器、DS18B20 温度传感器数据,LabVIEW 上位机绘制演化曲线

【R78/G15 开发板测评】串口打印 DHT11 温湿度传感器、DS18B20 温度传感器数据,LabVIEW 上位机绘制演化曲线 主要介绍了 R78/G15 开发板基于 Arduino IDE 环境串口打印温湿度传感器 DHT11 和温度传感器 DS18B20 传感器的数据,并通过LabVIEW上位机绘制演…

基于MFC实现的赛车游戏

一、问题描述 游戏背景为一环形车道图,选择菜单选项“开始游戏”则可开始游戏。游戏的任务是使用键盘上的方向键操纵赛道上的蓝色赛车追赶红色赛车,红色赛车沿车道顺时针行驶,出发点和终点均位于车道左上方。任一赛车先达到终点则比赛结束。…

实验三 JDBC数据库操作编程(设计性)

实验三 JDBC数据库操作编程(设计性) 实验目的 掌握JDBC的数据库编程方法。掌握采用JDBC完成数据库链接、增删改查,以及操作封装的综合应用。实验要求 本实验要求每个同学单独完成;调试程序要记录调试过程中出现的问题及解决办法…

Java期末复习暨学校第二次上机课作业

Java期末复习暨学校第二次上机课作业:了解程序的控制结构,掌握顺序结构程序的设计方法,掌握分支程序设计方法。 第一题: 闰年有两种判断方式: (1):能被4整除但不能被100整除 &…