Service Weaver:Google开源基于分布式应用程序开发的框架,重新定义微服务边界

news2025/1/11 20:01:46
大家好,我是萧楚河,公众号:golang面试经典讲解,感谢关注,一起学习一起成长。

一、前言

今年6月,一群谷歌员工(由谷歌软件工程师Michael Whittaker领导)发表了一篇名为“Towards Modern Development of Cloud Applications”的论文。

正如Whittaker等人所指出的,从架构上讲,微服务本身设置就有问题,它是一个没有边界的结构它们将逻辑边界(如何编写代码)与物理边界(如何部署代码)混为一谈。这就是问题的开始。

因此,谷歌的工程师们提出了一种堪称“微服务2.0”的方法。将应用程序构建为逻辑整体,但将其交给自动化运行时,后者可以根据应用程序所需的内容和可用的内容来决定在哪里运行工作负载。

基于新提出的结构,他们能够将系统的延迟降低15倍,成本降低9倍。

“从有组织的模块化代码开始,我们就可以将部署架构作为实现细节,”Google开发人员倡导者Kelsey Hightower在10月份对这项工作表示了下一步计划。

鉴于以上实践,诞生了Service Weaver。

1.1 什么是Service Weaver

ServiceWeaver是一个用于编写、部署和管理分布式应用程序的编程框架。您可以在机器上本地运行、测试和调试Service Weaver应用程序,然后使用单个命令将该应用程序部署到云中。

Service Weaver应用程序由许多组件组成。组件被呈现为常规Go接口,组件之间通过调用这些接口定义的方法来相互交互。这使得编写Service Weaver应用程序变得容易。你不需要编写任何联网或序列化代码,你只要写Go。Service Weaver还提供用于日志记录、度量、跟踪、路由、测试等的库。

1.2 什么是模块单体应用?

对于不熟悉的人来说,模块化单体应用是一种体系结构,其中整个应用程序都写成一个单独的应用程序,在一个单一的代码库中。模块化方面意味着单体应用被分成单独的组件,并且在不同组件之间有干净明确的接口。

这里是一个例子:
在这里插入图片描述

在这个单体应用中,有三个组件:订单、支付和运输。每个组件实现单体应用的一个特定部分,关键在于每个组件的大部分都是私有的,并且组件之间的任何通信都是通过明确定义的接口进行的。

这使得每个组件的内部可以进行更改和更新,而不会影响任何其他组件,假设接口未更改或破坏。

当多个团队在单体应用上工作时,这确实有助于在团队之间设定明确的边界,并使每个组件独立于其他任何组件发展,同时在组件之间显示明确的依赖关系。

每当你的单体应用被部署时,它都被部署为一个单一的应用程序,每个单体应用的实例都运行一个单一的进程。例如,如果你要部署到AWS,每个单体应用的实例都将作为一个进程运行在EC2实例上。

二、Service Weaver工作原理

2.1 与模块化单体应用区别

Service Weaver和传统的模块化单体应用之间的区别在于部署方式。使用Service Weaver构建的应用程序在部署时,不是将所有组件运行在同一台机器上的一个大进程。

在这里插入图片描述
相反,每个组件都作为一个独立的微服务进行部署。这非常巧妙,因为您既可以获得将所有代码放在单个代码库中并进行方便的本地开发的好处,又可以获得运行分布式架构的好处,其中您可以根据需要缩放每个组件,例如内存,CPU和实例数量等。

2.2 如何工作的?

ServiceWeaver的核心抽象是组件。组件就像一个参与者,ServiceWeaver应用程序是作为一组组件来实现的。具体地说,组件用一个常规Go接口表示,组件通过调用这些接口定义的方法来相互交互。

2.2.1 单组件

在本节中,我们将定义一个简单的hello组件,它只打印一个字符串并返回。首先,运行go mod init hello来创建一个go模块。

mkdir hello/
cd hello/
go mod init hello

然后,创建一个名为main.go的文件,其中包含以下内容:

package main

import (
“context”
“fmt”
“log”

"github.com/ServiceWeaver/weaver"

)

