前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >干货 | 浅谈Node.js在携程的应用

干货 | 浅谈Node.js在携程的应用

作者头像
五月君
发布2019-08-06 14:16:17
9460
发布2019-08-06 14:16:17
举报
文章被收录于专栏:Nodejs技术栈

作者简介

潘斐斐,携程无线平台研发部高级研发工程师。2008年加入携程,目前负责携程Node.js技术栈的基础平台研发工作。

携程在2017年9月份正式上线了Node.js应用,本文主要介绍近两年Node.js技术栈在携程的应用和体系情况。

一、技术栈

1.1 应用部署

应用部署主要分为以上四个步骤:Develop-> Build ->Release -> Publish

  • Coding阶段会使用脚手架和中间件开发应用,中间件后面会介绍到。
  • Build Docker会负责源码的构建功能,包括一些C++模块的编译和集成环境,同时会设置构建的缓存机制。
  • Release Docker负责应用的启动和运行,相对轻量级,更需要关注的是Docker的数量、CPU、内存等基础信息。
  • Publish负责应用启动之后的健康检查,健康检查完成之后会将Docker拉入集群并提供外部访问。

1.2 版本选择

在Build阶段,会选择Node.js的版本。提供了三个固定版本分别是v6.10.2,v8.9.4 和 v10.15.1。目前 v6.10.2 版本已经基本进入非维护阶段,并逐步更新下线,版本的更迭与Node.js官方几乎保持同步,为保证性能最优,推荐优选最新的LTS。

当时选择Node.js固定版本是考虑到编译环境的简单和稳定性。Node.js中间件和第三方库都需要做预编译,为了保证编译环境的简单和应用稳定,会选择固定的某一个版本。

同时针对这3个固定的版本,中间件发布的时候,也会一并提供window/linux/mac这3个平台预编译的包。Linux预编译包是为了Build Docker和Release Docker准备的,windows和mac预编译的包是为了开发工程师本地开发的时候准备的。

1.3 构建原则

“靠前构建原则”

如果能在线下编译的尽量线下编译,不要在运行构建。例如:

  • C++模块的预编译
  • 访问SOA或者数据库的环境配置
  • Babel或者TS

二、运维与监控

2.1 Docker化

Node.js应用部署在Docker上,采用Nginx+PM2的模式。

2.2 核心指标

Nginx会监控整个Docker上所有应用的情况:

1)CPU util:CPU总的使用率

2)CPU throttle count&time:CPU被限制的次数和CPU使用率被限制的总时间。这两个指标的上升一般表示应用有CPU密集型操作,需要检查一下是否有大量的计算等操作。

3)Mem RSS used:这个指标上升一般显示应用内存泄漏的问题。

4)HTTP imcoming&outgoging:http request的数量变化趋势。如果有错误响应或者超过了告警的阈值,则会在趋势图中显示。

5)Connection reset:这个指标如果上升,表示应用出现了大量的拒绝请求,例如是服务器的并发数超过了原本的承载量等原因。

Nginx中监控的是整个Docker的情况,但是我们更需要的是监控应用的指标。

应用一般采用PM2 cluster – i max模式启动,最大化利用CPU。

1)Heartbeat(心跳信息)

每个worker一分钟发送一次Heartbeat(心跳信息)给到CAT数据中心。一般来说,如果Heartbeat告警的话,需要立刻查看一下错误日志,是不是有异常错误导致进程已经退出了。

Heartbeat主要包括CPU、Memory、网络信息等。这些信息和上述提到的Nginx信息不是一个维度的。这个更细节的关注了应用的情况,而不是整个Docker的情况。如果需要分析应用细节的问题,是需要查看这里的Heartbeat信息。

2)性能情况

一般来说,中间件会处理应用常规的性能日志记录。包括:

  • 每一个响应的请求耗时(服务端逻辑处理耗时,不包括网络耗时)
  • 每一个Transaction的耗时。一个Transaction可以简单理解为一个有功能意义的代码片段。
  • 跨应用调用的请求耗时

