AICon议程上新60%,阿里国际、360智脑、科大讯飞、蔚来汽车分享大模型探索与实践 了解详情
写点什么

Uber 如何实现 Go 代码中的动态数据竞争检测

  • 2022-07-12
  • 本文字数:2839 字

    阅读完需:约 9 分钟

Uber 如何实现 Go 代码中的动态数据竞争检测

本文是 Uber 在 Go 代码中数据竞争经验两篇文章中的第一篇。详细版本将在 2022 年 ACM SIGPLAN 编程语言设计与实现(Programming Languages Design and Implementation,PLDI)中发表。在本文系列的第二部分,我们将介绍关于 Go 中竞争模式的学习。


Uber 已将 Go 作为主要编程语言,广泛用于开发微服务。我们的 Go 单体仓库由大约 5000 万行代码组成,包含大约 2100 个独特的 Go 服务。Go 使并发性成为一流公民;在函数调用前加上 go 关键字,就会异步运行调用。在 Go 中,这些异步函数调用被称作 goroutines。开发人员通过在单个运行的 Go 程序中创建 goroutines,从而隐藏了延迟(例如,对其他服务的 IO 或 RPC 调用)。goroutines 被认为是 “轻量级的”,Go 的运行时上下文在操作系统(OS)线程上切换它们。Go 程序员经常随意使用 goroutines。两个或多个 goroutines 可以通过消息传递(通道)或共享内存进行数据通信。共享内存恰好是 Go 中最常用的数据通信方式。


在 Go 中,如果两个或更多的 goroutines 访问同一个内存地址时,那么至少有一块是写入的,而且它们之间没有排序,这就是 Go 内存模型所定义的数据竞争。在我们的微服务中,由于数据竞争而导致的 Go 程序的中断是一个反复出现的、令人头疼的问题。由于上述问题,我们关键的、面向客户的服务总共瘫痪了数个小时,造成客户的不便,也影响了我们的收益。在本文中,我们将会讨论 Go 的一个默认动态竞争检测器,它将会在 Go 的开发环境中不断检测数据竞争。这一部署实现了对 2000 多个竞争的检测,使两百多名工程师修复了约 1000 个数据竞争。


动态检测数据竞争


动态竞争检测包括通过检测共享内存访问和同步构造来分析程序的执行。在 Go 中进行单元测试,生成多个 goroutine,这是一个很好的开始,可以进行动态竞争检测。Go 有一个内置的竞争检测器,可以用来在编译时检测代码,以及检测执行过程中的数据竞争。在内部,Go 的竞争检测器采用了 ThreadSanitizer 运行时库,通过结合锁集和基于之前的算法来报告数据竞争。


与动态竞争检测相关的重要属性如下:


  • 由于动态竞争检测依赖于分析的执行,所以不会报告源代码中的所有竞争。

  • 检测到的竞争集依赖于线程交错,甚至程序的输入没有变化,但会在多次运行中发生变化。

何时部署动态数据竞争检测器?


我们在仓库中使用了超过 10 万个 Go 单元测试来执行代码和检测数据竞争。然而,我们面临着一个具有挑战性的问题,即何时部署竞争检测器。


在拉取请求(pull request,PR)时,运行动态数据竞争检测器存在以下问题:


  • 竞争检测具有不确定性。这样,拉取请求所引起的竞争可能不会被曝光,并且可能不会被检测到。这种行为的后果是,随后的良性拉取请求可能会受到检测到的休眠竞争的影响,从而被错误地阻止,进而影响开发人员的生产力。此外,由于在我们 5000 万行的代码库中存在预先存在的数据竞争,这也是一件不可能的事情。

  • 动态数据竞争检测器占用的空间是 2~20 倍,内存开销是 5~10 倍,这可能导致违反我们的 SLA,或者增加硬件成本。


图 1:动态竞争检测工作流的架构


基于这些考虑,我们决定在事后定期在代码快照上部署竞争检测器,这包括以下步骤:


