Java程序员清洗数据的小故事

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 阿里云SLS YYDS,世上无难事,只要肯攀登,办法总比困难多

背景

公司在已有IM项目中开发新业务功能,后端没埋点,团队没有BI,领导提了几个数据指标,统计每天A聊天功能使用人数,B功能功能使用人数,整体功能使用人数,还有就是最离谱的,要统计一次消息发送在服务器内消耗的时间。

了解到该项目线上有8台服务器,服务器日志存储7天,没有权限直接下载日志;接了阿里云SLS,SLS上会存120天的日志,超过天数的会放在阿里云oss 上进行冷备。

跟业务开发的同事明确日志格式以及相关指标数据提取对应的日志特征。关于消息耗时,就针对业务相关的消息,取了一百条消息的相关日志,进行取平均值,实在是不能每条都监控到。


开搞

计划

统计人数的任务

方案1,通过阿里云的sls 编写查询语句进行查询统计,下载少量日志编写代码进行验证sls 数据是否准确;

方案2,通过运维下载相关周期的日志,编写相关清洗代码,进行统计

统计耗时的任务

方案,通过上面查到的发消息人可确定消息内容,基于消息内容检索全部日志,整理贯穿服务的日志记录来计算消息转发耗时。

统计方案1 实践

阿里云sls 功能是采集服务日志,构建相关索引,提供日志聚合,搜索服务。当然其强大的支持sql 进行查询的功能,属实是强,但是也存在一定的学习成本。话不多说,来活儿了,就先想想怎么干。

image.png

既然有sls 这种神器(对我而言确实是),就直接用sls 进行搜索,这样能节省一定采集数据的时间,也不用劳烦运维同学。没有明确要哪一天的日志,我就先写一个能查出数据的语句出来。

那先基于A聊天功能实现一个搜索语句

__tag__:__path__: "/home/logs/im/MsgRcvMoblie.log" and "RCV from\:" and "groupchat" 
| select  
approx_distinct(cast(split(cast(split(content, ';') as array(varchar))[1],'from:') as array(varchar))[2]) AS num 
where content like '%hjbp%'

解释一下上面的语句:

第一行是明确日志文件以及相关日志格式,相当于明确数据源;

第二行的’|‘ 相当于linux 中的管道,这样就可以通过sql 对前面的数据源进行格式化;

第三行使用到了sls 支持的几个函数,具体可以通过阿里云日志服务帮助文档 搜索查看;

第四行使用了支持的like 模糊查询。

以上语句按一天的时间范围执行下来查询结果是不精确的。

image.png

为了能精确一些,想着一天我分三次查询缩小时间范围是可以做到精确查询的,那么这个语句就是可用的了,接下来进行验证逻辑的编写。

直接通过sls 是可以下载少量日志的,而且是csv 格式的,通过Java 让我从心底里抵触,就选择了5年前学了点儿皮毛的python 进行处理。大概的处理跟上面语句很类似,只是数据源比较多,通过pandas 库很快的读取csv 文件中的日志,并且方便处理成文件。

很快啊,验证的结果也是类似的贴一下我low low的代码

# 获取有关发消息各个指标数据
def get_data():
    # 读取日志
    f = open('D:/work/log/downloaded_data.txt',encoding='UTF-8')
    # 设置一个set 存用户id
    hjbp = set()
    for line in f:
        jSon = json.loads(line)
        content = jSon['content']
        # 获取符合标准的数据,有了上面sls 的准备写起来也就轻松了
        if content.__contains__('RCV from') and content.__contains__('groupchat') and  content.__contains__('hjbp'):
            hjbp.add(str.split(str.split(content,";")[0],"from:")[1])
    print("hjbp:", len(hjbp))
#main 函数执行
if __name__ == '__main__':
    get_data()

跟运维要了一天的数据,然后执行对比sls 查到的结果,一比一完美复刻,嗯,阿里云sls yyds。

上面这代码,Java 也是可以实现的啊,怎么就非得用python呢?实际上,我写完sls 的查询语句后,直接实现第二个任务,就是统计耗时的任务了,耗时任务实现中详解。

可天不遂人愿,产品需求是要30天的数据,sls 上述语句,5个指标分别执行,一天一个指标要执行3次,30天,我好崩溃,这5*3*30 查询次数谁顶得住啊,sls 咋这么废物啊。赶紧想解决方案,好在写了验证脚本,方案一其实已经实现了大半的方案二功能。在上述脚本中增加mysql 中的group by 功能即可实现,哈哈哈。不禁佩服起自己的严谨。