3)错误/告警信息

错误告警信息是应用中需要重点关注的,包括:

  • 应用逻辑出错,例如处理JSON数据出错等。
  • HTTP请求出错,会记录状态码、请求地址、返回内容
  • 应用中使用了不同版本的同一个包,会报一条告警信息通知开发工程师

4)详细数据日志

详细数据日志一般有开发工程师针对应用的逻辑埋点,而非中间件统一处理。这些日志会包括返回数据的记录,具体运行在哪一段transaction中。这些日志一般是故障发生时,用来复盘时的辅助手段。

2.3 监控模型

一开始的监控日志是扁平化的,只能看到一条一条简单的日志,但无法将他们的关系串联起来。为了方便排障,设计了调用树的模型,可以将应用中的多个transaction串联起来。

2.4 日志排障

应用发布上线后,需要关注系统的保障通知。经常遇到的故障是发现随着时间的推移,Mem RSS Used这根线会不停的飙升。

遇到这种情况,基本猜测是发生了Memory-Leak(内存泄漏)。我们需要分析heapdump来定位具体的问题点。

不建议在应用中定期发送heapdump的信息来监控,比较消耗内存。所以我们一般在发布到测试阶段,发现问题之后,采样几个不同时间点heapdumpsnapshot进行比对。使用的是开源的heapdump。

首先将两份snapshot文件加载到chrome中,查看statistics,对比这里的内存变化和Docker中的内存变化。

如果两者的变化一致,那么就说明内存泄漏的确发生在Heap区域,那么就可以进行两份snapshot的对比。

如果两者变化不一致,Docker变化量明显比Heapdump的多,那么就说明内存泄漏可能出现非Heap区域(堆外内存区域),需要查看一下snapshot中Buffer的数量是否有变化,是不是buffer导致的,或者查看一下Node.js的官方的changelog是否有提到memory issue。

三、公共服务

3.1 服务调用

SOA client:SOA客户端主要负责调用JAVA/.NET/Node.js等各技术栈的SOA服务。主要服务于数据聚合的场景。

3.2 存储服务

1)Ceph(资源存储客户端),主要存储静态资源,包含JS/CSS/图片等;

2)Redis(Redis客户端),为应用提供Redis缓存服务;

3)Kafka (消息系统) 消息生产者和消费者;

3.3 缓存服务

缓存中间件Cache主要解决以下问题:

实现跨进程共享内存和跨进程锁。(参考开源模块node-shared-cache )

3.4 公共业务

1)监控模块目前携程Node.js支持三种场景的日志

  • 场景一:CAT日志埋点,树状结构展示日志,监控服务运行快慢、监控异常、以及自定义事件监控告警。目前携程CAT已开源 CAT
  • 场景二:可通过特定事件、特定时间、特定tag值过滤查询日志
  • 场景三:可基于时间序列查看各种性能数据聚合结果,如统计某个中间件使用次数、某请求结果的平均值等。

2)foundation-framework基础模块

  • 为不同环境下所有应用提供统一的获取AppId、环境等基础配置的API
  • 提供IPv4、IPv6的检查和IPv6的全地址转换

3)qconfig-client 该中间件支持从携程内部服务配置中心获取不同文件类型的配置,支持配置热更新。

4)携程Node.js还提供:获取mysql数据库连接信息、ABTest、pm2跨进程通讯等功能模块。

3.5 DR (Disaster Recovery)

为支持DR,nodeJS中间件做以下处理:

1)服务连接失败重试机制。

2)通过IP地址访问服务时,需定时重新获取服务IP地址。

3)同一服务存在多个IP地址时,依次通过不同IP地址访问服务,直到成功或全部失败。

4)特定数据缓存。

在某个服务器宕机或某个IDC机房毁坏情况下,目前nodeJS中间件大部分无需任何操作,可自动恢复;部分中间件需重启应用,以保证应用可用性和数据的实时性。

四、应用场景

