> For the complete documentation index, see [llms.txt](https://freebsd-journal-cn.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://freebsd-journal-cn.bsdcn.org/20150708-qi-ye-ji-freebsd/groupon-s-deal-on-freebsd.md).

# Groupon 在 FreeBSD 上的实践

* 原文：[GROUPON’s Deal on FreeBSD](https://freebsdfoundation.org/our-work/journal/browser-based-edition/freebsd-in-the-enterprise/)
* 作者：**SEAN CHITTENDEN**

熟悉的外观和手感，略有不同的装饰，效果却更佳。

早上 7:27，我在上班路上排队等计量灯，手机亮了，数据库团队一位资深工程师发来消息：

“你有时间帮忙调试吗？我们大概率遇到一个 BSD 问题。”

我皱眉，开始想他可能卡在哪里。我不太确定他们团队当前项目进展到哪一步，所以也无法轻易推测。问题是，这家伙通常不会联系我，除非他真的卡住了。所以在我第一杯咖啡还没喝到一半时听到“BSD 问题”，感觉不太好，这绝对不是我想开启一天的方式。

我的日程排满了会议，包括一个演示和两个交付物，更不用说那些不时出现、需要立即关注的突发升级。但“BSD 问题”听起来像一个无底洞，又异常具体。

我回复：“我要上高速了，你能打给我吗？”他回：“你能到 tmux(1) 前面再回来吗？”

“糟了，”我想，“这大概是真事。”我们几个月没遇到任何问题了，也许是时候碰上一个 OS bug 了。运维团队正在敲定其最新一代数据库容器化平台，听到我们碰到问题并不让我意外，因为我们仍在处理当前迭代的某些细节。毕竟，我们曾经玩过 VIMAGE，所以也不是没有可能。此外，最近一次部署有超过 5 PB 的存储，如果发现今早我们碰到的是大型部署常见的什么小问题，也不会让我意外。

当我拐过最后一个弯快到办公室时，我收到全球数据库团队经理 Chris Schneider 的短信：“嘿，Bob 需要帮助，觉得自己遇到了 BSD 问题，因为调试新的服务检查守护进程时看到了 listen(2) 队列溢出的内核消息。”我想：“呼！新代码，而且在应用的网络代码里，应该很简单。”

事情就是这样的。随着 FreeBSD 在组织中的部署规模扩大，每隔几个月我们都会集体碰到“新奇异的错误消息”，把它们加入我们的 repertoire，并围绕它们建立流程和理解。

## 背景

一年多前，Groupon 开始开发下一代数据库平台，旨在提升可靠性、降低运维成本，并为存储行业中一些可预见的变化（尤其是固态硬盘 SSD 的普及和广泛采用）增加弹性。当数据库项目启动时，我的老板指示我使用 SSD，因为他想摆脱我们已经在内部使用的一些更昂贵的闪存技术。虽然传统的闪存硬件多年来一直够用，但其集成的 OS 驱动和硬件在运维上一直有问题，而其成本使得在整个数据库层全面部署变得不切实际。于是我们开工了。

构建大型部署时，大数定律不仅是在讨论中方便引用的定理，它必须是基本的设计考量。“不应该发生”这样的字眼是禁忌，是表明需要更多研究和分析的明显信号。与业务的任何其他部分一样，识别战略和运营规划假设并管理风险/收益至关重要。然而，如果企业确实设法将所有已知问题或“风险”纳入规划假设，那他们是熟练的、有点幸运的，还有点先知先觉。如果规划假设未能识别和考虑所有已知风险，或未能创建相应的应急方案使风险可接受，那最好有充分的理由。在本例中，计划中的整合程度（硬件减少超过 15:1）和从旋转介质转向 SSD 带来的运营效率提升明显是收益；然而，闪存单元的数量和数据保真度被识别为存储介质变化带来的风险。我们事先就知道这一点，所以从一开始就必须做些什么来管理识别出的风险。

在运维中，我们的一些主要规划假设包括：一定比例的服务器会死机、硬盘会故障、RAM 会出现单比特奇偶错误、数据中心会宕机。我们理解并为所有这些情况做规划——备用服务器、使用热插拔硬盘托架、采购 ECC RAM、地理冗余举措——还有更多。SSD（相对于旋转锈盘）的引入对运营模型带来了实质性变化，因为基于闪存单元的 SSD 比特错误率（BER）显著升高。我们清楚地知道，存储介质的这一变化将导致数据在静止时损坏——腐烂——的速率有实质性增加。对于比特腐烂，大数定律表明这不是“是否”的问题，而是“何时”和“多频繁”的问题。这使我们有必要更新团队的规划假设和风险缓解策略。

从旋转锈盘迁移到 SSD 的性能提升是巨大的。10K RPM 硬盘的寻道时间平均在 2 到 5 毫秒之间，但第 99 百分位延迟可以达到几十甚至几百毫秒。从毫秒（“ms”，千分之一秒）到微秒（“us”，百万分之一秒）代表着三个数量级的提升，这种性能提升现在能推广到所有团队和应用，而不仅仅是 Tier-1 数据库。当然，性能提升对基准测试来说不错，但对工程团队来说，性能提升转化为真实的效率提升，缩短开发周期。频繁缓存未命中、原本需要 50–100ms 的低效查询现在只需 60–200us。CPU 使用率上升到理想水平，工程团队不必再那么担心性能优化工作。实际上，使用 SSD 让我们能通过缩短许多产品的交付时间将 OpEx 换成 CapEx，但代价是什么，组织该如何应对？

在卡内基梅隆大学和 Facebook 于 2015 年 6 月 ACM SIGMETRICS ’15 大会上发表出色的研究《A Large-Scale Study of Flash Memory Failures in the Field》之前一年，我们就已经在为数据库平台设计方案，以补偿我们在 SSD 上观察到的比特腐烂。当时我们在看到错误，但不知道问题会有多普遍，只知道我们预期它会发生，因此必须为这种必然性做补偿。当 CMU/FB 的闪存论文发表时，他们的发现与我们观察到的非常一致；然而，他们的测试方法要广泛得多，结果也更深刻。以下是他们发现的几个要点：

* 六家不同的主要 SSD 厂商
* 不可纠正比特错误率（UBER）相当常见
* 最可靠的存储平台在 12 个月期间至少有 4.2% 的安装出现过一次 UBER
* 最不可靠的平台在相同持续时间和工作负载下至少有 34.1% 的安装出现过一次 UBER

显然 SSD 仍处于早期阶段，情况会随时间改善，但不同厂商之间 UBER 的差异值得注意。对于一种工作负载，我们选择了一家厂商的平台，在不到四个月的时间内经历了超过 15% 的 UBER，预计在类似的 12 个月周期内会稳定在 30–40% 左右。我们做的一个非科学观察是：会抛出 UBER 的硬盘会抛出大量错误，而且 UBER 的分布在机群中并不均匀（即一些硬盘抛出大量错误，其他抛出很少或不抛出错误——我们尚未研究原因）。

也许你在心里想：“一个比特翻转又怎样？只是一个比特。一个 GB 是 80 亿比特，一个比特不应该影响什么。”在 8 万亿比特中，一个比特微不足道，但如果翻转的比特恰好在 **/usr/local/bin/vim** 里，导致它拒绝启动，那还微不足道吗？如果比特翻转发生在数据库表的中间，你怎么知道？vim(1) 的例子并非夸张，因为它是第一个检测到 UBER 的程序。错误发生在一台测试机器配置三个月后，它的 mtime 是三个月前，然后有一天 **BAM**。基本上比特腐烂就是这样发生的：它默默、安静、按概率在深夜某处杀死一个比特，没有任何声张或有益的错误消息。试试在测试环境中用条带磁盘代替镜像跑几个月。在一张满是 0 和 1 的硬盘上，突然其中一个翻转了。这个星球上也许有人比你更倒霉，你不会有任何错误，但那种程度的否认不会改变现实。祝大家好梦。

假设你没有选择那个有三分之一硬盘抛出 UBER 的平台，更令人担忧的是 UBER 的发生率与 SSD 的使用率成正比增加。在本文发表时，根据 CMU/FB 闪存论文，来自可靠厂商的 SSD 在 12 个月使用周期内经历至少一次 UBER 的概率将稳定在十分之一到二十五分之一之间。根据服务器中的硬盘密度，如果你每台服务器装 24 个 SSD，那可能每台服务器每年超过 1 次 UBER，如果你每台服务器只放 2 个 SSD，那略超过十分之一的服务器会出问题。我们对在生产中使用 SSD 还感到不安吗？如果没有，我建议你找来 CMU/FB 闪存论文好好琢磨，因为这些错误率太高了，不能简单忽视。

换个说法：如果比特腐烂代表干草堆里的一根针，那么每两捆干草中有一根针可接受吗？每两捆干草中一根针呢？翻转的比特导致问题的概率有多大？每个季度给每捆干草添加一打新针怎么样？会有人注意或在意吗？如果我们把干草堆的比喻从缝纫针换成附近诊所的用过的皮下注射针，你的组织对风险的胃口会改变吗？谢了，不用了。无知不是福，我们需要的是数据库存储层的确定性，而非概率和运气。

为运维环境提供一些背景：Groupon 的核心业务是提供令客户愉悦的商业体验。业务本身要求运营效率、可靠性和正确性。截至 2015 年第一季度的过去 12 个月中，Groupon 的总交易额为 63 亿美元。仅 2015 年第一季度我们就售出了 5400 万件商品（商品数反映取消和退款前售出的代金券和产品），截至 2015 年第一季度累计售出超过 8 亿件商品。截至第一季度末，我们月均独立访客超过 1.6 亿，超过 80% 的客户回到网站进行未来购买（ForeSee Groupon 客户满意度研究，2015 年 3 月——Groupon 委托）。

这一业务的很大一部分将落在这个新平台上，所以正确性是我们不能不确定的事情。我们需要为未来做规划，并接受：在处理大量数据时，理论上可能发生的事情就会发生，而且会以可预测的速率发生。为了保证 PB 级数据在各种应用（它们可能有也可能没有能力校验自己的数据）上的信息保真度，我们需要某种方式来缓解 SSD 带来的已识别风险。

解决方案和结果在此时应该显而易见，但一路走来意想不到的收益——无论技术还是组织层面——既多又显著。

## FreeBSD 来救场

世界上有许多技术问题，但许多真正困难的问题与其说是技术问题，不如说是组织问题。我们需要克服的首要问题是运行那些没有能力校验自身静止数据的应用，这个技术问题需要一个技术解决方案。2014 年，Groupon 是一个以 Linux 为主的店铺。经过多次争吵、讨论、评审和替代方案测试，我们选择 FreeBSD 加 ZFS 作为这个问题的技术解决方案。

在拥有出色生产记录的成熟操作系统中，FreeBSD 难以超越。然而，在我们决定并承诺使用 FreeBSD 作为迫在眉睫、日益严重的比特错误率（“比特腐烂”）问题的解决方案之后，下一个问题是：“但它能融合吗？”我们找到了解决比特腐烂问题的方法，但不确定组织的其他部分将如何适应一个非 Linux 的操作系统。

从技术上讲，更改或增加对另一个操作系统的支持意味着什么？事实证明，如果你已经准备好处理多种 Linux 发行版，那并不算什么。“那么这个项目要支持当前增长、整合之前的收购、为未来的应用和产品发布做规划，并且还要更换数据库层的操作系统？”“是的，因为变化没那么大。”当然，前期需要一些投入，但类比更接近于拥有一辆奔驰然后买一辆宝马，学会有效驾驶新车。换挡杆在不同位置，收音机不同，但两者都是出色的工程产品，都需要汽油，都能舒适气派地将你送到目的地。

## 满不在乎的 fsck

DTrace 支持，加上轻松构建定制内核的能力和 poudriere(1) 的使用，是做出决定时最初出现在“优势”一栏的大件。然而，文件系统检查 fsck(1) 的缺失也悄悄成为一种优势，现在它已成为没有人想念甚至不再谈论的较大项目之一。想象一下在一台拥有 288TB 存储的近线备份服务器上运行 fsck(1)。传统的面向块的文件系统将需要数天或数周才能完成。用 ZFS？零。字面意义上的零时间。这样的活动和担忧在我们现代环境中已是过时之物，没有人对它们的缺席感慨万千。不过在 ZFS 引入时，这是一个经常出现的问题，因为文件系统检查是管理员遇到麻烦时可以使用的工具之一。拿走像 fsck(1) 这样根深蒂固的工具，凸显了组织变更的挑战之一：因学习新事物或在生产中信任新事物而产生的个人焦虑需要考虑。

在承诺这个方向之前，数据库管理团队中有些人明显存在顾虑。FreeBSD 不是 Linux，所以它不同，但有多大不同？支持一个新操作系统并不一定只是确保所有程序编译并运行。FreeBSD 在实质上不同吗？过渡会是一种压倒性的体验吗？每个管理员熟悉新操作系统需要多少工作量？不确定性或疑虑何时会消退？

我们的答案是举办一系列 30 分钟的在线教程和开放式问答环节。为了满足全球团队的日程需求，我们每隔几天在太平洋夏令时早上 6:30 安排视频电话会议，过一遍 FreeBSD 的某个方面。为了让对话保持开放并专注于每个人的学习需求，我们根据技能水平和已识别的性格特征分组，使开放式问答对每个人都是高效且双向的。

第一次会议简单到通过 ssh(1) 登录、登入 MySQL 和 PostgreSQL、运行一些基本可观测性命令，如 top(8)、iostat(8)、vmstat(8)、一些新命令如 systat(8) 和 gstat(8)。压倒性的反应是：“这和我们习惯的没什么不同。”最后，我们重温 `top -m io` 作为一个“再加一件事”的时刻，这带来了不少“哦！你的意思是我不必再 XYZ 了？”未知变得令人兴奋，现在对每个人的日常活动都有帮助。

之后的会议快速推进，涵盖基本系统与 ports(7) 的区别、使用 pkg(1)、手工编译一个 Port、**/etc** 和 **/usr/local/etc** 之间的差异。不久后，我们进入一些更浑浊的水域，如 pf(4) 和 ipfw(8)、FreeBSD 中为何有多个防火墙的历史。在几次会议中，一些基于 DTrace 的可观测性工具零星出现，用以展示一些延迟分位数、计数、堆栈跟踪等。意图不是现在就教 DTrace，而是给出视角并灌输这样的理解：“如果其他方法都失败了，还有 DTrace。”如果真的在生产中用 DTrace 来识别问题，那你大概率不是在过人生中最不紧张的一天，周围会有其他人帮忙。

直到大约第四次会议我们才引入 ZFS。在那个研讨会上，我们涵盖了快照、克隆、zpool scrub 和回滚。为了强调 ZFS 更深刻的用途之一，我们还提前复制了一个 1TB 的小型数据库。在问答期间，我们在不关闭进程的情况下拍摄了 ZFS 快照，用一堆虚假拙劣的 UPDATE、DELETE 和 DROP TABLE 破坏了 600GB 的数据。然后我们关闭数据库，在大约 30 秒内回滚到之前的快照。当我们把进程重新启动时，它有大约 5 分钟的复制延迟需要追赶。与其他在拍摄时会带来性能损失的快照技术相比，ZFS 简直像魔法。

> **提示**
>
> 在 `zfs snapshot` 期间使用 DTrace 测量 VFS 写延迟。用个位数微秒（而非毫秒）级的写延迟让人惊叹（见框 1）。

对于旋转锈盘来说还不错。是不是有人忘了说 ZFS 也可以非常非常快？

每个人接受新事物的速率和应对使用新事物带来的焦虑的速率各不相同，但焦虑的轨迹明显：从学习新事物的恐惧或兴奋（通常两者兼有），到因缺乏知识或经验而产生的不安，到接受和拥抱新事物，最终到那些曾经半令人不安的日常活动变得自然和舒适。更换技术不仅仅关乎技术，更关乎与人合作、建立必要熟悉度以在组织中推广技术。

> **提示**
>
> 做基准测试和其他高光测试来证明系统并不脆弱，同时增强信心、对抗焦虑。例如，把一台配有 Fusion IO 卡的 Linux 主机上的随机写工作负载移到 FreeBSD 和 ZFS 上，只给 zpool 16 块旋转磁盘。建议：把一个超过 10 万条 ganglia 指标的写入流指向 RRD 文件（见下页框 2）。

一周内，大多数人在 FreeBSD 和 Linux 之间转换的个人“罗塞塔石碑”完成了 50%，再过两周接近 80%。每个人都相当自信，他们的肌肉记忆在压力下在 FreeBSD 上和在 Linux 上一样有效。事实证明，FreeBSD 是一个出色的跨界平台，无需在脑海中重新映射 top(1) 到 prstat(1) 这类基础命令，就能掌握 ZFS 和 DTrace。基础命令的流畅性是使这种过渡成为可能的原因之一。关于 pf.conf(5) 中 include 的文件名限制等古怪问题会被升级处理，但它们通常是在 FreeBSD 中积极使用各种功能的副产品。

巧合的是，这个项目的启动与 OpenSSL 漏洞的爆发同时发生，因此快速构建和部署更新软件包的能力成为最受欢迎的功能之一。在 40 分钟多一点的时间里，使用我们自己的定制补丁，对所使用的每个软件包的完整重建就可供全球安装。在半打文件中拧几个旋钮，就能集成内部定制软件，每个软件包都在隔离的干净室 jail(8) 中构建，并具备一条延伸回原始软件包作者的良好信任链。这是一个开箱即用的胜利，只需部署 poudriere(1) 即可实现，我们几天内就完成了。从那以后，我们每个月只花几个小时维护一个完整版本，这种敏捷性是显而易见的。正如一位工程师所说：“poudriere(1) 是一件美妙的事物，值得欣赏。”软件包构建基础设施使 FreeBSD 与其他受维护的平台相比脱颖而出。

在文化上，我们已经随着焦虑的起伏拐过了弯，人们调整过来并开始蓬勃发展。对生产中 FreeBSD 的普遍担忧已经消退，我们不再觉得需要“以防万一”带着笔记本电脑出门。“哇，我们以前做不到这个”这样的说法曾一度司空见惯；然后一切都稳定到生产力和平台增强使用的稳态。我们实际发现了 ZFS 去重的良好、正当用途（版本化历史软件包），在 vlan(4) 标记的 LACP lagg(4) 接口上使用 carp(4) 成了“标准做法”等等。通过 lz4 压缩，我们每台服务器的有效存储容量增加了一倍多（在将大量 SSD 投入生产时这很重要），然而在初始测试、部署和采用几个月后，我们仍未见到比特腐烂的怪物。

## 在黑暗中等待

数据库项目的愿景是：构建一个对比特腐烂有弹性的数据库平台，让数据库团队能够管理。这个目标的后半部分已经实现，但直到第一批系统配置好几个月后我们才有了第一次捕获。从那以后，每隔几周我们就看到 ZFS 检测并修复错误（见框 3）。我们的第一次“捕获”发生在好几个月前，每次有人注意到，我们就能说：“就这样发生了”，然后继续生活，不在意。4.5K 被修复？可能是一个比特翻转。45M 被修复？某家厂商的 SSD 控制器可能在 scrub 之间反复崩溃，写出了相当数量的伪造数据。我们能做所有这些，因为 ZFS 能检测损坏的比特，并为冗余足够的构造良好的 zpool 自愈。自动。运行时。对应用透明。

我们确实 scrub zpool，有些需要很长时间才能完成。大型砖块需要几周才能完成（见框 4）。其他带 SSD 的仍需要相当长的时间运行（见框 5）。

这项工作没有“任务完成”的时刻。它只是一个警觉的、持续的迭代、反应、为未来优化、提高我们迭代和改进当前状况速率的过程。但这意味着我们成功缓解了技术风险吗？是的。千真万确。迭代速率随着所有工具的扎根而缓慢开始，但现在我们已到第三次、可以说是第四次迭代，迭代之间的持续时间在缩短，每次迭代的改进在增加。在技术方面，我们正在有效地使用 poudriere(1)，使用 iocage(8) 部署数据库，迁移到将比之前使用 carp(4) 的第 2 层方案扩展性更好的基于 DNS 的故障转移机制。

那么之前那个“BSD 问题”呢？结果是服务检查脚本的问题，有点吧。FreeBSD 不需要你翻遍 `netstat -s` 来找溢出计数器；相反，内核会发出一条有用的错误消息，告知管理员未 accept(2) 的文件描述符的 listen(2) 队列溢出了。在开发过程中，Bob 在请求处理程序里塞了一个 60 秒的 sleep(3) 调用来测试某些东西，这本身没问题，但负载均衡器每秒都在猛击服务检查守护进程，而 listen(2) backlog 只有 8，所以恰好 8 秒后内核就开始猛烈输出信息性消息。修复很简单，花了 20 分钟添加：混入多线程套接字处理程序，调整几个方法调用，允许多个线程参与 accept(2) 新连接。从开启到解决 60 分钟。一个简单的问题，实际上不需要升级，但有一个微妙的差异，也是对单一文化主导思维后果的提醒。

向组织引入技术变更需要成功驾驭必要的人员变更要素。考虑将成为长期参与者或所产生技术变更的所有者的个人需求，应是整个变更过程的首要目标。经历这一变更过程的人在完全与变更对齐之前，会经历一系列阶段。当并非所有受益者都参与了研究或决策过程时尤其如此（这在大型组织中经常发生）。我们采用的模型围绕处理公告和介绍、个人焦虑、建立技术和组织接受度，然后实现稳定的生产力和运营收益。考虑引入外部培训来填补理解的空白（其中许多可能超越特定操作系统的细节，我们为更广泛的受众这样做了，效果很好——感谢 Rich 和 Dru），举办小型研讨会，甚至分享“战争故事”。一旦考虑到组织变更，技术变更的成果对我们来说令人信服，工具箱中的额外工具被证明是有价值的，并缓解了我们规划假设中识别的风险（见框 6）。能在微秒级别监控 IO 性能，并拥有自动的比特腐烂自愈？是的，谢谢。哦，还有，睡个好觉。我们确实如此。

CMU/FB 闪存论文的另一个有趣发现包含在第 4 节中，值得注意的是，720GB SSD 的早期故障期在写入约 3TB 数据后开始消退。考虑到 RAID 和每台主机仅 8 个 SSD，这意味着当前一代 SSD 在投入生产前应有一个写入略超 24TB 数据的烧录程序。随着技术变得更加健壮，我不确定这个建议是否仍然准确。

***

**SEAN CHITTENDEN** 是 Groupon 生产运营的架构师（<seanc@groupon.com>）。他是 FreeBSD（<seanc@FreeBSD.org>）和 PostgreSQL 社区的长期参与者，在包括数据库、网络和存储在内的大规模 web 基础设施领域拥有超过 15 年经验。在之前的人生中，他拥有并经营一家数据中心和技术经销商，客户包括 Facebook 和 Yammer，之后成为硅谷初创公司中机器里的幽灵。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://freebsd-journal-cn.bsdcn.org/20150708-qi-ye-ji-freebsd/groupon-s-deal-on-freebsd.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
