2017年6月

LinuxCon 2017 (北京)已经结束几天了,一些不能现场亲临的朋友纷纷询问有无 LC3 大会的重头戏 Linus Torvalds 专访的视频,也有在现场看了讲演而意犹未尽的同学希望进一步看到演讲稿。

经过参加本次 LC3 大会的 Linux 中国代表队的诸位小伙伴的努力,我们终于收集到部分资源分享给大家。由于演讲稿还在陆续更新当中,目前只有部分演讲稿释出,一旦找到新的演讲稿,我们会陆续跟进补充。

Linus Torvalds 专访

采访者:VMware 副总裁兼首席开源官 Dirk Hohndel

本视频来自 @d0u9 现场录制并剪辑,未配置字幕。

以下中文的会议日程来自 LinuxCon 官方,其中存在翻译不正确之处,敬请指出。

2017-06-19 日程

09:00-10:30 主题演讲

  • Linux 基金会执行董事 Jim Zemlin
  • 中国开源推进联盟荣誉主席 陆首群
  • 华为开放软件与系统首席架构师 侯培新
  • OpenStack 基金会执行董事 Jonathan Bryce
  • 微软亚太研发集团云计算与企业事业部资深合伙人 梁戈碧

11:00-11:40

11:40-12:10

13:35-14:15

14:15-14:55

14:55-15:35

15:35-16:05

16:15-17:35 主题演讲

  • 中国联通网络技术研究院技术专家周伟博士
  • 思科系统工程首席技术官兼首席架构师 Dave Ward
  • 才云科技CEO张鑫
  • 华为网络产品线战略和产业发展副总裁任旭东

2017-06-20 日程

09:00-10:30 主题演讲

  • Linux和Git创始人 Linus Torvalds 和 VMware 副总裁兼首席开源官 Dirk Hohndel
  • 中国移动研究院副院长杨志强
  • 阿里云首席架构师唐洪
  • SUSE首席技术官 Thomas Di Giacomo

11:00-11:40

11:40-12:10

  • FOSSology - 高清许可证合规新功能——西门子股份公司/Michael Jaeger
  • uKVM上的64位的单核ARM – ARM/Wei Chen
  • 容器网络概述——红帽/Rajat Chopra
  • 基地容器的大规模机器学习平台——阿里云/Kai Zhang
  • 使用预防性工具强化物联网端点——Almaden研究中心/Rabimba Karanjai
  • 使用Kubernetes的云原生微服务架构对已有系统进行整体化迁移——云原生计算基金会/Dan Kohn
  • 阿里巴巴基于Linux内核资源的管理工作——阿里云/Tao Ma
  • 优化基于Linux分布式存储系统的尾部延时——阿里云/Wang Xiaorui
  • 仅使用FD.io VPP实现高性能服务功能链——英特尔/Yi Yang

13:35-14:15

14:15-14:55

14:55-15:35

15:35-16:05

  • OpenSDS:云原生存储管理的大规模应用——Futurewei /Steven Tan,
  • BoF:Fedora,CentOS和EPEL ——红帽/Brian Exelbierd
  • IaaS背景下的内存带宽服务——英特尔/Vikas Shivappa
  • 通用VNF配置管理和编制——Canonical/Adam Israel,Canonical

16:15-17:15 主题演讲

  • 红帽高级副总裁兼亚太区总经理 Dirk-Peter van Leeuwen
  • 谷歌 Kubernetes 技术负责人 Ian Lewis
  • 英特尔开源软件技术中心 陈旭

17:15-18:00 Linux 基金会执行董事 Jim Zemlin 致闭幕词

(陆续更新中……)

Facebook 经常使用数据驱动的分析方法来做决策。在过去的几年,用户和产品的增长已经需要我们的分析工程师一次查询就要操作数十 TB 大小的数据集。我们的一些批量分析执行在古老的 Hive 平台( Apache Hive 由 Facebook 贡献于 2009 年)和 Corona 上——这是我们定制的 MapReduce 实现。Facebook 还不断增加其对 Presto 的用量,用于对几个包括 Hive 在内的内部数据存储的 ANSI-SQL 查询。我们也支持其他分析类型,比如 图数据库处理 graph processing 和机器学习(Apache Giraph)和流(例如:PumaSwiftStylus)。

同时 Facebook 的各种产品涵盖了广泛的分析领域,我们与开源社区不断保持沟通,以便共享我们的经验并从其他人那里学习。Apache Spark 于 2009 年在加州大学伯克利分校的 AMPLab 由 Matei Zaharia 发起,后来在2013 年贡献给 Apache。它是目前增长最快的数据处理平台之一,由于它能支持流、批量、命令式(RDD)、声明式(SQL)、图数据库和机器学习等用例,而且所有这些都内置在相同的 API 和底层计算引擎中。Spark 可以有效地利用更大量级的内存,优化整个 流水线 pipeline 中的代码,并跨任务重用 JVM 以获得更好的性能。最近我们感觉 Spark 已经成熟,我们可以在一些批量处理用例方面把它与 Hive 相比较。在这篇文章其余的部分,我们讲述了在扩展 Spark 来替代我们一个 Hive 工作任务时的所得到经验和学习到的教训。

用例:实体排名的特征准备

Facebook 会以多种方式做实时的 实体 entity 排名。对于一些在线服务平台,原始特征值是由 Hive 线下生成的,然后将数据加载到实时关联查询系统。我们在几年前建立的基于 Hive 的老式基础设施属于计算资源密集型,且很难维护,因为其流水线被划分成数百个较小的 Hive 任务。为了可以使用更加新的特征数据和提升可管理性,我们拿一个现有的流水线试着将其迁移至 Spark。

以前的 Hive 实现

基于 Hive 的流水线由三个逻辑 阶段 stage 组成,每个阶段对应由 entity\_id 划分的数百个较小的 Hive 作业,因为在每个阶段运行大型 Hive 作业 job 不太可靠,并受到每个作业的最大 任务 task 数量的限制。

这三个逻辑阶段可以总结如下:

  1. 过滤出非产品的特征和噪点。
  2. 在每个(entity\_id, target\_id)对上进行聚合。
  3. 将表格分割成 N 个分片,并通过自定义二进制文件管理每个分片,以生成用于在线查询的自定义索引文件。