4.1 DA(DataAggregation)

图3 Introduction of BFF(Backend for Frontend)

(摘自https://www.jianshu.com/p/eb1875c62ad3)

DA这一层主要的功能是能够提升加载速度,降低重复的数据逻辑处理。

在DA之前,前端展示一般需要请求多条服务做数据聚合。更复杂的情况是,如果需要适配多个平台(Web/Android/IOS),那么就需要服务写多个接口,造成重复的开发和维护工作。

DA主要负责将数据做逻辑处理,包括缓存、展示限制等,为前端提供更轻量级的服务。

本着“服务自治,服务于UI”的原则,我们用前端工程师更熟悉的JavaScript开发是非常合适的选择,可以降低学习和开发成本,带来更大的灵活性和高效性。实践下来,引入了数据聚合层之后,性能提升在20%左右。

4.2 SSR(Server-SideRendering)

服务端在携程的引入主要考量有几点:

1)SEO的.NET+V8的老架构

2)SPA模式首屏性能问题

3)JS技术栈陈旧等诸多问题

4)不同平台重复编码,无法实现代码同构

所以设计一套SSR的框架来解决历史问题,最终带来了30%的开发效率提升和20%的性能优化。

目前携程的SSR框架是NFES,感兴趣的同学可以点击详细了解。

4.3 内部工具

Node.js技术栈的内部工具,主要在几个方向:

1)构建工具,例如发布平台中的Node.js应用的构建工具

2)跨平台的GUI的工具,一般基于electron框架开发

3)静态资源的发布

五、小结

经过一年多的积累,携程已经上线500+的应用。这一年多,我们比较关注的方向是中间件建设和应用性能的监控优化,后续将计划实践一些Node.js技术栈的框架建设和工程化方向,希望能通过更稳定的基础设施,探索新的应用场景,提升开发效率。

作者简介

潘斐斐,携程无线平台研发部高级研发工程师。2008年加入携程,目前负责携程Node.js技术栈的基础平台研发工作。

携程在2017年9月份正式上线了Node.js应用,本文主要介绍近两年Node.js技术栈在携程的应用和体系情况。

一、技术栈

1.1 应用部署

应用部署主要分为以上四个步骤:Develop-> Build ->Release -> Publish

  • Coding阶段会使用脚手架和中间件开发应用,中间件后面会介绍到。
  • Build Docker会负责源码的构建功能,包括一些C++模块的编译和集成环境,同时会设置构建的缓存机制。
  • Release Docker负责应用的启动和运行,相对轻量级,更需要关注的是Docker的数量、CPU、内存等基础信息。
  • Publish负责应用启动之后的健康检查,健康检查完成之后会将Docker拉入集群并提供外部访问。

1.2 版本选择

在Build阶段,会选择Node.js的版本。提供了三个固定版本分别是v6.10.2,v8.9.4 和 v10.15.1。目前 v6.10.2 版本已经基本进入非维护阶段,并逐步更新下线,版本的更迭与Node.js官方几乎保持同步,为保证性能最优,推荐优选最新的LTS。

当时选择Node.js固定版本是考虑到编译环境的简单和稳定性。Node.js中间件和第三方库都需要做预编译,为了保证编译环境的简单和应用稳定,会选择固定的某一个版本。

同时针对这3个固定的版本,中间件发布的时候,也会一并提供window/linux/mac这3个平台预编译的包。Linux预编译包是为了Build Docker和Release Docker准备的,windows和mac预编译的包是为了开发工程师本地开发的时候准备的。

1.3 构建原则

“靠前构建原则”

如果能在线下编译的尽量线下编译,不要在运行构建。例如:

  • C++模块的预编译
  • 访问SOA或者数据库的环境配置
  • Babel或者TS

二、运维与监控

2.1 Docker化

Node.js应用部署在Docker上,采用Nginx+PM2的模式。

2.2 核心指标

Nginx会监控整个Docker上所有应用的情况:

1)CPU util:CPU总的使用率

