你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

从 VM 见解查询地图数据

启用进程和依赖关系时,系统会在 VM 见解中收集计算机和进程清单数据以支持地图功能。 除了使用地图分析此数据外,还可以直接使用 Log Analytics 查询这些数据。 本文介绍可用数据并提供示例查询。

VM Insights 会收集性能和连接指标、计算机和进程库存数据以及运行状况信息,并将其转发到 Azure Monitor 中的 Log Analytics 工作区。 此数据可用于 Azure Monitor 中的查询。 此数据可应用于包括迁移计划、容量分析、发现和按需性能故障排除在内的方案。

重要

必须为 VM 见解启用进程和依赖项,才能创建本文中讨论的表。

映射记录

除了在进程或计算机启动或添加到 VM 见解时生成的记录外,还针对每个唯一计算机和进程每小时生成一条记录。 VMComputer 表中的字段和值映射到 ServiceMap Azure 资源管理器 API 中计算机资源的字段。 VMProcess 表中的字段和值映射到 ServiceMap Azure 资源管理器 API 中进程资源的字段。 _ResourceId 字段与相应的资源管理器资源中的名称字段匹配。

包含内部生成的可用于标识唯一进程和计算机的属性:

  • 计算机:使用 _ResourceId 来唯一标识 Log Analytics 工作区中的计算机。
  • 进程:使用 _ResourceId 来唯一标识 Log Analytics 工作区中的进程

由于在指定的时间范围内,指定的进程和计算机可能存在多条记录,因此针对同一个计算机或进程的查询可能返回多条记录。 若要仅添加最新记录,请在查询中添加 | summarize arg_max(TimeGenerated, *) by ResourceId

连接和端口

VMConnectionVMBoundPort 提供有关计算机的连接(入站和出站)以及在其上处于打开/活动状态的服务器端口的信息。 还可以通过 API 公开连接指标。使用这些 API 可以获取某个时间范围内的特定指标。 在侦听套接字上接受后生成的 TCP 连接是入站连接,而通过连接到某个给定的 IP 和端口创建的 TCP 连接则是出站连接。 Direction 属性表示连接的方向,该方向可以设置为 inboundoutbound

这些表中的记录是基于依赖项代理报告的数据生成的。 每条记录表示 1 分钟时间间隔内观测到的结果。 TimeGenerated 属性表示时间间隔的开始时间。 每条记录包含用于识别相应实体(即连接或端口)以及与该实体关联的指标的信息。 目前,只会报告使用“基于 IPv4 的 TCP”发生的网络活动。

为了控制成本和复杂性,连接记录不会显示单个物理网络连接。 多个物理网络连接分组到一个逻辑连接中,然后在相应的表中反映该逻辑连接。 这意味着,VMConnection 表中的记录表示逻辑分组,而不是观测到的单个物理连接。 在给定的一分钟时间间隔内对以下属性共用相同值的物理网络连接聚合到 VMConnection 中的一个逻辑记录内。

指标

VMConnectionVMBoundPort 中包括指标数据以及有关在给定逻辑连接或网络端口(BytesSentBytesReceived)上发送和接收的数据量的信息。 其中还包括响应时间,即调用方等待远程终结点处理和响应通过连接发送的请求的时间(ResponseTimeMaxResponseTimeMinResponseTimeSum)。 报告的响应时间是底层应用程序协议的真实响应时间的估算值。 它是基于物理网络连接的源与目标端之间的数据流观测结果,使用试探法计算得出的。 从概念上讲,它是请求的最后一个字节离开发送方的时间与响应的最后一个字节返回发送方的时间之间的差值。 这两个时间戳用于描述给定物理连接上的请求和响应事件。 两者的差表示单个请求的响应时间。

此算法是求近似值,根据给定网络连接所用的实际应用程序协议,其成功度各不相同。 例如,当前做法非常适合基于请求-响应的协议(例如 HTTP (S)),但不适合单向协议或基于消息队列的协议。

