.NET LINQ分析AWS ELB日志避免996

前言

小明是个单纯的 .NET开发,一天大哥叫住他,安排了一项任务:

“小明,分析一下我们 超牛逼网站上个月的所有 AWS ELB流量日志,这些日志保存在 AWS S3上,你分析下,看哪个 API的响应时间中位数最长。”

“对了,别用 Excel,哥给你写好了一段 Python脚本,可以自动解析统计一个 AWS ELB文件的日志,你可以利用一下。”

“好的✌,大哥真厉害!”。

小明看了一下,然后傻眼了,在管理控制台中,九月份 AWS ELB日志文件翻了好几页都没翻完,大概算算,大概有 1000个文件不止。想想自己又不懂 Python,又不是搞数据分析专业出身的,这个“看似简单”的工作完不成,这周怕是陪不了女朋友,搞不好还要 996.ICU,小明几乎要流下了没有技术的泪水……

不怕!会.NET就行!

要完成这项工作,光老老实实将文件从管理控制台下载到本地,估计都够喝一壶。若小明稍机灵点,他可能会找到 AWS S3的文件管理器,然后……发现只有付费版才有批量下载功能。

其实要完成这项工作,只需做好两项基本任务即可:

  • 从 AWS S3下载9月份的所有 ELB日志

  • 聚合并分析这1000多个日志文件,然后按响应时间中位数倒排序

AWS资源

能在管理控制台上看到的 AWS资源, AWS都提供了各语言的 SDK可供操作(可在 SDK上操作的东西,如批量下载,反倒不一定能在界面上看到)。SDK支持多种语言,其中(显然)也包括 .NET

对于 AWS S3的访问, Amazon提供的 NuGet包叫:AWSSDK.S3,在 VisualStudio中下载并安装,即可运行本文的示例。

要使用 AWSSDK.S3,首先需要实例化一个 AmazonS3Client,并传入 aws access keyaws secret keyAWS区域等参数:

var credentials = new BasicAWSCredentials(	Util.GetPassword("aws_live_access_key"), 	Util.GetPassword("aws_live_secret_key"));	
var s3 = new AmazonS3Client(credentials, RegionEndpoint.USEast1);

注意:本文的所有代码全部共享这一个 s3的实例。因为根据文档, AmazonS3Client实例是设计为线程安全的。

在下载 AWS S3的文件(对象)之前,首先需要知道有哪些对象可供下载,可通过 ListObjectsV2Async方法列出某个 bucket的文件列表。注意该方法是分页的,经我的测试,无论 MaxKeys参数设置多大,该接口最多一次性返回 1000条数据,但这显然不够,因此需要循环分页去拿。

分页时该响应对象中包含了 NextContinuationTokenIsTruncated属性,如果 IsTruncated=true,则 NextContinuationToken必定有值,此时下次调用 ListObjectsV2Async时的请求参数传入 NextContinuationToken即可实现分页获取 S3文件列表的功能。

这个过程说起来有点绕,但感谢 C#提供了 yield关键字来实现 协程-coroutine,代码写起来非常简单:

IEnumerable<List<S3Object>> Load201909SuperCoolData(AmazonS3Client s3)	
{	ListObjectsV2Response response = null;	do	{	response = s3.ListObjectsV2Async(new ListObjectsV2Request	{	BucketName = "supercool-website",	Prefix = "AWSLogs/1383838438/elasticloadbalancing/us-east-1/2019/09",	ContinuationToken = response?.NextContinuationToken, 	MaxKeys = 100, 	}).Result;	yield return response.S3Objects;	} while (response.IsTruncated);	
}

注意:Prefix为前缀, AWS ELB日志都会按时间会有一个前缀模式,从文件列表中找到这一模式后填入该参数。

接下来就简单了,通过 GetObjectAsync方法即可下载某个对象,要直接分析,最好先转换为字符串,拿到文件流 stream后,最简单的方式是使用 StreamReader将其转换为字符串:

IEnumerable<string> ReadS3Object(AmazonS3Client s3, S3Object x)	
{	using GetObjectResponse obj = s3.GetObjectAsync(x.BucketName, x.Key).Result;	using var reader = new StreamReader(obj.ResponseStream);	while (!reader.EndOfStream)	{	yield return reader.ReadLine();	}	
}

注意:

  1. GetObjectAsync方法返回的 GetObjectResponse类实现了 IDisposable接口,因为它的 ResponseStream实际上是非托管资源,需要单独释放。因此需要使用 using关键字来实现资源的正确释放。

  2. 可以直接调用 StreamReader.ReadToEnd()方法直接获取全部字符串,然后再通过 Split将字符串按行分隔,但这样会浪费大量内存,影响性能。