2)CPU throttle count&time:CPU被限制的次数和CPU使用率被限制的总时间。这两个指标的上升一般表示应用有CPU密集型操作,需要检查一下是否有大量的计算等操作。

3)Mem RSS used:这个指标上升一般显示应用内存泄漏的问题。

4)HTTP imcoming&outgoging:http request的数量变化趋势。如果有错误响应或者超过了告警的阈值,则会在趋势图中显示。

5)Connection reset:这个指标如果上升,表示应用出现了大量的拒绝请求,例如是服务器的并发数超过了原本的承载量等原因。

Nginx中监控的是整个Docker的情况,但是我们更需要的是监控应用的指标。

应用一般采用PM2 cluster – i max模式启动,最大化利用CPU。

1)Heartbeat(心跳信息)

每个worker一分钟发送一次Heartbeat(心跳信息)给到CAT数据中心。一般来说,如果Heartbeat告警的话,需要立刻查看一下错误日志,是不是有异常错误导致进程已经退出了。

Heartbeat主要包括CPU、Memory、网络信息等。这些信息和上述提到的Nginx信息不是一个维度的。这个更细节的关注了应用的情况,而不是整个Docker的情况。如果需要分析应用细节的问题,是需要查看这里的Heartbeat信息。

2)性能情况

一般来说,中间件会处理应用常规的性能日志记录。包括:

  • 每一个响应的请求耗时(服务端逻辑处理耗时,不包括网络耗时)
  • 每一个Transaction的耗时。一个Transaction可以简单理解为一个有功能意义的代码片段。
  • 跨应用调用的请求耗时

3)错误/告警信息

错误告警信息是应用中需要重点关注的,包括:

  • 应用逻辑出错,例如处理JSON数据出错等。
  • HTTP请求出错,会记录状态码、请求地址、返回内容
  • 应用中使用了不同版本的同一个包,会报一条告警信息通知开发工程师

4)详细数据日志

详细数据日志一般有开发工程师针对应用的逻辑埋点,而非中间件统一处理。这些日志会包括返回数据的记录,具体运行在哪一段transaction中。这些日志一般是故障发生时,用来复盘时的辅助手段。

2.3 监控模型

一开始的监控日志是扁平化的,只能看到一条一条简单的日志,但无法将他们的关系串联起来。为了方便排障,设计了调用树的模型,可以将应用中的多个transaction串联起来。

2.4 日志排障

应用发布上线后,需要关注系统的保障通知。经常遇到的故障是发现随着时间的推移,Mem RSS Used这根线会不停的飙升。

遇到这种情况,基本猜测是发生了Memory-Leak(内存泄漏)。我们需要分析heapdump来定位具体的问题点。

不建议在应用中定期发送heapdump的信息来监控,比较消耗内存。所以我们一般在发布到测试阶段,发现问题之后,采样几个不同时间点heapdumpsnapshot进行比对。使用的是开源的heapdump。

首先将两份snapshot文件加载到chrome中,查看statistics,对比这里的内存变化和Docker中的内存变化。

如果两者的变化一致,那么就说明内存泄漏的确发生在Heap区域,那么就可以进行两份snapshot的对比。

如果两者变化不一致,Docker变化量明显比Heapdump的多,那么就说明内存泄漏可能出现非Heap区域(堆外内存区域),需要查看一下snapshot中Buffer的数量是否有变化,是不是buffer导致的,或者查看一下Node.js的官方的changelog是否有提到memory issue。

三、公共服务

3.1 服务调用

SOA client:SOA客户端主要负责调用JAVA/.NET/Node.js等各技术栈的SOA服务。主要服务于数据聚合的场景。

3.2 存储服务

1)Ceph(资源存储客户端),主要存储静态资源,包含JS/CSS/图片等;

2)Redis(Redis客户端),为应用提供Redis缓存服务;

3)Kafka (消息系统) 消息生产者和消费者;

3.3 缓存服务

缓存中间件Cache主要解决以下问题:

