【解析向】腾讯云的Windows Server日志配置收集工具是个什么鬼?(3)

回顾上篇,解释了场景“2”中的四个标签,也介绍了对应着Windows Server中的四个功能在日常运维中究竟起到什么作用以及如何去驾驭他们。

通过一个架构或者一个开放化的工具去学习一套框架或者一个系统是最具实战价值的,但是如果希望在理论上有所建树,还是建议系统地从书籍或者官网白皮书中去学习更加,具备源码解读能力的建议直接看源码,当然Windows Server并没有开放源码(即使是笔者在担任微软MVP期间也仍然未能取得像其他国家MVP能够能到有限WIndows Server 源码的权限)。

所以要更加深入的学习Windows Server,除了日积月累的经验,靠的就是实战与不断去排错积累而来。作为Windows Server的脚本大当家——PowerShell,就是最具代表性的脚本语言,其功能在微软系架构(Exchange/AD/SystemCenter/Azure)上杀伤力不是大蟒蛇(Python)所能比拟的,所以今天继续给大家讲解场景”2“剩余的场景。

GetDVersion GetGPOResult GetProduct GetFireWall GetProcess GetServe GetPRS GetFileMD5 GetVPMen GetLoggedOnUserSession GetPlanList GetPort GetDiskStatus GetDumpFile GetCloudInit GetSpLogID GetHardDiskStatus GetHardCPUStatus GetHardMenStatus GetHardBiosStatus GetHRaid (一共涉及21项,划去的是已讲解的。)

1、GetProcess,进程,一个Windows与Linux均有的概念,与Linux一样,Windows的进程可以拥有多个子进程或者线程,而在腾讯云的日志收集工具里的收集是采getprocess 来实现:

    get-process -ErrorAction SilentlyContinue | select-object * | Fl

为了收集完整,看到作者特意加了select-object *(关于-ErrorAction SilentlyContinue的作用文末会聊聊),意在将get-process命令中的所有属性全部输出,其实输出全部属性值有意义吗?个人觉得并没有太大意义,我们先来看看输出所有属性的效果是怎么样的:

__NounName : Process

Name : BaradAgent

Handles : 328

VM : 98607104

WS : 15638528

PM : 5967872

NPM : 20048

Path : C:\Program Files\QCloud\Monitor\Barad\BaradAgent.exe

Company :

CPU : 53.921875

FileVersion :

ProductVersion :

Description :

Product :

Id : 7548

PriorityClass : Normal

HandleCount : 328

WorkingSet : 15638528

PagedMemorySize : 5967872

PrivateMemorySize : 5967872

VirtualMemorySize : 98607104

TotalProcessorTime : 00:00:53.9218750

BasePriority : 8

ExitCode :

HasExited : False

ExitTime :

Handle : 924

MachineName : .

MainWindowHandle : 0

MainWindowTitle :

MainModule : System.Diagnostics.ProcessModule (BaradAgent.exe)

MaxWorkingSet : 1413120

MinWorkingSet : 204800

Modules : {System.Diagnostics.ProcessModule (BaradAgent.exe), System.Diagnostics.ProcessModule (ntdl

l.dll), System.Diagnostics.ProcessModule (wow64.dll), System.Diagnostics.ProcessModule (wo

w64win.dll)…}

NonpagedSystemMemorySize : 20048

NonpagedSystemMemorySize64 : 20048

PagedMemorySize64 : 5967872

PagedSystemMemorySize : 127992

PagedSystemMemorySize64 : 127992

PeakPagedMemorySize : 6098944

PeakPagedMemorySize64 : 6098944

PeakWorkingSet : 15892480

PeakWorkingSet64 : 15892480

PeakVirtualMemorySize : 116744192

PeakVirtualMemorySize64 : 116744192

PriorityBoostEnabled : True

PrivateMemorySize64 : 5967872

PrivilegedProcessorTime : 00:00:23.9218750

ProcessName : BaradAgent

ProcessorAffinity : 3

Responding : True

SessionId : 0

StartInfo : System.Diagnostics.ProcessStartInfo

StartTime : 2018/5/28 16:55:41

SynchronizingObject :

Threads : {7440, 6088, 3700, 1468…}

UserProcessorTime : 00:00:30

VirtualMemorySize64 : 98607104

EnableRaisingEvents : False

StandardInput :

StandardOutput :

StandardError :

WorkingSet64 : 15638528

Site :

Container :

其实作为Windows Server运维者,什么时候会关注进程情况?无非就是系统卡顿/服务异常(假死/夯住)/系统被入侵或者中毒时,则这四个场景的核心进程属性值应该关心什么呢?

首先是Name,这个Name是软件开发者在编译时赋予的,通常指的是进程名而非软件名(与软件下所对应的具体可执行服务程序对应),通常为何关心这个呢?篡改,最常见的就是Windows Server下的svchost伪装,经常可以看到有进度软件伪装成svchost来进行入侵动作,所以可以通过这个值直接看到进程的真实名称。

