过去的开发模型采用以后端为中心的MVC体系结构方式。 具体来说,每次项目评审时,前后端都要先约定一起接口,然后分别进行开发,开发完成后,前端向后端提供页面,后端需要配置并返回数据。 基于这种开发模式,导致了总工作量的增加,同时沟通和协调成本的消耗也非常显著。
前后端分离
为了摆脱这种过于依赖前后端的情况,(其实前端也不想每次修改和发布时都发布到后端,后端也不想每次前端只改变标题时就发布,影响服务器的稳定性)
前后端分离、最基本的2个模式有可能有中间层也有可能没有中间层。
第一,如果没有web中间层的话很简单。 提供放置在静态资源机器上的html模板。 html模板引用了所需的js和css。 访问页面时,将此静态模板返回给用户,然后运行js并在浏览器中通过ajax向api请求数据以呈现页面。
(前后端分离)
二是有节点中间层。 2009年,随着node的横向进入,将前端逐渐推向了后端。 有了node,JavaScript可以做更多的事情。
B站在最初进行前后端分离时,也确实是用第一种方法进行的。 现在仍然有https://www.bilibili.com/account/history (可以显示网页的源代码)等页面。 对于不需要seo的页面来说,是个好方法。 前端开发完成后,用webpack将对应的js和css打包并上传到cdn,将参考webpack打包的对应资源的html文件上传到专用的静态机器,进行运行时配置路由后端同学提供对应的api接口即可。 前后端分开维护,自己按自己的节奏行走,降低了页面和服务的结合度
这种方式确实是一种可以立即进行前后端分离的方法。 我们花了一段时间,在pc端使用vue进行重构,在移动端的H5端使用react进行重构。 虽然进度很快,但慢慢地也出现了弊端。
对于第一个屏幕,第一个屏幕有一个白色屏幕,因为他要等待资源加载完成才能进行渲染。 如果是单页的话还好,spa APP的话加载时间会变长,白屏的时间会严重影响用户的体验。 此外,由于国内搜索公司与spa APP不兼容,客户端呈现对seo很不友好,因此有seo需求的页面需要服务最终呈现。
(B站首页,右模块进行服务渲染,左模块未进行服务渲染) )。
那么,依赖node进行服务最终渲染被提上了日程。
选型
首先进行node框架的选定。 市面上有三种主流框架。 hapi express koa,还有一些是打包的、定制的框架。 例如,eggjs等。
我从一开始就排除了eggjs。 第一,eggjs非常强大,有很多功能,所以有一些完全不能用。 因此,他将处于或重或轻的水平。 第二,eggjs对我来说是黑匣子,如果有什么问题,需要很长时间才能解决。 (但是,有很多借鉴eggjs的地方。 果然很强)
而且剩下的三个框架,express的使用方法比较简单,文档也很多,很全面,所以选择了express。 (之后也重构了==! )
然后是前端框架的选定。 前端框架的主流有很多,所以我用react和vue,比如ng r v。 他们有可以前后同源的优势。 不需要写两个同样的逻辑,太棒了。
(同构逻辑大概是这样吧)
以前,前后端分离的时候,是在pc上用vue重新构建的,所以当然,这次的服务终端渲染也是在vue上构建并使用vue ssr。 (这也为我后来的想法埋下了伏笔)
先选一个简单的页面做样本吧。 使用tag页面吧。 (被上帝选中的孩子( https://www.bilibili.com/tag/3503159 ) ) ) )。
开发
目录结构
- client【客户端代码同种代码】
- build【构建相关】
- PC 【pc端vue项目】
- package.json
- config
- config.local.js【本地开发配置】
- dist【构建目录装载资源目录】
- server【服务器端代码】
-控制器【控制器】
-电脑
- route.js
- core [核心代码库]
- service [方法库]
-视图
- PC [vue构建后文件]
- tag.html [生成后模板]
- tag.json [构建后的bundle]
- manifest.json
- apps.js [启动项目]
最初设计时,客户端代码和服务器端代码位于同一个git库中,client包含vue的代码和webpack的包逻辑。 服务器上是服务器端的代码,使用的是类mvc结构。
Client内的vue的开发代码是参考vue ssr官方给出的例子制作的,使用createBundleRender方法
const { createbundlerenderer }=require ( vue-server-renderer ) )
const renderer=createbundlerenderer (服务器绑定,{
. } )
配置的推荐配置(参考: https://SSR.vue js.org/zh/build-config.html ) )。
简单来说,它提供了两个条目: entry-client.js。 一个主要是客户端执行条目,打包的是客户端引用代码集合manifest,另一个打包entry-server.js的是服务器端执行逻辑,集成在bundle.json中然后传达给上面的createBundleRender方法就可以了
server文件夹中的逻辑非常简单,core中包含启动项目的某些express核心代码的路由注册等逻辑。 有趣的是,我们的路由参考了eggjs的路由注册方式,使用了稍微修改和结构化的方式
配置优于代码,它将访问地址与相应的控制器相关联。
这里还有一个过滤器其实是在运行controller之前注册middlewares优先运行的。
我忽略了压力测试。 压力测试以后再说吧。
在线部署
在线部署是使用docker进行的。 配置为1C 4G配置,使用两个实例运行。 (到目前为止的镜像逻辑的构筑等不具体介绍)
此后,每天的访问量约为100W,服务器性能稳定。 在那期间,发生了故障。 也就是说,这里的一个状态与用户的登录状态有关,所以在服务器端请求接口时,需要带着cookie进行请求。 到时候忘记加了再加的话,这有点弊端很麻烦。
调用vuesssr时必须将其带到context中。 然后,需要在asyncData方法中一个接一个地传递,最后用action得到并送到api。
现在让我们再看一次tag页面。
ssr html
(我带来了不错的数据)
重建
其实不久,大约三个月吧。 node的版本迅速上升。 从7.6版开始,节点支持async/await语法糖。 不需要使用yield和*函数。 这样的话,koa对于await/async的支持是最好的。 我们果断地放弃了express,选择了koa2。
其实除了koa2支持async之外,还有一个原因就是我们koa是洋葱式的执行方式,所以我之前说过了,只有控制器的预处理,没有后处理。 像这样,我可以很容易地执行前后处理。 Koa的执行效率也优于express
正如我之前说的,选择vue为后面的重构埋下伏笔的就是这里
首先,我访问了部署中心进行项目。 部署中心是做什么用的? 记录脚本的版本号。 这样,配置中心就可以轻松控制前端页面使用的脚本版本。 更改脚本的版本号不需要重新启动和更新服务。
然后,我篡改了vue的打包组件,带来了与他打包的文件相对应的版本号(版本号为hash值)。
现在,vue前端的逻辑将更新,只需从配置中心分发到服务器端,而无需重新启动服务,就可以使用哪个版本的vue构建生成器。 一举两得。
主机设置
图中的conf是配置中心,我们的server与conf进行了长时间的连接,当conf的配置被更新时通知服务器,服务器拉动新的bundle和manifest进行渲染。 Ok太棒了
全民SSR
重构结束后,让我们再访问一个项目
主页,好的,让我们做主页吧
首页和tag页面
其实几乎一样。 没有什么特别的地方。 唯一不同的是量很大。 一天可能有1000W的访问量。 那么,在CDN的上面添加缓存,在服务器的上面也添加缓存。 破费( perfect )! ~
服务器端的缓存在文件中落地。 在收到第一个请求时渲染完成后,可以在本地写入文件,然后在下次访问时直接使用此本地文件进行渲染,而无需再次渲染。 之后,在有效期内进行控制。
在这里发现了问题。 这意味着每次更新都打包tag和index,但必须单独打包每个项目,然后单独更新。 可以通过参数控制打包哪个吗? 好的。 首先重写webpack.config.js,合并公共部分,私人分多次用package.json写
每次这样更新项目时,只需打包对应的项目即可,在访问了很多项目后,打包和开发时的热加载不会变慢。
由于访问了两层缓存,首页在线时,我们将服务从两个docker实例扩展到了六个。 ( docker扩展真的很方便。 )多亏了缓存的优点,服务器没有压力
当然首页不是像说的那样,这么随意就在线了,降级方案是必要的,降级方案多亏了vue的强大
Vue在浏览器端进行检查。 ( data-server-render=true ) ),是否在服务器端进行了渲染。 如果没有在服务器端进行渲染,客户端将再次执行逻辑进行渲染。 这样,我们在重新打包时,只需保留原始客户机渲染的index.html即可。 当然,您也应该在重新客户端执行时执行asyncData中的方法。 不这样做的话,数据会不足哦。 So easy~
接下来的一级分区和二级分区也分别被访问,虽然中途出现了一些问题,但最后一切都顺利解决了。 以后有机会的话,就其中遇到的问题再写一篇文章吧。
重建
我们的项目正在有序地从原来的静态页面客户端过渡到呈现、服务最终呈现,同时我们也在内部进行这个促销。 几个兄弟部门也因为面临我们以前的seo问题,或者想让最初的画面更快等理由,很乐意使用我们制作的车轮。 但是,我们的项目暂时没有普及性。 兄弟部门要使用,只能复制我们的库,然后删除业务逻辑,添加自己的逻辑。 成本很高。 另外,如果这边更新了什么,他们就需要手动同步,很麻烦。
我们花了一点时间。 首先,取出core核心库,与日志中心连接方式、配置中心连接方式等几种通用方法一起,制作npm包并发布在公司内部的npm源代码上,使client独立于库之外开发时不过度依赖node server .配置中心使项目支离破碎,但最终通过配置中心集中于同一服务,回到了前后端分离。 但是,不仅是前后端分离,前端独立开发的同事也带来了服务端渲染,一举两得。 设计体系结构图:
分割
顺便说一下,我们开发了两个脚手架,轻松地创建了项目,并添加了webpack配置和package.json配置
这样分割的话,项目会很干净。 前端开发前端的vue项目,服务端有npm包,便于升级和维护。 node服务也不需要一直重新启动,可以根据配置更新逻辑和热更新。
结束后,许多兄弟部门也开始访问。
压力测试
因为每个公司的情况都不一样,所以通过组件缓存、页面缓存等可以达到优化的目的,达到承载项目流量的标准。 这里说的情况是没有任何缓存时的冲压结果。
我们进行过几次不同级别的压力测量。 毕竟,性能需要满足要求。 我记得当时出版样品在线的时候,VUE在2.3.x的性能不太好。 VUE是基于虚拟DOM(vnode )实现的,是一个CPU密集型项目,压力测量时CPU很快达到100%,TPS很低,所以页面上添加的项目比较复杂,嵌套多的话,1C4G的
我看到了很多将vuessr与字符串模板进行比较的文章,他们的比较和demo一样简单,vue没有组件嵌套,性能比较可能确实相似,但是页面的复杂性上升了,组件嵌套
例如,我们的首页一、二级分区每天命中node的量和文章的量差不多,但文章用的是首页三分之一的机器。 机器的cpu和内存使用量相同。 因为文章项目使用的是字符串模板。
总结
在整个过程中,需要前端学生、后端学生的共同努力,后端api学生原本直接结合模板输出数据的方式都需要转变为api接口,这是前后端分离的基础。 对于基础设施,可以逐步发展完善。 像我们最初构建的时候一样,构建的配置文件的所有版本号都必须手动放置在配置中心,这很费时间,容易出错。 渐渐地,配置中心开放了api接口,使我们的访问变得方便,顺利地实现了配置同步的自动化。 上线的时候马上公开就可以了。
在用node做中间层的过程中,也遇到过内存泄漏、性能瓶颈等问题。 以后有机会的话,再写文章介绍吧。 在这一年里,B站发展很快,前端也有意识地在意前端的性能,把页面做得更好、更快。
从未停下脚步,我们还在路上!
王者荣耀和小兵互动是七周年的一个活动玩法,想要完成和小兵互动领取加星卡,那么就要按照下面主编提供的方法去
文章导读:现在哪个仙侠手游好?主编今天来给大家推荐一些治愈唯美的手游吧,现在哪个仙侠手游好的推荐,相信有很对
我的世界冰火传说沙蚁螫针剑怎么做很多玩家不知道,冰火传说有很多非常好用的道具武器,沙蚁螫针剑对于其他生物
在《三角战略(TRIANGLE STRATEGY)》中,安娜的定位是刺客/切后排/控制/残局收割,非常强悍的女刺客,可以在单挑敌人
在《三角战略(TRIANGLE STRATEGY)》中,强盗头子的定位是战士/坦克/前排/盗贼,特色偷道具,机动中规中矩,数值方面还
在《三角战略(TRIANGLE STRATEGY)》中,王女-科迪莉亚是第15章选择帮助王子清除残党,特色是拥有诸多强大的恢复技
时间:2022-12-26
时间:2022-12-26
时间:2022-12-26
时间:2022-12-26
时间:2022-12-26
时间:2022-12-26
时间:2022-12-26
时间:2022-12-26
时间:2022-12-26
时间:2022-12-26