当CloudFront发布点绑定多个CNAME时候使用Athena分析日志来获得每个CNAME流量

本文介绍在一个CloudFront发布点绑定多个CNAME时候,如何使用Athena查询CloudFront日志以获得不同CNAME的流量分布。

一、背景

1、关于CNAME自定义域名

在使用CloudFront发布点的时候,每个发布点都有一个唯一的CloudFront自动分配的域名,例如dxxxxxxxxx.cloudfront.net的格式,这个域名可以很直接发起HTTPS访问,可以被嵌入应用程序调用。为了使用自己的域名,可在CloudFront上绑定CNAME别名,这也被叫做自定义域名,例如web01.abc.com,这样就可以使用用户自己的域名对CDN发布点进行访问。

这里需要注意,即便绑定了自定义域名web01.abc.com,系统自动分配的dxxxxxxxxx.cloudfront.net域名还是可以被访问的,它是一直有效的。不过,只要不把这个自动分配的域名公开,它是不会产生流量的。因此,所有的流量都会来自于web01.abc.com

2、绑定多个CNAME自定义域名时候的日志分析场景

如果一个CDN发布点只绑定了一个自定义域名,并且系统自动分配的dxxxxxxxxx.cloudfront.net也没有对外发布,那么分析日志的时候,本CDN发布点的所有流量都会是自定义域名产生的。这时候可在CloudFront界面的Usage菜单下,可看到本发布点的日志流量总和。如下截图。

一个CDN发布点支持绑定多个CNAME自定义域名,例如一个CDN发布点绑定web01.abc.comimage01.abc.com两个域名。此时就有了日志分析的需求,如何根据不同的域名来统计流量,如何分别获取web01image01哪一个流量高哪一个低。这时候使用Athena查询CloudFront的日志来确定用量。

二、打开CloudFront日志

进入CloudFront服务控制点,找到要打开日志的发布点,点击进入发布点详情。在General标签页下方,可以看到在Alternate domain names备用域名下,有两个绑定上的自定义域名,下一步就是打开日志。在Settings位置点击Edit。如下截图。

将页面向下滚动,在Standard logging标准日志位置,把开关设置为On。在下方输入CloudFront日志要输出的S3存储桶。这里建议使用一个独立的存储桶(建议把存储桶创建在美东1、美西2、法兰克福、新加坡区域)。如果是配置了多个CDN发布点都使用同一个S3存储桶保存日志,那么可以设置Prefix前缀即子目录,通过子目录来区分。如下截图。

点击保存后,打开日志功能完成。

现在对本CDN发布点做一些访问请求。CloudFront的Standard Log一般需要等待5-10分钟后,才能在S3存储桶内看到日志。如下截图。

将日志下载到本地,使用文本编辑器打开,可以看到这个文件是CSV格式的,以空格作为隔离符号,其中的字段sc-bytes是传输的字节数,字段x-host-header是本次访问使用的域名。如果所有访问都是通过CloudFront自己分配的dxxxxxxxxx.cloudfront.net的格式来访问的,那么这个x-host-header就会显示CloudFront分配的域名。如果访问是使用了自定义域名CNAME来访问,那么这里就会显示本次访问使用的CNAME的名字。如下截图。

日志格式样本如下:

#Version: 1.0
#Fields: date time x-edge-location sc-bytes c-ip cs-method cs(Host) cs-uri-stem sc-status cs(Referer) cs(User-Agent) cs-uri-query cs(Cookie) x-edge-result-type x-edge-request-id x-host-header cs-protocol cs-bytes time-taken x-forwarded-for ssl-protocol ssl-cipher x-edge-response-result-type cs-protocol-version fle-status fle-encrypted-fields c-port time-to-first-byte x-edge-detailed-result-type sc-content-type sc-content-len sc-range-start sc-range-end
2024-03-18  05:37:43    HKG60-C1    757612  13.248.48.10    GET d51vuyprlknbq.cloudfront.net    /APIGW/log/apigw-log-01.png 200 -   Mozilla/5.0%20(Macintosh;%20Intel%20Mac%20OS%20X%2010_15_7)%20AppleWebKit/605.1.15%20(KHTML,%20like%20Gecko)%20Version/17.3.1%20Safari/605.1.15 -   -   Miss    lepa9BqJcfUuxXihUsrvmqIqguWiGw7ec1SmYmaqj7X6StCe8vkoMg==    myworkshop.bitipcman.com    https   283 0.524   -   TLSv1.3 TLS_AES_128_GCM_SHA256  Miss    HTTP/2.0    -   -   9469    0.296   Miss    image/png   756274  -   -
2024-03-18  05:37:44    HKG60-C1    15510   13.248.48.10    GET d51vuyprlknbq.cloudfront.net    /favicon.ico    200 https://myworkshop.bitipcman.com/APIGW/log/apigw-log-01.png Mozilla/5.0%20(Macintosh;%20Intel%20Mac%20OS%20X%2010_15_7)%20AppleWebKit/605.1.15%20(KHTML,%20like%20Gecko)%20Version/17.3.1%20Safari/605.1.15 -   -   Miss    6UUfUNdTZe0dvwv-zJ0WjGRGePnKA_c8JpOhHjBUnFg9vIOtWvy1Hg==    myworkshop.bitipcman.com    https   102 0.292   -   TLSv1.3 TLS_AES_128_GCM_SHA256  Miss    HTTP/2.0    -   -   9469    0.292   Miss    image/x-icon    15086   -   -

