go-微服务初始

1.认识微服务架构

微服务诞生背景

  • 互联网行业的快速发展,需求变化快,用户数量变化快
  • 敏捷开发深入人心,用最小的代价,做最快的迭代,频繁修改,测试,上线
  • 容器技术的成熟,是微服务的技术基础

微服务架构的特点

  • 将系统服务层完全独立出来,并将服务层抽取为一个一个的微服务
  • 采用一些轻量协议进行传输
  • 服务拆分粒度更细,有利于资源重复利用,提高开发效率
  • 可以更加精准的制定每个服务的优化方案,提高系统可维护性
  • 相比ESB更轻量

什么是微服务

  • 使用一套小服务来开发单个应用的方式,每个服务运行在独立的进程里,一般采用轻量级的通讯机制互联,并且它们可以通过自动化的方式部署
    微服务的特点
  • 单一职责:独立的业务单独放在一个项目里,比如订单服务作为一个项目
  • 轻量级通信:http,rpc,非轻量级(例如Java的RMI)
  • 隔离性:每个服务相互隔离,不干扰
  • 有自己的数据
  • 技术多样性

架构

  • 单体架构
    1. 所有功能集成在一个项目中
    2. 项目整个打包,可以部署到服务器运行
    3. 应用与数据库可以分开部署,提高性能
    4. 优点:
      · 小项目的首选,开发成本低,架构简单
    5. 缺点:
      · 项目复杂之后,很难有扩展和维护
      · 扩展成本高,有瓶颈
      · 技术栈受限
      单体架构
  • 垂直架构
    1. 对于单体架构的拆分,大项目拆成单个的项目的架构
    2. 存在数据冗余
    3. 项目之间要处理数据同步,通过数据库同步
    4. 优点:
      · 小项目的首选,架构简单
      · 避免了单体架构的无限扩大
      · 技术不在受限
    5. 缺点:
      · 很多功能放在一个工程中,有一定瓶颈
      · 系统性能扩展要通过集群节点扩展,成本较高
      垂直架构
  • SOA架构(面向服务的架构)
    1. 将重复性的功能进行抽取,抽取成对应的服务
    2. 通过 ESB 服务总线去访问
    3. 优点:
      · 提高系统的可重用性
      · ESB 减少系统接口耦合问题
    4. 缺点:
      · 系统与服务界限模糊,不利于开发
      · ESB 服务接口协议不固定,不利于系统维护
      · 抽取粒度较大,仍存有一些耦合性
      在这里插入图片描述
  • 微服务架构
    1. 将服务层一个一个抽取为微服务
    2. 遵循单一原则
    3. 微服务之间采用一些轻量协议传输数据
    4. 优点:
      · 服务拆分粒度非常细,利于开发
      · 提高系统可维护性
      · 比 ESB 更轻量
      · 适用于互联网更新换代快的情况
    5. 缺点:
      · 服务过多,服务治理成本高
      · 开发技术要求更高
      在这里插入图片描述
      传统访问方式
      在这里插入图片描述
      微服务架构访问方式
      在这里插入图片描述

服务发现

传统服务发现方式
一般是IP:端口号访问
在这里插入图片描述)
微服务发现有两中,客户端发现和服务端发现
客户端发现
微服务启动后,将自己IP和端口进行注册,客户端查询注册,得到提供服务的IP和端口,通过负载均衡,访问微服务
在这里插入图片描述
**服务端发现:**客户端访问时,不去注册中心了,通过服务发现代理去直接访问
在这里插入图片描述

2.RPC远程调用

RPC(Remote Procedure Call),即远程过程调用。它允许像调用本地服务一样调用远程服务。
RPC是一种服务器-客户端(Client/Server)模式,经典实现是一个通过发送请求-接受回应进行信息交互的系统。
首先与RPC(远程过程调用)相对应的是本地调用。

基于tcp协议的RPC

server 端

package main
import (
	"fmt"
	"net"
	"net/rpc"
)
type Args struct {
	X, Y int
}

type ServiceA struct {
}

func (s *ServiceA) Add(args *Args, reply *int) error {
	*reply = args.X + args.Y
	return nil
}

func main() {
	service := new(ServiceA)
	//	注册服务
 	rpc.Register(service)
	fmt.Println("server register success...")
	listener, err := net.Listen("tcp", ":9091")
	if err != nil {
		log.Fatal("listen error:", e)
	}
	for {
		coon, _ := listener.Accept()
		rpc.ServeConn(coon)
	}
}

client 端

package main

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

type Args struct {
	X, Y int
}

func main() {
	//	建立连接
	client, err := rpc.Dial("tcp", "127.0.0.1:9091")
	if err != nil {
		log.Fatal("dialing:", err)
	}
	fmt.Println("client connect success...")
	
	// 同步调用
	args := &Args{10, 20}
	var reply int
	err = client.Call("ServiceA.Add", args, &reply)
	if err != nil {
		log.Fatal("ServiceA.Add error:", err)
	}
	fmt.Printf("ServiceA.Add: %d+%d=%d\n", args.X, args.Y, reply)

	// 异步调用
	var reply2 int
	divCall := client.Go("ServiceA.Add", args, &reply2, nil)
	replyCall := <-divCall.Done // 接收调用结果
	fmt.Println(replyCall.Error)
	fmt.Println(reply2)
}

这个RPC调用过程可以简化如下图所示
在这里插入图片描述

rpc原理

RPC 让远程调用就像本地调用一样,其调用过程可拆解为以下步骤。
在这里插入图片描述)
① 服务调用方(client)以本地调用方式调用服务;

② client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;

③ client stub找到服务地址,并将消息发送到服务端;

④ server 端接收到消息;

⑤ server stub收到消息后进行解码;

⑥ server stub根据解码结果调用本地的服务;

⑦ 本地服务执行并将结果返回给server stub;

⑧ server stub将返回结果打包成能够进行网络传输的消息体;

⑨ 按地址将消息发送至调用方;

⑩ client 端接收到消息;

⑪ client stub收到消息并进行解码;

⑫ 调用方得到最终结果。

  • 29
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值