需要考虑的一些要点包括:

  1. 如果进程在相同的 IP 地址上接受连接,但通过多个网络接口接受连接,则为每个接口单独报告一条记录。
  2. 带通配符 IP 的记录不包含任何活动。 包含此类记录的目的是表示在计算机上为入站流量开放了某个端口这一事实。
  3. 为了降低详细程度和数据量,存在带有特定 IP 地址的匹配记录(适用于相同的进程、端口和协议)时,将省略带通配符 IP 的记录。 省略了通配符 IP 记录后,具有特定 IP 地址的 IsWildcardBind 记录属性将设置为 True。此设置表示已通过报告计算机的每个接口公开了该端口。
  4. 仅在特定接口上绑定的端口的 IsWildcardBind 设置为 False

命名和分类

为提供方便,RemoteIp 属性中包含了连接的远程端的 IP 地址。 对于入站连接,RemoteIpSourceIp 相同;对于出站连接,它与 DestinationIp 相同。 RemoteDnsCanonicalNames 属性表示计算机针对 RemoteIp 报告的 DNS 规范名称。 RemoteDnsQuestions 属性表示计算机针对 RemoteIp 报告的 DNS 问题。 RemoveClassification 属性保留供将来使用。

恶意 IP

根据一组 IP 检查 VMConnection 表中的每个 RemoteIp 属性,以识别已知的恶意活动。 如果将 RemoteIp 标识为恶意,则会填充以下属性。 如果 IP 不被视为恶意,则这些属性为空。

  • MaliciousIp
  • IndicatorThreadType
  • Description
  • TLPLevel
  • Confidence
  • Severity
  • FirstReportedDateTime
  • LastReportedDateTime
  • IsActive
  • ReportReferenceLink
  • AdditionalInformation

示例映射查询

列出所有已知计算机

VMComputer | summarize arg_max(TimeGenerated, *) by _ResourceId

VM 上次重启的时间

let Today = now(); VMComputer | extend DaysSinceBoot = Today - BootTime | summarize by Computer, DaysSinceBoot, BootTime | sort by BootTime asc

按映像、位置和 SKU 分类的 Azure VM 摘要

VMComputer | where AzureLocation != "" | summarize by Computer, AzureImageOffering, AzureLocation, AzureImageSku

列出所有托管计算机的物理内存容量

VMComputer | summarize arg_max(TimeGenerated, *) by _ResourceId | project PhysicalMemoryMB, Computer

列出计算机名称、DNS、IP 和 OS

VMComputer | summarize arg_max(TimeGenerated, *) by _ResourceId | project Computer, OperatingSystemFullName, DnsNames, Ipv4Addresses

在命令行中查找带有“sql”的所有进程

VMProcess | where CommandLine contains_cs "sql" | summarize arg_max(TimeGenerated, *) by _ResourceId

按资源名称查找计算机(最新记录)

search in (VMComputer) "m-4b9c93f9-bc37-46df-b43c-899ba829e07b" | summarize arg_max(TimeGenerated, *) by _ResourceId

按 IP 地址查找计算机(最新记录)

search in (VMComputer) "10.229.243.232" | summarize arg_max(TimeGenerated, *) by _ResourceId

列出指定计算机上的所有已知进程

VMProcess | where Machine == "m-559dbcd8-3130-454d-8d1d-f624e57961bc" | summarize arg_max(TimeGenerated, *) by _ResourceId

列出所有运行 SQL Server 的计算机

VMComputer | where AzureResourceName in ((search in (VMProcess) "*sql*" | distinct Machine)) | distinct Computer

在我的数据中心列出 curl 的所有唯一产品版本

VMProcess | where ExecutableName == "curl" | distinct ProductVersion

发送和收到的字节数趋势

VMConnection | summarize sum(BytesSent), sum(BytesReceived) by bin(TimeGenerated,1hr), Computer | order by Computer desc | render timechart

哪些 Azure VM 传输的字节数最多

VMConnection | join kind=fullouter(VMComputer) on $left.Computer == $right.Computer | summarize count(BytesSent) by Computer, AzureVMSize | sort by count_BytesSent desc

链接状态趋势

VMConnection | where TimeGenerated >= ago(24hr) | where Computer == "acme-demo" | summarize dcount(LinksEstablished), dcount(LinksLive), dcount(LinksFailed), dcount(LinksTerminated) by bin(TimeGenerated, 1h) | render timechart

