OpenTSDB容器化之路

一.何为OpenTSDB?

官方表述是:基于HBase的分布式、可伸缩的时间序列数据库。

主要用途,做监控系统;譬如收集大规模集群(包括网络设备、操作系统、应用程序)的监控数据并进行存储、查询。

OpenTSDB是对外通信的无状态的服务器,在收到监控数据后,将数据写入到HBase。

二.YMM-TSDB v1架构

如下图,部署了多个OpenTSDB节点组成集群,上层使用阿里云SLB封装了一个写IP:Port和一个读IP:Port。

所有业务都使用写IP:Port向OpenTSDB写入数据,而读IP:Port主要用在Grafana里为绘制图表取数,同时也在少量报表JOB中使用。

这种架构可以满足监控的基本需求,但是缺点也非常明显:

  • 阿里云SLB有坑 当某个业务有大量数据的写或大范围的读时,通过SLB转到后端某个OpenTSDB进程上,可能会引发该OpenTSDB进程的OOM,如果Client源单一,阿里云SLB会继续把请求发向出问题的OpenTSDB进程,于是出现读写失败问题,此现象在Grafana上尤其明显,因为Grafana只部署在一台ECS上,即Client源单一。
  • 读写不分离 由于读和写是都通过阿里云SLB指向同一套OpenTSDB集群的,当这些OpenTSDB进程出现请求量异常时,无法明确是由写造成的还是读造成的,特别是聚合操作的读请求,不会有很大的网络OUT流量,但会引发OpenTSDB进程向HBase读取很多数据进行计算,使得网络IN流量突增,让我们误以为是读请求。
  • 业务不做分离 多个业务使用相同的写IP:Port和读IP:Port访问OpenTSDB,当某个OpenTSDB进程出故障时,无法定位到是哪个业务引发的,同时由于OpenTSDB进程失损,还会对其他业务的读写造成影响,激起连锁反应。 以上三点原因,让我们很难维护好OpenTSDB集群,每当OpenTSDB进程出现问题时,都可能重启,而无法定位到问题源予以彻底解决。

三.YMM-TSDB v2架构 - 容器

为了解决上述问题,首先想到的就是拆分OpenTSDB集群,并做业务分离。即让每个业务使用各自的OpenTSDB集群,可是还不够,还要做读写分离,这就变成每个业务要两套OpenTSDB集群。

于是我们面临以下问题:

  1. 没有那么多ECS部署OpenTSDB进程,一台ECS部署多个OpenTSDB进程,又有资源竞争问题,还要配置端口。
  2. 即使部署了这么多OpenTSDB进程,也没法有效管理,每个业务2读2写至少4个OpenTSDB进程,5个就得是20个OpenTSDB进程。
  3. 阿里云SLB有坑,如何让业务程序访问OpenTSDB呢,将多个IP:Port提供给业务吗,业务代码是否支持呢,已上线的业务还得改代码。
  4. 高可用是空白,还没有任何保障机制,当一个OpenTSDB进程出问题时,另一个OpenTSDB进程顶上,不影响到业务。
  5. 负载水平扩展,能不能做到在多个OpenTSDB进程间平摊业务访问量,比如一个特别大的业务,我们可以用多个OpenTSDB进程吃下。
  6. 自愈功能,我们不想去手动重启OpenTSDB进程,能不能检测到它挂了,就自动重启,I’m back!

如何破?容器化!

如果我们将OpenTSDB进程容器化后 :

1.不再需要那么多机器。一个容器就是一个OpenTSDB进程,端口也不用变,CPU和Mem完全独立,能够通过K8S Configmap进行配置,我们默认配置为1Core 4GB Mem。

2.部署便捷快速。制定出OpenTSDB的Docker镜像后,通过K8S Deployment方式能迅速建起数套OpenTSDB容器集群,并且K8S命令就可以完成对每套容器集群的管理。

