使用Azure WebJob自动备份日志到Storage,解决WebApp空间不足问题

Azure WebApp比自己租用IIS部署ASP.NET或者ASP.NET CORE程序有很大的优势,包括但不限于自动缩放(当然是要给钱的)、自动缩放无需配置负载均衡、Visual Studio集成好、部署上传速度快、不需要担心IIS环境部署容易出错等问题。

但有一些用户会觉得不太适应,因为Azure WebApp并非一台虚拟机,可以理解为一个类似于Docker容器,主要是给你程序运行资源,而不是给你用于存储的。Azure WebApp连Web访问日志和系统日志都是需要配置到一个Azure Storage Blob存储里面的,所以它的理念是让存储文件更加“分布式”——就是多个WebApp应该都把日志存放在一个集中的Storage里面。

但是这个给传统程序带来一些不方便,使用log4net、nlog等日志写入组件会需要写入磁盘,而Azure Storage不方便挂载到WebApp里面。如果日志写多了,很可能把Azure WebApp写爆。

那么有两种方法,一种是自定义一个log4net、nlog等的日志Appender,让日志写入到Azure Storage Blob存储或者Table存储里面都可以,这部分代码在GitHub上有一些。配置Appender到log4net.config或者nlog.config就可以使用。

但是笔者在自己试过写一个写入Azure Storage Table的日志记录程序之后,发现大部分情况下Azure Storage Table方案显得有点不方便,有一种更简单的适合更小型程序的方式,就是把log4net或者nlog生成的日志文件归档到Azure Storage Blob里面。

以下就是这个自动备份的程序代码:

Gitee代码Repository:https://gitee.com/gzkeith/webapp-logs-backup

首先需要建一个WebJob项目,直接在Visual Studio里面建就可以了,但我们如果要定时,则需要加入Microsoft.Azure.WebJobs.Extensions,使用Nuget添加:

注意我们使用的是2.x版本,需要保证Azure.WebJobs Nuget包和Extensions Nuget包同版本。现在已经有3.0版本刚刚出来了,写法完全不一样,截止到今天网上找不到多少参考,所以千万别直接升级到3.0或以后。

而目前Visual Studio也没有.net core的WebJob项目模板,暂时还是用.NET Framework 4.6来做吧。

WebJobs项目应该自带WindowsAzure.Storage,这个是使用Storage Blob存储必须的。然后笔者是强迫症升级了最新版本了,再之后,加入一个方便处理的包:Microsoft.Azure.Storage.DataMovement

这个包是微软自己写的,用来高效读写Storage的。用了它,减少处理二进制文件的复杂度。使用里面的TransportManager,直接把文件路径或者Stream传进去,设置一个缓存,UploadAsync就会自动分块多线程上传,不用自己做byte[]缓存了,能够在想要简单解决问题的时候满足我们的需要。

加好了Nuget包,记得在启动前设置UseTimers,不然cron表达式会不起作用:

然后我建立一个定时的WebJobs函数,因为是Debug需要,就设置为2分钟一次,实际上要按照日志文件的分割逻辑、写入空间量设定一个合理的备份时间避免写爆磁盘空间,又不要经常做无必要的轮询:

上面这里用了一个环境变量路径:WEBROOT_PATH

这是Azure WebApp自带的,能够直接进到WebApp的运行路径。如果通过GetCurrentDirectory获取执行位置,只会获取到一个临时文件位置,因为WebApp运行会先Copy到一个临时文件位置避免执行时锁死文件路径。

笔者这边使用nlog,直接把文件写到logs目录底下了:

所以直接组合了DirectoryInfo。

后面就是迭代里面的文件了。笔者直接使用nlog的.net core日志模式,文件名是nlog-all-yyyy-MM-dd.log和nlog-own-yyyy-MM-dd.log这样的格式。于是就扫描里面所有的nlog-*.log,除掉当前(必须使用UTC时间,WebApp上面运行是使用UTC时间的)的日志,其他的日志都归档。

这部分请直接参见代码,就不贴图了。

有一个位置需要注意的,使用DataMovement包的TransferManager.UploadAsync最好配置一下如果遇到文件重名就overwrite,否则会报错:

接着就是运行问题了。要保证WebJob按时触发不延迟,是需要把WebApp的“始终可用”打开的:

但是打开这个,显然收费的级别就最少要到B1,费用降不下去了:

WebApp的App Service Plan上去之后,有10GB存储就没那么容易写爆了,好像意义没那么大了。

其实也是可以在ASP.net程序里面做一个Web API接口,按照存储需要手动触发日志备份,这样就可以经济一点,但就需要做一个自己轮询自己的功能,隔一分钟调用自己一次进行扫描,扫描结束之后再延时调用自己下一次轮询。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181005G0ODIP00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券