实现跨进程共享内存和跨进程锁。(参考开源模块node-shared-cache )

3.4 公共业务

1)监控模块目前携程Node.js支持三种场景的日志

  • 场景一:CAT日志埋点,树状结构展示日志,监控服务运行快慢、监控异常、以及自定义事件监控告警。目前携程CAT已开源 CAT
  • 场景二:可通过特定事件、特定时间、特定tag值过滤查询日志
  • 场景三:可基于时间序列查看各种性能数据聚合结果,如统计某个中间件使用次数、某请求结果的平均值等。

2)foundation-framework基础模块

  • 为不同环境下所有应用提供统一的获取AppId、环境等基础配置的API
  • 提供IPv4、IPv6的检查和IPv6的全地址转换

3)qconfig-client 该中间件支持从携程内部服务配置中心获取不同文件类型的配置,支持配置热更新。

4)携程Node.js还提供:获取mysql数据库连接信息、ABTest、pm2跨进程通讯等功能模块。

3.5 DR (Disaster Recovery)

为支持DR,nodeJS中间件做以下处理:

1)服务连接失败重试机制。

2)通过IP地址访问服务时,需定时重新获取服务IP地址。

3)同一服务存在多个IP地址时,依次通过不同IP地址访问服务,直到成功或全部失败。

4)特定数据缓存。

在某个服务器宕机或某个IDC机房毁坏情况下,目前nodeJS中间件大部分无需任何操作,可自动恢复;部分中间件需重启应用,以保证应用可用性和数据的实时性。

四、应用场景

4.1 DA(DataAggregation)

图3 Introduction of BFF(Backend for Frontend)

(摘自https://www.jianshu.com/p/eb1875c62ad3)

DA这一层主要的功能是能够提升加载速度,降低重复的数据逻辑处理。

在DA之前,前端展示一般需要请求多条服务做数据聚合。更复杂的情况是,如果需要适配多个平台(Web/Android/IOS),那么就需要服务写多个接口,造成重复的开发和维护工作。

DA主要负责将数据做逻辑处理,包括缓存、展示限制等,为前端提供更轻量级的服务。

本着“服务自治,服务于UI”的原则,我们用前端工程师更熟悉的JavaScript开发是非常合适的选择,可以降低学习和开发成本,带来更大的灵活性和高效性。实践下来,引入了数据聚合层之后,性能提升在20%左右。

4.2 SSR(Server-SideRendering)

服务端在携程的引入主要考量有几点:

1)SEO的.NET+V8的老架构

2)SPA模式首屏性能问题

3)JS技术栈陈旧等诸多问题

4)不同平台重复编码,无法实现代码同构

所以设计一套SSR的框架来解决历史问题,最终带来了30%的开发效率提升和20%的性能优化。

目前携程的SSR框架是NFES,感兴趣的同学可以点击详细了解。

4.3 内部工具

Node.js技术栈的内部工具,主要在几个方向:

1)构建工具,例如发布平台中的Node.js应用的构建工具

2)跨平台的GUI的工具,一般基于electron框架开发

3)静态资源的发布

五、小结

经过一年多的积累,携程已经上线500+的应用。这一年多,我们比较关注的方向是中间件建设和应用性能的监控优化,后续将计划实践一些Node.js技术栈的框架建设和工程化方向,希望能通过更稳定的基础设施,探索新的应用场景,提升开发效率。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Nodejs技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 携程在2017年9月份正式上线了Node.js应用,本文主要介绍近两年Node.js技术栈在携程的应用和体系情况。
    • 一、技术栈
      • 二、运维与监控
        • 三、公共服务
          • 四、应用场景
            • 五、小结
            • 携程在2017年9月份正式上线了Node.js应用,本文主要介绍近两年Node.js技术栈在携程的应用和体系情况。
              • 一、技术栈
                • 二、运维与监控
                  • 三、公共服务
                    • 四、应用场景
                      • 五、小结
                      相关产品与服务
                      容器镜像服务
                      容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档