开课啦 dubbo-go 微服务升级实战

本文涉及的产品
云原生网关 MSE Higress,422元/月
可观测监控 Prometheus 版,每月50GB免费额度
应用实时监控服务-应用监控,每月50GB免费额度
简介: 杭州开课啦教育科技有限公司是一家致力于为中小学生提供学习辅导的在线教育公司,目前公司后端服务基础设施主要依托于阿里云原生,其中包含计算、网络、存储以及 Kubernetes 服务。

头图.png

曾凡维  杭州开课啦教育科技有限公司高级开发工程师
来源 | 阿里巴巴云原生公众号

杭州开课啦教育科技有限公司是一家致力于为中小学生提供学习辅导的在线教育公司,目前公司后端服务基础设施主要依托于阿里云原生,其中包含计算、网络、存储以及 Kubernetes 服务。

技术选型背景

2020 年是开课啦公司发展壮大的一年,整个公司团队由原来的几百人扩充至现在的几千人,在集中使用的时候基本上会有几千人同时在运营后台进行操作,公司原有的内部后台运营系统是用 PHP 搭建起来的,性能跟业务上已逐渐不能满足公司的需求规划,加上目前开课啦公司开发部已经做了微服务拆分,主体对外服务是 java 语言的 Dubbo 集群,后台系统需要无缝对接 java 的 Dubbo 服务,所以 PHP 已经逐渐不能满足开课啦公司的需求。

当时自己也调研过 PHP 的 Dubbo 项目,由于项目已基本无人更新维护所以 pass 掉,后面自己对简洁高性能的 go 语言感兴趣,然后就关注到了 Dubbo-go 项目,经过一段时间的调研之后发现 Dubbo Go 符合我们的业务需要,并且社区非常的活跃,后面便决定选用 Dubbo-go 作为后台的 pc 业务框架。

可能也有同学会问为什么不使用跨言支持程度更好的 gRPC 呢,因为很多公司最开始的 RPC 服务集群都是基于 Dubbo 生态构建的,如果换框架成本太大,所以基本不会考虑,gRPC 虽然跨语言支持程度更好但是很多东西都需要自己造轮子,比如服务注册,服务发现,日志监控等。

当时在决定选用 Dubbo-go 的时候开发内部也有一些反对的声音的,为什么不直接转 java,转 java 的话就没有跨语言通信的问题了,转 java 的问题在于入门成本高,而且对于整个公司的技术栈来说,保持语言的多样性,才能更加从容的应对未来的业务变化,Go 本身是一个不弱于 Java 的高性能语言,非常适合微服务架构。

面临的挑战

确定了框架选型后,我接到的首要任务便是要搭建出一套可快速创建业务项目的脚手架,开发出基于 HTTP 协议的 RPC 代理服务,部署需要接入公司的容器化部署平台,一切都是从零开始,在网上基本上找不到可以借鉴的资料。

首先是要进行 Dubbo-go 项目的架构的规划,确定项目目录结构,经过参考 Dubbo-go Demo 以及其它的 Go 项目最终确定了项目的目录结构,以下目录结构可作为参考。

1.png

为了与 Java 服务注册中心保持一致,Dubbo-go 在项目选型上选用如下组件:

  • 使用 zookeeper 作为注册中心
  • nacos 作为配置中心
  • 数据库 orm 采用 gorm
  • 消息队列使用 RocketMQ

为了增加开发的效率我们在 provider 服务初始化前可以对配置进行精简只保留最基础的配置就可以类似下面这种,provider 服务的编码参考 Dubbo-go demo 就可以了。

2.png

下面是服务启动的 main 方法代码:

3.png

Dubbo-go RPC 服务网关设计

一般使用 Dubbo,provider 端需要暴露出接口和方法,consumer 端要十分明确服务使用的接口定义和方法定义,还有入参返参类型等等信息,还需要基于 provider 端提供的 API,两端才能正常通信调用。

然而网关的使用场景是并不关心要调用的接口的详细定义,网关只关注要调用的方法、传递的参数、能接收返回结果就可以了,实现网关代理的基础是 Dubbo/Dubbo-go 的泛化调用特性。

下面是 Dubbo-go 官方给的 demo,泛化服务加载后需要等待 3 秒才能完成调用,然而在实际使用的时候肯定是不能实时加载服务去等待 3 秒,所以在网关应用启动时就需要加载缓存好需要泛化调的服务。

4.png

