如何利用微前端技术实现单体应用程序的现代化改造?在本篇教程中,我们将探讨如何将前端从单体架构当中剥离出来,并快速完成微前端架构迁移。本文作者将结合个人项目实践经验为大家介绍心得。
我们假设有这么一个单体代码库,它使用了某种后端模板引擎或者系统(例如 EJS 或者 ERB),但没有认真考虑前端的设计需求。或者更糟糕的是,前端的开发早于 SPA 的出现,或者还可能使用了类似 Ruby on Rails 那样的框架。因此,JavaScript 文件(例如.js.erb 文件或 AEM 片段等等)中可能包含了后端变量。 这种粗制滥造且各组件间紧密耦合的代码库几乎无法进行现代化升级。
我们当然希望不要再在这个单体系统中开发前端代码,我们希望转向更加 JavaScript 化的生态系统——但具体该怎么做?
大多数企业都负担不起(或者不愿负担)这种因工具淘汰带来的重写成本与停机时间。功能的演进需要开发的支持,但要保持同样的速度开发这些功能显然越来越困难。
正因如此,我们应该通过一种渐进且平滑的方式将单体逐步拆分为更多较小的部分,同时保证不让业务发生中断。
说来简单,但单体架构的拆分过程相当棘手。在进行前端迁移时需要为支持 JavaScript 的应用程序规划和开发新 api,拆分就变得尤为困难。
在等待新 API 开发和发布的过程中,前端迭代开发、微前端(MFE)实现和团队的自主行动都将陷入僵局。但真的要这样子吗? 错!我们可以对前端和后端进行解耦,让它们齐头并进。
下面将介绍一种方法,它能够顺利解耦前端,并将其移植成具有 SSR 的独立 MFE。如此一来,团队不再需要等待后端 API 被拆分成微服务或者等待后端 API 可用。这个方法叫作“由内而外替换单体”。
微前端通常包含以下两大重要依赖项:
根据我的个人经验,无论你的遗留系统属于 Rails、Java 还是.Net,用户身份认证一直是最难与单体后端进行剥离的部分。
MFE 有多种不同的架构规范。本文将重点介绍其中一种,即在后端微服务中非常流行的一个版本—— LOSA(Lots Of Small Applications,大量小应用) 。对于“由内而外”迁移来说,这是最理想的选择。
流经单体的 LOSA 请求 / 响应流
LOSA 应用(通常为微前端)属于独立的 Node.js 服务,能够在服务器端渲染网页的一部分或者某些片段。每个页面可以由多个 LOSA 服务组成。这些应用程序 / 微前端单独进行构建、部署,并运行在容器中。
上图所示为同一页面采用了三种不同的渲染方式,演示了一个增量迁移的过程。先是单体渲染页面,再过渡到 LOSA 微前端,然后变成垂直的微前端。最后,单体被彻底替换掉。
当然,单体仍然负责处理 HTTP 请求,并将最终响应发送至客户端。微前端可以放在集群的防火墙后面——仅提供给遗留系统使用,直到 API 网关和用户身份认证机制剥离完成(或者至少已经转化为 API 端点)。在此期间,我们不需要做太多的改动。
下图展示了迁移后的请求 / 响应流程。
首先,发出一个请求:
GET/POST 'https://MFEwebsite.com/parts/header?format=json
渲染页面内容需要各类数据,那些无法从已解耦端点查询到的“缺失”信息可以在请求期间以 props 的形式发送给 MFE。请求会经过一系列中间件,这些中间件负责渲染 react 应用程序,然后调用已解耦的 API,并将响应结果以 props 的形式返回。这些 props 最终将组成 window.INITIAL_STATE。
关于模板功能或者过滤器的实现方法,我向大家推荐 Hypernova。不过我自己并没用过,我已经习惯了一切自己动手,并在 Rails、Node 以及 php 后端中实现了类似的机制。但考虑到各类后端平台都有自己的特点,所以这里我就用 Hypernova 作为示例向大家讲解。
下面使用 express 实现 MFE 渲染端点:
GET/POST 'https://MFEwebsite.com/parts/header?format=json
{
html:'<div> ... </div>',
css:'/static/header.3042u3298423.css',
js:'/static/header.idhf93hf23iu.js',
initial_state:{items:[...]}
}
exportfunctionexampleRenderAPIware(req, res){
constrenderedMarkup = renderHTMLpage(
req,
this.index,
intial_state,
);
asyncRender.then(()=>{
constresponseobject = {
html: renderedMarkup,
initial_state,
js: jsResource,
css: cssResource,
};
res.status(200).end(JSON.stringify(responseObject));
});
}
发出这些初始 POST 请求的控制器也需要处理响应结果,将 JS 与 CSS 放在正确的位置,最后在遗留模板的对应位置渲染 React。之前通常由其他控制器负责处理的资产现在需要负责将脚本与样式注入到遗留标头与 body 标签的底部。请注意,单体仍然被作为布局引擎。我们也在替换其他部分,并以 React SSR 方式添加新功能。最终,这些 LOSA 应用将通过一个 MFE(或者借助 webpack 黑魔法,我自己开发了 webpack-external-import)整合在一起。
在迁移中,解耦并上线新的 API 到底会带来怎样的影响?
之前,在单体把数据传给 MFE 时,express 访问 HTTP 的请求正文。而现在,express 向 API 异步获取数据。虽然数据格式可能会发生变化,但 React 仍然能够正确获取到 props。
与旧单体相比,LOSA 架构的性能还不够好,通常需要 400 到 600 毫秒才能渲染出页面的特定部分。我们采用了异步 Worker 结构,这样就可以同时请求多项服务来渲染应用程序的不同部分(而不是渲染单个应用)。但这种作法提高了应用下线的难度,因为“生产故障”会导致侧边栏或页脚部分长时间缺失。因此,进一步拆分才是最好的选择。
我所说的 LOSA 异步 Worker 是这样的:我们使用大量的 Node 服务,每一个服务负责渲染页面的一个或多个组件。
遗留控制器(图中的灰色齿轮部分)可以将视图数据转给 POST 请求,而非后端模板引擎。回收数据机制则能够帮助后端减少支持负担。由于无需做出重大修改,后端开发人员能够腾出时间,专注于解耦数据服务,而前端也可以进行独立的开发。
视图数据被发送给了外部的 React 服务,而响应消息(包含了 HTML、样式表、初始状态以及 CSS URL)则被发送给后端模板引擎。现在,模板引擎只需要渲染 POST 请求所对应的响应,从而将视图或视图的一部分与原有单体剥离开来。
React 真的很慢!SSR 也不怎么快——因此新的 LOSA 架构解决方案无法带来理想的性能表现。我们的解决方案是: 在 React 内部进行片段缓存。
React 优化工作相当复杂,受篇幅所限,恐怕只能另起一篇文章详加说明了。总之,Graphana 数据显示,我们至少将渲染性能提高了一倍,不过轮循时间仍然很长。尽管 React 已经能够在内部快速完成渲染,但 150 毫秒的端到端时间还没有达到我们的预期。在下一篇文章中,我们将具体聊聊片段后端与片段缓存。
渲染时间一直是个麻烦事,即使是在 React 中采用了片段缓存之后,性能仍然无法令人满意。令我感到失望的是,虽然 Node.js 内部的渲染速度很快(约 20 毫秒),但整个流程仍然需要 140 到 200 毫秒才能完成。
简单来说,模板化、片段缓存与 gRPC/CQRS,移除 JSON 中臃肿的数据。React 在服务器端速度较慢,但请记住,一切拆分都只会让速度变得稍慢,而不是更快。
对于一切解决方案,如果不能在规模化场景下实现良好的成本效益,那么都将只是空谈。我们绝对不能容忍天文数字级的运营成本或者糟糕的性价比。大规模且廉价的解决方案才是好的解决方案。下面来看几点容易被忽视的成本要素:
流量: 1000 万次渲染 / 天
资源分配:
我的单线程 JavaScript 应用程序要比使用完整片段缓存的多线程后端系统更快。
架构和框架是独立的,本文仅仅是提出一种架构思路,而且这个架构也在百度的某款用户量很大的复杂前端产品中得以应用。基于这一套弹性架构并结合Vue/React的现代化开发理念,可以很好的完成高复杂度的前端系统。
软件架构(software architecture)是一系列相关的抽象模式,用于指导大型软件系统各个方面的设计。传统软件架构描述的对象是直接构成系统的抽象组件,侧重于系统的抽象、拆分、组织方式等
架构师的一个重要职责是,确保团队有共同的技术愿景,以帮助我们向客户交付他们想要的系统。在某些场景下,架构师只需要和一个团队一起工作,这时他们等同于技术引领者。在其他情况下,他们要对整个项目的技术愿景负责,通常需要协调多个团队之间,甚至是整个组织内的工作。
C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端通过数据库连接访问服务器端的数据
目的为保证服务器硬件故障时依然可用,数据依然保持并能够访问,手段:数据和服务的冗余备份以及失效转移机制,有状态 :在服务端保留之前的请求信息,用以处理当前请求(例如:session)无状态 :没有特殊状态的服务
动态应用,是相对于网站静态内容而言,是指以c/c++、php、Java、perl、.net等服务器端语言开发的网络应用软件,比如论坛、网络相册、交友、BLOG等常见应用。动态应用系统通常与数据库系统、缓存系统、分布式存储系统等密不可分。
本来没想写这个题材的,为了某某童鞋能够更好的茁壮成长,临时写一篇负载均衡的。负载均衡,大家可能听过什么3层负载均衡、4层负载均衡、7层负载均衡什么的?那这是怎么分的呢,ok,是根据osi七层网络模型来分的,例如nginx是工作在应用层
Kubernetes(k8s)是一款开源的优秀的容器编排调度系统,其本身也是一款分布式应用程序。虽然本系列文章讨论的是互联网架构,但是k8s的一些设计理念非常值得深思和借鉴,本人并非运维专家,本文尝试从自己看到的一些k8s的架构理念结合自己的理解来分析 k8s在稳定性
一般来说,除了当前的系统功能需求外,软件架构还需要关注性能、可用性、伸缩性、扩展性和安全性这5个架构要素。性能是网站的一个重要指标,任何软件架构设计档案都必须考虑可能会带来的性能问题。
本章介绍如何去构建高可用的服务,关键词:服务分级,超时设置,异步调用,服务降级,幂等性设计,一些架构设计中的常用方案,但是需要结合实际业务场景进行设计,没有一套方案能解决所有问题
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!