基于 Hive 的流水线建立该索引大概要三天完成。它也难于管理,因为该流水线包含上百个分片的作业,使监控也变得困难。同时也没有好的方法来估算流水线进度或计算剩余时间。考虑到 Hive 流水线的上述限制,我们决定建立一个更快、更易于管理的 Spark 流水线。

Spark 实现

全量的调试会很慢,有挑战,而且是资源密集型的。我们从转换基于 Hive 流水线的最资源密集型的第二阶段开始。我们以一个 50GB 的压缩输入例子开始,然后逐渐扩展到 300GB、1TB,然后到 20TB。在每次规模增长时,我们都解决了性能和稳定性问题,但是实验到 20TB 时,我们发现了最大的改善机会。

运行 20TB 的输入时,我们发现,由于大量的任务导致我们生成了太多输出文件(每个大小在 100MB 左右)。在 10 小时的作业运行时中,有三分之一是用在将文件从阶段目录移动到 HDFS 中的最终目录。起初,我们考虑两个方案:要么改善 HDFS 中的批量重命名来支持我们的用例,或者配置 Spark 生成更少的输出文件(这很难,由于在这一步有大量的任务 — 70000 个)。我们退一步来看这个问题,考虑第三种方案。由于我们在流水线的第二步中生成的 tmp\_table2 表是临时的,仅用于存储流水线的中间输出,所以对于 TB 级数据的单一读取作业任务,我们基本上是在压缩、序列化和复制三个副本。相反,我们更进一步:移除两个临时表并整合 Hive 过程的所有三个部分到一个单独的 Spark 作业,读取 60TB 的压缩数据然后对 90TB 的数据执行 重排 shuffle 排序 sort 。最终的 Spark 作业如下:

对于我们的作业如何规划 Spark?

当然,为如此大的流水线运行一个单独的 Spark 任务,第一次尝试没有成功,甚至是第十次尝试也没有。据我们所知,从 重排 shuffle 的数据大小来说,这是现实世界最大的 Spark 作业(Databrick 的 PB 级排序是以合成数据来说)。我们对核心 Spark 基础架构和我们的应用程序进行了许多改进和优化使这个作业得以运行。这种努力的优势在于,许多这些改进适用于 Spark 的其他大型作业任务,我们将所有的工作回馈给开源 Apache Spark 项目 - 有关详细信息请参阅 JIRA。下面,我们将重点讲述将实体排名流水线之一部署到生产环境所做的重大改进。

可靠性修复

处理频繁的节点重启

为了可靠地执行长时间运行作业,我们希望系统能够容错并可以从故障中恢复(主要是由于平时的维护或软件错误导致的机器重启所引发的)。虽然 Spark 设计为可以容忍机器重启,但我们发现它在足够强健到可以处理常见故障之前还有各种错误/问题需要解决。

  • 使 PipedRDD 稳健的 获取 fetch 失败(SPARK-13793):PipedRDD 以前的实现不够强大,无法处理由于节点重启而导致的获取失败,并且只要出现获取失败,该作业就会失败。我们在 PipedRDD 中进行了更改,优雅的处理获取失败,使该作业可以从这种类型的获取失败中恢复。
  • 可配置的最大获取失败次数(SPARK-13369):对于这种长时间运行的作业,由于机器重启而引起的获取失败概率显着增加。在 Spark 中每个阶段的最大允许的获取失败次数是硬编码的,因此,当达到最大数量时该作业将失败。我们做了一个改变,使它是可配置的,并且在这个用例中将其从 4 增长到 20,从而使作业更稳健。
  • 减少集群重启混乱:长时间运行作业应该可以在集群重启后存留,所以我们不用等着处理完成。Spark 的可重启的 重排 shuffle 服务功能可以使我们在节点重启后保留 重排 shuffle 文件。最重要的是,我们在 Spark 驱动程序中实现了一项功能,可以暂停执行任务调度,所以不会由于集群重启而导致的过多的任务失败,从而导致作业失败。

其他的可靠性修复

  • 响应迟钝的驱动程序(SPARK-13279):在添加任务时,由于 O(N ^ 2) 复杂度的操作,Spark 驱动程序被卡住,导致该作业最终被卡住和死亡。 我们通过删除不必要的 O(N ^ 2) 操作来修复问题。
  • 过多的驱动 推测 speculation :我们发现,Spark 驱动程序在管理大量任务时花费了大量的时间推测。 在短期内,我们禁止这个作业的推测。在长期,我们正在努力改变 Spark 驱动程序,以减少推测时间。
  • 由于大型缓冲区的整数溢出导致的 TimSort 问题(SPARK-13850):我们发现 Spark 的不安全内存操作有一个漏洞,导致 TimSort 中的内存损坏。 感谢 Databricks 的人解决了这个问题,这使我们能够在大内存缓冲区中运行。
  • 调整重排(shuffle)服务来处理大量连接:在重排阶段,我们看到许多执行程序在尝试连接重排服务时超时。 增加 Netty 服务器的线程(spark.shuffle.io.serverThreads)和积压(spark.shuffle.io.backLog)的数量解决了这个问题。
  • 修复 Spark 执行程序 OOM(SPARK-13958)(deal maker):首先在每个主机上打包超过四个 聚合 reduce 任务是很困难的。Spark 执行程序会内存溢出,因为排序程序(sorter)中存在导致无限增长的指针数组的漏洞。当不再有可用的内存用于指针数组增长时,我们通过强制将数据溢出到磁盘来修复问题。因此,现在我们可以每主机运行 24 个任务,而不会内存溢出。

性能改进

在实施上述可靠性改进后,我们能够可靠地运行 Spark 作业了。基于这一点,我们将精力转向与性能相关的项目,以充分发挥 Spark 的作用。我们使用 Spark 的指标和几个分析器来查找一些性能瓶颈。