# 获取有关发消息各个指标数据
def get_data():
    # 读取日志
    f = open('D:/work/log/downloaded_data.txt',encoding='UTF-8')
    # 设置一个set 存用户id
    hjbp = set()
    # 声明两个list
    date = []
    bplist = []
    t = "2022-03-23"
    for line in f:
        jSon = json.loads(line)
        content = jSon['content']
        nt = time.strftime('%Y-%m-%d', time.localtime(int(jSon['__time__'])))
        if not(t.__eq__(nt)):
            date.append(t)
            bplist.append(len(hjbp))
            t = nt
            hjbp.clear()
        # 获取符合标准的数据,有了上面sls 的准备写起来也就轻松了
        if content.__contains__('RCV from') and content.__contains__('groupchat') and  content.__contains__('hjbp'):
            hjbp.add(str.split(str.split(content,";")[0],"from:")[1])
    # 字典中的key值即为csv中列名 输出到csv
    dataframe = pd.DataFrame({'date': date, 'bpcount': bplist, 'sjcount': sjlist, 'tmcount': tmlist, 'pccount': plist, 'cyjcount': cyjlist})
    dataframe.to_csv("D:/work/log/test.csv", index=False, sep=',')
#main 函数执行
if __name__ == '__main__':
    get_data()

好在第一次跟运维要数据,给的是跨天的24小时数据,还能基于sls 验证一下这个脚本的实用性,完美。

可数据来源又成了问题,一天的日志100多m,30天的日志数据下载,无疑也是对运维工作难度的强迫,谁让咱心善呢,那sls 肯定开放api 吧,我写脚本基于写好的语句进行调用,不禁对自己更加佩服了。

api 调用的权限走工单,开好了发现不能用,运维那边还有事儿,我先准备好调用的代码,可没权限无法验证写的脚本是否能用。巧妇难为无米之炊,实在无奈,情况急转直下,眼看不能如期交付任务,一个比较好的运维弟弟给我带来了曙光。帮我提了一个阿里云的工单,跟工作人员反馈之后,建议点开sql 增强就行了。

赶紧实验,打开下图的sql 增强,点开之后会提示有费用,果然,阿里云就是这么会挣钱。实验下来,确实精准查30天你的数据也是可以的。

image.png

__tag__:__path__: "/home/logs/im/MsgRcvMoblie.log" and "RCV from\:" and "groupchat" 
| select 
  approx_distinct(cast(split(cast(split(content, ';') as array(varchar))[1],'from:') as array(varchar))[2]) AS bpnum ,date_format(__time__,'%Y-%m-%d') as d 
  where content like '%hjbp%' group by d  order by d 

优化最开始的查询语句,加上按天归集的group by 语句,搜索范围改成一个月,非常不错,sls yyds 哈哈哈哈。至此,圆满完成相关指标的统计,这要自己一个劲儿的搜,不得累死啊。

耗时任务

当写完sls 语句的时候,我觉得已经完成了大半的任务,接下来,搞这个耗时的吧,本来想着搜到相关数据之后,在sls 上直接看,肉眼找到接收时间跟发送时间,然后作差。当我搜了10条日志之后,我发现不对劲儿,这tm也很累,一个多小时才搞了这么点儿。

那时候还没想着通过api 进行查询数据,先下载好日志样本,也就是那一百条消息。然后到sls 上搜,基本上能搜到相关的10几条日志,然后下载,下载下来的是csv 格式的数据。用Java 读是不是很头疼吧。我认为是比较麻烦的,就选择了用python 处理。

写脚本,下数据。

# 获取有关发消息之间差值方法
def make_data():
    ave = 0
    for info in os.listdir('D:/downloads/csv'):
        domain = os.path.abspath('D:/downloads/csv')
        fn = os.path.join(domain, info)
        content = pd.read_csv(fn,encoding='ISO-8859-1')
        max = 1
        min = 1
        for i in range(len(content)):
            stime = str(content['content'][i]).split(' ')[0].replace('_',' ')
            if 'nan' == stime:
                continue
            time = dt.datetime.strptime(stime, '%Y-%m-%d %H:%M:%S.%f').timestamp() * 1000
            if(i == 0):
                max = time
                min = time
                continue
            if(max < time):
                max = time
                continue
            if(time < min):
                min = time
                continue
        ave += max - min
    print(ave / 100)

当我把所有日志数据下载下来之后,通过这样一个函数,卡卡卡,就得到了100条日志的耗时一相加一平均,害。齐活儿。

其实上面数据是不准的,希望有机会能在现有的业务中加点儿埋点,记录好消息在服务端的耗时。

总结

