跳转到主要内容

解析访问日志并为DNF镜像计数

项目描述

mirrors-countme

解析http access_log数据,查找DNF countme请求,并输出结构化数据,使我们能够估计使用各种Fedora发布版的人数。

有关DNF中的countme功能的更多信息,请参阅Changes/DNF Better Counting

工作原理

简短版

  • 从Fedora 32开始,DNF为每个启用了countme设置的仓库,每周向一个随机选择的HTTP请求添加“countme=N”。
  • parse-access-log.py解析mirrors.fedoraproject.org的日志,找到这些请求,并产生以下信息
    • 请求时间戳,仓库 & 架构
    • 客户端操作系统名称、版本、变种和架构
    • 客户端“年龄”,从1-4:1周、1个月、6个月或 >6个月。
  • 我们使用这些数据制作酷炫的图表和图形,并估计有多少Fedora用户以及他们正在使用什么。

技术细节

客户端行为 & 配置

DNF 4.2.9添加了countme选项,该选项在dnf.conf(5)中描述如下

确定是否应向每周随机选择的metalink/mirrorlist查询添加特殊标志。这允许仓库所有者通过在一周时间内计数此类查询来估计消耗其系统的系统数量,这比仅仅计数唯一IP地址(由于DHCP租期短和NAT而分别导致高估和低估)要准确得多。

该标志是一个简单的“countme=N”参数,附加到metalink和mirrorlist URL上,其中N是一个整数,表示该系统所属的“长期性”桶。以下定义了4个桶,根据自系统安装开始以来已过去多少完整周:1 = 第一周,2 = 第一月(2-4周),3 = 六个月(5-24周)和4 = 超过六个月(>24周)。这些信息旨在帮助区分短期安装和长期安装,并收集有关系统生命周期的其他统计信息。

请注意,默认值为False,因为我们不希望为配置的每个仓库都启用此功能。

从Fedora 32开始,我们在Fedora官方仓库配置中设置countme=1

[updates]
name=Fedora $releasever - $basearch - Updates
#baseurl=http://download.example/pub/fedora/linux/updates/$releasever/Everything/$basearch/
metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f$releasever&arch=$basearch
enabled=1
countme=1
repo_gpgcheck=0
type=rpm
gpgcheck=1
metadata_expire=6h
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
skip_if_unavailable=False

这意味着默认配置仅在使用官方Fedora仓库时添加“countme=N”,这些仓库都是通过HTTPS连接到mirrors.fedoraproject.org完成的。“countme=N”不会添加到对所选镜像的后续请求中。

隐私、随机化和用户计数

DNF通过每周向每个启用的仓库发送一个countme请求来确保countme数据的匿名性和准确性。那么它是如何决定每周开始的时间和如何选择哪个请求的呢?

首先,所有客户端使用相同的“周”:周0从时间戳345600开始(1970年1月5日星期一00:00:00 - POSIX时间的第一天),周长为604800秒(7×24×60×60)。

其次,所有客户端发送countme的随机机会相同 - 目前为1:4 - 在给定周内发送任何请求。一旦发送,客户端在该周的其余时间内不会为该仓库发送另一个countme

updates仓库的默认更新间隔为6小时,这意味着使用dnf-makecache.service的客户端可能会在给定周的最初24小时内发送countme - 而在剩下的时间里则不会。

这意味着由于一周开始时会有更多的countme请求,所以用户的每日总数不可靠地变化。但每周的总数应该是总人口的代表性样本。

有关libdnf如何处理随机化的更多详细信息,请参阅libdnf/repo/Repo.cpp:addCountmeFlag()

收集的数据

我们只查看HTTP请求本身中的数据。我们的日志行采用标准组合日志格式,如下所示[^IPvBeefy]

240.159.140.173 - - [29/Mar/2020:16:04:28 +0000] "GET /metalink?repo=fedora-modular-32&arch=x86_64&countme=1 HTTP/2.0" 200 18336 "-" "libdnf (Fedora 32; workstation; Linux.x86_64)"

我们只查看请求为“GET”,查询字符串包含“countme=N”,结果为200或302,并且User-Agent字符串与libdnf User-Agent标题匹配的日志行。