我们用来查找性能瓶颈的工具

  • Spark UI 指标:Spark UI 可以很好地了解在特定阶段所花费的时间。每个任务的执行时间被分为子阶段,以便更容易地找到作业中的瓶颈。
  • Jstack:Spark UI 还在执行程序进程上提供了一个按需分配的 jstack 函数,可用于中查找热点代码。
  • Spark 的 Linux Perf / 火焰图 Flame Graph 支持:尽管上述两个工具非常方便,但它们并不提供同时在数百台机器上运行的作业的 CPU 分析的聚合视图。在每个作业的基础上,我们添加了支持 Perf 分析(通过 libperfagent 的 Java 符号),并可以自定义采样的持续时间/频率。使用我们的内部指标收集框架,将分析样本聚合并显示为整个执行程序的火焰图。

性能优化

  • 修复 排序程序 sorter 中的内存泄漏(SPARK-14363)(30% 速度提升):我们发现了一个问题,当任务释放所有内存页时指针数组却未被释放。 因此,大量的内存未被使用,并导致频繁的溢出和执行程序 OOM。 我们现在进行了改变,正确地释放内存,并使大的分类运行更有效。 我们注意到,这一变化后 CPU 改善了 30%。
  • Snappy 优化(SPARK-14277)(10% 速度提升):有个 JNI 方法(Snappy.ArrayCopy)在每一行被读取/写入时都会被调用。 我们发现了这个问题,Snappy 的行为被改为使用非 JNI 的 System.ArrayCopy 代替。 这一改变节约了大约 10% 的 CPU。
  • 减少重排的写入延迟(SPARK-5581)(高达 50% 的速度提升):在 映射 map 方面,当将重排数据写入磁盘时,映射任务为每个分区打开并关闭相同的文件。 我们做了一个修复,以避免不必要的打开/关闭,对于大量写入重排分区的作业来说,我们观察到高达 50% 的 CPU 提升。
  • 解决由于获取失败导致的重复任务运行问题(SPARK-14649):当获取失败发生时,Spark 驱动程序会重新提交已运行的任务,导致性能下降。 我们通过避免重新运行运行的任务来解决这个问题,我们看到当获取失败发生时该作业会更加稳定。
  • 可配置 PipedRDD 的缓冲区大小(SPARK-14542)(10% 速度提升):在使用 PipedRDD 时,我们发现将数据从分类程序传输到管道进程的默认缓冲区的大小太小,我们的作业要花费超过 10% 的时间复制数据。我们使缓冲区大小可配置,以避免这个瓶颈。
  • 缓存索引文件以加速重排获取(SPARK-15074):我们观察到重排服务经常成为瓶颈, 减少程序 reducer 花费 10% 至 15% 的时间等待获取 映射 map 数据。通过深入了解问题,我们发现,重排服务为每个重排获取打开/关闭重排索引文件。我们进行了更改以缓存索引信息,以便我们可以避免文件打开/关闭,并重新使用该索引信息以便后续获取。这个变化将总的重排时间减少了 50%。
  • 降低重排字节写入指标的更新频率(SPARK-15569)(高达 20% 的速度提升):使用 Spark 的 Linux Perf 集成,我们发现大约 20% 的 CPU 时间正在花费探测和更新写入的重排字节写入指标上。
  • 可配置排序程序(sorter)的初始缓冲区大小(SPARK-15958)(高达 5% 的速度提升): 排序程序 sorter 的默认初始缓冲区大小太小(4 KB),我们发现它对于大型工作负载而言非常小 - 所以我们在缓冲区耗尽和内容复制上浪费了大量的时间。我们做了一个更改,使缓冲区大小可配置,并且缓冲区大小为 64 MB,我们可以避免大量的数据复制,使作业的速度提高约 5%。
  • 配置任务数量:由于我们的输入大小为 60T,每个 HDFS 块大小为 256M,因此我们为该作业产生了超过 250,000 个任务。尽管我们能够以如此多的任务来运行 Spark 作业,但是我们发现,当任务数量过高时,性能会下降。我们引入了一个配置参数,使 映射 map 输入大小可配置,因此我们可以通过将输入分割大小设置为 2 GB 来将该数量减少 8 倍。

在所有这些可靠性和性能改进之后,我们很高兴地报告,我们为我们的实体排名系统之一构建和部署了一个更快、更易于管理的流水线,并且我们提供了在 Spark 中运行其他类似作业的能力。

Spark 流水线与 Hive 流水线性能对比

我们使用以下性能指标来比较 Spark 流水线与 Hive 流水线。请注意,这些数字并不是在查询或作业级别的直接比较 Spark 与 Hive ,而是比较使用灵活的计算引擎(例如 Spark)构建优化的流水线,而不是比较仅在查询/作业级别(如 Hive)操作的计算引擎。

CPU 时间:这是从系统角度看 CPU 使用。例如,你在一个 32 核机器上使用 50% 的 CPU 10 秒运行一个单进程任务,然后你的 CPU 时间应该是 32 * 0.5 * 10 = 160 CPU 秒。

CPU 预留时间:这是从资源管理框架的角度来看 CPU 预留。例如,如果我们保留 32 位机器 10 秒钟来运行作业,则CPU 预留时间为 32 * 10 = 320 CPU 秒。CPU 时间与 CPU 预留时间的比率反映了我们如何在集群上利用预留的CPU 资源。当准确时,与 CPU 时间相比,预留时间在运行相同工作负载时可以更好地比较执行引擎。例如,如果一个进程需要 1 个 CPU 的时间才能运行,但是必须保留 100 个 CPU 秒,则该指标的效率要低于需要 10 个 CPU 秒而仅保留 10 个 CPU 秒来执行相同的工作量的进程。我们还计算内存预留时间,但不包括在这里,因为其数字类似于 CPU 预留时间,因为在同一硬件上运行实验,而在 Spark 和 Hive 的情况下,我们不会将数据缓存在内存中。Spark 有能力在内存中缓存数据,但是由于我们的集群内存限制,我们决定类似与 Hive 一样工作在核心外部。

等待时间:端到端的工作流失时间。

结论和未来工作