世上无难事,只要肯攀登,办法总比困难多;虽然上面代码比较简陋,而且简单。为什么鄙人还好意思拿出来讲呢,实在是这种锲而不舍的精神,解决了一个又一个的难题,让我精神大好,荣光换发,而且也体会到了这种结构性的数据日志,通过代码处理起来是最轻松的。而且也不禁感叹阿里云的sls 功能强大,但是使用起来入门还是有一定的成本的,比如说帮助文档里的那么多函数。希望有一天能出现识别人语言并实现需求的AI,大家都能轻松应对工作。

大家加油!!!

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
前端开发 JavaScript Java
java常用数据判空、比较和类型转换
本文介绍了Java开发中常见的数据处理技巧,包括数据判空、数据比较和类型转换。详细讲解了字符串、Integer、对象、List、Map、Set及数组的判空方法,推荐使用工具类如StringUtils、Objects等。同时,讨论了基本数据类型与引用数据类型的比较方法,以及自动类型转换和强制类型转换的规则。最后,提供了数值类型与字符串互相转换的具体示例。
141 3
|
3月前
|
Java 程序员
JAVA程序员的进阶之路:掌握URL与URLConnection,轻松玩转网络资源!
在Java编程中,网络资源的获取与处理至关重要。本文介绍了如何使用URL与URLConnection高效、准确地获取网络资源。首先,通过`java.net.URL`类定位网络资源;其次,利用`URLConnection`类实现资源的读取与写入。文章还提供了最佳实践,包括异常处理、连接池、超时设置和请求头与响应头的合理配置,帮助Java程序员提升技能,应对复杂网络编程场景。
97 9
|
15天前
|
人工智能 Java 程序员
【AI程序员】通义灵码 AI 程序员全面上线JAVA使用体验
通过 AI 程序编写一个JAVA后台项目登陆页面
322 17
|
12天前
|
数据采集 JSON Java
Java爬虫获取微店快递费用item_fee API接口数据实现
本文介绍如何使用Java开发爬虫程序,通过微店API接口获取商品快递费用(item_fee)数据。主要内容包括:微店API接口的使用方法、Java爬虫技术背景、需求分析和技术选型。具体实现步骤为:发送HTTP请求获取数据、解析JSON格式的响应并提取快递费用信息,最后将结果存储到本地文件中。文中还提供了完整的代码示例,并提醒开发者注意授权令牌、接口频率限制及数据合法性等问题。
|
27天前
|
存储 NoSQL Java
使用Java和Spring Data构建数据访问层
本文介绍了如何使用 Java 和 Spring Data 构建数据访问层的完整过程。通过创建实体类、存储库接口、服务类和控制器类,实现了对数据库的基本操作。这种方法不仅简化了数据访问层的开发,还提高了代码的可维护性和可读性。通过合理使用 Spring Data 提供的功能,可以大幅提升开发效率。
67 21
|
7天前
|
Java API 数据处理
深潜数据海洋:Java文件读写全面解析与实战指南
通过本文的详细解析与实战示例,您可以系统地掌握Java中各种文件读写操作,从基本的读写到高效的NIO操作,再到文件复制、移动和删除。希望这些内容能够帮助您在实际项目中处理文件数据,提高开发效率和代码质量。
16 0
|
1月前
|
存储 分布式计算 Hadoop
基于Java的Hadoop文件处理系统:高效分布式数据解析与存储
本文介绍了如何借鉴Hadoop的设计思想,使用Java实现其核心功能MapReduce,解决海量数据处理问题。通过类比图书馆管理系统,详细解释了Hadoop的两大组件:HDFS(分布式文件系统)和MapReduce(分布式计算模型)。具体实现了单词统计任务,并扩展支持CSV和JSON格式的数据解析。为了提升性能,引入了Combiner减少中间数据传输,以及自定义Partitioner解决数据倾斜问题。最后总结了Hadoop在大数据处理中的重要性,鼓励Java开发者学习Hadoop以拓展技术边界。
62 7
|
1月前
|
SQL Java 数据库连接
【潜意识Java】深入理解MyBatis的Mapper层,以及让数据访问更高效的详细分析
深入理解MyBatis的Mapper层,以及让数据访问更高效的详细分析
90 1
|
1月前
|
存储 Java BI
java怎么统计每个项目下的每个类别的数据
通过本文,我们详细介绍了如何在Java中统计每个项目下的每个类别的数据,包括数据模型设计、数据存储和统计方法。通过定义 `Category`和 `Project`类,并使用 `ProjectManager`类进行管理,可以轻松实现项目和类别的数据统计。希望本文能够帮助您理解和实现类似的统计需求。
109 17
|
3月前
|
JSON Java 程序员
Java|如何用一个统一结构接收成员名称不固定的数据
本文介绍了一种 Java 中如何用一个统一结构接收成员名称不固定的数据的方法。
58 3

热门文章

最新文章