CSDN|语雀的技术架构演进之路( 二 )

  • 丰富的云计算基础服务 , 保障语雀的服务端可以选用最适合语雀业务的的存储、队列、搜索引擎等基础服务;
  • 更多人工智能服务给语雀的产品带来了更多的可能性 , 包括 OCR 识图、智能翻译等服务 , 最终都直接转化成为了语雀的特色服务;
而在应用层 , 语雀的服务端依然还是以一个基于 Egg 框架的大型的 Node.js Web 应用为主 。 但是随着功能越来越多 , 也开始将一些相对比较独立的服务从主服务中拆出去 , 可以把这些服务分成几类:
  • 微服务类:例如多人实时协同服务 , 由于它相对独立 , 且长连接服务不适合频繁发布 , 所以我们将其拆成了一个独立的微服务 , 保持其稳定性 。
  • 任务服务类:像语雀提供的大量本地文件预览服务 , 会产生一些任务比较消耗资源、依赖复杂 。 我们将其从主服务中剥离 , 可以避免不可控的依赖和资源消耗对主服务造成影响 。
  • 函数计算类:类似 Plantuml 预览、Mermaid 预览等任务 , 对响应时间的敏感度不高 , 且依赖可以打包到阿里云函数计算中 , 我们会将其放到函数计算中运行 , 既省钱又安全 。
随着编辑器越来越复杂 , 在 slate 的基础上进行开发遇到的问题越来越多 。 最终语雀还是走上了自研编辑器的道路 , 基于浏览器的 Contenteditable 实现了富文本编辑器 , 通过 Canvas 实现了表格编辑器 , 通过 SVG 实现了思维导图编辑器 。 CSDN|语雀的技术架构演进之路
本文插图
语雀的这个阶段(也是现在所处的阶段)是商业化阶段 , 但是我们仍然保持了一个很小的团队 , 通过 JavaScript 全栈进行研发 。 底层的服务全面上云 , 借力云服务打造语雀的特色功能 。 同时为企业级用户和个人知识工作者者提供知识创作和管理工具 。
和函数计算的不解之缘语雀是一个复杂的 Web 应用 , 也是一个典型的数据密集型应用(Data-Intensive Application) , 背后依赖了大量的数据库等云服务 。 语雀服务端是 Node.js 技术栈 。 当提到 node 的时候 , 可能立刻就会有几个词浮现在我们脑海之中:单线程(single-threaded)、非阻塞(non-blocking)、异步(asynchronously programming) , 这些特性一方面非常的适合于构建可扩展的网络应用 , 用来实现 Web 服务这类 I/O 密集型的应用 , 另一方面它也是大家一直对 node 诟病的地方 , 对 CPU 密集型的场景不够友好 , 一旦有任何阻塞进程的方法被执行 , 整个进程就被阻塞 。 像语雀这样用 node 实现整个服务端逻辑的应用 , 很难保证不会出现一些场景可能会消耗大量 CPU 甚至是死循环阻塞进程的 , 例如以 markdown 转换举例 , 由于用户的输入无法穷举 , 总有各种可能让转换代码进入到一个低效甚至是死循环的场景之中 。 在 node 刚出世的年代 , 很难给这些问题找到完美的解决办法 , 而即便是 Java 等基于线程并发模型的语言 , 在遇到这样的场景也很头痛 , 毕竟 CPU 对于 web 应用来说都是非常重要的资源 。 而随着基础设置越来越完善 , 当函数计算出现时 , node 最大的短板看起来有了一个比较完美的解决方案 。 阿里云函数计算是事件驱动的全托管计算服务 。 通过函数计算 , 您无需管理服务器等基础设施 , 只需编写代码并上传 , 只需要为代码实际运行所消耗的资源付费 , 代码未运行则不产生费用 。 把函数计算引入之后 , 我们可以将那些 CPU 密集型、存在不稳定因素的操作统统放到函数计算服务中去执行 , 而我们的主服务再次回归到了 I/O 密集型应用模型 , 又可以愉快的享受 node 给我们带来的高效研发福利了!以语雀中遇到的一个实际场景来举例 , 用户传入了一些 HTML 或者 Markdown 格式的文档内容 , 我们需要将其转换成为语雀自己的文档格式 。 在绝大部分情况下 , 解析用户输入的内容都很快 , 然而依然存在某些无法预料到的场景会触发解析器的 bug 而导致死循环的出现 , 甚至我们不太敢升级 Markdown 解析库和相关插件以免引入更多的问题 。 但是随着函数计算的引入 , 我们将这个消耗 CPU 的转换逻辑放到函数计算上 , 语雀的主服务稳定性不会再被影响 。


推荐阅读