这时一般会将这个 stream缓存到本地磁盘以供慢慢分析,但也可以一鼓作气直接将该 stream转换为字符串直接分析。本文将采取后者做法。

分析1000多个文件

每个 ELB日志文件的格式如下:

2019-08-31T23:08:36.637570Z SUPER-COOLELB 10.0.2.127:59737 10.0.3.142:86 0.000038 0.621249 0.000041 200 200 6359 291 "POST http://super-coolelb-10086.us-east-1.elb.amazonaws.com:80/api/Super/Cool HTTP/1.1" "-" - -	
2019-08-31T23:28:36.264848Z SUPER-COOLELB 10.0.3.236:54141 10.0.3.249:86 0.00004 0.622208 0.000045 200 200 6359 291 "POST http://super-coolelb-10086.us-east-1.elb.amazonaws.com:80/api/Super/Cool HTTP/1.1" "-" - -

可见该日志有一定格式, Amazon提供了该日志的详细文档中文说明:https://docs.aws.amazon.com/zh_cn/elasticloadbalancing/latest/application/load-balancer-access-logs.html#access-log-entry-format

根据文档,这种日志可以通过按简单的空格分隔来解析,但后面的 RequestInfoUserAgent字段稍微麻烦点,这种可以使用 正则表达式来实现比较精致的效果:

public static LogEntry Parse(string line)	
{	MatchCollection s = Regex.Matches(line, @"[\""].+?[\""]|[^ ]+");	string[] requestInfo = s[11].Value.Replace("\"", "").Split(' ');	return new	{	Timestamp = DateTime.Parse(s[0].Value),	ElbName = s[1].Value,	ClientEndpoint = s[2].Value,	BackendEndpoint = s[3].Value,	RequestTime = decimal.Parse(s[4].Value),	BackendTime = decimal.Parse(s[5].Value),	ResponseTime = decimal.Parse(s[6].Value),	ElbStatusCode = int.Parse(s[7].Value),	BackendStatusCode = int.Parse(s[8].Value),	ReceivedBytes = long.Parse(s[9].Value),	SentBytes = long.Parse(s[10].Value),	Method = requestInfo[0],	Url = requestInfo[1],	Protocol = requestInfo[2],	UserAgent = s[12].Value.Replace("\"", ""),	SslCypher = s[13].Value,	SslProtocol = s[14].Value,	};	
}

LINQ

数据下载好了,解析也成功了,这时即可通过强大的 LINQ来进行分析。这里将用到以下的操作符:

  • SelectMany 数据“打平”(和 js数组的 .flatMap方法类似)

  • Select 数据转换(和 js数组的 .map方法类似)

  • GroupBy 数据分组

首先,通过 AWSSDKListObjectsV2Async方法,获取的是文件列表,可以通过 .SelectMany方法将多个下载批次“打平”:

Load201909SuperCoolData(s3)	.SelectMany(x => x)

然后通过 Select,将单个文件 Key下载并读为字符串:

Load201909SuperCoolData(s3)	.SelectMany(x => x)	.SelectMany(x => ReadS3Object(s3, x))

然后再通过 Select,将文件每一行日志转换为一条 .NET对象:

Load201909SuperCoolData(s3)	.SelectMany(x => x)	.SelectMany(x => ReadS3Object(s3, x))	.Select(LogEntry.Parse)

有了 .NET对象,即可利用 LINQ进行愉快地分析了,如小明需要求,只需加一个 GroupBySelect,即可求得根据 Url分组的响应时间中位数,然后再通过 OrderByDescending即按该数字排序,最后通过 .Dump显示出来:

Load201909SuperCoolData(s3)	.SelectMany(x => x)	.SelectMany(x => ReadS3Object(s3, x))	.Select(LogEntry.Parse)	.GroupBy(x => x.Url)	.Select(x => new	{	Url = x.Key, 	Median = x.OrderBy(x => x.BackendTime).ElementAt(x.Count() / 2)	})	.OrderByDescending(x => x.Median)	.Dump();

运行效果如下:

640?wx_fmt=png

多线程下载

解析和分析都在内存中进行,因此本代码的瓶颈在于下载速度。

上文中的代码是串行、单线程下载,带宽利用率低,下载速度慢。可以改成并行、多线程下载,以提高带宽利用率。

传统的多线程需要非常大的功力,需要很好的技巧才能完成。但 .NET4.0发布了 ParallelLINQ,只需极少的代码改动,即可享受到多线程的便利。在这里,只需将在第二个 SelectMany后加上一个 AsParallel(),即可瞬间获取多线程下载优势:

