开课啦 dubbo-go 微服务升级实战
简介: 杭州开课啦教育科技有限公司是一家致力于为中小学生提供学习辅导的在线教育公司,目前公司后端服务基础设施主要依托于阿里云原生,其中包含计算、网络、存储以及 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 项目最终确定了项目的目录结构,以下目录结构可作为参考。
为了与 Java 服务注册中心保持一致,Dubbo-go 在项目选型上选用如下组件:
- 使用 zookeeper 作为注册中心
- nacos 作为配置中心
- 数据库 orm 采用 gorm
- 消息队列使用 RocketMQ
为了增加开发的效率我们在 provider 服务初始化前可以对配置进行精简只保留最基础的配置就可以类似下面这种,provider 服务的编码参考 Dubbo-go demo 就可以了。
下面是服务启动的 main 方法代码:
Dubbo-go RPC 服务网关设计
一般使用 Dubbo,provider 端需要暴露出接口和方法,consumer 端要十分明确服务使用的接口定义和方法定义,还有入参返参类型等等信息,还需要基于 provider 端提供的 API,两端才能正常通信调用。
然而网关的使用场景是并不关心要调用的接口的详细定义,网关只关注要调用的方法、传递的参数、能接收返回结果就可以了,实现网关代理的基础是 Dubbo/Dubbo-go 的泛化调用特性。
下面是 Dubbo-go 官方给的 demo,泛化服务加载后需要等待 3 秒才能完成调用,然而在实际使用的时候肯定是不能实时加载服务去等待 3 秒,所以在网关应用启动时就需要加载缓存好需要泛化调的服务。
经过对 Dubbo-go 泛化调用 demo 的研究,发现用该特性设计 dubbo-go 网关是可行的,难点在于我们需要把每一个需要网关代理 RPC 服务方法的参数以及服务的路径等配置获取到并缓存起来,这样才能在调用前初始化好泛化调用服务,一个服务的配置如下。
由于是用 go 语言做的网关代理,所以不能通过 Java 的 jar 包来获取到 Java RPC 服务配置,如果通过人工维护的话工作量太大,而且易出错,显然是不可接受的。经过一段时间的了解,Java 服务可以通过注解来实现配置的获取,Java 端在方法上加上注解后启动服务的时候会将配置信息通过消息发送到 MQ,网关消费这些消息来实现获取 Java RPC 服务的配置。
Dubbo Go 的 RPC 服务由于 go 语言不支持注解,所以我经过思考自己写了一个扫描代码的小工具,在每个 RPC 服务方法前加上对应的注释,通过对注释的扫描来获取 RPC 服务的配置,获取到配置后在项目目录内生成 RPC 服务配置,启动应用的时候读取配置发送到 MQ。
网关代理实现之后还可以在网关的基础实现更多的功能,比如 token 验证、白名单、限流、熔断、日志监控功能,网关代理请求实现效果如下:
容器化部署
公司内部的容器化部署环境为阿里云的 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)
...
}
作者:曾凡维, 一个有 9 年服务端业务开发经验的一线程序员,曾在腾讯阅文等多家公司担任后端开发工程师,目前就职杭州开课啦教育科技有限公司,从事 go 语言服务基础架构和中间件及部分业务开发工作。
原文链接
本文为阿里云原创内容,未经允许不得转载
开课啦 dubbo-go 微服务升级实战的更多相关文章
- Dubbo学习系列之六(微服务架构实战)
看了最近文章的反馈,似乎波澜不惊的样子,应该是看官觉得都是小菜,那我就直上硬菜,人狠话不多,开始!准备:Idea201902/JDK11/ZK3.5.5/Gradle5.4.1/RabbitMQ3.7 ...
- 传统保险企业基于 Dubbo 的微服务实践
本文整理自中国人寿保险(海外)股份有限公司深圳中心技术总监家黄晓彬在 Dubbo 社区开发者日深圳站的现场分享. 中国人寿保险(海外)股份有限公司负责香港.澳门.新加坡和印尼的业务开发,和国内业务不同 ...
- 《Spring Cloud与Docker微服务架构实战》配套代码
不才写了本使用Spring Cloud玩转微服务架构的书,书名是<Spring Cloud与Docker微服务架构实战> - 周立,已于2017-01-12交稿.不少朋友想先看看源码,现将 ...
- springcloud与docker微服务架构实战--笔记
看了<微服务那些事>之后,Spring boot和Spring Cloud的关系理清楚了,Spring cloud各个模块的作用也了解了. 但是,Spring cloud 与Docker的 ...
- 《Spring Cloud微服务 入门 实战与进阶》
很少在周末发文,还是由于昨晚刚收到实体书,还是耐不住性子马上发文了. 一年前,耗时半年多的时间,写出了我的第一本书<Spring Cloud微服务-全栈技术与案例解析>. 时至今日,一年的 ...
- Spring Cloud微服务安全实战_00_前言
一.前言: 一直以来对服务安全都很感兴趣,所以就学习.这是学习immoc的 jojo老师的 <Spring Cloud微服务安全实战课程>的笔记,讲的很好. 课程简介: 二.最终形成的架 ...
- Spring cloud微服务安全实战_汇总
Spring cloud微服务安全实战 https://coding.imooc.com/class/chapter/379.html#Anchor Spring Cloud微服务安全实战-1-1 课 ...
- Spring Cloud与Docker微服务架构实战 PDF版 内含目录
Spring Cloud与Docker微服务架构实战 目录 1 微服务架构概述 1 1.1 单体应用架构存在的问题1 1.2 如何解决单体应用架构存在的问题3 1.3 什么是微服务3 1.4 微服务 ...
- CODING DevOps 微服务项目实战系列第一课,明天等你
CODING DevOps 微服务项目实战系列第一课<DevOps 微服务项目实战:DevOps 初体验>将由 CODING DevOps 开发工程师 王宽老师 向大家介绍 DevOps ...
- CODING DevOps 微服务项目实战系列第二课来啦!
近年来,工程项目的结构越来越复杂,需要接入合适的持续集成流水线形式,才能满足更多变的需求,那么如何优雅地使用 CI 能力提升生产效率呢?CODING DevOps 微服务项目实战系列第二课 <D ...
随机推荐
- 用免费GPU部署自己的stable-diffusion项目(AI生成图片)
2021年时出现了 openAI 的 DALL,但是不开源.2022年一开年,DALL-E 2发布,依然不开源.同年7月,Google 公布其 Text-to-Image 模型 Imagen,并且几乎 ...
- r-nacos v0.4.0版本发布
r-nacos是一个用 rust重新实现的nacos. r-nacos比java实现的nacos更轻量.快速.稳定:合适在开发.测试.受资限服务等环境平替nacos服务使用. r-nacos v0.4 ...
- Linux安装Oracle12C及一些参考
目录 安装 系统配置 安装前装备 安装依赖包 创建用户和组 修改内核参数 修改系统资源限制 创建安装目录及设置权限 设置oracle环境变量 安装Oracle 一些参考 compat-libstdc+ ...
- Oracle 索引原理
B-Tree索引 一个B树索引只有一个根节点,它实际就是位于树的最顶端的分支节点. 可以用下图一来描述B树索引的结构.其中,B表示分支节点,而L表示叶子节点. 对于分支节点块(包括根节点块)来说,其所 ...
- Springboot访问html页面
项目结构如图 1.html页面创建 在原有的项目resouces目录下创建static包,并在static下创建pages,然后在pages包下index.html. index.html内容 < ...
- 感悟:FPGA的串行及并行设计思路
前言 FPGA设计过程中, 会遇到大量的串行转并行或者并行转串行的问题; 这些问题主要体现在FPGA对于速度和面积的均衡上; 一般而言, FPGA使用并行的设计可以提高处理的速度, 消耗更多的资源; ...
- GFLV2:边界框不确定性的进一步融合,提点神器 | CVPR 2021
GFLV2基于GFLV1的bbox分布进行改进,将分布的统计信息融入到定位质量估计中,整体思想十分创新和完备,从实验结果来看,效果还是挺不错的 来源:晓飞的算法工程笔记 公众号 论文: Gener ...
- 我们正在被 DDoS 攻击,但是我们啥也不干,随便攻击...
最近,一场激烈的攻防大战在网络世界悄然上演. 主角不是什么国家安全局或者黑客组织,而是一家名不见经传的创业公司--TablePlus. DDoS 攻击者们摩拳擦掌,跃跃欲试.他们从四面八方蜂拥而至,誓 ...
- #线性dp#CF1110D Jongmah
题目 分析 考虑三个 \((i,i+1,i+2)\) 可以用 \((i,i,i)\) 和 \((i+1,i+1,i+1)\) 和 \((i+2,i+2,i+2)\) 代替, 所以这样的三元组本质上最多 ...
- #斜率优化,单调栈#洛谷 5504 [JSOI2011] 柠檬
题目 分析 设\(dp[i]\)表示前\(i\)个贝壳可以获得的最大收益, 则\(dp[i]=\max\{dp[j-1]+S(c[i]-c[j]+1)^2\}[s_i==s_j]\) 可以发现当且仅当 ...