经过对 Dubbo-go 泛化调用 demo 的研究,发现用该特性设计 dubbo-go 网关是可行的,难点在于我们需要把每一个需要网关代理 RPC 服务方法的参数以及服务的路径等配置获取到并缓存起来,这样才能在调用前初始化好泛化调用服务,一个服务的配置如下。

5.png

由于是用 go 语言做的网关代理,所以不能通过 Java 的 jar 包来获取到 Java RPC 服务配置,如果通过人工维护的话工作量太大,而且易出错,显然是不可接受的。经过一段时间的了解,Java 服务可以通过注解来实现配置的获取,Java 端在方法上加上注解后启动服务的时候会将配置信息通过消息发送到 MQ,网关消费这些消息来实现获取 Java RPC 服务的配置。

Dubbo Go 的 RPC 服务由于 go 语言不支持注解,所以我经过思考自己写了一个扫描代码的小工具,在每个 RPC 服务方法前加上对应的注释,通过对注释的扫描来获取 RPC 服务的配置,获取到配置后在项目目录内生成 RPC 服务配置,启动应用的时候读取配置发送到 MQ。

网关代理实现之后还可以在网关的基础实现更多的功能,比如 token 验证、白名单、限流、熔断、日志监控功能,网关代理请求实现效果如下:

6.png

容器化部署

公司内部的容器化部署环境为阿里云的 K8s,部署至 K8s 平台只需要提供镜像文件,由于 Dubbo-go 编译后是一个二进制的文件,不需任何额外的第三方库,能在 Docker 环境下稳定运行。有 docker 镜像文件如下图所示,可以用 centos 等任一 linux 发行版作为 base 镜像。