func main() {
if err := weaver.Run(context.Background(), serve); err != nil {
log.Fatal(err)
}
}

// app is the main component of the application. weaver.Run creates
// it and passes it to serve.
type app struct{
weaver.Implements[weaver.Main]
}

// serve is called by weaver.Run and contains the body of the application.
func serve(context.Context, *app) error {
fmt.Println(“Hello”)
return nil
}

在构建和运行应用程序之前,我们需要运行ServiceWeaver的代码生成器,称为weavergenerate。weavergenerate编写一个weaver_gen.go文件,其中包含ServiceWeaver运行时所需的代码。我们将详细说明weaver generate到底做了什么,以及为什么我们稍后需要运行它。最后,运行应用程序!

$ go mod tidy
$ weaver generate .
$ go run .
Hello

2.2.2 多组件

在ServiceWeaver应用程序中,任何组件都可以调用任何其他组件。为了演示这一点,我们引入了第二个Reverser组件。创建一个文件Reverser.go。转到以下内容:

package main

import (
    "context"

    "github.com/ServiceWeaver/weaver"
)

// Reverser component.
type Reverser interface {
    Reverse(context.Context, string) (string, error)
}

// Implementation of the Reverser component.
type reverser struct{
    weaver.Implements[Reverser]
}

func (r *reverser) Reverse(_ context.Context, s string) (string, error) {
    runes := []rune(s)
    n := len(runes)
    for i := 0; i < n/2; i++ {
        runes[i], runes[n-i-1] = runes[n-i-1], runes[i]
    }
    return string(runes), nil
}

Reverser组件由Reverse接口表示,该接口具有反转字符串的Reverse方法。reverser结构是我们对reverser组件的实现(如weaver.Implements[Reverser]所示它包含的字段)。

接下来,在main.go中编辑应用程序组件以使用reverser组件:


package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ServiceWeaver/weaver"
)

func main() {
    if err := weaver.Run(context.Background(), serve); err != nil {
        log.Fatal(err)
    }
}

type app struct{
    weaver.Implements[weaver.Main]
    reverser weaver.Ref[Reverser]
    hello    weaver.Listener
}

func serve(ctx context.Context, app *app) error {
    // Call the Reverse method.
    // The hello listener will listen on a random port chosen by the operating
    // system. This behavior can be changed in the config file.
    fmt.Printf("hello listener available on %v\n", app.hello)

    // Serve the /hello endpoint.
    http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
        name := r.URL.Query().Get("name")
        if name == "" {
            name = "World"
        }
        reversed, err := app.reverser.Get().Reverse(ctx, name)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        fmt.Fprintf(w, "Hello, %s!\n", reversed)
    })
    return http.Serve(app.hello, nil)
}

应用程序结构有一个类型为weaver.Ref[Reverser]的新字段,提供对反向器组件的访问权限。

2.2.3 多进程执行

我们已经了解了如何通过go run在单个流程中运行Service Weaver应用程序。现在,我们将在多个进程中运行我们的应用程序,在作为RPC执行的组件之间进行方法调用。首先,创建一个名为weaver.toml的TOML配置文件,其中包含以下内容:

[serviceweaver]
binary = "./hello"

[multi]
listeners.hello = {address = "localhost:12345"}

此配置文件指定ServiceWeaver应用程序的二进制文件,以及hello侦听器的固定地址。接下来,使用weaver multi-deploy构建并运行应用程序:

go build                        # build the ./hello binary
weaver multi deploy weaver.toml # deploy the application

2.3 微服务如何组合?

我发现图表有助于理解的一个例子,这是Google解释了这些不同部分如何组合在一起的图表:

在这里插入图片描述
我们还没有谈到 Service Weaver 框架的多功能性。传统微服务的一个缺点是,你经常会遇到接口过于频繁的问题。毕竟,没有人能预见架构的演变方向。

然后,你不得不忍受增加的延迟和更高的网络调用失败率,或者花时间将这两个微服务合并起来。

