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接口,按照存储需要手动触发日志备份,这样就可以经济一点,但就需要做一个自己轮询自己的功能,隔一分钟调用自己一次进行扫描,扫描结束之后再延时调用自己下一次轮询。
领取专属 10元无门槛券
私享最新 技术干货