我们使用的数据只有时间戳、查询参数(repoarchcountme)和libdnf User-Agent数据。

libdnf User-Agent数据

正如上面的日志行所示,libdnf发送的User-Agent标题如下

User-Agent: libdnf (Fedora 32; workstation; Linux.x86_64)

此字符串在libdnf/utils/os-release.cpp:getUserAgent()中构建,格式如下

{product} ({os_name} {os_version}; {os_variant}; {os_canon}.{os_arch})

其中值如下

product : "libdnf"

os_name : /etc/os-release NAME

os_version : /etc/os-release VERSION_ID

os_variant : /etc/os-release VARIANT_ID

os_canon : rpm %_os(通过libdnf getCanonOS()

os_arch : rpm %_arch(通过libdnf getBaseArch()

(libdnf的旧版本会将libdnf/{LIBDNF_VERSION}发送到product,但出于隐私考虑,在libdnf 0.37.2中删除了版本字符串;参见libdnf提交d8d0984。)

repo=arch=countme=

repo=arch=的值与.repo文件中URL中设置的值完全相同。

repo是repo的metalink URL中repo=之后出现的任意字符串。接受为repo的值由mirrormanager决定;有关一些复杂的细节,请参见mirrormanager2/lib/repomap.py

arch通常设置为arch=$basearch,这意味着os_archrepo_arch通常是相同的值。但是,客户端使用与rpm的%_arch不同的arch=是有效的,例如,i686系统可以使用i386 repo,因此repo_archos_arch可能是不同的值。

dnf.conf(5)中所述,countme是一个值从1到4,表示系统的“年龄”,以自系统首次安装以来完整的周数计算。这些值是

  1. 一周或更少(0-1周)
  2. 最多一个月(2-4周)
  3. 最多六个月(5-24周)
  4. 超过六个月(25+周)

这些定义在libdnf/repo/Repo.cpp:COUNTME_BUCKETS

OK,但在Fedora中我们如何实际使用它呢?

由于原始日志数据包含可用于跟踪或识别用户的IP和时间戳,我们只在Fedora基础设施的私有部分运行解析和计数,并仅发布匿名汇总数据。

实际上,这是一个三步的过程

  1. 每天运行countme-update-rawdb.sh以解析日志数据到rawdb
  • rawdb是针对每个countme击的结构的SQLite数据库
  • 保持私有,因为它包含IP地址和时间戳
  • 典型的日志数据:每天约6GB
  • 典型的解析时间:约5分钟(Intel Core i7-6770HQ,2.60GHz)
  • 典型的rawdb大小:每天约8MB(F32);我猜测保留3个并发版本1年的数据大约需要10GB。
  • 保留历史数据可以让我们在发现由于配置错误/恶意客户端而导致的重大错误时快速重新计算计数
  1. 运行countme-update-totals.sh以读取rawdb并更新totalsdb
  • 按周统计每个击的计数,按以下分组
    • 系统信息:os_nameos_versionos_variantos_archsys_age
    • 请求的repo:repo_tagrepo_arch
  • 仅生成我们有完整日志数据的周的数据
  • 没有时间戳或IP地址
  • 典型的解析时间:很小,<~5秒
  • 典型的totalsdb大小:每周约55KB(F32每周约700行)
  • 更新后,(重新)生成totals.csv
  1. 发布更新的totals.dbtotals.csv

贡献

您需要合法允许提交任何贡献到该项目。这在细节上可以在开发者证书起源网站上找到。您通过在git提交日志消息中添加Signed-off-by后缀来证明这一点,您可以通过使用git commit--signoff/-s选项来完成此操作。

[^IPvBeefy]:不用担心,240.159.140.173是一个假IP地址。实际上,它是🌭(热狗),U+1F32D的4字节UTF-8编码。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

mirrors_countme-0.1.4.tar.gz (66.4 kB 查看哈希值)

上传时间 源代码

构建分发

mirrors_countme-0.1.4-py3-none-any.whl (43.5 kB 查看哈希值)

上传时间 Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面