(a) 通过执行仓库中的所有单元测试来进行动态竞争检测。

(b) 通过向适当的 bug 所有者提交任务来报告所有未解决的竞争。


一个检测到的竞争报告包含以下细节:


  • 冲突的内存地址。

  • 2 个冲突访问的调用链(又称调用上下文或堆栈跟踪)。

  • 与每个访问相关的内存访问类型(读取或写入)。


我们解决了几个问题,通过对报告的堆栈竞争进行散列,并应用启发式方法来确定负责修复该错误的潜在开发人员,这样就可以避免重复的竞争。尽管我们已经选定了这种部署路径,但是,如果所检测到的竞争不会妨碍构建,并作为警告通知开发人员,或者对动态竞争检测进行了改善,使得 CI 时间的确定性检测是可行的,那么 CI 时间的部署是可以实现的。

部署的效果


我们在 2021 年 4 月推出了这一部署,并在 6 个月里收集数据。我们的方法帮助检测了单体仓库中的 2000 个数据竞争,每天有数百名 Go 开发人员提交的数据。在报告的 2000 个竞争中,有 1011 个竞争被 210 个不同的工程师修复。我们观察到,有 790 个独特的补丁来修复这些竞争,这表明了独特的根源数量。我们还收集了 6 个多月期间未解决的故障总数的统计数据,并将其报告如下:


图 2:6 个月内未解决的数据竞争的数量(2021 年 4 月~2021 年 9 月)


在推出的初始阶段(2~3 个月),我们向受让方提供了关于解决数据竞争问题的建议。在这一阶段,未解决的竞争已经出现了明显的减少。后来,随着指导工作的减少,我们注意到,未解决的竞争总数在逐渐增加。该图还表明,未解决的竞争数的波动,这是由于对竞争的修复、新竞争的引入、开发人员对测试的启用和禁用,以及动态竞争检测的基本非确定性。在报告了所有预先存在的竞争后,我们还观察到,工作流平均每天会创建大约 5 个新的竞争报告。


图 3:提交和修复的 Jira 任务的数量说明


就运行我们的离线数据竞争检测器的开销而言,我们注意到,在没有数据竞争检测的情况下,在所有的测试中,95% 的运行时间是 25 分钟,而在启用数据竞争之后,增加了 4 倍,达到约 100 分钟。在数十名工程师的调查中,大约在推出该系统 6 个月后,52% 的开发人员认为该系统有用,40% 的人没有参与该系统,8% 的人认为该系统没有用。

展望未来


我们在这次部署中的经验表明有以下进展:


  • 需要建立可在持续集成(CI)期间部署的动态竞争检测器。这需要新的检测器有效解决由于非确定性和开销带来的挑战。

  • 在这之前,设计算法为检测到的数据竞争寻找根源并确定适当的拥有者,有助于加速数据竞争的修复。

  • 我们已经确定了与 Go 中的数据竞争有关的基本编码模式(在本博客系列的第二部分中将会介绍),而 CI 时间的静态分析检测可能会捕捉到其中一个子集。

  • 所检测的竞争集依赖于输入的测试套件。能够在其他类型的测试(除单元测试外)上运行竞争检测,如集成测试、端到端测试、黑盒测试,甚至生产跟踪,都能帮助检测更多的竞争。

  • 我们还认为,对输入测试套件的时间表进行模糊处理的程序分析工具可以暴露出线程交错,从而增强检测到的竞争集。

  • 最后,目前的方法依赖于通过单元测试的多线程执行的可用性,而手动构建此类测试时,不一定能考虑到所有可能的情况。自动生成多线程执行,其中包含 racy 行为,并且利用检测器来验证竞争,这是一种高效的调试工具。


作者介绍:


Murali Krishna Ramanathan 是一名高级软件工程师,负责 Uber 工程的多项代码质量计划。他是 Piranha 的架构师,Piranha 是一个重构工具,可以自动删除因特性标记过期而导致的代码。他的兴趣是开发工具来解决软件开发的挑战,包括特性标记、自动代码重构和开发人员的工作流,以及自动测试生成以提高软件质量。


