关于架构:PingCode-技术架构揭秘

10次阅读

共计 8102 个字符,预计需要花费 21 分钟才能阅读完成。

本文由 Worktile 产品研发部负责人徐海峰分享

PingCode 是一款智能化研发管理工具,由 Worktile 团队打造,对标国外的 Jira,致力于研发治理自动化、数据化、智能化,帮忙企业晋升研发效力,这款产品 2019 年 Q2 开始启动,于 2019 年底正式公布,刚公布的时候叫 Worktile 研发版,2020 年 08 月 31 日正式独立为 PingCode,那么作为一款全新的研发工具,很多人会比较关心,这款 SaaS 产品底层的技术架构到底是什么?明天由我这个在 Worktile 待了八年之久的新生代农民工给大家具体揭秘一下。

技术选型

相熟 Worktile 的敌人肯定晓得,咱们作为一家活的有点久的守业公司,始终都是应用 Node.js 作为服务端底层技术,在 2019 年之前,咱们曾经应用 Node.js 开发了 6 年之久,随同着 Node.js 从 0.x 版本升级到了最新的 14.x(当然当初官网曾经是 17.x 了),从到处 callback 的时代到大一统的asynca wait,也见证着 Node.js 基金会的分与合,Node.js 有很多长处,但同时也有很多毛病,特地是做中大型的企业级利用,没有类型零碎是一个永远的痛,好在 2018 年咱们引入了 TypeScript,这几乎就是给 Node.js 锦上添了一朵花,咱们很庆幸在 2018 年就全面转向了 TypeScript,那么作为 2019 年的工夫点开启一个新的产品,咱们毫无悬念持续 ALL IN Node.js + TypeScript,同是加上 MongoDB ​和 Redis​,几乎是绝配。

前端的技术选型也是毫无悬念,咱们是国内为数不多 Angular 动摇追捧者之一的公司,Angular 的哲学也十分合乎我司的气质,保持长期主义,谋求极致,什么招人艰难,造就人啊都不是问题,对于 PingCode 的前端想更多理解的能够查看 Worktile 前端工程化之路。

以下这张图根本笼罩了 PingCode 核心技术栈,之前一个架构叫 MEAN​ (代表 MongoDB + Express + Angular + Node.js),我感觉当初能够叫 MTAN(代表 MongoDB + TypeScript + Angular + Node.js)。

单体利用到微服务架构

Worktile 过来始终是一个单体利用,甚至过了很多年后才彻底的前后端拆散,那么 PingCode 矩阵式的产品构造状态决定了最合适的架构模式是微服务架构,每个子产品独立仓储、独立开发和独立部署,PingCode 整体的分层架构图如下所示:

我司的仓储和服务采纳的是 古希腊神话人物 命名法,所以你会看到: chaoserostyphonatlas 等古希腊人物。

微服务最难的就是如何拆分服务,纵向来看,咱们提供了一些根底的服务,别离为:

  • Atlas: 文件服务,封装 AWS S3 相干的性能,蕴含: 上传、下载、预览等和文件相干的性能,在公有部署环境下,无缝切换到 MinIO
  • Iris: 音讯服务,次要蕴含音讯告诉,Feed(实时更新告诉)相干性能,次要采纳 SocketIO 和 Redis
  • Typhon: 帐号服务,蕴含注册、登录、成员治理、受权、验证相干通用性能

PingCode 是矩阵式的子产品的构造模式,所以咱们能够很轻松的依照子产品划分微服务,当然有局部子产品之间也会有深度的耦合,所以产品状态决定了咱们能够抉择一种无脑的横向划分式。

  • Agile: 麻利开发子产品,提供 Scrum 和 Kanban 两种麻利开发的我的项目模板
  • Testhub: 测试治理子产品,提供测试用例,测试计划等和测试相干的性能点
  • Wiki:知识库子产品,企业级知识库。
  • 等等 …

