spark streaming 应用实例数据可视化

150 阅读3分钟

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战」。

先前做了一个 spark steaming 的简单实例,把用户的行为信息做了一个简单的统计,之后输出到了 redis 。当时我们只是做了输出操作还没有具体的使用它输出的数据。

甚至可以说当时留下了一个问题,因为spark streaming 它采用的是分区的分布式计算,而输出的输出的时候我们是让每个分区自行输出每一条记录,这会造成数据是以分成碎片的形式到达 redis 消息总线的。

现在我们要做数据的可视化就需要自行的收集这些数据了,假定数据是按顺序到达的,我们先前做的小实例的间隔是 5s ,这足够保证这一点了。

先前也说过为输出添加处理时间戳,这样每个段数据可以看作是下面这样

timestamp,label,value

那么可以预见的是这里数据会类似于我们输入数据流一样,而标识不同数据段的是所谓时间戳。如果我们把这个时间戳当作键,它可以转化成我们经常做的流处理操作,同样也是 groupby ,不过好消息是,这个 groupby 不用做其他的操作。 那么它其实就相当于我们先前写过的有序序列的分组(因为时间戳实际上是递增的)。

假设使用 go 来写,推送方式使用以前提及过的 EventSource 方法,redis 连接客户端使用 go-redis v8 ,可以这样书写代码。

	oneRecord := make(map[string]int) //数据
	curKey := ""
	for msg := range ch { # 这里是接受消息的 channel
		entities := strings.Split(msg.Payload, ",")
		key := entities[0]
		if key == curKey {
			//储存数据
			value, _ := strconv.Atoi(entities[2])
			oneRecord[entities[1]] = value
		} else {
			if curKey != "" { // 推送数据
				value, _ := strconv.Atoi(entities[2])
				oneRecord["timestamp"] = value
				jsonData, _ := json.Marshal(oneRecord)
				_, _ = w.Write([]byte(fmt.Sprintf("event: message\ndata: %s \n retry: 5000\n\n ", jsonData)))# EventSource帧格式
				f.Flush() # ;刷新缓冲区,推送数据
			}
			curKey = key
                        value, _ := strconv.Atoi(entities[2])
			oneRecord[entities[1]] = value
		}
	}

为了收集数据,这里使用了一个哈希表,把每种行为的数据都收集起来了,然后当切换到下一个 key ,也就是下一波数据达到时,推送先前的数据发送到浏览器。

然后到浏览器端,反而简单了,对于浏览器而言,它接受到的数据其实都是完整的几个值记录。而且在浏览器中,EventSource 的设计是回调函数的形式,那么要做的就是解析成json数据,把数据添加到y轴数据的数组中,然后顺便调用 echart 的 setOption 刷新图标就可以了。

这样整个数据就连通了,在服务端中稍微饶了点弯,因为没有使用数据库。不过也算是完成了处理结果的实时显示。还有一个小问题是由于推送数据依赖下一个被处理数据的到达,会造成数据一个延迟。在这里只有5s左右的时间,相对来讲可以接受,如果有更长的延迟,则需要换一些其他的处理方式了。