Facebook 的性能和可扩展的分析在产品开发中给予了协助。Apache Spark 提供了将各种分析用例统一为单一 API 和高效计算引擎的独特功能。我们挑战了 Spark,来将一个分解成数百个 Hive 作业的流水线替换成一个 Spark 作业。通过一系列的性能和可靠性改进之后,我们可以将 Spark 扩大到处理我们在生产中的实体排名数据处理用例之一。 在这个特殊用例中,我们展示了 Spark 可以可靠地重排和排序 90 TB+ 的中间数据,并在一个单一作业中运行了 25 万个任务。 与旧的基于 Hive 的流水线相比,基于 Spark 的流水线产生了显着的性能改进(4.5-6 倍 CPU,3-4 倍资源预留和大约 5 倍的延迟),并且已经投入使用了几个月。

虽然本文详细介绍了我们 Spark 最具挑战性的用例,越来越多的客户团队已将 Spark 工作负载部署到生产中。 性能 、可维护性和灵活性是继续推动更多用例到 Spark 的优势。 Facebook 很高兴成为 Spark 开源社区的一部分,并将共同开发 Spark 充分发挥其潜力。


via: https://code.facebook.com/posts/1671373793181703/apache-spark-scale-a-60-tb-production-use-case/

作者:Sital Kedia, 王硕杰, Avery Ching 译者:wyangsun 校对:wxy

本文由 LCTT 组织编译,Linux中国 荣誉推出

即使你是一个 Linux 新人,你可能也已经知道它不是一个单一的、整体的操作系统,而是一群项目。这个星座中不同的“星”组成了“发行版”。每个都提供了自己的 Linux 模式。

感谢这一系列发行版所提供的多种选择,这有助于了解 Linux 如何开始并随后激增的。因此,这里会简要介绍一下 Linux 的历史。

Linus Torvalds,内核构建者

大多数熟悉 Linux 的人都已经听说过它的创建者 Linus Torvalds (题图中的人),但是并不知道他最初为何创建它。在 1991 年,Torvalds 还是一名在芬兰学习计算机的大学生。作为一个独立的个人项目,他希望为他的独特硬件创建一个类 Unix 内核。

“内核”是操作系统的一部分,它介乎于操作系统和硬件之间,通过其固件进行协调。本质上,它是系统的核心。开发内核不是一个小工程,但是 Torvalds 渴望挑战,并且发现他自己有这个罕见的技能。

由于他刚接触内核,他希望得到其他人的帮助来确保他走在正确的轨道上,因此他通过在早期的互联网论坛 Usenet 发布他的内核代码,并征求了老牌的老手的经验。然后贡献者就涌来了。

在建立了一个对论坛提交的补丁进行审查以及选择性地集成它们的流程后,Torvalds 意识到他聚集起了一个非正式的团队。在项目发展之后,它很快成为了一个比较正式的开发团队。

Richard Stallman 的角色

虽然 Torvalds 以及他的团建创造了 Linux 内核,但是没有 Richard Stallman 的工作也不会有随后 Linux 众多发行版的传播,Richard 在十年之前发起了一个自由软件运动。

受到许多核心 Unix 程序和系统功能缺乏透明度的阻挠,Stallman 决定自己编写一个,与任何想要它的人自由共享源代码,并且开放提交。他创造了许多核心程序的主体,并在 1983 年发布,统称为 “GNU 项目”。

没有它们,内核不会有那么多的用量。基于 Linux 的操作系统的早期设计人员很乐意将 GNU 工具集成到他们的项目中。

不同的团队开始出现 - 每个团队都有自己的计算功能和架构的理念。他们将 Linux 内核、GNU 实用程序和他们自己的原始软件结合在一起,然而“发行”了 Linux 操作系统的变体。

服务器发行版

每个发行版有它自己的设计逻辑和目的,但是要了解它们的细微差别,需要了解上游和下游开发人员之间的区别。“上游开发人员”负责实际创建项目并发布,以供个人下载或将其包含在其他项目中。相比之下,“下游开发人员”或“软件包维护人员”是指每个发布上游程序的人员,他们对每个上游程序的版本进行调整以适应下游项目的使用情况。

虽然大多数 Linux 发行版包含一些(自己的)原生项目,但大部分发行版开发主要是对 Linux 内核、GNU 工具和庞大的用户程序生态系统的“下游”工作。

许多发行通过优化特定使用场景来彰显它们的特征。例如,某些项目被设计作为服务器运行。为部署服务器而量身定制的发行版通常会避开上游项目中快速推出的最新功能,而倾向于发布一个经过彻底测试的、基础的基本软件,系统管理员可以依靠它来顺利运行。

针对服务器的发行版的的开发团队经常很大,并且有富有经验的程序员可以为每个版本提供多年的支持。

桌面发行版

也有很多的发行版针对桌面用户。事实上,一些知名的发行版通过提供简单的安装以及直观的界面来与商业的操作系统竞争。这些发行版通常包含了大量的软件仓库,它包含了用户可以想到的每个软件,这样用户可以定制它们自己的系统。

由于可用性是关键,他们可能会投入部门大量的员工来创建一个特征鲜明的、发行版特定的桌面,或调整已有的桌面以适应其设计理念。以用户为中心的发行版往往会加快其下游开发时间表,有助于及时为用户提供新功能。

“滚动发布”项目,这是一种桌面发行版的子集,其被设计成紧跟潮流。滚动发布项目的包维护人员在为每个上游程序完成调整后分别发布其新版本,而不是等待所需的上游程序的开发达到某一特定的节点,然后将其集成到单个版本中。

这种方法的一个优点是安全性,因为其关键补丁的发布将比非滚动发行版更快。另一个好处是新功能立即可用,不然用户需要等待才行。滚动发布的缺点是需要更多的人工干预和仔细维护,因为某些升级可能会与其他升级相冲突从而破坏系统。

嵌入式系统

另外一个 Linux 发行版类别是“嵌入式系统”,它被极致裁剪(相对与服务器和桌面发行版)来适应特定的使用情况。

我们经常会忘记那些连接到因特网的任何东西,或者比一个简单的计算器复杂的东西,都是计算机。而计算机需要操作系统。因为 Linux 是自由的并且高度模块化,所以它通常是硬件厂商的选择。

在大多数情况下,如果你看见一台智能电视、一台连接互联网的照相机、甚至是一辆车,你看到的都是 Linux 设备。特别是每部非 iPhone 的智能手机都运行着不同的嵌入式 Linux。

Linux 现场版