咱们在 2019 年抉择微服务架构有以下两个起因:

  • 过来曾经有了 6 年的技术积攒,2018 年也开始自研了合乎咱们的 TypeScript 底层框架 CHAOS
  • 同时随着人员的壮大,须要思考一种适配多团队多组织的架构模式,微服务是必选之路

微服务架构带来的挑战

采纳微服务架构后,对于开发和运维的要求都会变高,这其实不是一个简略的架构降级,而是整个产研能力的降级,初创公司后期还是单体架构更适合,所以在抉择微服务架构之前先问一下本人:你筹备好了吗?

那么对于开发和运维来说,微服务到底带来了哪些挑战呢?

开发的挑战

微服务次要给咱们开发带来了三大挑战,别离为:

那么咱们先看看 形象 ​,形象是一个开发者十分重要的能力,这个能力决定了咱们是否能够成长为一名合格架构师,是否能够脱离业务做基础架构相干工作,过来因为单体利用过于简略,对于形象的能力要求不高,微服务后每个服务都是独立仓储、独立开发,随着复杂度的晋升,以前在单体利用下一把梭的形式就不实用了。举个例子: 注册胜利后会创立团队,团队创立后每个子产品须要初始化业务数据(比方示例我的项目)

因为注册的性能是在 Typhon 帐户服务中,帐户服务是一个被其余子产品都调用的根底服务,在单体利用下通过EventBus​发送一个告诉,其余子模块订阅进行初始化即可,甚至还能够间接调用其余模块的初始化逻辑代码,然而微服务下每个子服务是独立的,让帐户服务调用每个子产品的 RPC 会导致依赖凌乱,最终可能会引入音讯队列,每个子产品加一个初始化的服务订阅音讯队列,那么自身很简略的性能就变得复杂,微服务架构对于开发人员的要求也就进步了,开发须要站在更高的角度思考如何形象,服务间如何更好的通信等等以前在单体利用下不必思考的问题。

还有就是每个服务都是独立的,就须要把通用的根底类库以及每个服务的 SDK 抽取进去,业务根底类库的抽取须要的就是 形象 能力​,如果业务形象都做不好那如何做基础架构呢。咱们基于 TypeScript 形象了一个底层的框架CHAOS​(相当于 NestJS),同时形象了底层的业务类库EROS​和PC-CORE​,下图是根底类库相干的依赖和模块示意图。

第二个挑战就是 工程​,下面曾经提到了咱们会有多个根底类库以及服务的 SDK,这些公有类库包如何治理和公布等等一些列工程相干问题随之而来。

对于公有类库的公布,咱们一开始是应用 GitHub 的一个公有仓储作为类库的包,而后在业务中通过配置依赖的 GitHub 链接实现的,应用如下:

为此还独自开发了个发包工具公布到 git 仓储中,感兴趣的能够查看 git-publish

"dependencies: {"@worktile/chaos":"git+ssh://git@github.com:worktile/chaos-built.git#1.0.0",}

起初 GitHub 提供了仓储的公有 Package,咱们就间接应用 GitHub 的公有仓储进行包治理,这样就不必独自创立一个 built​仓储来寄存类构建后的产物了,之前还要给开发人员独自调配这个 built 仓储的权限等等。采纳 GitHub 公有包后只须要开发人员配置创立一个AccessToken​ 即可,这样只有有拜访仓储的对应权限就能够装置或者公布仓储公有包的权限。

对于工程咱们还遇到了 release​, 版本治理 ​, 分支治理​等等一系列问题,这些都是在微服务架构模式下须要一一解决的问题,没有规范的计划,适宜团队并满足以后团队需要的都是好的计划,工程问题也是咱们团队从团伙走向正规军的必经之路,所以对于开发人员来说除了写业务代码外可能还须要写开发工具,开发标准文档等等。