Load201909SuperCoolData(s3)	.SelectMany(x => x)	.AsParallel() // 重点	.SelectMany(x => ReadS3Object(s3, x))	.Select(LogEntry.Parse)	.GroupBy(x => x.Url)	.Select(x => new	{	Url = x.Key, 	Median = x.OrderBy(x => x.BackendTime).ElementAt(x.Count() / 2)	})	.OrderByDescending(x => x.Median)	.Dump();

注意:写 AsParallel()的位置有讲究,这取决于你对性能瓶颈的把控。总的来说:

  • 太靠后了不行,因为 AsParallel之前的语句都是串行的;

  • 靠前了也不行,因为靠前的代码往往数据量还没扩大,并行没意义;

扩展

到了这一步,如果小明足够机灵,其实还能再扩展扩展,将平均值,总响应时间一并求出来,改动代码也不大,只需将下方那个 Select改成如下即可:

    .Select(x => new	{	Url = x.Key, 	Median = x.OrderBy(x => x.BackendTime).ElementAt(x.Count() / 2), 	Avg = x.Average(x => x.BackendTime), 	Sum  = x.Sum(x => x.BackendTime), 	})

运行效果如下:

640?wx_fmt=png

总结

看来并不需要 python,有了 .NETLINQ两大法宝,看来小明周末又可以陪女朋友了?

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313335.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络摄像头实时获取信息

转自&#xff1a;http://blog.csdn.net/yong_hen/article/details/42460387#quote 转自&#xff1a;http://blog.csdn.net/leo2007608/article/details/9885219 代码&#xff1a; openCV版本&#xff1a;2.4.10. 平台&#xff1a;win7 [cpp] view plaincopy #include <op…

[ASP.NET Core 3框架揭秘] 依赖注入:依赖注入模式

IoC主要体现了这样一种设计思想&#xff1a;通过将一组通用流程的控制权从应用转移到框架之中以实现对流程的复用&#xff0c;并按照“好莱坞法则”实现应用程序的代码与框架之间的交互。我们可以采用若干设计模式以不同的方式实现IoC&#xff0c;比如我们在前面介绍的模板方法…

微软100题第5题

转载自&#xff1a;http://blog.csdn.net/littlestream9527/article/details/8104731 http://blog.csdn.net/v_july_v/article/details/6370650 http://blog.csdn.net/insistgogo/article/details/7689297 下面&#xff0c;我试图用最清晰易懂&#xff0c;最易令人理解的思维…

北京Dotnet分享会 || 精英论坛第三期

编者按&#xff1a;没有一成不变的定律&#xff0c;没有长久不衰的流行&#xff0c;更没有一劳永逸的侥幸&#xff0c;只有自己刻苦努力、脚踏实地、兢兢业业的学习和工作&#xff0c;才会成为这个社会永远不会被淘汰的中流砥柱。一、昨夜西风凋碧树昨夜西风凋碧树&#xff0c;…

微软开源微服务运行时Dapr,赋能云原生应用开发

Dapr 是一个可移植的、由事件驱动的 Serverless 运行时&#xff0c;用于跨云和边缘构建分布式应用程序。10月9日&#xff0c;正式以 MIT 协议开源。Dapr 使开发人员能够轻松地构建弹性、无状态和有状态的微服务&#xff0c;让它们在云和边缘位置上运行&#xff0c;并包含了开发…

最大堆和最小堆

堆和栈的区别&#xff1a;一、堆栈空间分配区别&#xff1a;1、栈&#xff08;操作系统&#xff09;&#xff1a;由操作系统自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局部变量的值等。其操作方式类似于数据结构中的栈&#xff1b;2、堆&#xff08;操作系统&…

认知的高度 = 人生的高度

大家好&#xff0c;我是Z哥。我们每个人&#xff0c;每天要和很多不同的人打交道。我相信下面的场景每个程序员都有遇到过&#xff0c;业务方在某个模块下新提出了一个功能&#xff0c;但是你希望做新功能之前先把这个模块的低质量代码重构一下。但是&#xff0c;不管你怎么摆事…

VSCode开发.NETCore项目入门(1)设置中文语言环境

安装VSCode最新地址&#xff1a;https://code.visualstudio.com/&#xff0c;下载后安装即可配置语言环境打开安装好的VSCode软件&#xff0c;可以看到刚刚安装的VSCode软件默认使用的是英文语言环境&#xff0c;如下图&#xff1a;使用快捷键【CtrlShiftP】来配置&#xff0c;…

微软100题第11题

参照&#xff1a;http://blog.csdn.net/caryaliu/article/details/8107089 参照&#xff1a;http://blog.csdn.net/lalor/article/details/7626678 把二叉树看成一个图&#xff0c;父子节点之间的连线看成是双向的&#xff0c;我们姑且定义"距离"为两个节点之间的个…