最后,有一些 Linux 发行版并不需要永久性地安装在计算机中,而是驻留在 USB 记忆棒上,并允许在其它的计算机上启动它们,而无需计算机硬盘。

这些 “现场版(live)” 的系统可以被优化来执行一些任务。从修复损坏的系统到进行安全评估到高度安全地浏览因特网。

由于这些 现场版 Linux 发行版通常针对解决特定的问题,因此它们一般都包含特定的工具,像磁盘分析和恢复程序、网络监控程序和加密工具。它们还占用很小的空间,因此它们可以快速启动。

你如何选择?

这绝不是 Linux 发行版类型的全面列表,但它应该可以让你大致了解 Linux 生态系统的范围和多样化了。

在每个类别下都有许多选择,因此你会如何选择一个最能符合你需求的版本呢?

一种方式是试验。在 Linux 社区中,来回尝试不同的发行版,或者为用户根据他们的需求在不同的机器上运行不同的发行版,这都很常见。

在将来的文章中,我会展示每种类型发行版的几个例子,以便你可以自己尝试,并开始探索最喜欢的发行版的旅程。


作者简介:

自 2017 年以来 Jonathan Terrasi 一直是 ECT 新闻网的专栏作家。他的主要兴趣是计算机安全(特别是 Linux 桌面),加密和分析政治和时事。他是全职自由作家和音乐家。他的背景包括在芝加哥委员会发表的保卫人权法案文章中提供技术评论和分析。


via: http://www.linuxinsider.com/story/84489.html

作者:Jonathan Terrasi 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

开源项目的首要挑战是找出最佳的贡献者协作方式

 title=

开源项目要面对的首要挑战之一是如何在贡献者之间沟通。这里有很多的选择:论坛、聊天频道、 工单 issue 、邮件列表、 拉取请求 pull request 等等。我们该选择哪个合适的来使用,我们又该如何做呢?

令人遗憾的是,项目本身往往不愿做出约束性的决定,而是选择“上述所有”。这就导致了一个支离破碎的社区:有些人使用 Slack/Mattermost/IRC,而有些人使用论坛,有些使用邮件列表,有些则存在于工单之中,很少有人能够读到所有这些途径的内容。

在我帮助其建立内外部社区的组织中,这是一个常见的问题。我们会选择哪个渠道,以及出于什么目的?另外,何时可以对它们之一说不呢?

这就是我想在此处深度探讨的。

结构化和非结构化

我并不是个聪明人。因此,我倾向于将问题分成小的部分,这样我可以更好地理解它们。类似地,我倾向于将一个情景中各种选择拆解成更小的部分,来更好地理解它们的目的。我在沟通渠道的选择上也使用这种方法。

我认为有两大沟通渠道的分类:结构化和非结构化。

结构化渠道在每个单独的沟通单元中都有非常具体的重点。例子如:GitHub / GitLab /Jira 的 工单 issue 。一个工单是与 bug 或功能有关的一个非常具体的信息。在初始的工单帖子发布之后引发的系列讨论中,通常非常集中在该特定话题上,并会有一个结果(比如 bugfix 或者一个功能的最终计划)。结果通常都反映在状态(例如 “FIXED”、“WONTFIX” 或 “INVALID”)中。这意味着你可以了解沟通的始末,而无需阅读中间的内容。

类似的,拉取/合并请求也是结构化的。它们集中在特定类型(通常是代码)的贡献上。在最初的拉取/合并请求后,讨论会非常集中在一个结果上:让贡献符合要求,且合并入代码库中。

另一个例子是 StackOverflow/AskBot 这类的问答帖子。这些帖子以一个问题开始,接着被编辑以及回复来提供对这个问题的精确答案。

通过这些结构化机制,通常几乎不会偏离其本来结构。你不会在工单、拉取请求或问答话题上看到有人问别人他们的孩子/猫/狗/家人在做什么。偏离话题在社区是不可接受的,这是结构化媒体的力量的一部分:它是集中和(通常)高效的。

反之,非结构化媒体包括聊天频道和论坛。在这些环境中,通常会有一个主题(例如频道或分论坛的主题),但是其中的会话与特定结果或结论的关系要小得多,而且通常情况下可能会更普遍。例如,在开发者邮件列表中,你会看到一系列讨论,包括一般问题、新功能的想法、架构争论以及与社区自身运营相关的讨论。每一个讨论都希望让参与者保持对话的焦点、主题和工作效率。但你可以想象,情况往往不是这样的, 这种讨论可能会偏离一个富有成效的结果。

记录的影响

除了结构化和非结构化沟通的微妙不同外,所记录的内容以及它们如何搜索的所带来的影响也很重要。

典型的,所有的结构化渠道都是记录的。人们可以参考以前的 bug,来自 StackOverflow 的问题可以被反复地重新利用。你可以搜索一些东西,即使有很多讨论、常见问题、拉取请求或者提问,都会被更新以反映最终结论。

这是一个重点:我们希望能够快速、轻松地挖掘旧问题/提问/拉取请求等,并链接到它们、引用它们。这里的一个关键部分是我们把这个内容转换成可以引用的材料,从而可以用来教育和告知人们以前的知识。随着社区的发展,我们的结构化沟通成为一种知识库,可以通过以往的经验来告知未来。

而非结构化沟通变得越来越糟。一方面,论坛的搜索通常都简单高效,但是它们当然充满了非结构化的对话,所以你正在寻找的东西可能被埋在讨论之中。例如,许多社区使用论坛作为支持工具。虽然这是一个更强大的平台,但是问题在于,一个问题的答案可能是在 16 楼或者 340 楼中有回复。随着越来越多的信息来源(比如 Twitter)的轰炸,我们越来越不耐烦地阅读大量的材料,这对于非结构化媒体来说可能是一个问题。

一个有趣的特定案例是实时聊天。历史上,很多年来,IRC 为实时聊天铺平了道路,对于大多数 IRC 用户而言很少有(如果有的话)记录这些讨论的念头。的确,一些项目(比如 Ubuntu)记录了 IRC 日志,但是这通常不是有用的资源。如我的伙伴 Atwood 有一次跟我说的:“如果你不得不在聊天中搜索一些东西时,你已经输了。”

