乐趣区

关于前端:北斗监控概述之架构篇三

用户浏览页面生产的数据,会被 SDK 整顿成 3+1 类数据,再上报给后端。后端将这些数据进行解决、存储、再加工后,被展现进去被最终的开发者生产。

当初,尽管咱们能够应用 node.js 来开发后端局部。然而,要 hold 住团体外部所有的前端监控申请,还是挺难的,要同时解决上面 3 个难点:

  • 流量大: 预计单日申请峰值可达 10 亿次
  • 数据量大:预计每日产生数据峰值可达 5TB
  • 实时性强:须要提供分钟级别的告警、剖析性能

前端开发同学是最理解前端监控零碎的需要的,然而对于海量数据处理咱们的前端团队并没有教训,那么应该怎么应答大数据的挑战呢?

咱们给出的答案是,单干。JavaScript 和 Java 团队单干,施展各自的劣势,用 JavaScript 解决业务,用 Java 解决大数据。 团队整体上分为 3 个小组:

  • SDK 小组。负责收集数据。
  • Java 小组。负责接管、预处理海量的数据(Java)。
  • 全栈小组。负责数据再加工 (node.js) 和展现(web)。

整体架构

通过 Java 和 Node 的联合,咱们的监控平台既领有高效的大数据处理能力,也领有良好适应业务疾速变动的能力,整体架构如下:

数据存储:Java 与 Node 的桥梁

Java 与 node.js 进行数据交换的桥梁就是,数据存储系统。 咱们一共用到了 4 类数据存储系统,它们各有各的偏重。咱们先简略介绍一下这 4 类数据存储系统。

MySQL Redis ElasticSearch Apache Druid
形容 关系型数据库 基于内存的键值对存储数据库 基于 Lucene 搜索引擎构建的存储 高性能的实时剖析数据库
主数据模型 Relational Key-value Search Engine Time Series DBMS
应用场景 项目表、权限表、告警表 共享缓存、分布式锁 全文搜寻 聚合剖析、告警
  • MySQL 是大家最相熟的,它是关系型数据库,相似于 Excel 的表。它的数据是一行行的存储,在咱们的业务表中用的较多。
  • Redis 在咱们的监控场景中,次要用于 Java node.js 的共享缓存,另外还有分布式锁。

    • Redis 用的是内存来存储数据的,比 MySQL 用的磁盘存储数据的性能更好,因而更适宜比拟频繁的数据操作。
  • ElasticSearch (简称 ES),在咱们的监控场景中次要用于日志的全文搜寻。

    • ES 会通过分词构建的索引间接查找,比 MySQL 要一行一行的全表扫描性能更好,因而更适宜通过谬误关键字、堆栈关键字来搜寻具体的报错信息这类场景。
  • Druid 在咱们的监控场景中次要用于日志的聚合剖析。

    • 比方 count(*),Druid 是列式存储聚合,剖析时能够间接读取一列数据,MySQL 要一行一行的全表扫描进行聚合剖析,因而 Druid 更适宜大数据的聚合剖析。

当然具体的业务场景须要具体的剖析。如果你们的业务数据量不大,不会遇到性能问题,那么 MySQL + Redis 兴许就够了,不必焦急上 ES 或 Druid 来优化性能。如果你们的业务数据量很大,PV 都破亿了,倡议架构设计的时候,就须要思考用上 ES 或 Druid。

性能架构

技术架构是整体我的项目的构造,其中设计细节必须联合性能能力更容易让大家了解,所以必须得先和大家介绍一下性能架构。