.NET Core 3.0】框架之十三 || 部署攻略

本文有配套视频&#xff1a;https://www.bilibili.com/video/av58096866/?p9一、部署1、WIN_独立部署感谢群里&#xff08;白云&#xff09;小伙伴&#xff0c;博主 小淋科技 提出的方案(需要 netcore2.1 )&#xff0c;我竟然忽略了&#xff0c;该打该打&#xff0c;官档都读…

Python import以及os模块

转自&#xff1a;http://jianpx.iteye.com/blog/486466 http://blog.chinaunix.net/uid-27838438-id-4087978.html Import: 1. import 实际上是python虚拟机把当前的globals()和locals()传进__builtins__.__import__内置函数了&#xff0c;所以实际上干活的是那个__import__函…

.Net Core3.0 配置Configuration

准备.NET core和.NET项目配置上有了很大的改变&#xff0c;支持的也更加丰富了比如命令行&#xff0c;环境变量&#xff0c;内存中.NET对象&#xff0c;设置文件等等。.NET项目我们常常把配置信息放到webConfig 或者appConfig中。配置相关的源码https://github.com/aspnet/Exte…

asp.net core 3.0 中使用 swagger

asp.net core 3.0 中使用 swaggerIntro上次更新了 asp.net core 3.0 简单的记录了一下 swagger 的使用&#xff0c;那个项目的 api 比较简单&#xff0c;都是匿名接口不涉及到认证以及 api 版本控制&#xff0c;最近把另外一个 api 项目升级到了 3.0&#xff0c;还是遇到了一些…

由微软100题“求和不用for while”引出的static类成员的知识

转自&#xff1a;http://www.cnblogs.com/gysm/archive/2011/09/16/2179277.html C类中谈到static,我们可以在类中定义static成员&#xff0c;static成员函数&#xff01;Cprimer里面讲过&#xff1a;static成员它不像普通的数据成员&#xff0c;static数据成员独立于该类的任意…

MCN是啥?了解一下这5个互联网热词

骗子刷量&#xff0c;黑吃黑半斤八两前几天一件事火爆了互联网圈&#xff0c;一场搞笑的骗局&#xff0c;一场蜂群传媒导演的“僵尸舞台剧”&#xff1a;一条一夜爆红的视频 流量却为0&#xff01;。一个电商商家卖产品有投放需求&#xff0c;找到了微博上一家 MCN 机构的一个女…

为什么我不建议你去外包公司?

前言在我离开上家公司之前&#xff0c;我的直属领导找我聊了一番。除了问候我有没有找好下家之外&#xff0c;还千叮咛万嘱咐我千万不要去外包公司&#xff0c;否则会在简历上留下无法磨灭的污点。当时的我对于外包公司的了解并不深&#xff0c;只是道听途说外包公司很坑&#…

友浩达优选上新,原生态农产品,买得安心,吃得放心

大闸蟹还在热卖&#xff0c;需要的同学可以访问 各位一直支持队长的朋友们友浩达优选上新了本着为大家推荐好东西的想法商城里上架的商品都是队长亲自挑选有质量保证的口碑好商品这次&#xff0c;来看看队长又给大家带了哪些好东西本次上新全是各地优选原生态农产品食品优质、安…

树莓派4上跑 .NET Core 3.0,这次,真·64位!

导语前不久我写了一篇《Gentoo由于 Windows 10 IoT Core &#xff08;以及上面的UWP们&#xff09;暴尸荒野而苟且偷生使用 Linux 的我&#xff0c;已经彻底开荤了。最近我发现有个叫 Gentoo 的 Linux 系统&#xff0c;支持树莓派4的64位CPU。项目地址&#xff1a;https://gith…

asp.net core 使用 AccessControlHelper 控制访问权限

asp.net core 使用 AccessControlHelper 控制访问权限Intro由于项目需要&#xff0c;需要在基于 asp.net mvc 的 Web 项目框架中做权限的控制&#xff0c;于是才有了这个权限控制组件&#xff0c;最初只是支持 netframework&#xff0c;后来 dotnetcore 2.0 发布了之后添加了对…

Caffe 增加自定义 Layer 及其 ProtoBuffer 参数

转载自&#xff1a;http://blog.csdn.net/kkk584520/article/details/52721838 http://blog.csdn.net/kkk584520 博客内容基于新书《深度学习&#xff1a;21 天实战 Caffe》&#xff0c;书中课后习题答案欢迎读者留言讨论。以下进入正文。 在使用 Caffe 过程中经常会有这样的…