连接失败趋势

VMConnection | where Computer == "acme-demo" | extend bythehour = datetime_part("hour", TimeGenerated) | project bythehour, LinksFailed | summarize failCount = count() by bythehour | sort by bythehour asc | render timechart

绑定端口

VMBoundPort
| where TimeGenerated >= ago(24hr)
| where Computer == 'admdemo-appsvr'
| distinct Port, ProcessName

多台计算机中已打开端口的数目

VMBoundPort
| where Ip != "127.0.0.1"
| summarize by Computer, Machine, Port, Protocol
| summarize OpenPorts=count() by Computer, Machine
| order by OpenPorts desc

按已打开端口的数目对工作区中的进程评分

VMBoundPort
| where Ip != "127.0.0.1"
| summarize by ProcessName, Port, Protocol
| summarize OpenPorts=count() by ProcessName
| order by OpenPorts desc

聚合每个端口的行为

然后,可以使用此查询按活动对端口评分,例如,入站/出站流量最多的端口或连接数最多的端口。

VMBoundPort
| where Ip != "127.0.0.1"
| summarize BytesSent=sum(BytesSent), BytesReceived=sum(BytesReceived), LinksEstablished=sum(LinksEstablished), LinksTerminated=sum(LinksTerminated), arg_max(TimeGenerated, LinksLive) by Machine, Computer, ProcessName, Ip, Port, IsWildcardBind
| project-away TimeGenerated
| order by Machine, Computer, Port, Ip, ProcessName

汇总一组计算机的出站连接

// the machines of interest
let machines = datatable(m: string) ["m-82412a7a-6a32-45a9-a8d6-538354224a25"];
// map of ip to monitored machine in the environment
let ips=materialize(VMComputer
| summarize ips=makeset(todynamic(Ipv4Addresses)) by MonitoredMachine=AzureResourceName
| mvexpand ips to typeof(string));
// all connections to/from the machines of interest
let out=materialize(VMConnection
| where Machine in (machines)
| summarize arg_max(TimeGenerated, *) by ConnectionId);
// connections to localhost augmented with RemoteMachine
let local=out
| where RemoteIp startswith "127."
| project ConnectionId, Direction, Machine, Process, ProcessName, SourceIp, DestinationIp, DestinationPort, Protocol, RemoteIp, RemoteMachine=Machine;
// connections not to localhost augmented with RemoteMachine
let remote=materialize(out
| where RemoteIp !startswith "127."
| join kind=leftouter (ips) on $left.RemoteIp == $right.ips
| summarize by ConnectionId, Direction, Machine, Process, ProcessName, SourceIp, DestinationIp, DestinationPort, Protocol, RemoteIp, RemoteMachine=MonitoredMachine);
// the remote machines to/from which we have connections
let remoteMachines = remote | summarize by RemoteMachine;
// all augmented connections
(local)
| union (remote)
//Take all outbound records but only inbound records that come from either //unmonitored machines or monitored machines not in the set for which we are computing dependencies.
| where Direction == 'outbound' or (Direction == 'inbound' and RemoteMachine !in (machines))
| summarize by ConnectionId, Direction, Machine, Process, ProcessName, SourceIp, DestinationIp, DestinationPort, Protocol, RemoteIp, RemoteMachine
// identify the remote port
| extend RemotePort=iff(Direction == 'outbound', DestinationPort, 0)
// construct the join key we'll use to find a matching port
| extend JoinKey=strcat_delim(':', RemoteMachine, RemoteIp, RemotePort, Protocol)
// find a matching port
| join kind=leftouter (VMBoundPort 
| where Machine in (remoteMachines) 
| summarize arg_max(TimeGenerated, *) by PortId 
| extend JoinKey=strcat_delim(':', Machine, Ip, Port, Protocol)) on JoinKey
// aggregate the remote information
| summarize Remote=makeset(iff(isempty(RemoteMachine), todynamic('{}'), pack('Machine', RemoteMachine, 'Process', Process1, 'ProcessName', ProcessName1))) by ConnectionId, Direction, Machine, Process, ProcessName, SourceIp, DestinationIp, DestinationPort, Protocol

后续步骤