虽然 IRC 在记录上有所不足,而 Slack 和 Mattermost 会好点。交流会被归档,但是问题仍旧存在:你为什么会想在海量的聊天信息中找出一个人提出的观点呢?其他的渠道能更好地引用先前的讨论。

不过,这的确创造了一个有趣的机会。聊天相比其他媒体有个一贯的好处是能体现这是个怎样的人。结构化的渠道,甚至非结构化的渠道,如论坛和邮件列表,很少鼓励闲聊。但聊天是的,聊天时你会问:“你周末怎么样?”、 “你见过这个游戏吗?”还有“你下周会看 Testament,Sepultura 和 Prong 吗?” (好吧,也许问最后一个问题的只有我。)

因此,虽然实时聊天相比前面的那些方式也许更低效一些,但是它的确增进了人们的关系。

你想喝点什么

因此,回到我们最初的对于开源社区的提问:我们要选择哪个?

虽然这个答案对于不同的项目会不同,但我想在两个层面思考。

首先,你通常应该优先考虑结构化沟通。这是完成有形工作的地方:问题/工单、拉取请求、问答讨论等等。如果你资源有限,那么专注在这些渠道上,你可以用较少的时间和金钱支出,获得社区的高效产出。

再者,如果你热衷于建立一个可以专注于工程、宣传、翻译、文档等方面的更广泛的社区,那么探究是否引入非结构化渠道就有意义了。 社区不仅仅是为了完成工作,也是为了建立关系和友谊,在工作中相互支持,帮助人们在社区中发展壮大。非结构化通信是一个有用的工具。

当然,我只是在一个大的话题上浅谈辄止。 不过我希望在如何评估和选择沟通渠道的价值方面,为大家提供了一些辨析。记住,少即是多:不要被拥有所有的渠道的妄想而诱惑,否则你会得到一个支离破碎社区,就像一个空荡荡的餐厅一样。

愿原力与你同在,请让我知道你进行的如何。你可以通过我的网站和邮箱 [email protected] 联系到我。

(题图: Opensource.com)


作者简介:

Jono Bacon 是一名领先的社区管理者、演讲者、作者和播客。他是 Jono Bacon Consulting 的创始人,提供社区策略/执行、开发者工作流程和其他服务。他以前曾担任 GitHub、Canonical、XPRIZE、OpenAdvantage 的社区总监,并为很多组织曾经提供建议和咨询。


via: https://opensource.com/article/17/5/much-ado-about-communication

作者:Jono Bacon 译者:geekpi 校对:jasminepeng

本文由 LCTT 原创编译,Linux中国 荣誉推出

任何写过比 hello world 复杂一些的程序的人都应该使用过调试器(如果你还没有,那就停下手头的工作先学习一下吧)。但是,尽管这些工具已经得到了广泛的使用,却并没有太多的资源告诉你它们的工作原理以及如何开发,尤其是和其它那些比如编译器等工具链技术相比而言。

此处有一些其它的资源可以参考:

我们将会支持以下功能:

  • 启动、暂停、继续执行
  • 在不同地方设置断点

    • 内存地址
    • 源代码行
    • 函数入口
  • 读写寄存器和内存
  • 单步执行

    • 指令
    • 进入函数
    • 跳出函数
    • 跳过函数
  • 打印当前代码地址
  • 打印函数调用栈
  • 打印简单变量的值

在最后一部分,我还会大概介绍如何给你的调试器添加下面的功能:

  • 远程调试
  • 共享库和动态库支持
  • 表达式计算
  • 多线程调试支持

在本项目中我会将重点放在 C 和 C++,但对于那些将源码编译为机器码并输出标准 DWARE 调试信息的语言也应该能起作用(如果你还不知道这些东西是什么,别担心,马上就会介绍到啦)。另外,我只关注如何将程序运行起来并在大部分情况下能正常工作,为了简便,会避开类似健壮错误处理方面的东西。

系列文章索引

随着后面文章的发布,这些链接会逐渐生效。

  1. 准备环境
  2. 断点
  3. 寄存器和内存
  4. Elves 和 dwarves
  5. 源码和信号
  6. 源码层逐步执行
  7. 源码层断点
  8. 调用栈
  9. 读取变量
  10. 之后步骤

LCTT 译注:ELF —— 可执行文件格式 Executable and Linkable Format ;DWARF(一种广泛使用的调试数据格式,参考 WIKI)。

准备环境

在我们正式开始之前,我们首先要设置环境。在这篇文章中我会依赖两个工具:Linenoise 用于处理命令行输入,libelfin 用于解析调试信息。你也可以使用更传统的 libdwarf 而不是 libelfin,但是界面没有那么友好,另外 libelfin 还提供了基本完整的 DWARF 表达式求值器,当你想读取变量的值时这能帮你节省很多时间。确认你使用的是 libelfin 我的 fbreg 分支,因为它提供 x86 上读取变量的额外支持。

一旦你在系统上安装或者使用你喜欢的编译系统编译好了这些依赖工具,就可以开始啦。我在 CMake 文件中把它们设置为和我其余的代码一起编译。

启动可执行程序

在真正调试任何程序之前,我们需要启动被调试的程序。我们会使用经典的 fork/exec 模式。

