基于OpenResty和Node.js的微服务架构实践

news/2024/7/8 2:30:33 标签: java, lua, javascript

什么是微服务?

传统的单体服务架构是单独服务包,共享代码与数据,开发成本较高,可维护性、伸缩性较差,技术转型、跨语言配合相对困难。而微服务架构强调一个服务负责一项业务,服务可以单独部署,独立进行技术选型和开发,服务间松耦合,服务依赖的数据也独立维护管理。虽然微服务存在部署复杂、运维难度较大、分布式事务控制难、容错要求高等缺点,但总体而言,微服务的优点远大于其复杂性。

图片描述

微服务架构需要注意哪些问题?

微服务架构,首先考虑客户端与服务端之间的通信问题。有两种解决办法,一是客户端与多个服务端直接进行通信,但存在对外暴露接口细节、众多接口协议无法统一、客户端的代码复杂、服务端升级相对困难等问题。二是客户端访问统一的API网关,由API网关调用众多服务接口,易实现统一通信协议,降低客户端和服务端代码耦合,也可以达到统一的鉴权和流控,然而此方式存在延时增加的风险,可能使API网关成为系统发展的瓶颈。

图片描述

微服务架构是分布式服务架构,如何进行服务的注册和发现也是需要解决的问题。一种是通过客户端发现,调用方需要知道所有依赖服务的地址,开发成本较高,协议升级比较困难。另一种是通过统一网关发现具体服务的地址,对客户端来说实现比较简单,能够在网关进行统一鉴权和流控,要求网关高度可用性。

图片描述

调用微服务尽可能做到有序,避免相互调用,杜绝循环调用。服务间要有清晰的层次关系,上层服务可以依赖下层服务,如果遇到下层服务需要同步消息给上层调用方的情况,可以考虑通过消息队列异步解耦,比如订单/审核系统在创建订单或者改变订单状态时,可以考虑使用双写(即写入数据库后,同时在消息队列也写一份),异构系统(比如订单执行系统)可以通过订阅消息保存异构数据。

个推在微服务上有哪些实践?

个推的服务场景主要有三种。其一是个推推送场景,通过Java语言开发,SOA的架构方式来实现,保证信息推送的实时性与高并发性,这块微服务改造比较困难;其二是广告交易平台,比如投放平台、DMP数据管理,以Java为主进行开发,对并发数要求较高,我们在逐步进行基于Java的微服务框架的微服务化尝试;其三是web业务系统,它为前端提供无状态的业务API接口,是典型的request/response方式,同时,这是我们目前微服务实践最多的场景。

图片描述

随着业务快速发展,公司web相关的业务系统开发需求不断增加,这些系统都涉及到用户管理,后台管理,权限管理等。为进一步提高团队开发效率,我们对服务进行平台化、模块化改造,选择了如上的技术选型。

图片描述

个推的整体架构如上图所示。请求先经过LVS/HaProxy,到达基于OpenResty实现的API网关,API网关会根据请求将流量upstream到服务单元。服务单元作为一个整体,支持通过Lua、Node.js、Java等语言实现业务逻辑,启动时向Zookeeper注册,API网关会从Zookeeper获取服务单元部署信息。

图片描述

服务单元如上图所示。它由Openresty统一对外暴露服务端,Openresty内置了lua语言,可以在weblua框架中通过编写lua程序来进行业务逻辑处理。Openresty通过proxy_pass,upstream将请求转给webnode处理,也可以在Openresty中通过配置处理Java业务逻辑。服务单元就像一个抽屉柜,具体的业务(app)就像一个抽屉,只要尺寸符合抽屉柜的要求,就能将抽屉推入到抽屉柜中,抽屉所用的语言不作要求。

图片描述

Openresty集成了lua脚本作为编程语言,使用Zookeeper服务注册。为了解决lua与Zookeeper不适配问题,在Openresty启动时启动websocket服务,Node.js进程启动时同步启动websocket的client,这样每个Node.js进程会和Openresty保持长连接和心跳,Openresty会选择一个Node.js进程,启动Zookeeperclient完成服务注册。API网关也是基于服务单元通过类似的方式实现完成服务注册的。

图片描述

服务单元在Openresty层完成了统一鉴权,不会产生额外的性能开销。