其次是Handle(HandleCount ,Handle,类似Linux下的file-max(proc/sys/fs/file-max),当系统异常夯住或者无法打开新的窗口或者创建新的进程时,就要看看是否某个进程Handles占用过多了,如何判断占用是否过多?WS2K8R2(Windows Server 2008R2)的句柄默认上限为10000(腾讯云/阿里云默认未作任何调整),最高上限可以调到18000,这里要根据自身的内存情况,理论上2Gb RAM以上的系统句柄调整为18000并不会有问题,作为腾讯云的运维,笔者曾经见过一个木马程序(其实就是勒索病毒)伪装的svchost竟然多达9000+句柄,后来在反编译后发现该伪装进程有个BUG,就是申请VM(虚拟内存,后面讲到)后并没有释放,导致每次执行就会重复调起多个句柄来记录关系,当然勒索木马并不会考虑性能与稳定性。

第三个是虚拟内存(VirtualMemorySize,VM),虚拟内存是什么?对应着Linux SWAP(有一些可忽略的不同因素),作为Windows Cache,VM有着举足轻重的作用,在进程中,如果VM Size的值过大(不断递增,增量明显比其他多,且不见下降)的话,那就可能程序出现内存泄漏,这也是众多桌面卡顿/远程卡顿/系统卡顿的罪魁祸首之一,Windows的”保护“机制就是尽可能让现场保留,或者说其Dump级别太高,不像Linux OOM后可以促发CrashDump,所以通常我们会建议客户设置好触发蓝屏的设置,以便系统crash时可以进行手动触发蓝屏,然而很多客户并不会这么做(或许国内Linux用户居多,已经思维定式?),有了Dump文件后,可以通过分析知道当时哪个进程占用的内存以及VM多,就明白哪里出了问题。

最后几个比较重要的分别是CPU,PagedSystemMemorySize,WorkingSet,分别代表着CPU使用情况,已命中的虚拟内存大小(即真实的虚拟内存占用)以及已命中的物理内存大小(即真实的物理内存大小)。

若知道对应的进程情况,其实从日志收集工具所呈现出来的内容仅仅只能知晓哪里可能出了问题,但是具体问题的影响以及相关情况建议使用有号称Windows系统瑞士军刀之称Windows Sysinternals中的Procexp可以看到更为详细的情况(比如系统IRQ情况等):

Procexp界面

2、GetServer,获取服务列表,使用了GetService 同样使用了select *来输出所有属性,然而其实这个输出也仅仅只能看到一些基本信息,来看下输出的结果是:

Name : AppIDSvc

RequiredServices : {CryptSvc, RpcSs, AppID}

CanPauseAndContinue : False

CanShutdown : False

CanStop : False

DisplayName : Application Identity

DependentServices : {}

MachineName : .

ServiceName : AppIDSvc

ServicesDependedOn : {CryptSvc, RpcSs, AppID}

ServiceHandle : SafeServiceHandle

Status : Stopped

ServiceType : Win32ShareProcess

Site :

Container :

主要关注的两个属性是,DependentServices ,Status,分别代表着依赖的服务以及本服务状态,腾讯云目前有采用DHCP(腾讯云官方提供),有时候会发现一些客户的机器异常获取不到IP,不少案例是因为客户的DHCP Client及其依赖服务未开启导致,这个时候这个GetServer就起作用了,但是……

服务导致系统异常通常是因为恶意服务注册,所以我们更关心的其实是服务路径以及自开启情况,在这里的输出并没有出来,相对理想的排错场景应该是,输出服务的注册路径,对比是否与原生一致,不一致则代表服务器存在问题,由于有些进程来源服务所创建,如果可以的话,应该输出其关系(站在Windows Server运维者角度来说,这个逻辑确实比较复杂,而且在PowerShell 2.0版本中并没有直接命令,如果要到这种级别的映射,只能通过前面一篇所讲的WMI对象来进行获取了)。

一个服务真正应该关心的值

3、GetPRS ,意在获取当前的性能值,从脚本中可以到是采用wmi对象然后自行进行转换:

        $cpu = gwmi –computername $Server win32_Processor
        $men = gwmi -ComputerName $Server win32_OperatingSystem

由于在wmi对象里没有直接对于memory的性能指标(集合在OperatingSystem中),所以工具作者采用了先获取整体对象再从os对象里取FreePhysicalMemory与TotalVisibleMemorySize然后两者在进行二次计算得出内存占比,CPU则直接通过Processor值获取。

同时可以看到在GetPRS中硬生生的插进了一段WimObject——Win32_LogicalDisk,从语法来看,应该是后面所增加的,毕竟在Windows Servers运维者中看到当前性能其实意义不会太大(除非在故障现场,但是既然可以运行日志收集工具那么性能方面至少不会太差),因为这种性能收集只是当时态,无法收集到历史态(Windows没有类似Linux中的atop),若要收集历史态这个收集工具就变成了监控态了,然而腾讯云有云监控,虽然粒度不是很低,但是基本的性能指标历史态都有(极端情况下经常存在无法收集指标情况,而在Linux上这一点就健壮多了,可以说在Windows Server的开发上云监控并没有太用心)。

所以强行插入的LogicalDisk确实比单纯的收集几大件的性能(当然采用wmi对象获取出来的性能数据要比任务管理器所呈现的要精准)要好多了:

性能收集出来的效果

4、GetPlanList,在Windows Server里对标Linux Crontab的就是”计划任务“,即Schedule服务。从命令行获取计划任务其实很多种方式,在PowerShell 3.0中有专门的模块来获取计划任务——ScheduledTasks(GetCommandModuleScheduledTasks进行查看)。

腾讯云的Windows Server OS类型从08R2到16都有,而2012以下版本采用的是PowerShell 2.0,为了考虑兼容性,可以看到该工具采用牺牲一点信息量来完成兼容性的兼顾,核心脚本如下:

        $schedule = new-object -com ("Schedule.Service")
        $schedule.connect($servername)
        $tasks = $schedule.getfolder("\").gettasks(0)

5、GetDumpFile

Dump文件,相当于Linux中的vmcore,在Windows中也是举足轻重,工具制作者采用了两种分支:

$TFD = Test-Path "C:\Windows\MEMORY.DMP"
    $TMiniD = Test-Path "C:\Windows\Minidump\*.DMP"
    $date = Get-Date
    if ($TFD -eq $true)
    {
        $FileDateRS = Get-ChildItem -Path "C:\Windows\MEMORY.DMP" -Recurse -ErrorAction:SilentlyContinue | `
Where-Object -FilterScript {
            (((get-date) - ($_.CreationTime)).days -le 14 `
            -and $_.PsISContainer -ne $True)
        } | Select-Object FullName
        if ($FileDateRS)
        { "——————————$date : 存在FullDump文件,说明系统为蓝屏宕机,由于FullDump较大,请您手动提取————————————
    " | Out-File -Append ".\$Dirfilename\$Logfilename" }
    }
    else
    {
        "——————————$date : 未产生Dump文件,说明系统非蓝屏宕机————————————
    " | Out-File -Append ".\$Dirfilename\$Logfilename"
    }
    if ($TMiniD -eq $true)
    {
        $FileRS = Get-ChildItem "C:\Windows\Minidump\*.DMP" | Sort-Object creationtime -Descending | Select-Object -First 1
        $FileDateRS = Get-ChildItem -Path $FileRS -Recurse -ErrorAction:SilentlyContinue | `
Where-Object -FilterScript {
            (((get-date) - ($_.CreationTime)).days -le 14 `
            -and $_.PsISContainer -ne $True)
        }
        if ($FileDateRS)
        {
            #Copy-Item $FileDateRS $Dirfilename
            "——————————$date : 存在MiniDump文件,说明系统为蓝屏宕机,由于Dump文件较大,请您手动提取————————————
    " | Out-File -Append ".\$Dirfilename\$Logfilename"
        }
        else
        {
            "——————————$date : 未产生MiniDump文件,说明系统非蓝屏宕机————————————
    " | Out-File -Append ".\$Dirfilename\$Logfilename"
        }