int main(int argc, char* argv[]) {
    if (argc < 2) {
        std::cerr << "Program name not specified";
        return -1;
    }

    auto prog = argv[1];

    auto pid = fork();
    if (pid == 0) {
        //we're in the child process
        //execute debugee

    }
    else if (pid >= 1)  {
        //we're in the parent process
        //execute debugger
    }

我们调用 fork 把我们的程序分成两个进程。如果我们是在子进程,fork 返回 0,如果我们是在父进程,它会返回子进程的进程 ID。

如果我们是在子进程,我们要用希望调试的程序替换正在执行的程序。

   ptrace(PTRACE_TRACEME, 0, nullptr, nullptr);
   execl(prog.c_str(), prog.c_str(), nullptr);

这里我们第一次遇到了 ptrace,它会在我们编写调试器的时候经常遇到。ptrace 通过读取寄存器、内存、逐步调试等让我们观察和控制另一个进程的执行。其 API 非常简单;你需要给这个简单函数提供一个枚举值指定你想要进行的操作,然后是一些取决于你所提供的值可能会被使用也可能会被忽略的参数。函数原型看起来类似:

long ptrace(enum __ptrace_request request, pid_t pid,
            void *addr, void *data);

request 是我们想对被跟踪进程进行的操作;pid 是被跟踪进程的进程 ID;addr 是一个内存地址,用于在一些调用中指定被跟踪程序的地址;datarequest 相应的资源。返回值通常是一些错误信息,因此在你实际的代码中你也许应该检查返回值;为了简洁我这里就省略了。你可以查看 man 手册获取更多(关于 ptrace)的信息。

上面代码中我们发送的请求 PTRACE_TRACEME 表示这个进程应该允许父进程跟踪它。所有其它参数都会被忽略,因为 API 设计并不是很重要,哈哈。

下一步,我们会调用 execl,这是很多诸多的 exec 函数格式之一。我们执行指定的程序,通过命令行参数传递它的名称,然后用一个 nullptr 终止列表。如果你愿意,你还可以传递其它执行你的程序所需的参数。

在完成这些后,我们就会和子进程一起结束;在我们结束它之前它会一直执行。

添加调试循环

现在我们已经启动了子进程,我们想要能够和它进行交互。为此,我们会创建一个 debugger 类,循环监听用户输入,然后在我们父进程的 main 函数中启动它。

else if (pid >= 1)  {
    //parent
    debugger dbg{prog, pid};
    dbg.run();
}
class debugger {
public:
    debugger (std::string prog_name, pid_t pid)
        : m_prog_name{std::move(prog_name)}, m_pid{pid} {}

    void run();

private:
    std::string m_prog_name;
    pid_t m_pid;
};

run 函数中,我们需要等待,直到子进程完成启动,然后一直从 linenoise 获取输入直到收到 EOFCTRL+D)。

void debugger::run() {
    int wait_status;
    auto options = 0;
    waitpid(m_pid, &wait_status, options);

    char* line = nullptr;
    while((line = linenoise("minidbg> ")) != nullptr) {
        handle_command(line);
        linenoiseHistoryAdd(line);
        linenoiseFree(line);
    }
}

当被跟踪的进程启动时,会发送一个 SIGTRAP 信号给它,这是一个跟踪或者断点中断。我们可以使用 waitpid 函数等待这个信号发送。

当我们知道进程可以被调试之后,我们监听用户输入。linenoise 函数它自己会用一个窗口显示和处理用户输入。这意味着我们不需要做太多的工作就会有一个支持历史记录和导航命令的命令行。当我们获取到输入时,我们把命令发给我们写的小程序 handle_command,然后我们把这个命令添加到 linenoise 历史并释放资源。

处理输入

我们的命令类似 gdb 以及 lldb 的格式。要继续执行程序,用户需要输入 continuecont 甚至只需 c。如果他们想在一个地址中设置断点,他们会输入 break 0xDEADBEEF,其中 0xDEADBEEF 就是所需地址的 16 进制格式。让我们来增加对这些命令的支持吧。

void debugger::handle_command(const std::string& line) {
    auto args = split(line,' ');
    auto command = args[0];

    if (is_prefix(command, "continue")) {
        continue_execution();
    }
    else {
        std::cerr << "Unknown command\n";
    }
}

splitis_prefix 是一对有用的小程序:

std::vector<std::string> split(const std::string &s, char delimiter) {
    std::vector<std::string> out{};
    std::stringstream ss {s};
    std::string item;

    while (std::getline(ss,item,delimiter)) {
        out.push_back(item);
    }

    return out;
}

bool is_prefix(const std::string& s, const std::string& of) {
    if (s.size() > of.size()) return false;
    return std::equal(s.begin(), s.end(), of.begin());
}

我们会把 continue_execution 函数添加到 debuger 类。

void debugger::continue_execution() {
    ptrace(PTRACE_CONT, m_pid, nullptr, nullptr);

    int wait_status;
    auto options = 0;
    waitpid(m_pid, &wait_status, options);
}

现在我们的 continue_execution 函数会用 ptrace 告诉进程继续执行,然后用 waitpid 等待直到收到信号。


总结

现在你应该编译一些 C 或者 C++ 程序,然后用你的调试器运行它们,看它是否能在函数入口暂停、从调试器中继续执行。在下一篇文章中,我们会学习如何让我们的调试器设置断点。如果你遇到了任何问题,在下面的评论框中告诉我吧!

你可以在这里找到该项目的代码。


via: http://blog.tartanllama.xyz/c++/2017/03/21/writing-a-linux-debugger-setup/

作者:Simon Brand 译者:ictlyh 校对:jasminepeng

本文由 LCTT 原创编译,Linux中国 荣誉推出

开源 open source ”这个词,指的是事物规划为可以公开访问的,因此人们可以修改并分享。

这个词最初是起源于软件开发中,指的是一种开发软件的特殊形式。但到了今天,“开源”已经泛指一组概念——就是我们称之为的“开源的方式”。这些概念包括开源项目、产品,或是自发倡导并欢迎开放变化、协作参与、快速原型、公开透明、精英体制以及面向社区开发的原则。

什么是开源软件?

开源软件的源代码任何人都可以审查、修改和增强。

源代码 source code ”是软件中大部分计算机用户都没见过的部分,程序员可以修改代码来改变一个软件(“程序”或“应用”)工作的方式。程序员如果可以接触到计算机程序源代码,就可以通过添加功能或修复问题来改进这个软件。

开源软件和其它类型的软件有什么不同?

有些软件只有创建它的人、团队、组织才能修改,并且控制维护工作。人们称这种软件是“ 专有 proprietary ”或“ 闭源 closed source ”软件。

专有软件只有原作者可以合法地复制、审查,以及修改这个软件。为了使用专有软件,计算机用户必须同意(通常是在软件第一次运行的时候签署一份显示的许可)他们不会对软件做软件作者没有表态允许的事情。微软 Office 和 Adobe Photoshop 就是专有软件的例子。

开源软件不一样。它的作者让源代码对其他人提供,需要的人都可以查看、复制、学习、修改或分享代码。LibreOfficeGIMP 是开源软件的例子。