第三个挑战就是 合作​,每个团队负责本人的产品或者服务,服务会有依赖会有调用,那么团队之间如何合作呢?咱们把所有根底类库和 SDK 对立采纳 Kanban 的形式进行项目管理,大家都能够提交 Issue 和奉献代码,对所有人都是通明的,每个根底库都会有个负责人,次要负责 Code Review 和类库的布局,当然合作还蕴含其余方方面面,咱们采纳麻利的形式继续迭代,继续改良。

下图就是基础设施的 Kanban 我的项目示例:

以上是微服务架构对于咱们造成的三大挑战,或者对于形象,工程之类的问题你可能想到的解决方案就是 Monorepo,然而 Monorepo 也不是银弹,后期可能是最好的解决方案,然而随着仓储代码的宏大和成员的增多,也会遇到一些列的问题,比方构建慢,测试工夫长,抵触等等 Monorepo 的问题,所以咱们在三年前做了一些三年后才看到收益的事件,这也是咱们对 PingCode 产品的信念,但回过头来看,这些挑战丝毫不影响咱们产品迭代的速度,和竞品比起来丝毫不弱,甚至更强。

运维的挑战

微服务导致服务增多、仓储增多,依赖关系简单,那么对于运维来说,如何治理好这些服务就变得比拟艰难,咱们也是在 2019 年引入 Jenkins 了实现 CI、CD。

有 CI、CD 但如果没有测试根本是很难前行的,在 PingCode 的服务端中咱们也会强制每个 API 都有测试,并且业务代码的测试覆盖率必须在 80% 以上,根底类库必须要到 90% 以上,尽管测试覆盖率指标不齐全代表测试的全面性,但至多外围逻辑会被笼罩,其次对于业务耦合的服务还会有集成测试、长久化测试以及性能测试等,其实测试不是微服务带来的间接挑战,单体利用下也须要测试。

除了 CI、CD 外,所有的服务对立采纳 Kubernetes 进行容器化部署,服务的监控和预警、ELB、日志等等和运维相干的挑战都随之而来,日志存储采纳 ElasticSearch,治理和查看采纳了 Kibana。

单服务架构

微服务会把所有的服务拆分,然而对于一个单服务来说,咱们大多数子产品的架构都是相似的,除了通用的性能外,会依照模块进行划分,每个模块大抵分三层蕴含:Facade 层​(其实就是 API 或者 Controller 层,这一层只蕴含路由定义和参数输出和输入,不蕴含业务逻辑),Service 层​(畛域层,也是业务逻辑层),Repository 层​(蕴含对于数据库单个实体的增删改查操作,每个 Repository 会对于一个 Entity 实体)。

上面的代码段示意一个ProjectEntity​和ProjectRepository

@collectionName("agile_projects")
@indexes<ProjectEntity>([
    {team: Direction.ascending,}
])
export class ProjectEntity extends BusinessEntity {
    public name?: string;

    public name_pinyin?: string;

    public description?: string;

    public icon?: string;

    public color?: string;

    public identifier?: string;

    public members?: PrincipalMember[];

    @defaultValue(() => Visibility.private)
    public visibility?: Visibility;
}

@injectable()
export class ProjectRepository extends DefaultBusinessRepository<ProjectEntity> {constructor() {super(ProjectEntity);
    }
}

一个 Facade 示例代码如下:

@facade()
@middlewares(typhonClient.passport.authMiddleware(), 
 typhonClient.application.applicationExpireMiddleware(ApplicationType.agile)
)
export class ProjectFacade extends FacadeBase {@inject()
    private projectService: ProjectService;

    @post("/project", CreateProjectRequest)
    @middlewares(projectPermission.authCreateProjectMiddleware())
    public async createProject(request: CreateProjectRequest): Promise<Response<ProjectEntity, void>> {const project = await this.projectService.createProject(request);
        return new Response(project);
    }
}