3.每套容器集群包含多个容器。我们默认为4个,这些容器又分部在多个K8S节点上,我们使用K8S Service在多个容器上提供HA,使用阿里云SLB在多个K8S Node间实现HA。

4.每套容器集群中的多个容器可以实现负载分摊。K8S Deployment可以实现容器数量动态增加,负载水平扩展问题完美解决。

5.K8S容器自带自愈功能。当检测到OpenTSDB进程无响应时,可自动重启容器,其他存活容器可继续提供服务,不影响业务。

于是我们有如下新的架构图:

  • 将写入拆分成四套容器:opsmonitor(运维监控脚本)、opsfalcon(falcon基础指标监控)、onlineservice(除大数算法外的所有线上服务监控数据)、bdalg(大数据&算法专用)。
  • 将读取拆分成两套容器:grafana_read(grafana读,不包含大数算法)、bdalg_read(大数算法读)。

四、必要的K8S概

1.Kubernetes 简介

Kubernetes是Google基于Borg开源的容器编排调度引擎,作为CNCF(Cloud Native Computing Foundation)最重要的组件之一,它的目标不仅仅是一个编排系统,而是提供一个规范,可以让你来描述集群的架构,定义服务的最终状态,Kubernetes可以帮你将系统自动地达到和维持在这个状态。作为云原生应用的基石,Kubernetes相当于一个云操作系统,其重要性不言而喻。

2.使用资源类型说明:

  • Deployment Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController 来方便的管理应用。
  • Configmap 许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。这些配置信息需要与docker image解耦,你总不能每修改一个配置就重做一个image吧?ConfigMap API给我们提供了向容器中注入配置信息的机制,ConfigMap可以被用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。
  • Service Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector(查看下面了解,为什么可能需要没有 selector 的 Service)实现的。
  • PodDisruptionBudge 应用程序所有者可以为每个应用程序创建一个 PodDisruptionBudget 对象(PDB)。PDB 将限制在同一时间自愿中断的复制应用程序中宕机的 Pod 的数量。例如,基于定额的应用程序希望确保运行的副本数量永远不会低于仲裁所需的数量。Web 前端可能希望确保提供负载的副本的数量永远不会低于总数的某个百分比。
  • Taint和Toleration Taint(污点)和 Toleration(容忍)可以作用于 node 和 pod 上,其目的是优化 pod 在集群间的调度,这跟节点亲和性类似,只不过它们作用的方式相反,具有 taint 的 node 和 pod 是互斥关系,而具有节点亲和性关系的 node 和 pod 是相吸的。另外还有可以给 node 节点设置 label,通过给 pod 设置 nodeSelector将 pod 调度到具有匹配标签的节点上。Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod 上,则表示这些 pod 可以(但不要求)被调度到具有相应 taint 的节点上。
  • nodeLabel Label是附着到object上(例如Pod)的键值对。可以在创建object的时候指定,也可以在object创建后随时指定。Labels的值对系统本身并没有什么含义,只是对用户才有意义。Kubernetes最终将对labels最终索引和反向索引用来优化查询和watch,在UI和命令行中会对它们排序。不要在label中使用大型、非标识的结构化数据,记录这样的数据应该用annotation。

3.YMM-TSDB v2容器内部架构

五、简单介绍下实现方式

1.第一阶段,通过Taint(污点)、Toleration(容忍)、nodeSelector、nodeLabel、externalTrafficPolicy等k8s特性,将中间件节点与线上其他业务进行隔离。

a. Taint和Toleration,创建驱逐策略,将业务应用驱逐出该节点,集群内新生成pod不会调度到该节点,配合yaml中tolerations,实现该opentsdb pod不被该节点驱逐,命令举例如下:

$ kubectl taint nodes prod.op.k8s.mdnode-00.hz dedicated::NoSchedule-
$ kubectl taint nodes prod.op.k8s.mdnode-00.hz dedicated=opentsdb:NoSchedule