就像专有软件那样,用户在使用开源软件时必须接受一份许可证的条款——但开源许可的法律条款和专有软件的许可截然不同。

开源许可证影响人们使用、学习、修改以及分发的方式。总的来说,开源许可证赋予计算机用户按他们想要的目的来使用开源软件的许可。一些开源许可证(人们称之为 左版 copyleft ”)规定任何发布了修改过的开源软件的人,同时还要一同发布它的源代码。此外,另一些开源许可规定任何修改和分享一个程序给其他人的人,还要分享这个程序的源代码,而且不能收取许可费用。

开源软件许可证有意地提升了协作和分享,因为它们允许其他人对代码作出修改并将改动包含到他们自己的项目中。开源许可证鼓励开发者随时访问、查看、修改开源软件,前提是开发者在分享成果的时候允许其他人也能够做相同的事情。

开源软件只是对开发者很重要?

不。开源技术和开源思想对开发者和非开发者都有益。

因为早期的创造者基于开源技术构建了互联网本身的大部分——比如 Linux 操作系统Apache Web 服务器应用——任何今天使用互联网的人都受益于开源软件。

每当计算机用户浏览网页、检查邮件、和朋友聊天、在线收听流媒体音乐、玩多人游戏的时候,他们的电脑、手机或游戏主机都会连接到一个全球性的计算机网络,使用开源软件来路由并将他们的数据传输到面前的“本地”设备上。完成这些重要工作的计算机通常位于很远的地方,用户不会实际看到或物理接触到它们——所以有些人称之为“远程计算机”。

越来越多的人开始依赖于远程计算机,在可以在本地完成的任务在线完成。举个例子,人们可能会使用在线文字处理、电子邮件管理、图片编辑工具,而在本地的个人电脑并没有安装运行相应的软件。人们轻松地使用浏览器或手机应用访问这些程序。当他们这么做的时候,他们参与到了“远程计算”中。

一些人将远程计算称为“云计算”,因为它涉及的活动(像是存储文件、分享照片、观看视频)不仅包含本地设备,还有一个远程计算机全球网络,像是围绕在周围的大气。

云计算是日常生活一个越来越重要的概念,离不开连接互联网的设备。一些云计算应用,比如 Google 应用,是专有的。其它的,像 OwnCloud 和 NextCould 是开源的。

云计算应用运行在一些额外的软件“之上”,这些软件帮助它们流畅高效地操作,所以人们经常说那个软件运行在云计算应用“之下”,为那些应用扮演一个“平台”。云计算平台可以是开源或闭源的。OpenStack 是一个开源云计算平台的例子。

为什么人们更倾向于使用开源软件?

人们相对于专有软件更倾向于开源软件有很多原因,包括:

可控。很多人青睐开源软件因为相对其它类型软件他们可以拥有更多的可控。他们可以检查代码来保证它没有做任何不希望它做的事情,并且可以改变不喜欢的部分。不是开发者的用户也可以从开源软件获益,因为他们可以以任何目的使用这个软件——而不仅仅是某些人认为他们应该有的目的。

训练。其他人喜欢开源软件是因为它可以帮助他们成为更好的开发者。因为开源代码可以公开访问,学生可以在学习创建更好的软件时轻松地从中学习。学生还可以在提升技能的时候分享他们的成果给别人,获得评价和批评。当人们发现程序源代码中的错误的时候,可以将这个错误分享给其他人,帮助他们避免犯同样的错误。

安全。一些人倾向开源软件是因为他们认为它比专有软件更安全和稳定。因为任何人都可以查看和修改开源软件,就会有人可能会注意到并修正原作者遗漏的错误或疏忽。并且因为这么多的开发者可以在同一开源软件上工作,而不用事先联系获取原作者的授权,相比专有软件,他们可以更快速地修复、更新和升级开源软件。

稳定。许多用户在重要、长期的项目中相较专有软件更加青睐开源软件。因为开发者公开分发开源软件的源代码,如果最初的开发者停止开发了,关键任务依赖该软件的用户可以确保他们的工具不会消失,或是陷入无法修复的状态。另外,开源软件趋向于同时包含和按照开放标准进行操作。

“开源”不是只是意味着某样东西是免费的吗?

不。这是个“开源”实践中的常见误解,“开源”概念的含义不只是指经济方面的

开源软件开发者可以为他们创建或贡献的开源软件收取费用。但在一些情况下,由于开源许可证可能会要求他们在将软件卖给他人的时候发布源代码,一些开发者发现向用户收取软件服务和支持(而不是软件本身)的费用会更加合算。通过这种方式,他们的软件仍然保持免费,而他们从帮助他人安装、使用、解决问题中赚取费用。

尽管一些开源软件可能是免费的,但开源软件的编程和解决问题的技能可能十分有价值。许多雇主特别寻求雇佣在开源软件方面有工作经验的开发者

什么是“在软件之外”的开源?

在 Opensource.com,我们想说我们对于开源价值和原则应用到软件之外领域的方式很有兴趣。我们更愿意不仅将开源视为一种计算机软件开发和许可的方式,也把它视作一种态度。

实现“开源方式”的生活的各个方面,意味着表达一种分享的意愿,通过透明的方式和他人协作(这样其他人也可以关注和加入),拥抱失败,将它作为一种改进的手段,以及期待(甚至鼓励)所有人都可以这么做。

这也意味着在让世界变得更好的过程中扮演一个积极的角色,这只有在每个人都可以接触到对世界进行规划的途径时才有可能。

这个世界充满了“源代码”——蓝图食谱规则——它们引导和塑造我们思考和行动的方式。我们相信这些深层代码(无论是什么形式)应该是开放、可接触、分享的——这样人们可以参与其中并让它变得更好。

在这里,我们诉说开源价值对生活所有领域的影响的故事——科学教育政府工业、健康、法律,以及组织动态。我们是一个社区,告诉他人开源的方式如何成为最好的方式,因为对开源的爱和其它一样:当它被分享的时候它会变得更好。

在哪里能够获得关于开源的更多信息?

我们编辑了一些资源来帮助你学到更多关于开源的内容。我们推荐你从阅读我们的开源问答、指南、教程开始。


via: https://opensource.com/resources/what-open-source

作者:<opensource.com> 译者:alim0x 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出