对于咱们底层框架 CHAOS,这里再多介绍一下,CHOAS 提供了从利用、路由、容器再到数据拜访层的一个满足咱们业务需要的一整套企业级框架,那么对于利用和路由,咱们是基于 Koa.js 之上的二度封装,CHAOS 屏蔽了 Koa 相干 API,这样即便底层切换到 Express 或者更先进的 Web 框架对于用户来说也是无感的,其次就是 Repository 也是对于 mongodb 模块的二度封装,除此之外的一些外围性能是齐全自研的,包含:

  • Container: 容器,帮忙利用轻松实现依赖注入
  • Rpc: 微服务 RPC 通信框架
  • Reminder: 定时工作的根底类库,负责提供工作的注册、执行、错误处理等
  • 其余模块 …

    微前端架构

    和微服务架构一样,咱们也是在 2019 年引入了微前端,因为没有找到适合的微前端框架,咱们自研了 ngx-planet – 一个我认为是最好用的 Angular 框架下的微前端解决方案。以下是整个微前端的架构示意图:

Portal​ 是主利用,也叫基座利用,它负责左侧的导航、全局数据管理、告诉、搜寻等全局性能,最重要的是运行时通过 ngx-planet 实现子利用的注册、加载和销毁。

每个利用依照子产品划分,构建提供 manifest.json​ 动态资源文件列表,主利用会依据这个资源列表加载响应的脚本和款式。

那么采纳微前端架构后对于前端开发带来的挑战和微服务是相似的,我也从 形象 ​、 工程 ​和 合作​ 三方面论述一下。

第一个就是 形象​, 咱们在 2018 年曾经打造了外部的组件库,那么在 2019 年微前端后也开始须要构建业务组件库,做业务组件其实最能考验开发者的形象能力,组件库的组件能够参考别的组件库对应组件的设计和 API,然而业务组件库无从参考,咱们常常会遇到某个小伙伴吃力心理提交了一个业务组件库的 PR,后果一 Code Review 发现这个曾经反对了或者有比这更好的解决方案,所以起初咱们制订了一个标准,当你对于组件库或者业务组件提交一个新个性的时候形容一下具体的场景和需要,而后思考一下你筹备如何设计(蕴含 API 参数,命名,构造等等)而后在评论中 @一下大家,这样所有人都能够基于你的计划进行头脑风暴,最终确定一个大家感觉比较完善的计划。

在 PingCode 中咱们除了应用了第三方的 highcharts 作为报表库以外,根本没有引入过其余第三方库,不是说咱们的团队有如许的厉害,而是得益于 Angular 的 CDK , 通过 CDK 能够轻松开发组件库和业务组件库,CDK 让咱们这种前端 20 人不到的团队把 不可能​变成了 可能​(当然组价库的局部组件也会借鉴(chao) Angular Material 和 NG-ZORRO 等优良组件库的做法)。有人说咱们是 Angular 框架下国内轮子造的最多的公司,其中就蕴含:

  • Angular 微前端框架 ngx-planet
  • Angular 甘特图组件 ngx-gantt
  • Slate 框架 Angular 视图层 slate-angular
  • Angular 组件文档生成工具 docgeni
  • 简略好用的状态治理库 @tethys/store

这些都不是 KPI 我的项目,都是咱们在解决 PingCode 和 Worktile 遇到的理论业务问题,无奈 Angular 社区没有更好的计划,咱们满足了本人同时为了回馈社区开源进来了而已,咱们也会继续欠缺和迭代曾经开源的类库,开源自身对于开发来说也是一个技术挑战,做好开源我的项目其实是很不容易的。以上这些特定场景的解决方案都是形象能力的体现,PingCode 前端开发者也在做这些开源我的项目的过程晋升了形象能力。