b.节点标签,创建节点标签,标示节点,用于筛选节点,配合yaml中nodeSelector,实现分配pod到指定节点,命令举例如下:

$ kubectl label nodes prod.op.k8s.mdnode-00.hz opentsdb=true

c. Deployment yaml配置,配合上面驱逐策略、节点标签,最终实现只有yaml中配置以下策略的应用能够在该节点启动,其他应用将不被调度到该节点,配置举例如下:

tolerations:
- key: "dedicated"
operator: "Equal"
value: "opentsdb"
effect: "NoSchedule" nodeSelector:
opentsdb: "true"

2.第二阶段,容器化opentsdb,使用Deployment定义yaml,通过env标签自定义HeapSize大小,利用探针对opentsdb使用httpGet进行健康检查。

a. 健康检查,用于检测opentsdb是否正常运行,配置举例如下:

livenessProbe:
httpGet:
path: /
port: 4242
initialDelaySeconds: 600
periodSeconds:
failureThreshold: 3

b. 环境变量,用于往image中传递参数,实现自定义heap size,配置举例如下:

env:
- name: HBASE_HOME
value: "/opt/hbase/bin/"
- name: JVMXMX
value: "-Xmx4096m"

c. 滚动升级,滚动升级中,将先启动新pod再销毁老pod,配置举例如下:

strategy:
rollingUpdate:
maxSurge: 10%
maxUnavailable: 0
type: RollingUpdate

3.第三阶段,加入监控sidecar,将原有opentsdb监控脚本进行容器化,跟随opentsdb主进程启动,通过localhost访问opentsdb进程,传入监控数据。

a. 容器化监控脚本,容器化原有opentsdb监控脚本,配置举例如下:

#FROM python:2.7.15-alpine3.6
COPY requirements.txt /requirements.txt
RUN pip install -r /requirements.txt
COPY src /app
WORKDIR /app
CMD ["sh", "/app/start.sh"]

b. Deployment yaml添加sidecar,实现监控sidecar,监控进程跟随主进程启动,与主进程共享namespace,使用localhost直接访问主进程,配置举例如下:

- name: monitoring
image: harbor.ymmoa.com/monitoring/opentsdb-monitoring:v0.0.4
imagePullPolicy: Always
command: ["sh","/app/start.sh"]

六、上线后遇到的问题

1.Service 类型配置不当导致opentsdb crash 解决方法:起初service配置使用NodePort默认选项,进行压测pod状态一直正常,准备在node上面加一层SLB作为负载均衡,但是通过SLB压opentsdb就出现pod随机CRASH的现象。随后,调整Service 参数externalTrafficPolicy: Local,故障随后接触,通过SLB可以正常查询数据。 参数说明:service.spec.externalTrafficPolicy 的值为 Local,请求就只会被代理到本地 endpoints 而不会被转发到其它节点。这样就保留了最初的源 IP 地址。如果没有本地 endpoints,发送到这个节点的数据包将会被丢弃。这样在应用到数据包的任何包处理规则下,你都能依赖这个正确的 source-ip 使数据包通过并到达 endpoint。

2.TSDB向后端HBase发送compaction请求,导致HBase执行该操作时跑满网卡 解决方法:对HBase配置了hbase.hstore.compaction.throughput.lower.bound和hbase.hstore.compaction.throughput.higher.bound参数后,限制HBase执行compacte操作时可用的带宽,以避免跑满网卡而影响正常的读写操作 参数说明:hbase.hstore.compaction.throughput.lower.bound, 合并占用吞吐量下限;hbase.hstore.compaction.throughput.higher.bound,合并占用吞吐量上限。

七、全新监控图表

K8S节点监控

TSDB容器监控

TSDB监控

作者: 满帮集团技术保障部冷振国、朱慧君、王杰

  • 发表于:
  • 本文为 InfoQ 中文站特供稿件
  • 首发地址https://www.infoq.cn/article/DNYrUpgMmw7aRFggxKDY
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券