我们可以用“通道化”来阐述服务间的调用问题。我们将微服务之间的调用比喻成水管,从水管的一端流进去的是请求信息,那么从另一端流出来的也应该是请求信息,我们只要求流入流出的信息保持一致,而不关心这些信息在传输过程中经过了转换或其他过程。如上图,A、B之间的调用通过进程内require就能实现,而A、C间的调用是通过服务单元内的http完成的。

Q&A

Q:微服务架构在运维部署是否会很麻烦?

A:随着微服务的不断推进,服务数量势必会越来越多,这就需要考虑DEVOPS。比如代码提交之后通过Jenkins自动触发打包编译,自动生成版本号,进而触发自动测试部署和自动化测试,测试通过后进行一键部署升级、支持升级失败自动回滚等。我们目前已经实现了自动打包和测试部署,后续环节正在推进。

Q:Openresty里对Session管理进行了处理,开发人员会不会觉得不方便?

A:在引入微服务框架之前,公司有很多独立业务服务,每个服务都有自己的账号系

统实现登录验证逻辑。虽然有现成的代码模块可以用,但每次都需要重新测试验证。如今,具体的业务服务都可以通过Openresty完成鉴权并统一对外,对开发和测试人员来说,反而减少了一定的工作量。


http://www.niftyadmin.cn/n/735342.html

相关文章

JS 前端路由:单页面应用的路由原理和实现

JS 前端路由:单页面应用的路由原理和实现 文章目录JS 前端路由:单页面应用的路由原理和实现简介参考完整示例代码正文从页面刷新到路由跳转单页面应用的优劣前端路由分类前端路由实现项目架构Hash 实现History 实现结语简介 在浏览器的默认行为中&#…

Base64 Base64URL 编码方案(附 js 代码实现)

Base64 & Base64URL 编码方案(附 js 代码实现) 文章目录Base64 & Base64URL 编码方案(附 js 代码实现)简介参考完整示例代码正文什么是 Base64?Base64 转换规则Base64URL 规则Base64 转换字符表转换规则图解在 JavaScript 中进行 Base64 编码Base64 编码 js…

获取 CSS样式

兼容写法 : 我们这个元素里面的属性很多, left top width 我们想要某个属性, 就应该 返回改属性,所有继续封装 返回当前样式的 函数。 1 var demo document.getElementById("demo"); 1 function getStyle(obj,…

JS 动画:给网页下个雪吧

JS 动画:给网页下个雪吧 文章目录JS 动画:给网页下个雪吧简介参考完整示例代码正文1. 一朵雪花2. 很多雪花3. 让雪花动起来4. 快速划过的雪花5. 雪花摇曳6. 最终效果结语简介 前些日子面试的时候被问到 raf 的问题,写了篇 JS 动画基础: 细说…

React 项目启动2:使用 webpack 手动创建 React 项目(附加 React Router + Redux)

React 项目启动2:使用 webpack 手动创建 React 项目(附加 React Router Redux) 文章目录React 项目启动2:使用 webpack 手动创建 React 项目(附加 React Router Redux)前言正文1 项目依赖1.1 选用技术栈1.2 依赖包1.3 依赖包版本号1.4 依赖包版本选用说…

jsf和facelets的生命周期

一、JSF生命周期 JSF是基于事件驱动。JSF生命周期分为两个主要阶段:执行阶段和渲染阶段。 1.执行阶段 分为六个阶段: 恢复视图阶段当客户端请求一个JavaServer Faces页面时,JavaServer Faces实现开始恢复视图阶段。 在此阶段,JSF将…

典型分布式系统分析:MapReduce

在 《分布式学习最佳实践:从分布式系统的特征开始(附思维导图)》一文中,提到学习分布式系统的一个好方法是思考分布式系统要解决的问题,有哪些衡量标准,为了解决这些问题;提出了哪些理论、协议、…

CSS 预处理器: Sass/Scss Less

CSS 预处理器: Sass/Scss & Less 文章目录CSS 预处理器: Sass/Scss & Less前言Why 预处理器?Sass?Scss?正文1. 预处理器的编译工具Less 编译Sass/Scss 编译2. Gulp 实现自动化编译3. 预处理器功能3.0 预处理器功能概述3.1 变量(Varia…