由于Dump文件源自于系统自身的保护机制,且由内存生成,架构上来说比PowerShell要底,没有现成PowerShell进行解析,所以看到这里的实现基本是基于copyitemGetChildItemTestPath 这类基础命令进行收集,由于Dump文件是基于内存,也就是说有可能存在几G到几十G的Dump文件,工具作者在这里做了判断如果是FullDump就不做提取,对于minidump,则提取14天之内的最新Dump文件,这也合理,对于Dump文件的产生、分析可以看我之前写的《如何分析 WindowsDump:Dump 起源与初始设置(一)》、《如何分析 WindowsDump:BSOD 分析与 WinDbg 使用(二)》。

6、场景2的最后几个,由于是一些特殊规则收集及基础知识,就不一一展开:

  • GetPort:收集服务器已开放的端口,通常用来排查是否为网络问题
  • GetDiskStatus:收集服务器硬盘状态,比Systeminfo更加细致;
  • GetCloudInit:Cloud-init服务状态收集,腾讯云服务日志收集;
  • GetSpLogID:根据指定日志ID收集特定日志是否存在;
  • GetFileMD5:收集部分文件MD5值(通过与基础镜像做对比)进行;
  • GetVPMen:收集虚拟内存并做简单对比,对比具体语句,通过对比缓存使用情况来判断是否正常与否,这也是收集工具里少有实际进行逻辑判断的模块:
        if ($vAllocatedBaseSize -ge $vPeakUsage)
        {
            "
    当前分配的页面缓存为$vAllocatedBaseSize
    已用的页面缓存大小为$vPeakUsage
    当前页面缓存设置正常
" | Out-File -Append ".\$Dirfilename\$Logfilename"
        }
        else
        {
            "
    当前分配的页面缓存为$vAllocatedBaseSize
    已用的页面缓存大小为$vPeakUsage
    当前页面缓存设置异常
" | Out-File -Append ".\$Dirfilename\$Logfilename"
        }
  • GetLoggedOnUserSession:类似于Linux中的w,收集在线用户,可以检测是否入侵;

7、至于场景“2”剩余的Hard部分,由于需要一定篇幅来描述腾讯云的硬件解决方案,将在下一篇做阐述。