第二个挑战是 工程​,和微服务的一样,过来没有采纳 Monorepo 间接上的微前端,具体起因就不一一说了,然而到目前为止,对于微前端带来的外围工程问题,咱们都解决了,发包采纳 GitHub 的公有 Package,一开始 Angular 编译类库特地慢,对于频繁发包的业务组件库带来了不小的挑战,随着 Angular 的降级,目前速度曾经显著回升,后续会通过 GitHub 的 Actions 做到主动发包,这样也就缩小了人工的反复操作。对于本地开发效率的晋升也始终是咱们比拟关注的问题,咱们自身有一个测试环境,所有的服务和前端利用都部署在这个外部能够拜访的测试环境中,前端的本地开发能够只启动本地服务,而后通过测试环境的 Portal 拜访本地即可,而后本地的 Portal 也能够应用测试环境的子利用,咱们的解决方案次要针对开发独自做了繁难的代理配置界面,能够间接在微前端测拦挡并代理前端资源,无需本地启动利用和装置代理工具。

对于 合作​我想说一些和技术框架无关的事件,我自己始终有对代码的极致谋求,我心愿我所在的团队不是仅仅的实现工作,而是应该想如何做到最好,技术可能失去更好的晋升,即便当初能力达不到然而肯定要有一颗谋求极致的心,所以我常常看到一些不适合的命名或者不好的设计都会提出来,同时因为团队壮大后跨团队之间沟通会更少,为了让整个团队的技术气氛更加踊跃,咱们会保持双周一次的技术分享、每日一学、外部技术周刊等等进步大家沟通能力和分享能力的事。

Angular 前端架构

采纳微前端后,单个前端的架构就变的比较简单,PingCode 每个子产品依照个性模块划分业务,每个个性模块会蕴含:pages​stores​components​、pipe​services​ 等性能,除了个性模块外还会存在一些全局的 core​shared​,这里只寄存以后子产品的通过组件和服务,跨子产品的根本都曾经在业务组件库中。

PingCode 前端除了 Wiki 编辑器这种特定畛域外,最简单的就是数据管理(也能够叫状态治理),因为产品的状态决定咱们对于数据的实时性要求十分高,保障在不刷新页面的状况下数据能够实时更新数据, 数据更新会来自首次加载、编辑和 WebSocket,Angular 状态治理能够参考我几年前写的博客 Angular 真的须要状态治理么?次要基于咱们封装的一个小型状态治理类库 @tethys/store 实现 Service + Observable​组合,多 Store 的结构图为:

数据管理中最值得一说的就是援用数据的保护,PingCode 服务端 API 只会返回原子数据,前端通过 RxJS 进行数据的聚合,基于 @tethys/store 会十分不便,有工夫我会独自写文章具体介绍一下,数据格式如下图所示:

以上是我对 PingCode 产品的技术架构揭秘,懒懒散散说了很多或者和技术架构无关的话题,心愿给读者带来一些共鸣和思考,这也是一个中小研发团队一路走来的心路历程,PingCode 技术架构未必是做的最好的架构,然而站在目前的角度看是比拟适宜的架构,咱们会放弃初心,继续前进,为研发提供更好管理工具。


最初,举荐咱们的智能化研发管理工具 PingCode 给大家。

PingCode 官网

对于 PingCode

PingCode 是由国内老牌 SaaS 厂商 Worktile 打造的智能化研发管理工具,围绕企业研发治理需要推出了 Agile(麻利开发)、Testhub(测试治理)、Wiki(知识库)、Plan(我的项目集)、Goals(指标治理)、Flow(自动化治理)、Access(目录治理)七大子产品以及利用市场,实现了对我的项目、工作、需要、缺点、迭代布局、测试、指标治理等研发治理全流程的笼罩以及代码托管工具、CI/CD 流水线、自动化测试等泛滥支流开发工具的买通。

自正式公布以来,以酷狗音乐、商汤科技、电银信息、51 社保、万国数据、金鹰卡通、用友、国汽智控、智齿客服、易快报等知名企业为代表,曾经有超过 13 个行业的泛滥企业抉择 PingCode 落地研发治理。

正文完
 0