使用 Service Weaver,这个问题得到了解决。如果你查看上面的图表,你会发现有四个模块被定义了。当部署为微服务时,你会注意到 A 和 B 住在一起,C 和 D 是他们自己的微服务。

使用 Service Weaver,你可以自由地定义组件在哪里部署。你可以选择让多个组件一起运行在单个微服务中,或者将所有组件都部署为单独的微服务。如果你的应用程序演变到两个组件变得过于频繁,并且作为单独的微服务运行,你可以轻松地将它们合并,而不需要改变代码,并在 Service Weaver 中快速更改配置。

三、Service Weaver使用

这里基于我的理解对Service Weaver的初步介绍,鉴于很多人可能希望自己实践一下,可以通过如下地址进入官方网站进行学习:https://serviceweaver.dev

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

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

相关文章

对接第三方接口鉴权(Spring Boot+Aop+注解实现Api接口签名验证)

前言 一个web系统&#xff0c;从接口的使用范围也可以分为对内和对外两种&#xff0c;对内的接口主要限于一些我们内部系统的调用&#xff0c;多是通过内网进行调用&#xff0c;往往不用考虑太复杂的鉴权操作。但是&#xff0c;对于对外的接口&#xff0c;我们就不得不重视这个…

MySQL--基础篇

这里写目录标题 总览MySQl各个阶段基础篇总览 MySQL概述数据库相关概念查看本机MySQL版本号启停mysql打开windows服务管理windows命令行启停 连接mysql客户端mysql运行逻辑数据模型关系型数据库 总结 SQL总览SQL通用语法SQL语句分类DDL数据库操作表操作查询表创建表结构数据类型…

有什么安全处理方案可以有效防护恶意爬虫

常见的爬虫 有百度爬虫、谷歌爬虫、必应爬虫等搜索引擎类爬虫&#xff0c;此类爬虫经常被企业用于提高站点在搜索引擎内的自然排名&#xff0c;使得站点在各大搜索引擎中的排名能够提高&#xff0c;进一步通过搜索引擎来进行引流为企业增加业务流量。 恶意爬虫与合法、合规的搜…

看了致远OA的表单设计后的思考

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/n…

微信小程序的驾校预约管理系统

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一 、设计说明 1.1课题背景 在I…

【教学类-43-16】 20240106 推算5-9宫格数独可能出现的不重复题量(N宫格数独模板数量的推算)

作品展示&#xff1a; 通过对各种已有结果的人工推算&#xff0c;目前得到两个结论 一、阶乘基本样式的数量【【123】【321】【231】【132】【312】【312】】6组 结论&#xff1a;阶乘等于出现的基本样式数量 以下N*N格会出现的最大排序数量&#xff08;比如包含333222111这种…

Spring声明式事务业务bug

Spring 针对 Java Transaction API (JTA)、JDBC、Hibernate 和 Java Persistence API (JPA) 等事务 API&#xff0c;实现了一致的编程模型&#xff0c;而 Spring 的声明式事务功能更是提供了极其方便的事务配置方式&#xff0c;配合 Spring Boot 的自动配置&#xff0c;大多数 …

C++ 二进制图片的读取和blob插入mysql_stmt_init—新年第一课

关于二进制图片的读取和BLOB插入一共包含五步 第一步&#xff1a;初始化 MYSQL_STMT* stmt mysql_stmt_init(&mysql); 第二步&#xff1a;预处理sql语句 mysql_stmt_prepare(stmt,sql,sqllen); 第三步&#xff1a;绑定字段 mysql_stmt_bind_param(stmt,bind); 第四…

用友U8+CRM 逻辑漏洞登录后台漏洞复现

0x01 产品简介 用友U8 CRM客户关系管理系统是一款专业的企业级CRM软件&#xff0c;旨在帮助企业高效管理客户关系、提升销售业绩和提供优质的客户服务。 0x02 漏洞概述 用友 U8 CRM客户关系管理系统 reservationcomplete.php文件存在逻辑漏洞&#xff0c;未授权的攻击者通过…

手把手带你门SpringCloud