SDK 会将通用数据、性能数据、失常数据、异样数据进行上报。这些数据上报后,通过解决造成了监控平台的 5 个性能:

  • 明细查问:通过 ES 的搜寻性能能够展现某条日志的明细。
  • 轨迹查问:某个用户的浏览轨迹,包含性能、失常、异样日志记录(敏感信息须要用户受权才上报),通过 ES 将多种类型的日志按工夫程序排序,就能显示出某次用户的浏览轨迹了。
  • 我的项目看板:一个我的项目会有多种聚合指标,如 JS 异样、接口异样、白屏工夫等等,多种指标会一起申请回来,汇总一个看板中便于查看。
  • 项目分析:所谓的剖析就是异样、性能的具体散布状况,比方你能够对某个我的项目的 xx is undefind JS 谬误和通用数据中的机型关联起来,就能晓得它是在 android 还是 ios 散布的多了。将异样、性能与通用数据关联起来,就能对我的项目的某个异样、某个慢加载的机型、版本、地理位置等等通用数据进行剖析了。
  • 我的项目告警:当判断出某个指标超出阈值时,就要收回告警告诉开发者。具体会在第四篇开展。

设计细节

数据归类:Node 写 Redis,Java 读

数据是以 projectId 为维度存储在 ES、Druid 中的。但 Java 只能拿到 url,而 url 与 projectId 的对应关系是在监控平台填写的,因而须要 node.js 把 projectId 和 url 怎么关联的数据传给 Java。

projectId 与 url 怎么关联的数据,会被高频读取,所以 node.js 会把它们存在 redis。日志数据被上报时,java 就会去 redis 读最新 projectId 与 url 关联关系。再进行数据归类,并存在 ES/Druid 中。

具体的数据归类逻辑如下:

  1. 谬误日志 {error, url:”https://58.com/fang/list”}
  2. 先间接提取我的项目 ID
  3. 不存在则提取 URL “58.com/fang/list”
  4. 从 Redis HASH({“58.com/fang/list”: 3}) 中查找 ID
  5. 按我的项目 ID 维度归类

日志查问:Java 写 ES,Node 读

Java 把日志明细数据给 node.js 是通过 ES 进行的。具体的是,在 Java 数据归类后,将数据写到 ES 中。开发者在监控平台查问日志明细时,就申请 node.js,由 node.js 再申请 ES。

node.js 申请 ES 的要害参数如下:

"query": {
    "bool": {
        "filter": [{"range": {"timestamp": {"lte": 1607322167607,"gt": 1607235767606}}},
            {"term": {"projectId": 1}},
            {"term": {"type": "exception"}},
            {"wildcard": {"exception.content.keyword": "*TypeError*"}}
        ]
    }
}

在 ES 中,timestamp、projectId、exception 的索引当时就被创立了。比方,TypeError: Parameter 'url' must be a string, not object 这段文本,在 ES 外部会被分词为一个个单词,TypeError Parameter url must be a string not object,每个单词都是一个索引。这些索引组合的搜寻后果会有 0~N 条日志明细,都会被返回给 node.js。

node.js 再把数据返回给 web,在 web 中开展其中一条日志明细,并把它展现如下:

日志聚合:Java 写 Druid,Node 读

Java 把日志聚合数据给 node.js 是通过 Druid 进行的。具体的就是,日志数据被 SDK 上报给 Java,在 Java 数据归类后,将数据写到 Druid 中。开发者在监控平台查问日志聚合时,就申请 node.js,由 node.js 再申请 Druid。

node.js 申请 Druid 个别是通过 SQL 来申请的,一条申请 PV 的 SQL 如下:

SELECT 
    TIME_BUCKET(__time,'P1D','Asia/Shanghai') timestamp,
  pv  
FROM hdp_ubu_tech_wei_beidou_data  
WHERE 
    type='performance' AND
  __time>='2021-02-14T00:00:00+08:00' AND
  __time<='2021-02-14T23:59:59+08:00' 
GROUP BY 1

Druid 是为聚合剖析专门设计的工夫序列数据库。它能够对工夫进行智能的分区,比方,在下面咱们提到的 SQL 查问中,P1D 就是通知 Druid 要以天为单位分区,查问 pv 返回的就是一天的 pv。你能够更改配置,以小时、分钟进行分区,查问 pv 返回的就是一小时或一分钟的 pv。

日志聚合:聚合数据流转的整个流程

Druid 会对原始数据做预聚合,放慢查问的速度。示例如下:

node.js 把读取回来的数据返回给 web,由 web 展现如下(小时维度的 pv uv 数据):

退出移动版