Milind Chabbi 是 Uber 编程系统研究团队的一名员工研究员。他领导整个 Uber 在编译器优化、高性能并行计算、同步技术和性能分析工具方面的研究计划,使大型复杂的计算系统变得可靠和高效。


原文链接:


https://eng.uber.com/dynamic-data-race-detection-in-go-code/

2022-07-12 09:0911886

评论

发布
暂无评论
发现更多内容

复旦MOSS大模型开源了「中国版ChatGPT」,Github和Hugging Face同时上线

肥晨

三周年连更

华为云虚拟专用网络VPN常见问题解答

YG科技

Oracle Apex学习之系统变量

back_wang

oracle ebs oracle apex

AlDente免费版,限制 Macbook 最大充电量,保护电池健康

Rose

AlDente Mac版 AlDente macOS 充电量阈值

macOS 13 Ventura (苹果最新系统) v13.3.1正式版

Rose

macOS Ventura 苹果系统下载 Mac最新系统

华为云桌面,如何为企业构建新型工作方式

平平无奇爱好科技

Matlab实现粒子群算法

Shine

三周年连更

面试还不懂JVM调优,看这篇就够了

程序员小毕

程序员 面试 后端 架构师 jvm调优

达芬奇18补丁版下载 支持m1/m2/intel/win

Rose

DaVinci Resolve 18 达芬奇18破解版 视频剪辑调色软件

华为云桌面——云端上“最卷的云”

平平无奇爱好科技

华为云大数据BI解决方案,助力企业数字化运营

平平无奇爱好科技

摆脱终端束缚,华为云桌面助力企业数字化转型

平平无奇爱好科技

华为云CDN赋能企业数字化转型

YG科技

PHP 中数组是如何灵活支持多数据类型的?

架构精进之路

php 数组 后端 三周年连更

Qz学算法-数据结构篇(排序算法--基数、总结)

浅辄

数据结构 三周年连更

微服务 SpringBoot 整合 Redis GEO 实现附近商户功能

Bug终结者

java; Redis 核心技术与实战 三周年连更

浅谈华为云CDN在互联网领域的应用场景落地

YG科技

THREE.JS实现炫酷的3D简历网站

知心宝贝

前端 后端 3D ThreeJS 三周年连更

Downie下载vip会员视频教程?Downie4最新许可证

Rose

Downie下载 Downie使用教程 Downie 4许可证 Mac视频下载器 Downie破解版

华为云桌面随需而至,让办公数字化触手可及

平平无奇爱好科技

面试官:介绍一下什么是缓存雪崩、缓存击穿、缓存穿透?

做梦都在改BUG

Java redis 缓存穿透 缓存击穿 缓存雪崩

NFT加密钱包交易系统开发搭建技术

薇電13242772558

NFT

photoshop 2023【存储为窗口显示空白、黑屏】解决方法

Rose

ps 2023储存黑屏 Photoshop 2023

跨平台应用开发进阶(五十五):uni-app 获取设备信息及 APP 报无相应权限问题分析及解决

No Silver Bullet

uni-app 跨平台应用开发 三周年连更 问题分析及解决 设备信息

Spring Boot之log4j2基础使用入门|超级详细,建议收藏

bug菌

Spring Boot log4j2 三周年连更

Linux面试必备

袁袁袁袁满

三周年连更

灵活高效,华为云桌面实现随时随地办公

YG科技

华为云CDN加速,赋能企业数字化转型升级

YG科技

从源码全面解析 ArrayBlockingQueue 的来龙去脉

做梦都在改BUG

Java 源码 ArrayBlockingQueue

Oracle apex社区教程 PLSQL常用时间函数

back_wang

oracle apex

【直播回顾】数字化转型成为银行业发展的关键(下)

易观分析

数字化转型 银行

Uber 如何实现 Go 代码中的动态数据竞争检测_架构_Uber Engineering_InfoQ精选文章