LABEL maintainer="<xxx@xx.com>"
LABEL version="1.0"
LABEL description="KKL-GO-NKO-BASE"`

ARG envType=stable
#设置环境变量
ENV envType ${envType}
#编译打包好的压缩包
ADD ./target/nko-base-${envType}.tar.gz /app/

WORKDIR /app
EXPOSE 20000

镜像写好后提供给发布平台,发布平台机器启动镜像并解压打包文件,执行 Dubbo-Go 程序 。

Container entrypoint set to [bash, -c, tar -zxf nko-base-stable.tar.gz && SERVER_ENV=kubernetes && sh ./nko-base/bin/load.sh start -group=stable]

由于开发测试到生产一般是有多个部署环境的,所以我们需要改动的dubbo-go samples demo 里的编译脚本,让其支持多环境打包。

另外,Dubbo-go 默认注册的 IP 是 K8s pod 的虚拟 IP,不同 K8s 集群之间网络是不能互通的,所以如果需要跨集群调用就需要修改默认注册 IP,将默认注册的 pod IP + 端口 修改为 Kubernetes 实体机的 IP 加对应端口,Kubernetes 会在 pod 内写入实体机的 IP 加对应端口环境变量,应用程序可以通过读取环境变量获取实体机的 IP加端口,如果需要实现此功能需要修改 Dubbo-go 的注册逻辑。例如以 zookeeper 注册中心为例,我们可以通过扩展 registery/zookeeper/registry.go的 registerTempZookeeperNode 方法来实现修改注册 IP 跟端口,代码如下图,Dubbo-go 官方将在后面的版本以配置的形式支持自定义注册 IP 跟端口的功能。

func (r *zkRegistry) registerTempZookeeperNode(root string, node string) error {
  ...
  regIp = os.Getenv(constant2.RegistryEnvIP) //实体机的ip
  regPort = os.Getenv(constant2.RegistryEnvPort) //实体机的端口
  urlNode, _ := common.NewURL(node)
  role, _ := strconv.Atoi(urlNode.GetParam(constant.ROLE_KEY, ""))
  if role == common.PROVIDER && regIp != "" && regPort != "" {
    urlNode.Ip = regIp
    urlNode.Port = regPort
    node = url.QueryEscape(urlNode.String())
  }

  zkPath, err = r.client.RegisterTemp(root, node)
  ...
}

最后的话

如果使用 dubbo-go 过程中遇到一些问题,可以提交 issue 或者进社区钉钉群进行沟通交流。

个人建议:如果你做好了入坑 Dubbo-go 的准备,最好自己解决这些问题并给官方反馈 PR,遇到问题解决问题你才能成长并有所收获,不是吗?

欢迎对 apache/dubbo-go 项目有兴趣的同学通过搜索钉钉群号 31363295 加入交流群。

作者简介

曾凡维(github @jack15083), 一个有 9 年服务端业务开发经验的一线程序员,曾在腾讯阅文等多家公司担任后端开发工程师,目前就职杭州开课啦教育科技有限公司,从事 go 语言服务基础架构和中间件及部分业务开发工作。

2021 年,原 SpringCloud Alibaba Meetup 正式升级为云原生中间件 Meetup 从议题出品、活动形式、在线体验三大维度重磅升级。所有话题的 Demo 都会放到知行动手实验室 start.aliyun.com 供大家实操。

上海站亮点速递:

  •  Dubbo 3.0 Preview 版正式发布!
  •  Nacos 2.0 正式发布!
  •  云原生混沌工程控制台 ChaosBox 正式开源!
  •  Dapr V1.0 发布!中文文档上线!

点击即可报名活动!

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
2月前
|
JavaScript Java Go
探索Go语言在微服务架构中的优势
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出。本文将深入探讨Go语言在构建微服务时的性能优势,包括其在内存管理、网络编程、并发模型以及工具链支持方面的特点。通过对比其他流行语言,我们将揭示Go语言如何成为微服务架构中的一股清流。
141 53
|
3月前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
84 2
|
4月前
|
Go API Docker
热门go与微服务15
热门go与微服务15
40 2
|
17天前
|
存储 监控 供应链
微服务拆分的 “坑”:实战复盘与避坑指南
本文回顾了从2~3人初创团队到百人技术团队的成长历程,重点讨论了从传统JSP到前后端分离+SpringCloud微服务架构的演变。通过实际案例,总结了微服务拆分过程中常见的两个问题:服务拆分边界不清晰和拆分粒度过细,并提出了优化方案,将11个微服务优化为6个,提高了系统的可维护性和扩展性。
37 0
|
2月前
|
Dubbo Cloud Native 应用服务中间件
阿里云的 Dubbo 和 Nacos 深度整合,提供了高效的服务注册与发现、配置管理等关键功能,简化了微服务治理,提升了系统的灵活性和可靠性。
在云原生时代,微服务架构成为主流。阿里云的 Dubbo 和 Nacos 深度整合,提供了高效的服务注册与发现、配置管理等关键功能,简化了微服务治理,提升了系统的灵活性和可靠性。示例代码展示了如何在项目中实现两者的整合,通过 Nacos 动态调整服务状态和配置,适应多变的业务需求。
60 2
|
2月前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
2月前
|
Go 数据处理 API
Go语言在微服务架构中的应用与优势
本文摘要采用问答形式,以期提供更直接的信息获取方式。 Q1: 为什么选择Go语言进行微服务开发? A1: Go语言的并发模型、简洁的语法和高效的编译速度使其成为微服务架构的理想选择。 Q2: Go语言在微服务架构中有哪些优势? A2: 主要优势包括高性能、高并发处理能力、简洁的代码和强大的标准库。 Q3: 文章将如何展示Go语言在微服务中的应用? A3: 通过对比其他语言和展示Go语言在实际项目中的应用案例,来说明其在微服务架构中的优势。
|
2月前
|
运维 NoSQL Java
后端架构演进:微服务架构的优缺点与实战案例分析
【10月更文挑战第28天】本文探讨了微服务架构与单体架构的优缺点,并通过实战案例分析了微服务架构在实际应用中的表现。微服务架构具有高内聚、低耦合、独立部署等优势,但也面临分布式系统的复杂性和较高的运维成本。通过某电商平台的实际案例,展示了微服务架构在提升系统性能和团队协作效率方面的显著效果,同时也指出了其带来的挑战。
94 4
|
3月前
|
Cloud Native Go API
Go语言在微服务架构中的创新应用与实践
本文深入探讨了Go语言在构建高效、可扩展的微服务架构中的应用。Go语言以其轻量级协程(goroutine)和强大的并发处理能力,成为微服务开发的首选语言之一。通过实际案例分析,本文展示了如何利用Go语言的特性优化微服务的设计与实现,提高系统的响应速度和稳定性。文章还讨论了Go语言在微服务生态中的角色,以及面临的挑战和未来发展趋势。
|
3月前
|
运维 Go 开发者
Go语言在微服务架构中的应用与优势
本文深入探讨了Go语言在构建微服务架构中的独特优势和实际应用。通过分析Go语言的核心特性,如简洁的语法、高效的并发处理能力以及强大的标准库支持,我们揭示了为何Go成为开发高性能微服务的首选语言。文章还详细介绍了Go语言在微服务架构中的几个关键应用场景,包括服务间通信、容器化部署和自动化运维等,旨在为读者提供实用的技术指导和启发。