目录​​​​​ 1、什么是 SpringCloud&#xff1f; SpringCloud常用组件&#xff1a; 简单介绍组件间作用 2&#xff0c;SpringCloud相关组件&#xff1a;Eureka 3&#xff0c;Spring Cloud核心组件&#xff1a;Feign 4&#xff0c;Spring Cloud核心组件&#xff1a;Zuu…

软件测试|Docker exec命令详细使用指南

简介 Docker exec命令是Docker提供的一个强大工具&#xff0c;用于在正在运行的容器中执行命令。本文将详细介绍Docker exec命令的用法和示例&#xff0c;帮助大家更好地理解和使用这个命令。 Docker是一种流行的容器化平台&#xff0c;允许我们在容器中运行应用程序。有时候…

locust 快速入门--程序调试

背景 对测试的api引入locust后&#xff0c;不在使用requests库进行http请求了&#xff0c;而是通过client属性发送请求&#xff0c;实质是使用HttpSession。 问题&#xff1a;如果对locust程序进行调试 解决方案&#xff1a; 因为locust使用协程&#xff0c;需要开启pych…

微服务-java spi 与 dubbo spi

Java SPI 通过一个案例来看SPI public interface DemoSPI {void echo(); } public class FirstImpl implements DemoSPI{Overridepublic void echo() {System.out.println("first echo");} } public class SecondImpl implements DemoSPI{Overridepublic void ech…

万界星空科技云MES,助力客户快速构建数字工厂

一、MES发展趋势 1、定制化趋势 工业2.0、3.0的技术已较为成熟&#xff0c;部分制造业水平较为发达的国家已经率先进入以网络化、智能化为代表的工业4.0发展阶段,MES作为制造业规划层随着物联网等持续发展&#xff0c;为适应定制化时代&#xff0c;整体技术模块化、服务化将重…

解决Gitee每次push都需要输入用户名和密码

其实很简单&#xff0c;只需要使用命令 git config --global credential.helper store 在你下次push时只需要再输入一次用户名和密码&#xff0c;电脑就会保存下来&#xff0c;之后就无需进行输入了。

TypeScript 从入门到进阶之基础篇(三) 元组类型篇

系列文章目录 TypeScript 从入门到进阶系列 TypeScript 从入门到进阶之基础篇(一) ts基础类型篇TypeScript 从入门到进阶之基础篇(二) ts进阶类型篇 文章目录 系列文章目录TypeScript 从入门到进阶系列前言一、在TypeScript中使用元组二、TypeScript 中元组的使用场景1、让函…

从Spring Cloud Alibaba开始聊架构

作为SpringCloudAlibaba微服务架构实战派上下册和RocketMQ消息中间件实战派上下册的作者胡弦。 另外我的新书RocketMQ消息中间件实战派上下册&#xff0c;在京东已经上架啦&#xff0c;目前都是5折&#xff0c;非常的实惠。 https://item.jd.com/14337086.htmlhttps://item.jd…

【详解】求解迷宫所有路径(递归实现)----直接打穿迷宫

目录 递归的模型&#xff1a; 栈帧&#xff1a; 递归调用深度&#xff1a; ​编辑 用递归算法求解迷宫问题&#xff1a; 小结&#xff1a; 结语&#xff1a; 递归的小小总结&#xff0c;朋友们可以看看&#xff0c;有助于理解后面的递归程序。 递归的模型&#xff1a; …

钡铼技术2023年年度报告来了

不积跬步&#xff0c;无以至千里&#xff1b; 不积小流&#xff0c;无以成江海。 钡铼的2023年 平凡却又意义深远。 在工业自动化及物联网技术发展的道路上&#xff0c;钡铼技术每一个进步都源于不懈的努力和持续的积累。钡铼技术在过去的一年中&#xff0c;稳扎稳打&#xf…

QCharView使用

QChart是 QGraphicsWidget的子类。 QCharView是QGraphicsView的子类 QCharView概念:title、系列、图标Chart、视图 说明: 需要添加Qt组件charts 在使用QChart或者QChartView之前需要添加宏定义QT_CHARTS_USE_NAMESPACE &#xff08;其实是使用了命名空间&#xff09;&#xff…