现在使用Athena进行下一步查询。

三、使用Athena分析CloudFront日志按CNAME统计流量

1、本账号/本区域首次使用Athena用户的初始化配置

选择上一步的S3存储桶所在的Region,进入Athena服务控制台。如下截图。

进入Athena服务后,从左侧菜单找到Workgroups工作组设置。在2024年上半年,如果您在不同区域使用Athena,可能会遇到左侧菜单不一致的情况,这是由于各区域的Athena版本不一样。找到Workgroups后,点击进入,其中有一条是默认的Primary。点击进入。如下截图。

在工作组Primary的详情界面,可查看Query result location设置,这是Athena查询结果集所使用的S3存储桶,Athena查询结果会保存在这里。这个选项在第一次使用Athena时候必须设置好。点击Edit按钮进行配置。如下截图。

Query result location设置位置,输入S3存储桶用来保存Athena查询结果。这个存储桶要与之前的CloudFront日志的存储桶独立开,并且也是在Athena运行所在的区域。将事先创建好的存储桶填写进去。如下截图。

Athena首次设置设置完毕。

2、创建Athena表

在Athena界面上点击左侧的Query Editor按钮,在确认右侧的Database是选择了默认的default数据库,在查询Query部分输入如下的SQL脚本。

CREATE EXTERNAL TABLE IF NOT EXISTS default.cloudfront_logs (
  `date` DATE,
  time STRING,
  x_edge_location STRING,
  sc_bytes BIGINT,
  c_ip STRING,
  cs_method STRING,
  cs_host STRING,
  cs_uri_stem STRING,
  sc_status INT,
  cs_referrer STRING,
  cs_user_agent STRING,
  cs_uri_query STRING,
  cs_cookie STRING,
  x_edge_result_type STRING,
  x_edge_request_id STRING,
  x_host_header STRING,
  cs_protocol STRING,
  cs_bytes BIGINT,
  time_taken FLOAT,
  x_forwarded_for STRING,
  ssl_protocol STRING,
  ssl_cipher STRING,
  x_edge_response_result_type STRING,
  cs_protocol_version STRING,
  fle_status STRING,
  fle_encrypted_fields INT,
  c_port INT,
  time_to_first_byte FLOAT,
  x_edge_detailed_result_type STRING,
  sc_content_type STRING,
  sc_content_len BIGINT,
  sc_range_start BIGINT,
  sc_range_end BIGINT
)
ROW FORMAT DELIMITED 
FIELDS TERMINATED BY '\t'
LOCATION 's3://my-cloudfront-log-bucket/mydir/'
TBLPROPERTIES ( 'skip.header.line.count'='2' )

以上脚本中,需要替换S3存储桶的名称,然后点击Run按钮即可执行脚本。如下截图。

脚本执行完毕,可看到数据库创建成功。

3、查询特定CNAME的流量总和

编辑如下SQL代码,然后提交执行。

SELECT ROUND(SUM(sc_bytes)*1.0/1024/1024,2) AS total_DTO_MB
FROM default.cloudfront_logs
WHERE "x_host_header"='myworkshop.bitipcman.com';

在以上代码中,sc_byte字段是DTO传输的字节数,乘以1.0可以将其转换为浮点数,然后通过SUM函数求和,通过ROUND函数保留两位小数,这样就可以换算其单位MB了。如果不这样做,因为其默认是sc_byte是INT整数,在SQL运算中除法之后自动取整,结果就偏离很大,因此才使用这种表示方法做运算。如下截图。

4、一个发布点绑定多个CNAME时候分别求总和

如果一个发布点绑定了多个CNAME,希望针对所有CNAME求和,那么可以通过groupby函数来分别求和。

编辑如下SQL代码,然后提交执行。

SELECT "date" as LogDate,
    "x_host_header" AS Hostname,
    ROUND(SUM(sc_bytes) * 1.0 / 1024 / 1024, 2) AS total_DTO_MB
FROM default.cloudfront_logs
GROUP BY "date",
    "x_host_header";

这样即可分别求出多个CNAME各自的流量总和。如下截图。

四、参考文档

CloudFront标准日志 – 字段定义说明

https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html#LogFileFormat

使用Athena查询CloudFront标准日志

https://docs.aws.amazon.com/zh_cn/athena/latest/ug/cloudfront-logs.html#create-cloudfront-table-standard-logs