从Spark-Streaming谈数据库性能改进

当前业务场景中Mongodb的IOPS经过压测后的最大峰值为20000/s,在系统上线后,通过mongostat工具监控发现操作数经常会飙升至30000+。由于主要的操作是Spark流处理业务的insert操作,因此本文主要从Spark-Streaming方面来讨论优化Mongodb的性能。

spark-streaming 限速

背景

业务的主要流程是flower->kafka->spark-streaming->Mongodb
采集端现状:
由于采集器端flower的业务限制,基本的采集频率为分钟级别,同时,由于flower采用C语言开发的单机程序,将采集的数据发送到kafka时存在性能瓶颈(因为一台采集器要发送多种数据,量大且种类繁多),也就将数据进行了压缩,每100条数据压缩成1条发送到kafka。
spark-streaming现状
流处理部分则是使用了1分钟甚至10分钟窗口来获取kafka的数据,最后写入到mongodb中。
Mongodb现状
mongodb采用了主从模式,使用容器的形式部署,限制了内存和存储。通过iostat工具发现mongodb所处的磁盘%util长时间处于100%

分析

将mongostat工具的打印结果进行趋势绘图。命令如下

mongostat --port26000 –discover

每条数据的结果为:
在这里插入图片描述
这里只取主分片(26011、26022、26033)的观测结果,如下图所示:
shard11

shard22
shard33
从趋势来看这种写入明显存在突发的流量,为了观测这种突发情况,特意进行了隔离实验,仅运行一个Spark任务,且重新部署一套新的mongodb。而且,将Spark-Streaming的窗口时间设置为1秒,再次观察mongodb的写入趋势。为了简洁起见,这次只看主分片的总趋势:
one-spark-mongodb-insert
发现将流的窗口设置为1秒了,数据依然呈现出突发的写入情况,这个是我们所不希望看到的。同时监控Spark每秒从kafka收到的数据量,该收集方法是“dStream.count().print()”,不属于shuffle,因此不影响性能。
spark-streaming收集数据量
该图中前期存在消费不规律,这是因为当前kafka消费组中存在资源堆积。而在多次窗口消耗掉kafka堆积的数据后,则明显的呈现出规律性。即这个主题的数据是每分钟发送一次的。这个从上图中能够看到每次数据的波动正好是1分钟。
现在就能够解释清楚突发写入的主要原因了。spark的窗口短时间内从kafka中接受到100条数据,每条数据在写入数据库前要分解为100条(原来是100倍压缩),那么突发写入量就是10000条,而且这是一个spark作业的写入量。也就不难解释从Mongodb侧观察到的突发写入现象。

解决方案

为此考虑到对spark从kafka接收的数据量降低,修改变量为
“spark.streaming.kafka.maxRatePerPartition=10”(原来业务设置为3000),表示每秒spark的分区从kafka最多拉取10条数据,本测试中kafka共四个分区,而Spark使用了kafka的分区,也就是最多拉取40条数据。
限速为10后的mongodb-insert
从波峰和波谷角度出发,可以发现波峰比原来变低了,而且波谷的间隔减少了。由于kafka的数据是100条压缩为10条,所以看到这个插入量最大值在4000条,也就是Spark从kafka拉取了40条/秒。下面看Spark的拉取数量。
限速为10后的spark-streaming收集数据量
因此得出结论:Spark流处理的波峰是可以控制的,且时间窗口可以压缩到秒级别。
修改Spark的流处理参数“spark.streaming.kafka.maxRatePerPartition=1”,发现Spark仍然是每分区收集1条消息,如下所示:
限速为1后的mongodb-insert
该图中可以看出写入量在400左右波动,最高值有达到800,猜测这个是mongodb的延迟引起的(待考证)。实际上,400条是数据量较少的。下图显示Spark从kafka获取的数据情况。
限速为1后的spark-streaming收集数据量
可以发现Spark收集数据稳定在4条左右。那么突发流量就可以通过此方式“削峰”了。
然而实际中却存在一些取舍,如:1分钟的窗口中将A数据统计为B后,将B落盘,而且业务要求展示1分钟的数据。那么使用1秒钟的窗口仅将A数据落盘不仅提高了IOPS,也没有业务价值,这个时候不得不使用1分钟窗口。
因此该方法主要适用于简单的流处理业务进行限速。

附录

mongostat监控代码

主要方式是将mongostat工具的输出写入到一个文件中,然后使用python分析该文件

注意:文件格式要另存为utf-8格式,可以使用记事本的“另存为”方式,或者notepad++的编码设置

#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@time: 2018/12/26 11:47
@desc: 用于将mongostat工具的统计结果绘制为时间趋势图
"""
import os
import matplotlib.pyplot as plt
import numpy
import pandas


class Mongostat:
    OPT_TYPE = ["insert", "query", "update", "delete", "net_in", "net_out"]
    input_path = "E:/data/mongo/mongostat.log"
    output_path = "E:/data/mongo"

    def __init__(self, input_path, output_path):
        self.input_path = input_path
        self.output_path = output_path

    def get_mongostat(self):
        file = open(self.input_path)
        file_list = file.readlines()
        file.close()
        for lineNum, line in enumerate(file_list):
            if line.startswith("\n"):  # 删除空白行
                file_list.pop(lineNum)
        mongo_infos = 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值