响应式编程与响应式系统

Summary: 在恒久的迷惑与过多期待的海洋中，登上一组简单响应式设计原则的小岛。

在恒久的迷惑与过多期待的海洋中，登上一组简单响应式设计原则的小岛。

>
> 在恒久的迷惑与过多期待的海洋中，登上一组简单响应式设计原则的小岛。
>
>
>

![](/data/attachment/album/201708/12/183025r3x6x37axwc33e63.jpg)

>
> 下载 Konrad Malawski 的免费电子书[《为什么选择响应式？企业应用中的基本原则》](http://www.oreilly.com/programming/free/why-reactive.csp?intcmp=il-webops-free-product-na_new_site_reactive_programming_vs_reactive_systems_text_cta)，深入了解更多响应式技术的知识与好处。
>
>
>

自从 2013 年一起合作写了[《响应式宣言》](http://www.reactivemanifesto.org/)之后，我们看着响应式从一种几乎无人知晓的软件构建技术——当时只有少数几个公司的边缘项目使用了这一技术——最后成为<ruby> 中间件领域 <rt>  middleware field </rt></ruby>大佬们全平台战略中的一部分。本文旨在定义和澄清响应式各个方面的概念，方法是比较在*响应式编程*风格下和把*响应式系统*视作一个紧密整体的设计方法下编写代码的不同之处。

### 响应式是一组设计原则

响应式技术目前成功的标志之一是“<ruby> 响应式 <rt>  reactive </rt></ruby>”成为了一个热词，并且跟一些不同的事物与人联系在了一起——常常伴随着像“<ruby> 流 <rt>  streaming </rt></ruby>”、“<ruby> 轻量级 <rt>  lightweight </rt></ruby>”和“<ruby> 实时 <rt>  real-time </rt></ruby>”这样的词。

举个例子：当我们看到一支运动队时（像棒球队或者篮球队），我们一般会把他们看成一个个单独个体的组合，但是当他们之间碰撞不出火花，无法像一个团队一样高效地协作时，他们就会输给一个“更差劲”的队伍。从这篇文章的角度来看，响应式是一组设计原则，一种关于系统架构与设计的思考方式，一种关于在一个分布式环境下，当<ruby> 实现技术 <rp>  （ </rp> <rt>  implementation techniques </rt> <rp>  ） </rp></ruby>、工具和设计模式都只是一个更大系统的一部分时如何设计的思考方式。

这个例子展示了不经考虑地将一堆软件拼揍在一起——尽管单独来看，这些软件都很优秀——和响应式系统之间的不同。在一个响应式系统中，正是*不同<ruby> 组件 <rp>  （ </rp> <rt>  parts </rt> <rp>  ） </rp></ruby>间的相互作用*让响应式系统如此不同，它使得不同组件能够独立地运作，同时又一致协作从而达到最终想要的结果。

*一个响应式系统* 是一种<ruby> 架构风格 <rp>  （ </rp> <rt>  architectural style </rt> <rp>  ） </rp></ruby>，它允许许多独立的应用结合在一起成为一个单元，共同响应它们所处的环境，同时保留着对单元内其它应用的“感知”——这能够表现为它能够做到<ruby> 放大/缩小规模 <rp>  （ </rp> <rt>  scale up/down </rt> <rp>  ） </rp></ruby>，负载平衡，甚至能够主动地执行这些步骤。

以响应式的风格（或者说，通过响应式编程）写一个软件是可能的；然而，那也不过是拼图中的一块罢了。虽然在上面的提到的各个方面似乎都足以称其为“响应式的”，但仅就其它们自身而言，还不足以让一个*系统*成为响应式的。

当人们在软件开发与设计的语境下谈论“响应式”时，他们的意思通常是以下三者之一：

* 响应式系统（架构与设计）
* 响应式编程（基于声明的事件的）
* 函数响应式编程（FRP）

我们将调查这些做法与技术的意思，特别是前两个。更明确地说，我们会在使用它们的时候讨论它们，例如它们是怎么联系在一起的，从它们身上又能到什么样的好处——特别是在为多核、云或移动架构搭建系统的情境下。

让我们先来说一说函数响应式编程吧，以及我们在本文后面不再讨论它的原因。

### 函数响应式编程（FRP）

<ruby> 函数响应式编程 <rt>  Functional reactive programming </rt></ruby>，通常被称作 *FRP*，是最常被误解的。FRP 在二十年前就被 Conal Elliott [精确地定义过了](http://conal.net/papers/icfp97/)了。但是最近这个术语却被错误地 脚注1 用来描述一些像 Elm、Bacon.js 的技术以及其它技术中的响应式插件（RxJava、Rx.NET、 RxJS）。许多的<ruby> 库 <rp>  （ </rp> <rt>  libraries </rt> <rp>  ） </rp></ruby>声称他们支持 FRP，事实上他们说的并非*响应式编程*，因此我们不会再进一步讨论它们。

### 响应式编程

<ruby> 响应式编程 <rt>  Reactive programming </rt></ruby>，不要把它跟*函数响应式编程*混淆了，它是异步编程下的一个子集，也是一种范式，在这种范式下，由新信息的<ruby> 有效性 <rp>  （ </rp> <rt>  availability </rt> <rp>  ） </rp></ruby>推动逻辑的前进，而不是让<ruby> 一条执行线程 <rp>  （ </rp> <rt>  a thread-of-execution </rt> <rp>  ） </rp></ruby>去推动<ruby> 控制流 <rp>  （ </rp> <rt>  control flow </rt> <rp>  ） </rp></ruby>。

它能够把问题分解为多个独立的步骤，这些独立的步骤可以以异步且<ruby> 非阻塞 <rp>  （ </rp> <rt>  non-blocking </rt> <rp>  ） </rp></ruby>的方式被执行，最后再组合在一起产生一条<ruby> 工作流 <rp>  （ </rp> <rt>  workflow </rt> <rp>  ） </rp></ruby>——它的输入和输出可能是<ruby> 非绑定的 <rp>  （ </rp> <rt>  unbounded </rt> <rp>  ） </rp></ruby>。

<ruby>   “异步地”  <rp>  （ </rp> <rt>  Asynchronous </rt> <rp>  ） </rp></ruby>被牛津词典定义为“不在同一时刻存在或发生”，在我们的语境下，它意味着一条消息或者一个事件可发生在任何时刻，也有可能是在未来。这在响应式编程中是非常重要的一项技术，因为响应式编程允许[<ruby> 非阻塞式 <rp>  （ </rp> <rt>  non-blocking </rt> <rp>  ） </rp></ruby>]的执行方式——执行线程在竞争一块共享资源时不会因为<ruby> 阻塞 <rp>  （ </rp> <rt>  blocking </rt> <rp>  ） </rp></ruby>而陷入等待（为了防止执行线程在当前的工作完成之前执行任何其它操作），而是在共享资源被占用的期间转而去做其它工作。<ruby> 阿姆达尔定律 <rp>  （ </rp> <rt>  Amdahl's Law </rt> <rp>  ） </rp></ruby>  脚注2 告诉我们，竞争是<ruby> 可伸缩性 <rp>  （ </rp> <rt>  scalability </rt> <rp>  ） </rp></ruby>最大的敌人，所以一个响应式系统应当在极少数的情况下才不得不做阻塞工作。

响应式编程一般是<ruby> 事件驱动 <rp>  （ </rp> <rt>  event-driven </rt> <rp>  ） </rp></ruby>，相比之下，响应式系统则是<ruby> 消息驱动 <rp>  （ </rp> <rt>  message-driven </rt> <rp>  ） </rp></ruby>的——事件驱动与消息驱动之间的差别会在文章后面阐明。

响应式编程库的应用程序接口（API）一般是以下二者之一：

* <ruby> 基于回调的 <rp>  （ </rp> <rt>  Callback-based </rt> <rp>  ） </rp></ruby>—匿名的<ruby> 间接作用 <rp>  （ </rp> <rt>  side-effecting </rt> <rp>  ） </rp></ruby>回调函数被绑定在<ruby> 事件源 <rp>  （ </rp> <rt>  event sources </rt> <rp>  ） </rp></ruby>上，当事件被放入<ruby> 数据流 <rp>  （ </rp> <rt>  dataflow chain </rt> <rp>  ） </rp></ruby>中时，回调函数被调用。
* <ruby> 声明式的 <rp>  （ </rp> <rt>  Declarative </rt> <rp>  ） </rp></ruby>——通过函数的组合，通常是使用一些固定的函数，像 *map*、 *filter*、 *fold* 等等。

大部分的库会混合这两种风格，一般还带有<ruby> 基于流 <rp>  （ </rp> <rt>  stream-based </rt> <rp>  ） </rp></ruby>的<ruby> 操作符 <rp>  （ </rp> <rt>  operators </rt> <rp>  ） </rp></ruby>，像 windowing、 counts、 triggers。

说响应式编程跟<ruby>   数据流编程  <rp>  （ </rp> <rt>  dataflow programming </rt> <rp>  ） </rp></ruby>有关是很合理的，因为它强调的是*数据流*而不是*控制流*。

举几个为这种编程技术提供支持的的编程抽象概念：

* [Futures/Promises](https://en.wikipedia.org/wiki/Futures_and_promises)——一个值的容器，具有<ruby> 读共享/写独占 <rp>  （ </rp> <rt>  many-read/single-write </rt> <rp>  ） </rp></ruby>的语义，即使变量尚不可用也能够添加异步的值转换操作。
* <ruby> 流 <rp>  （ </rp> <rt>  streams </rt> <rp>  ） </rp></ruby> - [响应式流](http://reactive-streams.org/)——无限制的数据处理流，支持异步，非阻塞式，支持多个源与目的的<ruby> 反压转换管道 <rp>  （ </rp> <rt>  back-pressured transformation pipelines </rt> <rp>  ） </rp></ruby>。
* [数据流变量](https://en.wikipedia.org/wiki/Oz_(programming_language)#Dataflow_variables_and_declarative_concurrency)——依赖于输入、<ruby> 过程 <rp>  （ </rp> <rt>  procedures </rt> <rp>  ） </rp></ruby>或者其它单元的<ruby> 单赋值变量 <rp>  （ </rp> <rt>  single assignment variables </rt> <rp>  ） </rp></ruby>（存储单元），它能够自动更新值的改变。其中一个应用例子是表格软件——一个单元的值的改变会像涟漪一样荡开，影响到所有依赖于它的函数，顺流而下地使它们产生新的值。

在 JVM 中，支持响应式编程的流行库有 Akka Streams、Ratpack、Reactor、RxJava 和 Vert.x 等等。这些库实现了响应式编程的规范，成为 JVM 上响应式编程库之间的<ruby> 互通标准 <rp>  （ </rp> <rt>  standard for interoperability </rt> <rp>  ） </rp></ruby>，并且根据它自身的叙述是“……一个为如何处理非阻塞式反压异步流提供标准的倡议”。

响应式编程的基本好处是：提高多核和多 CPU 硬件的计算资源利用率；根据阿姆达尔定律以及引申的 <ruby> Günther 的通用可伸缩性定律 <rp>  （ </rp> <rt>  Günther’s Universal Scalability Law </rt> <rp>  ） </rp></ruby>  脚注3 ，通过减少<ruby> 序列化点 <rp>  （ </rp> <rt>  serialization points </rt> <rp>  ） </rp></ruby>来提高性能。

另一个好处是开发者生产效率，传统的编程范式都尽力想提供一个简单直接的可持续的方法来处理异步非阻塞式计算和 I/O。在响应式编程中，因活动(active)组件之间通常不需要明确的协作，从而也就解决了其中大部分的挑战。

响应式编程真正的发光点在于组件的创建跟工作流的组合。为了在异步执行上取得最大的优势，把<ruby>   反压  <rp>  （ </rp> <rt>  back-pressure </rt> <rp>  ） </rp></ruby>加进来是很重要，这样能避免过度使用，或者确切地说，避免无限度的消耗资源。

尽管如此，响应式编程在搭建现代软件上仍然非常有用，为了在更高层次上<ruby> 理解 <rp>  （ </rp> <rt>  reason about </rt> <rp>  ） </rp></ruby>一个系统，那么必须要使用到另一个工具：<ruby> 响应式架构 <rt>  reactive architecture </rt></ruby>——设计响应式系统的方法。此外，要记住编程范式有很多，而响应式编程仅仅只是其中一个，所以如同其它工具一样，响应式编程并不是万金油，它不意图适用于任何情况。

### 事件驱动 vs. 消息驱动

如上面提到的，响应式编程——专注于短时间的数据流链条上的计算——因此倾向于*事件驱动*，而响应式系统——关注于通过分布式系统的通信和协作所得到的弹性和韧性——则是[*消息驱动的*](http://www.reactivemanifesto.org/glossary#Message-Driven)  脚注4（或者称之为 <ruby> 消息式 <rp>  （ </rp> <rt>  messaging </rt> <rp>  ） </rp></ruby> 的）。

一个拥有<ruby> 长期存活的可寻址 <rp>  （ </rp> <rt>  long-lived addressable </rt> <rp>  ） </rp></ruby>组件的消息驱动系统跟一个事件驱动的数据流驱动模型的不同在于，消息具有固定的导向，而事件则没有。消息会有明确的（一个）去向，而事件则只是一段等着被<ruby> 观察 <rp>  （ </rp> <rt>  observe </rt> <rp>  ） </rp></ruby>的信息。另外，<ruby> 消息式 <rp>  （ </rp> <rt>  messaging </rt> <rp>  ） </rp></ruby>更适用于异步，因为消息的发送与接收和发送者和接收者是分离的。

响应式宣言中的术语表定义了两者之间[概念上的不同](http://www.reactivemanifesto.org/glossary#Message-Driven)：

>
> 一条消息就是一则被送往一个明确目的地的数据。一个事件则是达到某个给定状态的组件发出的一个信号。在一个消息驱动系统中，可寻址到的接收者等待消息的到来然后响应它，否则保持休眠状态。在一个事件驱动系统中，通知的监听者被绑定到消息源上，这样当消息被发出时它就会被调用。这意味着一个事件驱动系统专注于可寻址的事件源而消息驱动系统专注于可寻址的接收者。
>
>
>

分布式系统需要通过消息在网络上传输进行交流，以实现其沟通基础，与之相反，事件的发出则是本地的。在底层通过发送包裹着事件的消息来搭建跨网络的事件驱动系统的做法很常见。这样能够维持在分布式环境下事件驱动编程模型的相对简易性，并且在某些特殊的和合理的范围内的使用案例上工作得很好。

然而，这是有利有弊的：在编程模型的抽象性和简易性上得一分，在控制上就减一分。消息强迫我们去拥抱分布式系统的真实性和一致性——像<ruby> 局部错误 <rp>  （ </rp> <rt>  partial failures </rt> <rp>  ） </rp></ruby>，<ruby> 错误侦测 <rp>  （ </rp> <rt>  failure detection </rt> <rp>  ） </rp></ruby>，<ruby> 丢弃/复制/重排序 <rp>  （ </rp> <rt>  dropped/duplicated/reordered </rt> <rp>  ） </rp></ruby>消息，最后还有一致性，管理多个并发真实性等等——然后直面它们，去处理它们，而不是像过去无数次一样，藏在一个蹩脚的抽象面罩后——假装网络并不存在(例如EJB、 [RPC](https://christophermeiklejohn.com/pl/2016/04/12/rpc.html)、 [CORBA](https://queue.acm.org/detail.cfm?id=1142044) 和 [XA](https://cs.brown.edu/courses/cs227/archives/2012/papers/weaker/cidr07p15.pdf))。

这些在语义学和适用性上的不同在应用设计中有着深刻的含义，包括分布式系统的<ruby> 复杂性 <rp>  （ </rp> <rt>  complexity </rt> <rp>  ） </rp></ruby>中的 <ruby> 弹性 <rp>  （ </rp> <rt>  resilience </rt> <rp>  ） </rp></ruby>、 <ruby> 韧性 <rp>  （ </rp> <rt>  elasticity </rt> <rp>  ） </rp></ruby>、<ruby> 移动性 <rp>  （ </rp> <rt>  mobility </rt> <rp>  ） </rp></ruby>、<ruby> 位置透明性 <rp>  （ </rp> <rt>  location transparency </rt> <rp>  ） </rp></ruby>和 <ruby> 管理 <rp>  （ </rp> <rt>  management </rt> <rp>  ） </rp></ruby>，这些在文章后面再进行介绍。

在一个响应式系统中，特别是使用了响应式编程技术的，这样的系统中就即有事件也有消息——一个是用于沟通的强大工具（消息），而另一个则呈现现实（事件）。

### 响应式系统和架构

*响应式系统* —— 如同在《响应式宣言》中定义的那样——是一组用于搭建现代系统——已充分准备好满足如今应用程序所面对的不断增长的需求的现代系统——的架构设计原则。

响应式系统的原则决对不是什么新东西，它可以被追溯到 70 和 80 年代 Jim Gray 和 Pat Helland 在<ruby>   串级系统  <rp>  （ </rp> <rt>  Tandem System </rt> <rp>  ） </rp></ruby>上和 Joe aomstrong 和 Robert Virding 在 [Erland](http://erlang.org/download/armstrong_thesis_2003.pdf) 上做出的重大工作。然而，这些人在当时都超越了时代，只有到了最近 5 - 10 年，技术行业才被不得不反思当前企业系统最好的开发实践活动并且学习如何将来之不易的响应式原则应用到今天这个多核、云计算和物联网的世界中。

响应式系统的基石是<ruby> 消息传递 <rp>  （ </rp> <rt>  message-passing </rt> <rp>  ） </rp></ruby>，消息传递为两个组件之间创建一条暂时的边界，使得它们能够在 *时间* 上分离——实现并发性——和 <ruby> 空间 <rp>  （ </rp> <rt>  space </rt> <rp>  ） </rp></ruby> ——实现<ruby> 分布式 <rp>  （ </rp> <rt>  distribution </rt> <rp>  ） </rp></ruby>与<ruby> 移动性 <rp>  （ </rp> <rt>  mobility </rt> <rp>  ） </rp></ruby>。这种分离是两个组件完全<ruby>   隔离  <rp>  （ </rp> <rt>  isolation </rt> <rp>  ） </rp></ruby>以及实现<ruby> 弹性 <rp>  （ </rp> <rt>  resilience </rt> <rp>  ） </rp></ruby>和<ruby> 韧性 <rp>  （ </rp> <rt>  elasticity </rt> <rp>  ） </rp></ruby>基础的必需条件。

### 从程序到系统

这个世界的连通性正在变得越来越高。我们不再构建 *程序* ——为单个操作子来计算某些东西的端到端逻辑——而更多地在构建 *系统* 了。

系统从定义上来说是复杂的——每一部分都包含多个组件，每个组件的自身或其子组件也可以是一个系统——这意味着软件要正常工作已经越来越依赖于其它软件。

我们今天构建的系统会在多个计算机上操作，小型的或大型的，或少或多，相近的或远隔半个地球的。同时，由于人们的生活正变得越来越依赖于系统顺畅运行的有效性，用户的期望也变得越得越来越难以满足。

为了实现用户——和企业——能够依赖的系统，这些系统必须是 <ruby> 灵敏的 <rp>  （ </rp> <rt>  responsive </rt> <rp>  ） </rp></ruby> ，这样无论是某个东西提供了一个正确的响应，还是当需要一个响应时响应无法使用，都不会有影响。为了达到这一点，我们必须保证在错误( *弹性* )和欠载( *韧性* )下，系统仍然能够保持灵敏性。为了实现这一点，我们把系统设计为 *消息驱动的* ，我们称其为 *响应式系统* 。

### 响应式系统的弹性

弹性是与 *错误下* 的<ruby> 灵敏性 <rp>  （ </rp> <rt>  responsiveness </rt> <rp>  ） </rp></ruby>有关的，它是系统内在的功能特性，是需要被设计的东西，而不是能够被动的加入系统中的东西。弹性是大于容错性的——弹性无关于<ruby> 故障退化 <rp>  （ </rp> <rt>  graceful degradation </rt> <rp>  ） </rp></ruby>——虽然故障退化对于系统来说是很有用的一种特性——与弹性相关的是与从错误中完全恢复达到 *自愈* 的能力。这就需要组件的隔离以及组件对错误的包容，以免错误散播到其相邻组件中去——否则，通常会导致灾难性的连锁故障。

因此构建一个弹性的、<ruby> 自愈 <rp>  （ </rp> <rt>  self-healing </rt> <rp>  ） </rp></ruby>系统的关键是允许错误被：容纳、具体化为消息，发送给其他（担当<ruby> 监管者 <rp>  （ </rp> <rt>  supervisors </rt> <rp>  ） </rp></ruby>）的组件，从而在错误组件之外修复出一个安全环境。在这，消息驱动是其促成因素：远离高度耦合的、脆弱的深层嵌套的同步调用链，大家长期要么学会忍受其煎熬或直接忽略。解决的想法是将调用链中的错误管理分离，将客户端从处理服务端错误的责任中解放出来。

### 响应式系统的韧性

<ruby>   韧性  <rp>  （ </rp> <rt>  Elasticity </rt> <rp>  ） </rp></ruby>是关于 *欠载下的<ruby> 灵敏性 <rp>  （ </rp> <rt>  responsiveness </rt> <rp>  ） </rp></ruby>* 的——意味着一个系统的吞吐量在资源增加或减少时能够自动地相应<ruby> 增加或减少 <rp>  （ </rp> <rt>  scales up or down </rt> <rp>  ） </rp></ruby>（同样能够<ruby> 向内或外扩展 <rp>  （ </rp> <rt>  scales in or out </rt> <rp>  ） </rp></ruby>）以满足不同的需求。这是利用云计算承诺的特性所必需的因素：使系统利用资源更加有效，成本效益更佳，对环境友好以及实现按次付费。

系统必须能够在不重写甚至不重新设置的情况下，适应性地——即无需介入自动伸缩——响应状态及行为，沟通负载均衡，<ruby> 故障转移 <rp>  （ </rp> <rt>  failover </rt> <rp>  ） </rp></ruby>，以及升级。实现这些的就是 <ruby> 位置透明性 <rp>  （ </rp> <rt>  location transparency </rt> <rp>  ） </rp></ruby>：使用同一个方法，同样的编程抽象，同样的语义，在所有向度中<ruby> 伸缩 <rp>  （ </rp> <rt>  scaling </rt> <rp>  ） </rp></ruby>系统的能力——从 CPU 核心到数据中心。

如同《响应式宣言》所述：

>
> 一个极大地简化问题的关键洞见在于意识到我们都在使用分布式计算。无论我们的操作系统是运行在一个单一结点上（拥有多个独立的 CPU，并通过 QPI 链接进行交流）,还是在一个<ruby> 节点集群 <rp>  （ </rp> <rt>  cluster of nodes </rt> <rp>  ） </rp></ruby>（独立的机器，通过网络进行交流)上。拥抱这个事实意味着在垂直方向上多核的伸缩与在水平方面上集群的伸缩并无概念上的差异。在空间上的解耦 [...]，是通过异步消息传送以及运行时实例与其引用解耦从而实现的，这就是我们所说的位置透明性。
>
>
>

因此，不论接收者在哪里，我们都以同样的方式与它交流。唯一能够在语义上等同实现的方式是消息传送。

### 响应式系统的生产效率

既然大多数的系统生来即是复杂的，那么其中一个最重要的点即是保证一个系统架构在开发和维护组件时，最小程度地减低生产效率，同时将操作的 <ruby> 偶发复杂性 <rp>  （ </rp> <rt>  accidental complexity </rt> <rp>  ） </rp></ruby>降到最低。

这一点很重要，因为在一个系统的生命周期中——如果系统的设计不正确——系统的维护会变得越来越困难，理解、定位和解决问题所需要花费时间和精力会不断地上涨。

响应式系统是我们所知的最具 *生产效率* 的系统架构（在多核、云及移动架构的背景下）：

* 错误的隔离为组件与组件之间裹上[舱壁](http://skife.org/architecture/fault-tolerance/2009/12/31/bulkheads.html)（LCTT 译注：当船遭到损坏进水时，舱壁能够防止水从损坏的船舱流入其他船舱），防止引发连锁错误，从而限制住错误的波及范围以及严重性。
* 监管者的层级制度提供了多个等级的防护，搭配以自我修复能力，避免了许多曾经在侦查(inverstigate)时引发的操作<ruby> 代价 <rp>  （ </rp> <rt>  cost </rt> <rp>  ） </rp></ruby>——大量的<ruby> 瞬时故障 <rp>  （ </rp> <rt>  transient failures </rt> <rp>  ） </rp></ruby>。
* 消息传送和位置透明性允许组件被卸载下线、代替或<ruby> 重新布线 <rp>  （ </rp> <rt>  rerouted </rt> <rp>  ） </rp></ruby>同时不影响终端用户的使用体验，并降低中断的代价、它们的相对紧迫性以及诊断和修正所需的资源。
* 复制减少了数据丢失的风险，减轻了数据<ruby> 检索 <rp>  （ </rp> <rt>  retrieval </rt> <rp>  ） </rp></ruby>和存储的有效性错误的影响。
* 韧性允许在使用率波动时保存资源，允许在负载很低时，最小化操作开销，并且允许在负载增加时，最小化<ruby> 运行中断 <rp>  （ </rp> <rt>  outgae </rt> <rp>  ） </rp></ruby>或<ruby> 紧急投入 <rp>  （ </rp> <rt>  urgent investment </rt> <rp>  ） </rp></ruby>伸缩性的风险。

因此，响应式系统使<ruby> 生成系统 <rp>  （ </rp> <rt>  creation systems </rt> <rp>  ） </rp></ruby>很好的应对错误、随时间变化的负载——同时还能保持低运营成本。

### 响应式编程与响应式系统的关联

响应式编程是一种管理<ruby> 内部逻辑 <rp>  （ </rp> <rt>  internal logic </rt> <rp>  ） </rp></ruby>和<ruby> 数据流转换 <rp>  （ </rp> <rt>  dataflow transformation </rt> <rp>  ） </rp></ruby>的好技术，在本地的组件中，做为一种优化代码清晰度、性能以及资源利用率的方法。响应式系统，是一组架构上的原则，旨在强调分布式信息交流并为我们提供一种处理分布式系统弹性与韧性的工具。

只使用响应式编程常遇到的一个问题，是一个事件驱动的基于回调的或声明式的程序中两个计算阶段的<ruby> 高度耦合 <rp>  （ </rp> <rt>  tight coupling </rt> <rp>  ） </rp></ruby>，使得 *弹性* 难以实现，因此时它的转换链通常存活时间短，并且它的各个阶段——回调函数或<ruby> 组合子 <rp>  （ </rp> <rt>  combinator </rt> <rp>  ） </rp></ruby>——是匿名的，也就是不可寻址的。

这意味着，它通常在内部处理成功与错误的状态而不会向外界发送相应的信号。这种寻址能力的缺失导致单个<ruby> 阶段 <rp>  （ </rp> <rt>  stages </rt> <rp>  ） </rp></ruby>很难恢复，因为它通常并不清楚异常应该，甚至不清楚异常可以，发送到何处去。

另一个与响应式系统方法的不同之处在于单纯的响应式编程允许 *时间* 上的<ruby> 解耦 <rp>  （ </rp> <rt>  decoupling </rt> <rp>  ） </rp></ruby>，但不允许 *空间* 上的（除非是如上面所述的，在底层通过网络传送消息来<ruby> 分发 <rp>  （ </rp> <rt>  distribute </rt> <rp>  ） </rp></ruby>数据流）。正如叙述的，在时间上的解耦使 *并发性* 成为可能，但是是空间上的解耦使 <ruby> 分布 <rp>  （ </rp> <rt>  distribution </rt> <rp>  ） </rp></ruby>和<ruby> 移动性 <rp>  （ </rp> <rt>  mobility </rt> <rp>  ） </rp></ruby> （使得不仅仅静态拓扑可用，还包括了动态拓扑）成为可能的——而这些正是 *韧性* 所必需的要素。

位置透明性的缺失使得很难以韧性方式对一个基于适应性响应式编程技术的程序进行向外扩展，因为这样就需要分附加工具，例如<ruby> 消息总线 <rp>  （ </rp> <rt>  message bus </rt> <rp>  ） </rp></ruby>，<ruby> 数据网格 <rp>  （ </rp> <rt>  data grid </rt> <rp>  ） </rp></ruby>或者在顶层的<ruby> 定制网络协议 <rp>  （ </rp> <rt>  bespoke network protocol </rt> <rp>  ） </rp></ruby>。而这点正是响应式系统的消息驱动编程的闪光的地方，因为它是一个包含了其编程模型和所有伸缩向度语义的交流抽象概念，因此降低了复杂性与认知超载。

对于基于回调的编程，常会被提及的一个问题是写这样的程序或许相对来说会比较简单，但最终会引发一些真正的后果。

例如，对于基于匿名回调的系统，当你想理解它们，维护它们或最重要的是在<ruby> 生产供应中断 <rp>  （ </rp> <rt>  production outages </rt> <rp>  ） </rp></ruby>或错误行为发生时，你想知道到底发生了什么、发生在哪以及为什么发生，但此时它们只提供极少的内部信息。

为响应式系统设计的库与平台（例如 [Akka](http://akka.io/) 项目和 [Erlang](https://www.erlang.org/) 平台）学到了这一点，它们依赖于那些更容易理解的长期存活的可寻址组件。当错误发生时，根据导致错误的消息可以找到唯一的组件。当可寻址的概念存在组件模型的核心中时，<ruby> 监控方案 <rp>  （ </rp> <rt>  monitoring solution </rt> <rp>  ） </rp></ruby>就有了一个 *有意义* 的方式来呈现它收集的数据——利用<ruby> 传播 <rp>  （ </rp> <rt>  propagated </rt> <rp>  ） </rp></ruby>的身份标识。

一个好的编程范式的选择，一个选择实现像可寻址能力和错误管理这些东西的范式，已经被证明在生产中是无价的，因它在设计中承认了现实并非一帆风顺，*接受并拥抱错误的出现* 而不是毫无希望地去尝试避免错误。

总而言之，响应式编程是一个非常有用的实现技术，可以用在响应式架构当中。但是记住这只能帮助管理一部分：异步且非阻塞执行下的数据流管理——通常只在单个结点或服务中。当有多个结点时，就需要开始认真地考虑像<ruby> 数据一致性 <rp>  （ </rp> <rt>  data consistency </rt> <rp>  ） </rp></ruby>、<ruby> 跨结点沟通 <rp>  （ </rp> <rt>  cross-node communication </rt> <rp>  ） </rp></ruby>、<ruby> 协调 <rp>  （ </rp> <rt>  coordination </rt> <rp>  ） </rp></ruby>、<ruby> 版本控制 <rp>  （ </rp> <rt>  versioning </rt> <rp>  ） </rp></ruby>、<ruby> 编制 <rp>  （ </rp> <rt>  orchestration </rt> <rp>  ） </rp></ruby>、<ruby> 错误管理 <rp>  （ </rp> <rt>  failure management </rt> <rp>  ） </rp></ruby>、<ruby> 关注与责任 <rp>  （ </rp> <rt>  concerns and responsibilities </rt> <rp>  ） </rp></ruby>分离等等的东西——也即是：系统架构。

因此，要最大化响应式编程的价值，就把它作为构建响应式系统的工具来使用。构建一个响应式系统需要的不仅是在一个已存在的遗留下来的<ruby> 软件栈 <rp>  （ </rp> <rt>  software stack </rt> <rp>  ） </rp></ruby>上抽象掉特定的操作系统资源和少量的异步 API 和<ruby>   断路器  <rp>  （ </rp> <rt>  circuit breakers </rt> <rp>  ） </rp></ruby>。此时应该拥抱你在创建一个包含多个服务的分布式系统这一事实——这意味着所有东西都要共同合作，提供一致性与灵敏的体验，而不仅仅是如预期工作，但同时还要在发生错误和不可预料的负载下正常工作。

### 总结

企业和中间件供应商在目睹了应用响应式所带来的企业利润增长后，同样开始拥抱响应式。在本文中，我们把响应式系统做为企业最终目标进行描述——假设了多核、云和移动架构的背景——而响应式编程则从中担任重要工具的角色。

响应式编程在内部逻辑及数据流转换的组件层次上为开发者提高了生产率——通过性能与资源的有效利用实现。而响应式系统在构建 <ruby> 原生云 <rp>  （ </rp> <rt>  cloud native </rt> <rp>  ） </rp></ruby> 和其它大型分布式系统的系统层次上为架构师及 DevOps 从业者提高了生产率——通过弹性与韧性。我们建议在响应式系统设计原则中结合响应式编程技术。

### 脚注

>
> 1. 参考 Conal Elliott，FRP 的发明者，见[这个演示](https://begriffs.com/posts/2015-07-22-essence-of-frp.html)。
> 2. [Amdahl 定律](https://en.wikipedia.org/wiki/Amdahl%2527s_law)揭示了系统理论上的加速会被一系列的子部件限制，这意味着系统在新的资源加入后会出现<ruby> 收益递减 <rp>  （ </rp> <rt>  diminishing returns </rt> <rp>  ） </rp></ruby>。
> 3. Neil Günter 的<ruby>   通用可伸缩性定律  <rp>  （ </rp> <rt>  Universal Scalability Law </rt> <rp>  ） </rp></ruby>是理解并发与分布式系统的竞争与协作的重要工具，它揭示了当新资源加入到系统中时，保持一致性的开销会导致不好的结果。
> 4. 消息可以是同步的（要求发送者和接受者同时存在），也可以是异步的（允许他们在时间上解耦）。其语义上的区别超出本文的讨论范围。
>
>
>

---

via: <https://www.oreilly.com/ideas/reactive-programming-vs-reactive-systems>

作者：[Jonas Bonér](https://www.oreilly.com/people/e0b57-jonas-boner)， [Viktor Klang](https://www.oreilly.com/people/f96106d4-4ce6-41d9-9d2b-d24590598fcd) 译者：[XLCYun](https://github.com/XLCYun) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 组织编译，[Linux中国](https://linux.cn/) 荣誉推出


一篇缺失的 TypeScript 介绍

Summary:
本文的主旨是为了介绍我们是如何看待 TypeScript 的以及它在加强 JavaScript 开发中所起的作用。
我们也将尽可能地给出那些类型和编译方面的那些时髦词汇的准确定义。

![](/data/attachment/album/201708/13/132032snqnbgkvt7spgtgb.png)

**下文是 James Henry（[@MrJamesHenry](https://twitter.com/MrJamesHenry)）所提交的内容。我是 ESLint 核心团队的一员，也是 TypeScript 布道师。我正在和 Todd 在 [UltimateAngular](https://ultimateangular.com/courses) 平台上合作发布 Angular 和 TypeScript 的精品课程。**

>
> 本文的主旨是为了介绍我们是如何看待 TypeScript 的以及它在加强 JavaScript 开发中所起的作用。
>
>
> 我们也将尽可能地给出那些类型和编译方面的那些时髦词汇的准确定义。
>
>
>

TypeScript 强大之处远远不止这些，本篇文章无法涵盖，想要了解更多请阅读[官方文档](http://www.typescriptlang.org/docs)，或者学习 [UltimateAngular 上的 TypeScript 课程](https://ultimateangular.com/courses#typescript) ，从初学者成为一位 TypeScript 高手。

### 背景

TypeScript 是个出乎意料强大的工具，而且它真的很容易掌握。

然而，TypeScript 可能比 JavaScript 要更为复杂一些，因为 TypeScript 可能向我们同时引入了一系列以前没有考虑过的 JavaScript 程序相关的技术概念。

每当我们谈论到类型、编译器等这些概念的时候，你会发现很快会变的不知所云起来。

这篇文章就是一篇为了解答你需要知道的许许多多不知所云的概念，来帮助你 TypeScript 快速入门的教程，可以让你轻松自如的应对这些概念。

### 关键知识的掌握

在 Web 浏览器中运行我们的代码这件事或许使我们对它是如何工作的产生一些误解，“它不用经过编译，是吗？”，“我敢肯定这里面是没有类型的...”

更有意思的是，上述的说法既是正确的也是不正确的，这取决于上下文环境和我们是如何定义这些概念的。

首先，我们要作的是明确这些。

#### JavaScript 是解释型语言还是编译型语言？

传统意义上，程序员经常将自己的程序编译之后运行出结果就认为这种语言是编译型语言。

>
> 从初学者的角度来说，编译的过程就是将我们自己编辑好的高级语言程序转换成机器实际运行的格式。
>
>
>

就像 Go 语言，可以使用 `go build` 的命令行工具编译 .go 的文件，将其编译成代码的低级形式，它可以直接执行、运行。

```
# We manually compile our .go file into something we can run
# using the command line tool "go build"
go build ultimate-angular.go
# ...then we execute it!
./ultimate-angular

```

作为一个 JavaScript 程序员（这一刻，请先忽略我们对新一代构建工具和模块加载程序的热爱），我们在日常的 JavaScript 开发中并没有编译的这一基本步骤，

我们写一些 JavaScript 代码，把它放在浏览器的 `<script>` 标签中，它就能运行了（或者在服务端环境运行，比如：node.js）。

**好吧，因此 JavaScript 没有进行过编译，那它一定是解释型语言了，是吗？**

实际上，我们能够确定的一点是，JavaScript 不是我们自己编译的，现在让我们简单的回顾一个简单的解释型语言的例子，再来谈 JavaScript 的编译问题。

>
> 解释型计算机语言的执行的过程就像人们看书一样，从上到下、一行一行的阅读。
>
>
>

我们所熟知的解释型语言的典型例子是 bash 脚本。我们终端中的 bash 解释器逐行读取我们的命令并且执行它。

现在我们回到 JavaScript 是解释执行还是编译执行的讨论中，我们要将逐行读取和逐行执行程序分开理解（对“解释型”的简单理解），不要混在一起。

以此代码为例：

```
hello();
function hello(){
    console.log("Hello")
}

```

这是真正意义上 JavaScript 输出 Hello 单词的程序代码，但是，在 `hello()` 在我们定义它之前就已经使用了这个函数，这是简单的逐行执行办不到的，因为 `hello()` 在第一行没有任何意义的，直到我们在第二行声明了它。

像这样在 JavaScript 是存在的，因为我们的代码实际上在执行之前就被所谓的“JavaScript 引擎”或者是“特定的编译环境”编译过，这个编译的过程取决于具体的实现（比如，使用 V8 引擎的 node.js 和 Chome 就和使用 SpiderMonkey 的 FireFox 就有所不同）。

在这里，我们不会在进一步的讲解编译型执行和解释型执行微妙之处（这里的定义已经很好了）。

>
> 请务必记住，我们编写的 JavaScript 代码已经不是我们的用户实际执行的代码了，即使是我们简单地将其放在 HTML 中的 `<script>` ，也是不一样的。
>
>
>

#### 运行时间 VS 编译时间

现在我们已经正确理解了编译和运行是两个不同的阶段，那“<ruby> 运行阶段 <rt>  Run Time </rt></ruby>”和“<ruby> 编译阶段 <rt>  Compile Time </rt></ruby>”理解起来也就容易多了。

编译阶段，就是我们在我们的编辑器或者 IDE 当中的代码转换成其它格式的代码的阶段。

运行阶段，就是我们程序实际执行的阶段，例如：上面的 `hello()` 函数就执行在“运行阶段”。

#### TypeScript 编译器

现在我们了解了程序的生命周期中的关键阶段，接下来我们可以介绍 TypeScript 编译器了。

TypeScript 编译器是帮助我们编写代码的关键。比如，我们不需将 JavaScript 代码包含到 `<script>` 标签当中，只需要通过 TypeScript 编译器传递它，就可以在运行程序之前得到改进程序的建议。

>
> 我们可以将这个新的步骤作为我们自己的个人“编译阶段”，这将在我们的程序抵达 JavaScript 主引擎之前，确保我们的程序是以我们预期的方式编写的。
>
>
>

它与上面 Go 语言的实例类似，但是 TypeScript 编译器只是基于我们编写程序的方式提供提示信息，并不会将其转换成低级的可执行文件，它只会生成纯 JavaScript 代码。

```
# One option for passing our source .ts file through the TypeScript
# compiler is to use the command line tool "tsc"
tsc ultimate-angular.ts

# ...this will produce a .js file of the same name
# i.e. ultimate-angular.js

```

在[官方文档](http://www.typescriptlang.org/docs)中，有许多关于将 TypeScript 编译器以各种方式融入到你的现有工作流程中的文章。这些已经超出本文范围。

#### 动态类型与静态类型

就像对比编译程序与解释程序一样，动态类型与静态类型的对比在现有的资料中也是极其模棱两可的。

让我们先回顾一下我们在 JavaScript 中对于类型的理解。

我们的代码如下：

```
var name = 'James';
var sum = 1 + 2;

```

我们如何给别人描述这段代码？

“我们声明了一个变量 `name`，它被分配了一个 “James” 的**字符串**，然后我们又申请了一个变量 `sum`，它被分配了一个**数字** 1 和**数字** 2 的求和的数值结果。”

即使在这样一个简单的程序中，我们也使用了两个 JavaScript 的基本类型：`String` 和 `Number`。

就像上面我们讲编译一样，我们不会陷入编程语言类型的学术细节当中，关键是要理解在 JavaScript 中类型表示的是什么，并扩展到 TypeScript 的类型的理解上。

从每夜拜读的最新 ECMAScript 规范中我们可以学到（LOL, JK - “wat’s an ECMA?”），它大量引用了 JavaScript 的类型及其用法。

直接引自官方规范：

>
> ECMAScript 语言的类型取决于使用 ECMAScript 语言的 ECMAScript 程序员所直接操作的值。
>
>
> ECMAScript 语言的类型有 Undefined、Null、Boolean、String、Symbol、Number 和 Object。
>
>
>

我们可以看到，JavaScript 语言有 7 种正式类型，其中我们在我们现在程序中使用了 6 种（Symbol 首次在 ES2015 中引入，也就是 ES6）。

现在我们来深入一点看上面的 JavaScript 代码中的 “name 和 sum”。

我们可以把我们当前被分配了字符串“James”的变量 `name` 重新赋值为我们的第二个变量 sum 的当前值，目前是数字 3。

```
var name = 'James';
var sum = 1 + 2;

name = sum;

```

该 `name` 变量开始“存有”一个字符串，但现在它“存有”一个数字。这凸显了 JavaScript 中变量和类型的基本特性：

“James” 值一直是字符串类型，而 `name` 变量可以分配任何类型的值。和 `sum` 赋值的情况相同，1 是一个数字类型，`sum` 变量可以分配任何可能的值。

>
> 在 JavaScript 中，值是具有类型的，而变量是可以随时保存任何类型的值。
>
>
>

这也恰好是一个“动态类型语言”的定义。

相比之下，我们可以将“静态类型语言”视为我们可以（也必须）将类型信息与特定变量相关联的语言：

```
var name: string ＝ ‘James’;

```

在这段代码中，我们能够更好地显式声明我们对变量 `name` 的意图，我们希望它总是用作一个字符串。

你猜怎么着？我们刚刚看到我们的第一个 TypeScript 程序。

当我们<ruby> 反思reflect</ruby>我们自己的代码（非编程方面的双关语“反射”）时，我们可以得出的结论，即使我们使用动态语言（如 JavaScript），在几乎所有的情况下，当我们初次定义变量和函数参数时，我们应该有非常明确的使用意图。如果这些变量和参数被重新赋值为与我们原先赋值不同类型的值，那么有可能某些东西并不是我们预期的那样工作的。

>
> 作为 JavaScript 开发者，TypeScript 的静态类型注释给我们的一个巨大的帮助，它能够清楚地表达我们对变量的意图。
>
>
> 这种改进不仅有益于 TypeScript 编译器，还可以让我们的同事和将来的自己明白我们的代码。代码是用来读的。
>
>
>

### TypeScript 在我们的 JavaScript 工作流程中的作用

我们已经开始看到“为什么经常说 TypeScript 只是 JavaScript + 静态类型”的说法了。`: string` 对于我们的 `name` 变量就是我们所谓的“类型注释”，在编译时被使用（换句话说，当我们让代码通过 TypeScript 编译器时），以确保其余的代码符合我们原来的意图。

我们再来看看我们的程序，并添加显式注释，这次是我们的 `sum` 变量：

```
var name: string = 'James';
var sum: number = 1 + 2;

name = sum;

```

如果我们使用 TypeScript 编译器编译这个代码，我们现在就会收到一个在 `name = sum` 这行的错误： `Type 'number' is not assignable to type 'string'`，我们的这种“偷渡”被警告，我们执行的代码可能有问题。

>
> 重要的是，如果我们想要继续执行，我们可以选择忽略 TypeScript 编译器的错误，因为它只是在将 JavaScript 代码发送给我们的用户之前给我们反馈的工具。
>
>
>

TypeScript 编译器为我们输出的最终 JavaScript 代码将与上述原始源代码完全相同：

```
var name = 'James';
var sum = 1 + 2;

name = sum;

```

类型注释全部为我们自动删除了，现在我们可以运行我们的代码了。

>
> 注意：在此示例中，即使我们没有提供显式类型注释的 `: string` 和 `: number` ，TypeScript 编译器也可以为我们提供完全相同的错误 。
>
>
> TypeScript 通常能够从我们使用它的方式推断变量的类型！
>
>
>

#### 我们的源文件是我们的文档，TypeScript 是我们的拼写检查

对于 TypeScript 与我们的源代码的关系来说，一个很好的类比，就是拼写检查与我们在 Microsoft Word 中写的文档的关系。

这两个例子有三个关键的共同点：

1. **它能告诉我们写的东西的客观的、直接的错误：**
	* *拼写检查*：“我们已经写了字典中不存在的字”
	* *TypeScript*：“我们引用了一个符号（例如一个变量），它没有在我们的程序中声明”
2. **它可以提醒我们写的可能是错误的：**
	* *拼写检查*：“该工具无法完全推断特定语句的含义，并建议重写”
	* *TypeScript*：“该工具不能完全推断特定变量的类型，并警告不要这样使用它”
3. **我们的来源可以用于其原始目的，无论工具是否存在错误：**
	* *拼写检查*：“即使您的文档有很多拼写错误，您仍然可以打印出来，并把它当成文档使用”
	* *TypeScript*：“即使您的源代码具有 TypeScript 错误，它仍然会生成您可以执行的 JavaScript 代码”

### TypeScript 是一种可以启用其它工具的工具

TypeScript 编译器由几个不同的部分或阶段组成。我们将通过查看这些部分之一 The Parser（语法分析程序）来结束这篇文章，除了 TypeScript 已经为我们做的以外，它为我们提供了在其上构建其它开发工具的机会。

编译过程的“解析器步骤”的结果是所谓的抽象语法树，简称为 AST。

#### 什么是抽象语法树（AST）？

我们以普通文本形式编写我们的程序，因为这是我们人类与计算机交互的最好方式，让它们能够做我们想要的东西。我们并不是很擅长于手工编写复杂的数据结构！

然而，不管在哪种情况下，普通文本在编译器里面实际上是一个非常棘手的事情。它可能包含程序运作不必要的东西，例如空格，或者可能存在有歧义的部分。

因此，我们希望将我们的程序转换成数据结构，将数据结构全部映射为我们所使用的所谓“标记”，并将其插入到我们的程序中。

这个数据结构正是 AST！

AST 可以通过多种不同的方式表示，我使用 JSON 来看一看。

我们从这个极其简单的基本源代码来看：

```
var a = 1;

```

TypeScript 编译器的 Parser（语法分析程序）阶段的（简化后的）输出将是以下 AST：

```
{
  "pos": 0,
  "end": 10,
  "kind": 256,
  "text": "var a = 1;",
  "statements": [
    {
      "pos": 0,
      "end": 10,
      "kind": 200,
      "declarationList": {
        "pos": 0,
        "end": 9,
        "kind": 219,
        "declarations": [
          {
            "pos": 3,
            "end": 9,
            "kind": 218,
            "name": {
              "pos": 3,
              "end": 5,
              "text": "a"
            },
            "initializer": {
              "pos": 7,
              "end": 9,
              "kind": 8,
              "text": "1"
            }
          }
        ]
      }
    }
  ]
}

```

我们的 AST 中的对象称为节点。

#### 示例：在 VS Code 中重命名符号

在内部，TypeScript 编译器将使用 Parser 生成的 AST 来提供一些非常重要的事情，例如，发生在编译程序时的类型检查。

但它不止于此！

>
> 我们可以使用 AST 在 TypeScript 之上开发自己的工具，如代码美化工具、代码格式化工具和分析工具。
>
>
>

建立在这个 AST 代码之上的工具的一个很好的例子是：<ruby> 语言服务器 <rt>  Language Server </rt></ruby>。

深入了解语言服务器的工作原理超出了本文的范围，但是当我们编写程序时，它能为我们提供一个绝对重量级别功能，就是“重命名符号”。

假设我们有以下源代码：

```
// The name of the author is James
var first_name = 'James';
console.log(first_name);

```

经过代码审查和对完美的适当追求，我们决定应该改换我们的变量命名惯例；使用驼峰式命名方式，而不是我们当前正在使用这种蛇式命名。

在我们的代码编辑器中，我们一直以来可以选择多个相同的文本，并使用多个光标来一次更改它们。

![Manually select matches](/data/attachment/album/201708/13/132415ayb8oc930mh9sgzo.gif)

当我们把程序也视作文本这样继续操作时，我们已经陷入了一个典型的陷阱中。

那个注释中我们不想修改的“name”单词，在我们的手动匹配中却被误选中了。我们可以看到在现实世界的应用程序中这样更改代码是有多危险。

正如我们在上面学到的那样，像 TypeScript 这样的东西在幕后生成一个 AST 的时候，与我们的程序不再像普通文本那样可以交互，每个标记在 AST 中都有自己的位置，而且它有很清晰的映射关系。

当我们右键单击我们的 `first_name` 变量时，我们可以在 VS Code 中直接“重命名符号”（TypeScript 语言服务器插件也可用于其他编辑器）。

![Rename Symbol Example](/data/attachment/album/201708/13/132432w12dexx13qkx1316.gif)

非常好！现在我们的 `first_name` 变量是唯一需要改变的东西，如果需要的话，这个改变甚至会发生在我们项目中的多个文件中（与导出和导入的值一样）！

### 总结

哦，我们在这篇文章中已经讲了很多的内容。

我们把有关学术方面的规避开，围绕编译器和类型还有很多专业术语给出了通俗的定义。

我们对比了编译语言与解释语言、运行阶段与编译阶段、动态类型与静态类型，以及抽象语法树（AST）如何为我们的程序构建工具提供了更为优化的方法。

重要的是，我们提供了 TypeScript 作为我们 JavaScript 开发工具的一种思路，以及如何在其上构建更棒的工具，比如说作为重构代码的一种方式的重命名符号。

快来 UltimateAngular 平台上学习从初学者到 TypeScript 高手的课程吧，开启你的学习之旅！

---

via: <https://toddmotto.com/typescript-the-missing-introduction>

作者：James Henry 译者：[MonkeyDEcho](https://github.com/MonkeyDEcho) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何在 CentOS 上安装 Apache Hadoop

楼主如何在ubuntu 11.04安装hadoop

跟这个完全一样

![](/data/attachment/album/201708/13/210401f4ttrztmdrn7rxey.jpg)

Apache Hadoop 软件库是一个框架，它允许使用简单的编程模型在计算机集群上对大型数据集进行分布式处理。Apache™ Hadoop® 是可靠、可扩展、分布式计算的开源软件。

该项目包括以下模块：

* Hadoop Common：支持其他 Hadoop 模块的常用工具。
* Hadoop 分布式文件系统 （HDFS™）：分布式文件系统，可提供对应用程序数据的高吞吐量访问支持。
* Hadoop YARN：作业调度和集群资源管理框架。
* Hadoop MapReduce：一个基于 YARN 的大型数据集并行处理系统。

本文将帮助你逐步在 CentOS 上安装 hadoop 并配置单节点 hadoop 集群。

### 安装 Java

在安装 hadoop 之前，请确保你的系统上安装了 Java。使用此命令检查已安装 Java 的版本。

```
java -version
java version "1.7.0_75"
Java(TM) SE Runtime Environment (build 1.7.0_75-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.75-b04, mixed mode)

```

要安装或更新 Java，请参考下面逐步的说明。

第一步是从 [Oracle 官方网站](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html)下载最新版本的 java。

```
cd /opt/
wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.tar.gz"
tar xzf jdk-7u79-linux-x64.tar.gz

```

需要设置使用更新版本的 Java 作为替代。使用以下命令来执行此操作。

```
cd /opt/jdk1.7.0_79/
alternatives --install /usr/bin/java java /opt/jdk1.7.0_79/bin/java 2
alternatives --config java

```

```
There are 3 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
*  1           /opt/jdk1.7.0_60/bin/java
 + 2           /opt/jdk1.7.0_72/bin/java
   3           /opt/jdk1.7.0_79/bin/java

Enter to keep the current selection[+], or type selection number: 3 [Press Enter]

```

现在你可能还需要使用 `alternatives` 命令设置 `javac` 和 `jar` 命令路径。

```
alternatives --install /usr/bin/jar jar /opt/jdk1.7.0_79/bin/jar 2
alternatives --install /usr/bin/javac javac /opt/jdk1.7.0_79/bin/javac 2
alternatives --set jar /opt/jdk1.7.0_79/bin/jar
alternatives --set javac /opt/jdk1.7.0_79/bin/javac

```

下一步是配置环境变量。使用以下命令正确设置这些变量。

设置 `JAVA_HOME` 变量：

```
export JAVA_HOME=/opt/jdk1.7.0_79

```

设置 `JRE_HOME` 变量：

```
export JRE_HOME=/opt/jdk1.7.0_79/jre

```

设置 `PATH` 变量：

```
export PATH=$PATH:/opt/jdk1.7.0_79/bin:/opt/jdk1.7.0_79/jre/bin

```

### 安装 Apache Hadoop

设置好 java 环境后。开始安装 Apache Hadoop。

第一步是创建用于 hadoop 安装的系统用户帐户。

```
useradd hadoop
passwd hadoop

```

现在你需要配置用户 `hadoop` 的 ssh 密钥。使用以下命令启用无需密码的 ssh 登录。

```
su - hadoop
ssh-keygen -t rsa
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 0600 ~/.ssh/authorized_keys
exit

```

现在从官方网站 [hadoop.apache.org](https://hadoop.apache.org/) 下载 hadoop 最新的可用版本。

```
cd ~
wget http://apache.claz.org/hadoop/common/hadoop-2.6.0/hadoop-2.6.0.tar.gz
tar xzf hadoop-2.6.0.tar.gz
mv hadoop-2.6.0 hadoop

```

下一步是设置 hadoop 使用的环境变量。

编辑 `~/.bashrc`，并在文件末尾添加以下这些值。

```
export HADOOP_HOME=/home/hadoop/hadoop
export HADOOP_INSTALL=$HADOOP_HOME
export HADOOP_MAPRED_HOME=$HADOOP_HOME
export HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDFS_HOME=$HADOOP_HOME
export YARN_HOME=$HADOOP_HOME
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin

```

在当前运行环境中应用更改。

```
source ~/.bashrc

```

编辑 `$HADOOP_HOME/etc/hadoop/hadoop-env.sh` 并设置 `JAVA_HOME` 环境变量。

```
export JAVA_HOME=/opt/jdk1.7.0_79/

```

现在，先从配置基本的 hadoop 单节点集群开始。

首先编辑 hadoop 配置文件并进行以下更改。

```
cd /home/hadoop/hadoop/etc/hadoop

```

让我们编辑 `core-site.xml`。

```
<configuration>
<property>
  <name>fs.default.name</name>
    <value>hdfs://localhost:9000</value>
</property>
</configuration>

```

接着编辑 `hdfs-site.xml`：

```
<configuration>
<property>
 <name>dfs.replication</name>
 <value>1</value>
</property>

<property>
  <name>dfs.name.dir</name>
    <value>file:///home/hadoop/hadoopdata/hdfs/namenode</value>
</property>

<property>
  <name>dfs.data.dir</name>
    <value>file:///home/hadoop/hadoopdata/hdfs/datanode</value>
</property>
</configuration>

```

并编辑 `mapred-site.xml`：

```
<configuration>
 <property>
  <name>mapreduce.framework.name</name>
   <value>yarn</value>
 </property>
</configuration>

```

最后编辑 `yarn-site.xml`：

```
<configuration>
 <property>
  <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
 </property>
</configuration>

```

现在使用以下命令格式化 namenode：

```
hdfs namenode -format

```

要启动所有 hadoop 服务，请使用以下命令：

```
cd /home/hadoop/hadoop/sbin/
start-dfs.sh
start-yarn.sh

```

要检查所有服务是否正常启动，请使用 `jps` 命令：

```
jps

```

你应该看到这样的输出。

```
26049 SecondaryNameNode
25929 DataNode
26399 Jps
26129 JobTracker
26249 TaskTracker
25807 NameNode

```

现在，你可以在浏览器中访问 Hadoop 服务：http://your-ip-address:8088/ 。

[![hadoop](/data/attachment/album/201708/13/210539pb8fkxvzybmmhxjx.png)](http://www.unixmen.com/wp-content/uploads/2015/06/hadoop.png)

谢谢阅读！！！

---

via: [https://www.unixmen.com/setup-apache-hadoop-centos/](https://www.unixmen.com.hijacked/setup-apache-hadoop-centos/)

作者：[anismaj](https://www.unixmen.com/author/anis/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


4 个 Linux 桌面上的轻量级图像浏览器

gthumb这么好的东西，怎么能不上。

并不轻量

目前来讲，还是觉得eom（eye of mate desktop)最好用，其它的不是停止维护年久失修，就是用起来麻烦。

xnview也很不错

qiv 键盘控制的图像查看工具

>
> 当你需要的不仅仅是一个基本的图像浏览器，而是一个完整的图像编辑器，请查看这些程序。
>
>
>

![](/data/attachment/album/201708/14/114804v97eze7hd2zled7s.jpg)

像大多数人一样，你计算机上可能有些照片和其他图像。而且，像大多数人一样，你可能想要经常查看那些图像和照片。

而启动一个 [GIMP](https://www.gimp.org/) 或者 [Pinta](https://pinta-project.com/pintaproject/pinta/) 这样的图片编辑器对于简单的浏览图片来说太笨重了。

另一方面，大多数 Linux 桌面环境中包含的基本图像查看器可能不足以满足你的需要。如果你想要一些更多的功能，但仍然希望它是轻量级的，那么看看这四个 Linux 桌面中的图像查看器，如果还不能满足你的需要，还有额外的选择。

### Feh

[Feh](https://feh.finalrewind.org/) 是我以前在老旧计算机上最喜欢的软件。它简单、朴实、用起来很好。

你可以从命令行启动 Feh：只将其指向图像或者包含图像的文件夹之后就行了。Feh 会快速加载，你可以通过鼠标点击或使用键盘上的向左和向右箭头键滚动图像。不能更简单了。

Feh 可能很轻量级，但它提供了一些选项。例如，你可以控制 Feh 的窗口是否具有边框，设置要查看的图像的最小和最大尺寸，并告诉 Feh 你想要从文件夹中的哪个图像开始浏览。

![Feh](/data/attachment/album/201708/14/114826kppgbgiaep0vtie0.png "Feh")

*Feh 的使用*

### Ristretto

如果你将 Xfce 作为桌面环境，那么你会熟悉 [Ristretto](https://docs.xfce.org/apps/ristretto/start)。它很小、简单、并且非常有用。

怎么简单？你打开包含图像的文件夹，单击左侧的缩略图之一，然后单击窗口顶部的导航键浏览图像。Ristretto 甚至有幻灯片功能。

Ristretto 也可以做更多的事情。你可以使用它来保存你正在浏览的图像的副本，将该图像设置为桌面壁纸，甚至在另一个应用程序中打开它，例如，当你需要修改一下的时候。

![Ristretto](/data/attachment/album/201708/14/114827ao7coq2oho23722o.png "Ristretto")

*在 Ristretto 中浏览照片*

### Mirage

表面上，[Mirage](http://mirageiv.sourceforge.net/)有点平常，没什么特色，但它做着和其他优秀图片浏览器一样的事：打开图像，将它们缩放到窗口的宽度，并且可以使用键盘滚动浏览图像。它甚至可以使用幻灯片。

不过，Mirage 将让需要更多功能的人感到惊喜。除了其核心功能，Mirage 还可以调整图像大小和裁剪图像、截取屏幕截图、重命名图像，甚至生成文件夹中图像的 150 像素宽的缩略图。

如果这还不够，Mirage 还可以显示 [SVG 文件](https://en.wikipedia.org/wiki/Scalable_Vector_Graphics)。你甚至可以从[命令行](http://mirageiv.sourceforge.net/docs-advanced.html#cli)中运行。

![Mirage](/data/attachment/album/201708/14/114828z7dpnuyvfnc7y2gx.png "Mirage")

*使用 Mirage*

### Nomacs

[Nomacs](http://nomacs.org/) 显然是本文中最重量级的图像浏览器。它所呈现的那么多功能让人忽视了它的速度。它快捷而易用。

Nomacs 不仅仅可以显示图像。你还可以查看和编辑图像的[元数据](https://iptc.org/standards/photo-metadata/photo-metadata/)，向图像添加注释，并进行一些基本的编辑，包括裁剪、调整大小、并将图像转换为灰度。Nomacs 甚至可以截图。

一个有趣的功能是你可以在桌面上运行程序的两个实例，并在这些实例之间同步图像。当需要比较两个图像时，[Nomacs 文档](http://nomacs.org/synchronization/)中推荐这样做。你甚至可以通过局域网同步图像。我没有尝试通过网络进行同步，如果你做过可以分享下你的经验。

![Nomacs](/data/attachment/album/201708/14/114829zezdd4ldb64doe8d.png "Nomacs")

*Nomacs 中的照片及其元数据*

### 其他一些值得一看的浏览器

如果这四个图像浏览器不符合你的需求，这里还有其他一些你可能感兴趣的。

**[Viewnior](http://siyanpanayotov.com/project/viewnior/)** 自称是 “GNU/Linux 中的快速简单的图像查看器”，它很适合这个用途。它的界面干净整洁，Viewnior 甚至可以进行一些基本的图像处理。

如果你喜欢在命令行中使用，那么 **display** 可能是你需要的浏览器。 **[ImageMagick](https://www.imagemagick.org/script/display.php)** 和 **[GraphicsMagick](http://www.graphicsmagick.org/display.html)** 这两个图像处理软件包都有一个名为 display 的应用程序，这两个版本都有查看图像的基本和高级选项。

**[Geeqie](http://geeqie.org/)** 是更轻和更快的图像浏览器之一。但是，不要让它的简单误导你。它包含的功能有元数据编辑功能和其它浏览器所缺乏的查看相机 RAW 图像格式的功能。

**[Shotwell](https://wiki.gnome.org/Apps/Shotwell)** 是 GNOME 桌面的照片管理器。然而它不仅仅能浏览图像，而且 Shotwell 非常快速，并且非常适合显示照片和其他图形。

*在 Linux 桌面中你有最喜欢的一款轻量级图片浏览器么？请在评论区随意分享你的喜欢的浏览器。*

---

作者简介：

我是一名长期使用自由/开源软件的用户，并因为乐趣和收获写各种东西。我不会很严肃。你可以在这些网站上找到我：Twitter、Mastodon、GitHub。

via: <https://opensource.com/article/17/7/4-lightweight-image-viewers-linux-desktop>

作者：[Scott Nesbitt](https://opensource.com/users/scottnesbitt) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Samba 系列（十四）：在命令行中将 CentOS 7 与 Samba4 AD 集成

Summary: 本指南将向你介绍如何使用 Authconfig 在命令行中将无图形界面的 CentOS 7 服务器集成到 Samba4 AD 域控制器中。

![](/data/attachment/album/201708/14/175556fx2zo3er3vxuumun.jpg)

本指南将向你介绍如何使用 Authconfig 在命令行中将无图形界面的 CentOS 7 服务器集成到 [Samba4 AD 域控制器](/article-8065-1.html)中。

这类设置提供了由 Samba 持有的单一集中式帐户数据库，允许 AD 用户通过网络基础设施对 CentOS 服务器进行身份验证。

#### 要求

1. [在 Ubuntu 上使用 Samba4 创建 AD 基础架构](/article-8065-1.html)
2. [CentOS 7.3 安装指南](/article-8048-1.html)

### 步骤 1：为 Samba4 AD DC 配置 CentOS

1、 在开始将 CentOS 7 服务器加入 Samba4 DC 之前，你需要确保网络接口被正确配置为通过 DNS 服务查询域。

运行 `ip address` 命令列出你机器网络接口，选择要编辑的特定网卡，通过针对接口名称运行 `nmtui-edit` 命令（如本例中的 ens33），如下所示。

```
# ip address
# nmtui-edit ens33

```

[![List Network Interfaces](/data/attachment/album/201708/14/175810uz3uwc1iw2r21i92.jpg)](https://www.tecmint.com/wp-content/uploads/2017/07/List-Network-Interfaces.jpg)

*列出网络接口*

2、 打开网络接口进行编辑后，添加最适合 LAN 的静态 IPv4 配置，并确保为 DNS 服务器设置 Samba AD 域控制器 IP 地址。

另外，在搜索域中追加你的域的名称，并使用 [TAB] 键跳到确定按钮来应用更改。

当你仅对域 dns 记录使用短名称时, 已提交的搜索域保证域对应项会自动追加到 dns 解析 (FQDN) 中。

[![Configure Network Interface](/data/attachment/album/201708/14/175810sgkfhckg6vkovjph.png)](https://www.tecmint.com/wp-content/uploads/2017/07/Configure-Network-Interface.png)

*配置网络接口*

3、最后，重启网络守护进程以应用更改，并通过对域名和域控制器 ping 来测试 DNS 解析是否正确配置，如下所示。

```
# systemctl restart network.service
# ping -c2 tecmint.lan
# ping -c2 adc1
# ping -c2 adc2

```

[![Verify DNS Resolution on Domain](/data/attachment/album/201708/14/175810akrfkkok620r2jz3.png)](https://www.tecmint.com/wp-content/uploads/2017/07/Verify-DNS-Resolution-on-Domain.png)

*验证域上的 DNS 解析*

4、 另外，使用下面的命令配置你的计算机主机名并重启机器应用更改。

```
# hostnamectl set-hostname your_hostname
# init 6

```

使用以下命令验证主机名是否正确配置。

```
# cat /etc/hostname
# hostname

```

5、 最后，使用 root 权限运行以下命令，与 Samba4 AD DC 同步本地时间。

```
# yum install ntpdate
# ntpdate domain.tld

```

[![Sync Time with Samba4 AD DC](/data/attachment/album/201708/14/175811b9963uhbsywwbw96.png)](https://www.tecmint.com/wp-content/uploads/2017/07/Sync-Time-with-Samba4-AD-DC.png)

*与 Samba4 AD DC 同步时间*

### 步骤 2：将 CentOS 7 服务器加入到 Samba4 AD DC

6、 要将 CentOS 7 服务器加入到 Samba4 AD 中，请先用具有 root 权限的帐户在计算机上安装以下软件包。

```
# yum install authconfig samba-winbind samba-client samba-winbind-clients

```

7、 为了将 CentOS 7 服务器与域控制器集成，可以使用 root 权限运行 `authconfig-tui`，并使用下面的配置。

```
# authconfig-tui

```

首屏选择：

* 在 User Information 中：
	+ Use Winbind
* 在 Authentication 中使用[空格键]选择:
	+ Use Shadow Password
	+ Use Winbind Authentication
	+ Local authorization is sufficient

[![Authentication Configuration](/data/attachment/album/201708/14/175812n2nm84lmmh7jc8jc.png)](https://www.tecmint.com/wp-content/uploads/2017/07/Authentication-Configuration.png)

*验证配置*

8、 点击 Next 进入 Winbind 设置界面并配置如下：

* Security Model: ads
* Domain = YOUR\_DOMAIN (use upper case)
* Domain Controllers = domain machines FQDN (comma separated if more than one)
* ADS Realm = YOUR\_DOMAIN.TLD
* Template Shell = /bin/bash

[![Winbind Settings](/data/attachment/album/201708/14/175812vlssskbsyzqdssd7.png)](https://www.tecmint.com/wp-content/uploads/2017/07/Winbind-Settings.png)

*Winbind 设置*

9、 要加入域，使用 [tab] 键跳到 “Join Domain” 按钮，然后按[回车]键加入域。

在下一个页面，添加具有提升权限的 Samba4 AD 帐户的凭据，以将计算机帐户加入 AD，然后单击 “OK” 应用设置并关闭提示。

请注意，当你输入用户密码时，凭据将不会显示在屏幕中。在下面再次点击 OK，完成 CentOS 7 的域集成。

[![Join Domain to Samba4 AD DC](/data/attachment/album/201708/14/175814ma11plvh00hapu6b.png)](https://www.tecmint.com/wp-content/uploads/2017/07/Join-Domain-to-Samba4-AD-DC.png)

*加入域到 Samba4 AD DC*

[![Confirm Winbind Settings](/data/attachment/album/201708/14/175814r7558a8aamhmb7bt.png)](https://www.tecmint.com/wp-content/uploads/2017/07/Confirm-Winbind-Settings.png)

*确认 Winbind 设置*

要强制将机器添加到特定的 Samba AD OU 中，请使用 hostname 命令获取计算机的完整名称，并使用机器名称在该 OU 中创建一个新的计算机对象。

将新对象添加到 Samba4 AD 中的最佳方法是已经集成到[安装了 RSAT 工具](/article-8097-1.html)的域的 Windows 机器上使用 ADUC 工具。

重要：加入域的另一种方法是使用 `authconfig` 命令行，它可以对集成过程进行广泛的控制。

但是，这种方法很容易因为其众多参数造成错误，如下所示。该命令必须输入一条长命令行。

```
# authconfig --enablewinbind --enablewinbindauth --smbsecurity ads --smbworkgroup=YOUR_DOMAIN --smbrealm YOUR_DOMAIN.TLD --smbservers=adc1.yourdomain.tld --krb5realm=YOUR_DOMAIN.TLD --enablewinbindoffline --enablewinbindkrb5 --winbindtemplateshell=/bin/bash--winbindjoin=domain_admin_user --update  --enablelocauthorize   --savebackup=/backups

```

10、 机器加入域后，通过使用以下命令验证 winbind 服务是否正常运行。

```
# systemctl status winbind.service

```

11、 接着检查是否在 Samba4 AD 中成功创建了 CentOS 机器对象。从安装了 RSAT 工具的 Windows 机器使用 AD 用户和计算机工具，并进入到你的域计算机容器。一个名为 CentOS 7 Server 的新 AD 计算机帐户对象应该在右边的列表中。

12、 最后，使用文本编辑器打开 samba 主配置文件（`/etc/samba/smb.conf`）来调整配置，并在 `[global]` 配置块的末尾附加以下行，如下所示：

```
winbind use default domain = true
winbind offline logon = true

```

[![Configure Samba](/data/attachment/album/201708/14/175817no5sm6nrxssyy6y3.jpg)](https://www.tecmint.com/wp-content/uploads/2017/07/Configure-Samba.jpg)

*配置 Samba*

13、 为了在 AD 帐户首次登录时在机器上创建本地家目录，请运行以下命令：

```
# authconfig --enablemkhomedir --update

```

14、 最后，重启 Samba 守护进程使更改生效，并使用一个 AD 账户登陆验证域加入。AD 帐户的家目录应该会自动创建。

```
# systemctl restart winbind
# su - domain_account

```

[![Verify Domain Joining](/data/attachment/album/201708/14/175818c228xkmaxmvl84h8.jpg)](https://www.tecmint.com/wp-content/uploads/2017/07/Verify-Domain-Joining.jpg)

*验证域加入*

15、 通过以下命令之一列出域用户或域组。

```
# wbinfo -u
# wbinfo -g

```

[![List Domain Users and Groups](/data/attachment/album/201708/14/175818b5i4x789pk18ivbo.png)](https://www.tecmint.com/wp-content/uploads/2017/07/List-Domain-Users-and-Groups.png)

*列出域用户和组*

16、 要获取有关域用户的信息，请运行以下命令。

```
# wbinfo -i domain_user

```

[![List Domain User Info](/data/attachment/album/201708/14/175818le5soht6mwsxze58.jpg)](https://www.tecmint.com/wp-content/uploads/2017/07/List-Domain-User-Info.jpg)

*列出域用户信息*

17、 要显示域摘要信息，请使用以下命令。

```
# net ads info

```

[![List Domain Summary](/data/attachment/album/201708/14/175819iygqzt6m8ddbmdma.jpg)](https://www.tecmint.com/wp-content/uploads/2017/07/List-Domain-Summary.jpg)

*列出域摘要*

### 步骤 3：使用 Samba4 AD DC 帐号登录CentOS

18、 要在 CentOS 中与域用户进行身份验证，请使用以下命令语法之一。

```
# su - ‘domain\domain_user’
# su - domain\\domain_user

```

或者在 samba 配置文件中设置了 `winbind use default domain = true` 参数的情况下，使用下面的语法。

```
# su - domain_user
# su - domain_user@domain.tld

```

19、 要为域用户或组添加 root 权限，请使用 `visudocommand` 编辑 `sudoers` 文件，并添加以下截图所示的行。

```
YOUR_DOMAIN\\domain_username             ALL=(ALL:ALL) ALL      #For domain users
%YOUR_DOMAIN\\your_domain\  group            ALL=(ALL:ALL) ALL  #For domain groups

```

或者在 samba 配置文件中设置了 `winbind use default domain = true` 参数的情况下，使用下面的语法。

```
domain_username                  ALL=(ALL:ALL) ALL      #For domain users
%your_domain\  group             ALL=(ALL:ALL) ALL  #For domain groups

```

[![Grant Root Privileges on Domain Users](/data/attachment/album/201708/14/175821r616i6k3fs191ijc.jpg)](https://www.tecmint.com/wp-content/uploads/2017/07/Grant-Root-Privileges-on-Domain-Users.jpg)

*授予域用户 root 权限*

20、 针对 Samba4 AD DC 的以下一系列命令也可用于故障排除：

```
# wbinfo -p #Ping domain
# wbinfo -n domain_account #Get the SID of a domain account
# wbinfo -t  #Check trust relationship

```

21、 要离开该域, 请使用具有提升权限的域帐户对你的域名运行以下命令。从 AD 中删除计算机帐户后, 重启计算机以在集成进程之前还原更改。

```
# net ads leave -w DOMAIN -U domain_admin
# init 6

```

就是这样了！尽管此过程主要集中在将 CentOS 7 服务器加入到 Samba4 AD DC 中，但这里描述的相同步骤也适用于将 CentOS 服务器集成到 Microsoft Windows Server 2012 AD 中。

---

作者简介：

Matei Cezar - 我是一个电脑上瘾的家伙，开源和基于 linux 的系统软件的粉丝，在 Linux 发行版桌面、服务器和 bash 脚本方面拥有大约 4 年的经验。

---

via: <https://www.tecmint.com/integrate-centos-7-to-samba4-active-directory/>

作者：[Matei Cezar](https://www.tecmint.com/author/cezarmatei/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OCI 发布容器运行时和镜像格式规范 V1.0

Summary: 7 月 19 日是开放容器计划Open Container Initiative（OCI）的一个重要里程碑，OCI 发布了容器运行时和镜像规范的 1.0 版本。

本地化管理命令子集才是王道！！！

企业一定要使用标准化协议。第一异构设备对接问题少。第二避免厂家绑架。厂家吹自己的私有协议再好都是个问题。妈的生产系统大故障就是因为两个厂家的私有协议对不到一起导致网络大故障。那玩意太恐怖了。因此，各位企业IT们，倡议大家一定要首先支持和使用开放的标准协议产品。用脚投票其实是对自己权利最好的保护

![](/data/attachment/album/201708/14/235901fx9pzduux4g9t4t5.jpg)

7 月 19 日是<ruby> 开放容器计划 <rt>  Open Container Initiative </rt></ruby>（OCI）的一个重要里程碑，OCI 发布了容器运行时和镜像规范的 1.0 版本，而 Docker 在这过去两年中一直充当着推动和引领的核心角色。我们的目标是为社区、客户以及更广泛的容器行业提供底层的标准。要了解这一里程碑的意义，我们先来看看 Docker 在开发容器技术行业标准方面的成长和发展历史。

### Docker 将运行时和镜像捐赠给 OCI 的历史回顾

Docker 的镜像格式和容器运行时在 2013 年作为开源项目发布后，迅速成为事实上的标准。我们认识到将其转交给中立管理机构管理，以加强创新和防止行业碎片化的重要性。我们与广泛的容器技术人员和行业领导者合作，成立了<ruby> 开放容器项目 <rt>  Open Container Project </rt></ruby>来制定了一套容器标准，并在 Linux 基金会的支持下，于 2015 年 6 月在 <ruby> Docker 大会 <rp>  （ </rp> <rt>  DockerCon </rt> <rp>  ） </rp></ruby>上推出。最终在那个夏天演变成为<ruby> 开放容器计划 <rt>  Open Container Initiative </rt></ruby> (OCI）。

Docker 贡献了 runc ，这是从 Docker 员工 [Michael Crosby](https://github.com/crosbymichael) 的 libcontainer 项目中发展而来的容器运行时参考实现。 runc 是描述容器生命周期和运行时行为的运行时规范的基础。runc 被用在数千万个节点的生产环境中，这比任何其它代码库都要大一个数量级。runc 已经成为运行时规范的参考实现，并且随着项目的进展而不断发展。

在运行时规范制定工作开始近一年后，我们组建了一个新的工作组来制定镜像格式的规范。 Docker 将 Docker V2 镜像格式捐赠给 OCI 作为镜像规范的基础。通过这次捐赠，OCI 定义了构成容器镜像的数据结构（原始镜像）。定义容器镜像格式是一个至关重要的步骤，但它需要一个像 Docker 这样的平台通过定义和提供构建、管理和发布镜像的工具来实现它的价值。 例如，Dockerfile 等内容并不包括在 OCI 规范中。

![Docker 为 OCI 贡献的历史](/data/attachment/album/201708/14/235927nyyl68plj6zus6ko.png)

### 开放容器标准化之旅

这个规范已经持续开发了两年。随着代码的重构，更小型的项目已经从 runc 参考实现中脱颖而出，并支持即将发布的认证测试工具。

有关 Docker 参与塑造 OCI 的详细信息，请参阅上面的时间轴，其中包括：创建 runc ，和社区一起更新、迭代运行时规范，创建 containerd 以便于将 runc 集成到 Docker 1.11 中，将 Docker V2 镜像格式贡献给 OCI 作为镜像格式规范的基础，并在 [containerd](https://containerd.io/) 中实现该规范，使得该核心容器运行时同时涵盖了运行时和镜像格式标准，最后将 containerd 捐赠给了<ruby> 云计算基金会 <rt>  Cloud Native Computing Foundation </rt></ruby>（CNCF），并于本月发布了更新的 1.0 alpha 版本。

维护者 [Michael Crosby](https://github.com/crosbymichael) 和 [Stephen Day](https://github.com/stevvooe) 引导了这些规范的发展，并且为 v1.0 版本的实现提供了极大的帮助，另外 Alexander Morozov，Josh Hawn，Derek McGown 和 Aaron Lehmann 也贡献了代码，以及 Stephen Walli 参加了认证工作组。

Docker 仍然致力于推动容器标准化进程，在每个人都认可的层面建立起坚实的基础，使整个容器行业能够在依旧十分差异化的层面上进行创新。

### 开放标准只是一小块拼图

Docker 是一个完整的平台，用于创建、管理、保护和编排容器以及镜像。该项目的愿景始终是致力于成为支持开源组件的行业规范的基石，或着是容器解决方案的校准铅锤。Docker 平台正位于此层之上 -- 为客户提供从开发到生产的安全的容器管理解决方案。

OCI 运行时和镜像规范成为一个可靠的标准基础，允许和鼓励多样化的容器解决方案，同时它们不限制产品创新或遏制主要开发者。打一个比方，TCP/IP、HTTP 和 HTML 成为过去 25 年来建立万维网的可靠标准，其他公司可以继续通过这些标准的新工具、技术和浏览器进行创新。 OCI 规范也为容器解决方案提供了类似的规范基础。

开源项目也在为产品开发提供组件方面发挥着作用。containerd 项目就使用了 OCI 的 runc 参考实现，它负责镜像的传输和存储，容器运行和监控，以及支持存储和网络附件的等底层功能。containerd 项目已经被 Docker 捐赠给了 CNCF ，与其他重要项目一起支持云计算解决方案。

Docker 使用了 containerd 和其它自己的核心开源基础设施组件，如 LinuxKit，InfraKit 和 Notary 等项目来构建和保护 Docker 社区版容器解决方案。正在寻找一个能提供容器管理、安全性、编排、网络和更多功能的完整容器平台的用户和组织可以了解下 Docker Enterprise Edition 。

![Docker 栈](/data/attachment/album/201708/14/235932b2j0vnevnfdyjj22.jpg)

>
> 这张图强调了 OCI 规范提供了一个由容器运行时实现的标准层：containerd 和 runc。 要组装一个完整的像 Docker 这样具有完整容器生命周期和工作流程的容器平台，需要和许多其他的组件集成在一起：管理基础架构的 InfraKit，提供操作系统的 LinuxKit，交付编排的 SwarmKit，确保安全性的 Notary。
>
>
>

### OCI 下一步该干什么

随着运行时和镜像规范的发布，我们应该庆祝开发者的努力。开放容器计划的下一个关键工作是提供认证计划，以验证实现者的产品和项目确实符合运行时和镜像规范。[认证工作组](https://github.com/opencontainers/certification) 已经组织了一个程序，结合了<ruby> 开发套件 <rp>  （ </rp> <rt>  developing suite </rt> <rp>  ） </rp></ruby>的[运行时](https://github.com/opencontainers/runtime-tools)和[镜像](https://github.com/opencontainers/image-tools)规范测试工具将展示产品应该如何参照标准进行实现。

同时，当前规范的开发者们正在考虑下一个最重要的容器技术领域。云计算基金会的通用容器网络接口开发工作已经正在进行中，支持镜像签署和分发的工作正也在 OCI 的考虑之中。

除了 OCI 及其成员，Docker 仍然致力于推进容器技术的标准化。 OCI 的使命是为用户和公司提供在开发者工具、镜像分发、容器编排、安全、监控和管理等方面进行创新的基准。Docker 将继续引领创新，不仅提供提高生产力和效率的工具，而且还通过授权用户，合作伙伴和客户进行创新。

**在 Docker 学习更过关于 OCI 和开源的信息：**

* 阅读 [OCI 规范的误区](/article-8763-1.html)
* 访问 [开放容器计划的网站](https://www.opencontainers.org/join)
* 访问 [Moby 项目网站](http://mobyproject.org/)
* 参加 [DockerCon Europe 2017](https://europe-2017.dockercon.com/)
* 参加 [Moby Summit LA](https://www.eventbrite.com/e/moby-summit-los-angeles-tickets-35930560273)

（题图：vox-cdn.com）

---

作者简介：

Patrick Chanezon 是 Docker Inc. 技术人员。他的工作是帮助构建 Docker 。一个程序员和讲故事的人 （storyller），他在 Netscape 和 Sun 工作了10年的时间，又在Google，VMware 和微软工作了10年。他的主要职业兴趣是为这些奇特的双边市场“平台”建立和推动网络效应。他曾在门户网站，广告，电商，社交，Web，分布式应用和云平台上工作过。有关更多信息，请访问 linkedin.com/in/chanezon 和他的推特 @chanezon。

---

via: <https://blog.docker.com/2017/07/oci-release-of-v1-0-runtime-and-image-format-specifications/>

作者：[Patrick Chanezon](https://blog.docker.com/author/chanezon/)  译者：[rieonke](https://github.com/rieonke) 校对：[校对者ID](https://github.com/%E6%A0%A1%E5%AF%B9%E8%80%85ID)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


学习用 Python 编程时要避免的 3 个错误

这算是Python入门内容了，也算是Python的「坑」。

很好, 第一個真的沒想到

这个和js有点像

来自山西太原的 Chrome Mobile 39.0|Android 5.1 用户

>
> 这些错误会造成很麻烦的问题，需要数小时才能解决。
>
>
>

![](/data/attachment/album/201708/16/000829y5u4wm1kou8d55z6.jpg)

当你做错事时，承认错误并不是一件容易的事，但是犯错是任何学习过程中的一部分，无论是学习走路，还是学习一种新的编程语言都是这样，比如学习 Python。

为了让初学 Python 的程序员避免犯同样的错误，以下列出了我学习 Python 时犯的三种错误。这些错误要么是我长期以来经常犯的，要么是造成了需要几个小时解决的麻烦。

年轻的程序员们可要注意了，这些错误是会浪费一下午的！

### 1、 可变数据类型作为函数定义中的默认参数

这似乎是对的？你写了一个小函数，比如，搜索当前页面上的链接，并可选将其附加到另一个提供的列表中。

```
def search_for_links(page, add_to=[]):
    new_links = page.search_for_links()
    add_to.extend(new_links)
    return add_to

```

从表面看，这像是十分正常的 Python 代码，事实上它也是，而且是可以运行的。但是，这里有个问题。如果我们给 `add_to` 参数提供了一个列表，它将按照我们预期的那样工作。但是，如果我们让它使用默认值，就会出现一些神奇的事情。

试试下面的代码：

```
def fn(var1, var2=[]):
    var2.append(var1)
    print var2

fn(3)
fn(4)
fn(5)

```

可能你认为我们将看到：

```
[3]
[4]
[5]

```

但实际上，我们看到的却是：

```
[3]
[3, 4]
[3, 4, 5]

```

为什么呢？如你所见，每次都使用的是同一个列表，输出为什么会是这样？在 Python 中，当我们编写这样的函数时，这个列表被实例化为函数定义的一部分。当函数运行时，它并不是每次都被实例化。这意味着，这个函数会一直使用完全一样的列表对象，除非我们提供一个新的对象：

```
fn(3, [4])

```

```
[4, 3]

```

答案正如我们所想的那样。要想得到这种结果，正确的方法是：

```
def fn(var1, var2=None):
    if not var2:
        var2 = []
    var2.append(var1)
```

或是在第一个例子中：

```
def search_for_links(page, add_to=None):
    if not add_to:
        add_to = []
    new_links = page.search_for_links()
    add_to.extend(new_links)
    return add_to
```

这将在模块加载的时候移走实例化的内容，以便每次运行函数时都会发生列表实例化。请注意，对于不可变数据类型，比如[**元组**](https://docs.python.org/2/library/functions.html?highlight=tuple#tuple)、[**字符串**](https://docs.python.org/2/library/string.html)、[**整型**](https://docs.python.org/2/library/functions.html#int)，是不需要考虑这种情况的。这意味着，像下面这样的代码是非常可行的：

```
def func(message="my message"):
    print message
```

### 2、 可变数据类型作为类变量

这和上面提到的最后一个错误很相像。思考以下代码：

```
class URLCatcher(object):
    urls = []

    def add_url(self, url):
        self.urls.append(url)
```

这段代码看起来非常正常。我们有一个储存 URL 的对象。当我们调用 add\_url 方法时，它会添加一个给定的 URL 到存储中。看起来非常正确吧？让我们看看实际是怎样的：

```
a = URLCatcher()
a.add_url('http://www.google.com')
b = URLCatcher()
b.add_url('http://www.bbc.co.hk')
```

b.urls：

```
['http://www.google.com', 'http://www.bbc.co.uk']

```

a.urls：

```
['http://www.google.com', 'http://www.bbc.co.uk']

```

等等，怎么回事？！我们想的不是这样啊。我们实例化了两个单独的对象 `a` 和 `b`。把一个 URL 给了 `a`，另一个给了 `b`。这两个对象怎么会都有这两个 URL 呢？

这和第一个错例是同样的问题。创建类定义时，URL 列表将被实例化。该类所有的实例使用相同的列表。在有些时候这种情况是有用的，但大多数时候你并不想这样做。你希望每个对象有一个单独的储存。为此，我们修改代码为：

```
class URLCatcher(object):
    def __init__(self):
        self.urls = []

    def add_url(self, url):
        self.urls.append(url)
```

现在，当创建对象时，URL 列表被实例化。当我们实例化两个单独的对象时，它们将分别使用两个单独的列表。

### 3、 可变的分配错误

这个问题困扰了我一段时间。让我们做出一些改变，并使用另一种可变数据类型 - [**字典**](https://docs.python.org/2/library/stdtypes.html?highlight=dict#dict)。

```
a = {'1': "one", '2': 'two'}

```

现在，假设我们想把这个字典用在别的地方，且保持它的初始数据完整。

```
b = a

b['3'] = 'three'
```

简单吧？

现在，让我们看看原来那个我们不想改变的字典 `a`：

```
{'1': "one", '2': 'two', '3': 'three'}

```

哇等一下，我们再看看 **b**？

```
{'1': "one", '2': 'two', '3': 'three'}

```

等等，什么？有点乱……让我们回想一下，看看其它不可变类型在这种情况下会发生什么，例如一个**元组**：

```
c = (2, 3)
d = c
d = (4, 5)

```

现在 `c` 是 `(2, 3)`，而 `d` 是 `(4, 5)`。

这个函数结果如我们所料。那么，在之前的例子中到底发生了什么？当使用可变类型时，其行为有点像 **C** 语言的一个指针。在上面的代码中，我们令 `b = a`，我们真正表达的意思是：`b` 成为 `a` 的一个引用。它们都指向 Python 内存中的同一个对象。听起来有些熟悉？那是因为这个问题与先前的相似。其实，这篇文章应该被称为「可变引发的麻烦」。

列表也会发生同样的事吗？是的。那么我们如何解决呢？这必须非常小心。如果我们真的需要复制一个列表进行处理，我们可以这样做：

```
b = a[:]

```

这将遍历并复制列表中的每个对象的引用，并且把它放在一个新的列表中。但是要注意：如果列表中的每个对象都是可变的，我们将再次获得它们的引用，而不是完整的副本。

假设在一张纸上列清单。在原来的例子中相当于，A 某和 B 某正在看着同一张纸。如果有个人修改了这个清单，两个人都将看到相同的变化。当我们复制引用时，每个人现在有了他们自己的清单。但是，我们假设这个清单包括寻找食物的地方。如果“冰箱”是列表中的第一个，即使它被复制，两个列表中的条目也都指向同一个冰箱。所以，如果冰箱被 A 修改，吃掉了里面的大蛋糕，B 也将看到这个蛋糕的消失。这里没有简单的方法解决它。只要你记住它，并编写代码的时候，使用不会造成这个问题的方式。

字典以相同的方式工作，并且你可以通过以下方式创建一个昂贵副本：

```
b = a.copy()

```

再次说明，这只会创建一个新的字典，指向原来存在的相同的条目。因此，如果我们有两个相同的列表，并且我们修改字典 `a` 的一个键指向的可变对象，那么在字典 b 中也将看到这些变化。

可变数据类型的麻烦也是它们强大的地方。以上都不是实际中的问题；它们是一些要注意防止出现的问题。在第三个项目中使用昂贵复制操作作为解决方案在 99% 的时候是没有必要的。你的程序或许应该被改改，所以在第一个例子中，这些副本甚至是不需要的。

*编程快乐！在评论中可以随时提问。*

---

作者简介：

Pete Savage - Peter 是一位充满激情的开源爱好者，在过去十年里一直在推广和使用开源产品。他从 Ubuntu 社区开始，在许多不同的领域自愿参与音频制作领域的研究工作。在职业经历方面，他起初作为公司的系统管理员，大部分时间在管理和建立数据中心，之后在 Red Hat 担任 CloudForms 产品的主要测试工程师。

---

via: <https://opensource.com/article/17/6/3-things-i-did-wrong-learning-python>

作者：[Pete Savage](https://opensource.com/users/psav) 译者：[polebug](https://github.com/polebug) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Linux 包管理基础：apt、yum、dnf 和 pkg

dpkg 若要查看最近安裝的包，不如 rpm 方便。只能查看其一个文本格式的日志文件。

rpm --query --all --last | less

好文要支持！！！

或许是flatpak呢

wifi页面？？？ 不是wiki吗？

汗~

很详细！赞一个!

test

![Package_Management_tw_mostov.png-307.8kB](/data/attachment/album/201708/16/114539z1cbxu1mzsm2ssu1.png)

### 介绍

大多数现代的类 Unix 操作系统都提供了一种中心化的机制用来搜索和安装软件。软件通常都是存放在存储库中，并通过包的形式进行分发。处理包的工作被称为包管理。包提供了操作系统的基本组件，以及共享的库、应用程序、服务和文档。

包管理系统除了安装软件外，它还提供了工具来更新已经安装的包。包存储库有助于确保你的系统中使用的代码是经过审查的，并且软件的安装版本已经得到了开发人员和包维护人员的认可。

在配置服务器或开发环境时，我们最好了解下包在官方存储库之外的情况。某个发行版的稳定版本中的包有可能已经过时了，尤其是那些新的或者快速迭代的软件。然而，包管理无论对于系统管理员还是开发人员来说都是至关重要的技能，而已打包的软件对于主流 Linux 发行版来说也是一笔巨大的财富。

本指南旨在快速地介绍下在多种 Linux 发行版中查找、安装和升级软件包的基础知识，并帮助您将这些内容在多个系统之间进行交叉对比。

### 包管理系统：简要概述

大多数包系统都是围绕包文件的集合构建的。包文件通常是一个存档文件，它包含已编译的二进制文件和软件的其他资源，以及安装脚本。包文件同时也包含有价值的元数据，包括它们的依赖项，以及安装和运行它们所需的其他包的列表。

虽然这些包管理系统的功能和优点大致相同，但打包格式和工具却因平台而异：

| 操作系统 | 格式 | 工具 |
| --- | --- | --- |
| Debian | `.deb` | `apt`, `apt-cache`, `apt-get`, `dpkg` |
| Ubuntu | `.deb` | `apt`, `apt-cache`, `apt-get`, `dpkg` |
| CentOS | `.rpm` | `yum` |
| Fedora | `.rpm` | `dnf` |
| FreeBSD | Ports, `.txz` | `make`, `pkg` |

Debian 及其衍生版，如 Ubuntu、Linux Mint 和 Raspbian，它们的包格式是 `.deb`。APT 这款先进的包管理工具提供了大多数常见的操作命令：搜索存储库、安装软件包及其依赖项，并管理升级。在本地系统中，我们还可以使用 `dpkg` 程序来安装单个的 `deb` 文件，APT 命令作为底层 `dpkg` 的前端，有时也会直接调用它。

最近发布的 debian 衍生版大多数都包含了 `apt` 命令，它提供了一个简洁统一的接口，可用于通常由 `apt-get` 和 `apt-cache` 命令处理的常见操作。这个命令是可选的，但使用它可以简化一些任务。

CentOS、Fedora 和其它 Red Hat 家族成员使用 RPM 文件。在 CentOS 中，通过 `yum` 来与单独的包文件和存储库进行交互。

在最近的 Fedora 版本中，`yum` 已经被 `dnf` 取代，`dnf` 是它的一个现代化的分支，它保留了大部分 `yum` 的接口。

FreeBSD 的二进制包系统由 `pkg` 命令管理。FreeBSD 还提供了 `Ports` 集合，这是一个存在于本地的目录结构和工具，它允许用户获取源码后使用 Makefile 直接从源码编译和安装包。

### 更新包列表

大多数系统在本地都会有一个和远程存储库对应的包数据库，在安装或升级包之前最好更新一下这个数据库。另外，`yum` 和 `dnf` 在执行一些操作之前也会自动检查更新。当然你可以在任何时候对系统进行更新。

| 系统 | 命令 |
| --- | --- |
| Debian / Ubuntu | `sudo apt-get update` |
|  | `sudo apt update` |
| CentOS | `yum check-update` |
| Fedora | `dnf check-update` |
| FreeBSD Packages | `sudo pkg update` |
| FreeBSD Ports | `sudo portsnap fetch update` |

### 更新已安装的包

在没有包系统的情况下，想确保机器上所有已安装的软件都保持在最新的状态是一个很艰巨的任务。你将不得不跟踪数百个不同包的上游更改和安全警报。虽然包管理器并不能解决升级软件时遇到的所有问题，但它确实使你能够使用一些命令来维护大多数系统组件。

在 FreeBSD 上，升级已安装的 ports 可能会引入破坏性的改变，有些步骤还需要进行手动配置，所以在通过 `portmaster` 更新之前最好阅读下 `/usr/ports/UPDATING` 的内容。

| 系统 | 命令 | 说明 |
| --- | --- | --- |
| Debian / Ubuntu | `sudo apt-get upgrade` | 只更新已安装的包 |
|  | `sudo apt-get dist-upgrade` | 可能会增加或删除包以满足新的依赖项 |
|  | `sudo apt upgrade` | 和 `apt-get upgrade` 类似 |
|  | `sudo apt full-upgrade` | 和 `apt-get dist-upgrade` 类似 |
| CentOS | `sudo yum update` |  |
| Fedora | `sudo dnf upgrade` |  |
| FreeBSD Packages | `sudo pkg upgrade` |  |
| FreeBSD Ports | `less /usr/ports/UPDATING` | 使用 `less` 来查看 ports 的更新提示（使用上下光标键滚动，按 q 退出）。 |
|  | `cd /usr/ports/ports-mgmt/portmaster && sudo make install && sudo portmaster -a` | 安装 `portmaster` 然后使用它更新已安装的 ports |

### 搜索某个包

大多数发行版都提供针对包集合的图形化或菜单驱动的工具，我们可以分类浏览软件，这也是一个发现新软件的好方法。然而，查找包最快和最有效的方法是使用命令行工具进行搜索。

| 系统 | 命令 | 说明 |
| --- | --- | --- |
| Debian / Ubuntu | `apt-cache search search_string` |  |
|  | `apt search search_string` |  |
| CentOS | `yum search search_string` |  |
|  | `yum search all search_string` | 搜索所有的字段，包括描述 |
| Fedora | `dnf search search_string` |  |
|  | `dnf search all search_string` | 搜索所有的字段，包括描述 |
| FreeBSD Packages | `pkg search search_string` | 通过名字进行搜索 |
|  | `pkg search -f search_string` | 通过名字进行搜索并返回完整的描述 |
|  | `pkg search -D search_string` | 搜索描述 |
| FreeBSD Ports | `cd /usr/ports && make search name=package` | 通过名字进行搜索 |
|  | `cd /usr/ports && make search key=search_string` | 搜索评论、描述和依赖 |

### 查看某个软件包的信息

在安装软件包之前，我们可以通过仔细阅读包的描述来获得很多有用的信息。除了人类可读的文本之外，这些内容通常包括像版本号这样的元数据和包的依赖项列表。

| 系统 | 命令 | 说明 |
| --- | --- | --- |
| Debian / Ubuntu | `apt-cache show package` | 显示有关包的本地缓存信息 |
|  | `apt show package` |  |
|  | `dpkg -s package` | 显示包的当前安装状态 |
| CentOS | `yum info package` |  |
|  | `yum deplist package` | 列出包的依赖 |
| Fedora | `dnf info package` |  |
|  | `dnf repoquery --requires package` | 列出包的依赖 |
| FreeBSD Packages | `pkg info package` | 显示已安装的包的信息 |
| FreeBSD Ports | `cd /usr/ports/category/port && cat pkg-descr` |  |

### 从存储库安装包

知道包名后，通常可以用一个命令来安装它及其依赖。你也可以一次性安装多个包，只需将它们全部列出来即可。

| 系统 | 命令 | 说明 |
| --- | --- | --- |
| Debian / Ubuntu | `sudo apt-get install package` |  |
|  | `sudo apt-get install package1 package2 ...` | 安装所有列出来的包 |
|  | `sudo apt-get install -y package` | 在 `apt` 提示是否继续的地方直接默认 `yes` |
|  | `sudo apt install package` | 显示一个彩色的进度条 |
| CentOS | `sudo yum install package` |  |
|  | `sudo yum install package1 package2 ...` | 安装所有列出来的包 |
|  | `sudo yum install -y package` | 在 `yum` 提示是否继续的地方直接默认 `yes` |
| Fedora | `sudo dnf install package` |  |
|  | `sudo dnf install package1 package2 ...` | 安装所有列出来的包 |
|  | `sudo dnf install -y package` | 在 `dnf` 提示是否继续的地方直接默认 `yes` |
| FreeBSD Packages | `sudo pkg install package` |  |
|  | `sudo pkg install package1 package2 ...` | 安装所有列出来的包 |
| FreeBSD Ports | `cd /usr/ports/category/port && sudo make install` | 从源码构建安装一个 port |

### 从本地文件系统安装一个包

对于一个给定的操作系统，有时有些软件官方并没有提供相应的包，那么开发人员或供应商将需要提供包文件的下载。你通常可以通过 web 浏览器检索这些包，或者通过命令行 `curl` 来检索这些信息。将包下载到目标系统后，我们通常可以通过单个命令来安装它。

在 Debian 派生的系统上，`dpkg` 用来处理单个的包文件。如果一个包有未满足的依赖项，那么我们可以使用 `gdebi` 从官方存储库中检索它们。

在 CentOS 和 Fedora 系统上，`yum` 和 `dnf` 用于安装单个的文件，并且会处理需要的依赖。

| 系统 | 命令 | 说明 |
| --- | --- | --- |
| Debian / Ubuntu | `sudo dpkg -i package.deb` |  |
|  | `sudo apt-get install -y gdebi && sudo gdebi package.deb` | 安装 `gdebi`，然后使用 `gdebi` 安装 `package.deb` 并处理缺失的依赖 |
| CentOS | `sudo yum install package.rpm` |  |
| Fedora | `sudo dnf install package.rpm` |  |
| FreeBSD Packages | `sudo pkg add package.txz` |  |
|  | `sudo pkg add -f package.txz` | 即使已经安装的包也会重新安装 |

### 删除一个或多个已安装的包

由于包管理器知道给定的软件包提供了哪些文件，因此如果某个软件不再需要了，它通常可以干净利落地从系统中清除这些文件。

| 系统 | 命令 | 说明 |
| --- | --- | --- |
| Debian / Ubuntu | `sudo apt-get remove package` |  |
|  | `sudo apt remove package` |  |
|  | `sudo apt-get autoremove` | 删除不需要的包 |
| CentOS | `sudo yum remove package` |  |
| Fedora | `sudo dnf erase package` |  |
| FreeBSD Packages | `sudo pkg delete package` |  |
|  | `sudo pkg autoremove` | 删除不需要的包 |
| FreeBSD Ports | `sudo pkg delete package` |  |
|  | `cd /usr/ports/path_to_port && make deinstall` | 卸载 port |

### `apt` 命令

Debian 家族发行版的管理员通常熟悉 `apt-get` 和 `apt-cache`。较少为人所知的是简化的 `apt` 接口，它是专为交互式使用而设计的。

| 传统命令 | 等价的 `apt` 命令 |
| --- | --- |
| `apt-get update` | `apt update` |
| `apt-get dist-upgrade` | `apt full-upgrade` |
| `apt-cache search string` | `apt search string` |
| `apt-get install package` | `apt install package` |
| `apt-get remove package` | `apt remove package` |
| `apt-get purge package` | `apt purge package` |

虽然 `apt` 通常是一个特定操作的快捷方式，但它并不能完全替代传统的工具，它的接口可能会随着版本的不同而发生变化，以提高可用性。如果你在脚本或 shell 管道中使用包管理命令，那么最好还是坚持使用 `apt-get` 和 `apt-cache`。

### 获取帮助

除了基于 web 的文档，请记住我们可以通过 shell 从 Unix 手册页（通常称为 man 页面）中获得大多数的命令。比如要阅读某页，可以使用 `man`：

```
man page

```

在 `man` 中，你可以用箭头键导航。按 `/` 搜索页面内的文本，使用 `q` 退出。

| 系统 | 命令 | 说明 |
| --- | --- | --- |
| Debian / Ubuntu | `man apt-get` | 更新本地包数据库以及与包一起工作 |
|  | `man apt-cache` | 在本地的包数据库中搜索 |
|  | `man dpkg` | 和单独的包文件一起工作以及能查询已安装的包 |
|  | `man apt` | 通过更简洁，用户友好的接口进行最基本的操作 |
| CentOS | `man yum` |  |
| Fedora | `man dnf` |  |
| FreeBSD Packages | `man pkg` | 和预先编译的二进制包一起工作 |
| FreeBSD Ports | `man ports` | 和 Ports 集合一起工作 |

### 结论和进一步的阅读

本指南通过对多个系统间进行交叉对比概述了一下包管理系统的基本操作，但只涉及了这个复杂主题的表面。对于特定系统更详细的信息，可以参考以下资源：

* [这份指南](https://www.digitalocean.com/community/tutorials/ubuntu-and-debian-package-management-essentials) 详细介绍了 Ubuntu 和 Debian 的软件包管理。
* 这里有一份 CentOS 官方的指南 [使用 yum 管理软件](https://www.centos.org/docs/5/html/yum/)
* 这里有一个有关 Fedora 的 `dnf` 的 [wiki 页面](https://fedoraproject.org/wiki/Dnf) 以及一份有关 `dnf` [官方的手册](https://dnf.readthedocs.org/en/latest/index.html)
* [这份指南](https://www.digitalocean.com/community/tutorials/how-to-manage-packages-on-freebsd-10-1-with-pkg) 讲述了如何使用 `pkg` 在 FreeBSD 上进行包管理
* 这本 [FreeBSD Handbook](https://www.freebsd.org/doc/handbook/) 有一节讲述了[如何使用 Ports 集合](https://www.freebsd.org/doc/handbook/ports-using.html)

---

via: <https://www.digitalocean.com/community/tutorials/package-management-basics-apt-yum-dnf-pkg>

译者后记：

从经典的 `configure` && `make` && `make install` 三部曲到 `dpkg`，从需要手处理依赖关系的 `dpkg` 到全自动化的 `apt-get`，恩~，你有没有想过接下来会是什么？译者只能说可能会是 `Snaps`，如果你还没有听过这个东东，你也许需要关注下这个公众号了：**Snapcraft**

作者：[Brennen Bearnes](https://www.digitalocean.com/community/users/bpb)  译者：[Snapcrafter](https://github.com/Snapcrafter) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何建模可以帮助你避免在 OpenStack 中遇到问题

Summary: OpenStack 部署完就是一个 “僵栈（StuckStack）”，一般出于技术原因，但有时是商业上的原因，它是无法在没有明显中断，也不花费时间和成本的情况下升级的。

![](/data/attachment/album/201708/16/141938pc5fz0eckpwpczp0.jpg)

OpenStack 部署完就是一个 “<ruby> 僵栈 <rt>  StuckStack </rt></ruby>”，一般出于技术原因，但有时是商业上的原因，它是无法在没有明显中断，也不花费时间和成本的情况下升级的。在关于这个话题的最后一篇文章中，我们讨论了这些云中有多少陷入僵局，以及当时是怎么决定的与如今的大部分常识相符。现在 OpenStack 已经有 7 年了，最近随着容器编排系统的增长以及更多企业开始利用公共和私有的云平台，OpenStack 正面临着压力。

### 没有魔法解决方案

如果你仍在寻找一个可以没有任何问题地升级你现有的 <ruby> 僵栈 <rt>  StuckStack </rt></ruby> 的解决方案，那么我有坏消息给你：没有魔法解决方案，你最好集中精力建立一个标准化的平台，它可以有效地运营和轻松地升级。

廉价航空业已经表明，虽然乘客可能渴望最好的体验，可以坐在头等舱或者商务舱喝香槟，有足够的空间放松，但是大多数人会选择乘坐最便宜的，最终价值等式不要让他们付出更多的代价。工作负载是相同的。长期而言，工作负载将运行在最经济的平台上，因为在高价硬件或软件上运行的业务实际上并没有受益。

Amazon、Microsoft、Google 等大型公共云企业都知道，这就是为什么他们建立了高效的数据中心，并使用模型来构建、操作和扩展基础设施。长期以来，企业一直奉行以设计、制造、市场、定价、销售、实施为一体的最优秀的硬件和软件基础设施。现实可能并不总是符合承诺，但它现在还不重要，因为<ruby> 成本模式 <rt>  cost model </rt></ruby>在当今世界无法生存。一些组织试图通过改用免费软件替代，而不改变自己的行为来解决这一问题。因此，他们发现，他们只是将成本从获取软件变到运营软件上。好消息是，那些高效运营的大型运营商使用的技术，现在可用于所有类型的组织。

### 什么是软件模型？

虽然许多年来，软件程序由许多对象、进程和服务而组成，但近年来，程序是普遍由许多单独的服务组成，它们高度分布在数据中心的不同服务器以及跨越数据中心的服务器上。

![](/data/attachment/album/201708/16/141940wy1gc2zcpcypsfyq.png)

*OpenStack 服务的简单演示*

许多服务意味着许多软件需要配置、管理并跟踪许多物理机器。以成本效益的方式规模化地进行这一工作需要一个模型，即所有组件如何连接以及它们如何映射到物理资源。为了构建模型，我们需要有一个软件组件库，这是一种定义它们如何彼此连接以及将其部署到平台上的方法，无论是物理的还是虚拟的。在 Canonical 公司，我们几年前就认识到这一点，并建立了一个通用的软件建模工具 [Juju](https://www.ubuntu.com/cloud/juju)，使得运营商能够从 100 个通用软件服务目录中组合灵活的拓扑结构、架构和部署目标。

![](/data/attachment/album/201708/16/141950k2xss61p1mvppd0s.png)

*Juju 建模 OpenStack 服务*

在 Juju 中，软件服务被定义为一种叫做 Charm 的东西。 Charms 是代码片段，它通常用 python 或 bash 编写，其中提供有关服务的信息 - 声明的接口、服务的安装方式、可连接的其他服务等。

Charms 可以简单或者复杂，具体取决于你想要赋予的功能。对于 OpenStack，Canonical 在上游 OpenStack 社区的帮助下，为主要 OpenStack 服务开发了一套完整的 Charms。Charms 代表了模型的说明，使其可以轻松地部署、操作扩展和复制。Charms 还定义了如何升级自身，包括在需要时执行升级的顺序以及如何在需要时优雅地暂停和恢复服务。通过将 Juju 连接到诸如 [裸机即服务（MAAS）](https://www.ubuntu.com/server/maas) 这样的裸机配置系统，其中 OpenStack 的逻辑模型可以部署到物理硬件上。默认情况下，Charms 将在 LXC 容器中部署服务，从而根据云行为的需要，提供更大的灵活性来重新定位服务。配置在 Charms 中定义，或者在部署时由第三方工具（如 Puppet 或 Chef）注入。

这种方法有两个不同的好处：1 - 通过创建一个模型，我们从底层硬件抽象出每个云服务。2 - 使用已知来源的标准化组件，通过迭代组合新的架构。这种一致性使我们能够使用相同的工具部署非常不同的云架构，运行和升级这些工具是安全的。

通过全面自动化的配置工具和软件程序来管理硬件库存，运营商可以比使用传统企业技术或构建偏离核心的定制系统更有效地扩展基础架构。有价值的开发资源可以集中在创新应用领域，使新的软件服务更快上线，而不是改变标准的商品基础设施，这将会导致进一步的兼容性问题。

在下一篇文章中，我将介绍部署完全建模的 OpenStack 的一些最佳实践，以及如何快速地进行操作。如果你有一个现有的 <ruby> 僵栈 <rt>  StuckStack </rt></ruby>，那么虽然我们不能很容易地拯救它，但是与公有云相比，我们将能够让你走上一条完全支持的、高效的基础架构以及运营成本的道路。

### 即将举行的网络研讨会

如果你在旧版本的 OpenStack 中遇到问题，并且想要轻松升级 OpenStack 云并且无需停机，请观看我们的[在线点播研讨会](http://ubunt.eu/Bwe7kQ)，从 Newton 升级到 Ocata 的现场演示。

### 联系我们

如果你想了解有关迁移到 Canonical OpenStack 云的更多信息，请[联系这里](http://ubunt.eu/3OYs5s)。

（题图：乐高的空客 A380-800模型。空客运行 OpenStack）

---

作者简介：

专注于 Ubuntu OpenStack 的云产品经理。以前在 MySQL 和 Red Hat 工作。喜欢摩托车，遇见使用 Ubuntu 和 Openstack 做有趣事的人。

---

via: <https://insights.ubuntu.com/2017/07/18/stuckstack-how-modelling-helps-you-avoid-getting-a-stuck-openstack/>

作者：[Mark Baker](https://insights.ubuntu.com/author/markbaker/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


踢掉 FB+PL：Apache 的开源激进宣言？

这都讲了些什么

虽然不是很明白，不过，只基于BSD的许可协议不就好了

>
> 本文撰写参考了以下文章，并引用了该文章部分内容：[专利告诉你，为何 Apache 禁用 FB + PL 代码](/article-8764-1.html "专利告诉你，为何 Apache 禁用 FB + PL 代码")，作者：付钦伟。
>
>
>

![](/data/attachment/album/201708/16/175128su68huz76c7o1uu9.jpg)

### 哪里有压迫，哪里就有反抗

身为知识产权圈里的专利人，笔者钦佩开源情怀，并曾写道：即使专利人也有专利情怀，现实世界中开源与专利的碰撞依然难免丑陋。现在看来，这话有点轻描淡写了。

笔者未能认真发掘开源运动史，只好拍拍脑袋认定：**开源软件运动是针对知识产权制度，尤其是专利制度，对软件产业之压迫的暴动。**

“哪里有压迫，哪里就有反抗。”

这场轰轰烈烈的暴动在发展过程中，于 2017 年 7 月，“Apache Software Foundation 主管兼法律事务副主席 Chris Mattmann [正式发表声明称](https://issues.apache.org/jira/browse/LEGAL-303)：Facebook BSD+Patents license（以下简称 FB+PL）已经正式被列入 “[CategoryX](https://www.apache.org/legal/resolved.html#category-x)” 列表，因此 Apache 项目中将不能够包含或依赖于 Facebook Patents license 的代码；而已经发布的代码，涉及 FB+PL 许可证的，需要在 8 月 31 号前完成替换。”

简而言之，Apache 一脚将 FB+PL 踢出了。这是不是 Apache 在开源暴动中的激进声明？为什么这么说？

### 专利情怀

故事要从头讲起：

专利制度产生了，那时候大家并不认为这是一个万恶的吃人的制度。专利制度的根本目的还是促进技术进步，从而推动产业和经济发展。为了达成此目的，则需要合理保护发明人的积极性，具体而言，就是给予他们一定时期的专有保护为回报，在这种利益驱动下，他们会积极的做出发明，并通过申请专利，在向社会公布技术促进技术进步的同时，兑现专有保护。

>
> "Before then [the adoption of the United States Constitution], any man might instantly use what another had invented; so that the inventor had no special advantage from his own invention. The patent system changed this; secured to the inventor, for a limited time, the exclusive use of his invention; and thereby added the fuel of interest to the fire of genius, in the discovery and production of new and useful things. "
>
>
> -- Abraham Lincoln, Second lecture on discoveries and inventions, February 11, 1859
>
>
>

以上这段诠释了专利情怀的话出自美国总统林肯的演讲。只需要读懂这个短句就好了**：专利制度为天才之火添上利益之油。**

### 开源与专利的碰撞

到上世纪 90 年代，专利海盗开始大行其道，软件产业受害最深。在软件行业里，程序员和开发者需要开放、自由地交流和利用彼此的成果才利于行业发展。这一特性先天与专利制度八字不合。这个死结是一百多年的林肯总统绝对意料不到的。

从根本上，开源情怀在于：**对于自己的智力劳动成果，放弃可取得收益的专有权利，给软件松绑，从而利于成果的流通、利用，以及行业发展。**

绑在软件身上的主要知识产权绳索有两条：版权，专利。商标不起核心作用。解开版权这条绳索的方式比较成熟：版权开源许可证。而专利很微妙，最主要的原因是它的无形，主动权常常不在开源作者自己手里。**版权是属于作者的，所以作者有主动权；而专利属于申请人，申请人有主动权，申请人可以是任何第三方。**这是开源与专利之矛盾的根源。

对开源情怀的最大伤害在于：不知道是谁用专利这根无形绳索悄悄捆绑了自己的作品。这是开源人对专利的敏感和敌视的由来。开源人常常感到愤怒和难以理解的是：**为什么自己的智力成果，别人可以用专利来捆上？**

对不起，这一个很让人遗憾的回答：任何人都可以对包括已公开的开源技术在内的任何现有技术做出改进，并就改进获得专利权。而当有别人在某项开源技术比较可行的主要改进方向上都申请了专利，就相当于把主要出路都卡上了，那么这项开源技术也就被别人的专利绑上了。这种专利申请技术，在圈内有一个好听的名字：专利布局。防御性的专利布局可以用来对自己的技术成果形成严密保护。进攻性的专利布局可以用来摘别人的桃子的，包括摘开源的桃子。专利海盗就属于充分、高超地利用专利手段和法律程序，激进地玩进攻性专利布局来摘别人桃子的。有时，手法可以高超到骗过专利审查员的法眼，将与现有技术很接近的内容纳入自己的保护范围。软件行业是重灾区。

应当说，**在专利方面，对开源最大的威胁来自第三方，而不是开源的作者**、后续开发者、用户。在社区内，大家尝试在版权开源许可之外附加专利开源许可，但是因为这种附加许可的效力仅能延伸到后续开发者、用户，不能规制第三方或专利海盗，实质能达到的效果较为有限。

### Facebook 被踢的委屈

现在，我们重新梳理一下 Apache 踢 FB+PL 这件事。Apache 主要是对 Facebook Patents license，即对专利许可的条件不满意才开踢的。

Apache 的表态很干脆地捍卫了开源情怀，但是不是有些偏强硬激进了呢？

对于发展开源事业，首要的问题是什么呢？当然应当是分清谁是朋友，谁是敌人。然后，团结一切可以团结的进步力量，形成对敌统一战线。

笔者猜想，开源的敌人是第三方专利海盗，以及供专利海盗滋生的土壤。Facebook 看起来更像可以团结的朋友：Facebook 对开源有很积极的贡献和推动，其在专利许可方面的动作应当也没有越线。Facebook 如果真想以专利捆绑开源，另安排一个白手套作为第三方来布局专利，岂不干脆彻底？哪里还需要如此费事的搞 Facebook Patents license？**至少应当说，Facebook 还是出于基本善意的立场提出的专利许可。**

### 扒扒 Facebook 专利许可

再深入剖析这个问题，就要梳理 Facebook Patents license 的主要条款对开源的影响了。

[Facebook Patents license 的主要条款](https://github.com/facebook/react/blob/master/PATENTS)：

>
> Additional Grant of Patent Rights Version 2
>
>
> "Software" means the React software distributed by Facebook, Inc.
>
>
> Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
> ("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
> (subject to the termination provision below) license under any Necessary
> Claims, to make, have made, use, sell, offer to sell, import, and otherwise
> transfer the Software. For avoidance of doubt, no license is granted under
> Facebook's rights in any patent claims that are infringed by (i) modifications
> to the Software made by you or any third party or (ii) the Software in
> combination with any software or other technology.
>
>
> The license granted hereunder will terminate, automatically and without notice,
> if you (or any of your subsidiaries, corporate affiliates or agents) initiate
> directly or indirectly, or take a direct financial interest in, any Patent
> Assertion: (i) against Facebook or any of its subsidiaries or corporate
> affiliates, (ii) against any party if such Patent Assertion arises in whole or
> in part from any software, technology, product or service of Facebook or any of
> its subsidiaries or corporate affiliates, or (iii) against any party relating
> to the Software. Notwithstanding the foregoing, if Facebook or any of its
> subsidiaries or corporate affiliates files a lawsuit alleging patent
> infringement against you in the first instance, and you respond by filing a
> patent infringement counterclaim in that lawsuit against that party that is
> unrelated to the Software, the license granted hereunder will not terminate
> under section (i) of this paragraph due to such counterclaim.
>
>
> A "Necessary Claim" is a claim of a patent owned by Facebook that is
> necessarily infringed by the Software standing alone.
>
>
> A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
> or contributory infringement or inducement to infringe any patent, including a
> cross-claim or counterclaim.
>
>
>

简要而言，关键点有两个：

* Facebook 对免费专利许可设了限制条件：你不可以诉我知识产权侵权；
* 专利许可所涉及的专利，仅限于所涉及的开源软件本身，对于软件修改后或与其他技术共同使用而可能侵犯的专利，不在许可之列。

### 法律背景扑朔迷离

即使分析以上两个要点，也要仔细衡量，须考虑现实背景中的重要因素：

* 如果无专利许可，会如何？
* 许可不涉及实质性的对价。
* 许可涉及复杂的国际司法环境。

笔者认为，许可条款之外的上述背景中的三条因素才真正使许可的效力变得扑朔迷离。

就背景因素 1 而言，现实情况中，普遍存在开源许可证仅涉及版权而回避了专利的情况。这是社区当中大家普遍可以接受的条件。未提及专利，并不等于没有给予专利许可，尤其在许可证中没有明示“专利要另收钱”的情况下。有一个奇妙的东西，可以叫作基于诚实信用或善意公平原则的“默认许可”。

何为“默认许可”？简单讲，当你给人家什么东西去用，没有明示这个东西要收钱，人家用了之后，你向人家去收钱，这么做不太厚道吧？基于诚实信用或善意公平原则，通常法院不会支持这种像是给人下了套，然后去收钱的行为的，而会认为当你给人家东西去用，没有明示这个东西要收钱时，已经“默认许可”人家免费用了。

开源软件的作者或提供者，同时又作为相关专利的专利权人时，在提供了明确免除版权费用的许可证的情况下，如果在向用户交付产品的同时，没有明示要收取专利费，“默认许可”应当成立。从学术讨论的角度，也有将之称为“专利权权利用尽”的。但是由于未收钱，“专利权权利用尽”的成立更有困难些。笔者还是坚持“默认许可”路线。

但还是很遗憾，法律世界不同于软件世界。在软件世界里，每一段算法程序，在给定条件后，都会给你执行出一个清楚的结果。法律世界里很难如此。“默认许可”是否会得到司法完全支持？真的很难讲，各个国家，甚至一个国家在不同时期，都可能对相似的情况采取不同的思路并给出不同的分寸和方向的判决。在美国、英国、澳大利亚等海洋法系的国家，前后判例的一致性会比较高。而中国、德国等大陆法系国家，变化可能较大。以下将要讨论的诸多问题均受各国司法差异因素影响，以下不再赘述。

总之，不确定性较大。**尽管笔者对各国实际判例缺少一手研究，但从法理和情理上倾向于在专利“默认许可”成立，即利于开源免费。**

就背景因素 2 而言，许可是否涉及实质性的对价是很重要的因素。实际上，我们现在讨论的是许可证，性质又不同于协议，但一些相关因素可以类比来考虑。没有实质性对价，指没有因交易性的收获进行实质支付，比如，支付价款。在这种情形下，许可证或协议在性质上更类似于赠与，对有关方的权利义务要求未必牢固。比如，Facebook 将自己开发的软件拿出来开源，自己付出了开发成本，却没有向使用者收取费用；使用者可以较随意地拿 Facebook 的开源软件免费使用。如果由于这种免费的行为中暗藏玄机，而导致 Facebook 或使用者要承受重大的义务、付出重大代价，则是有失基本公平的，除非有特别原因。所以，各国从司法的角度，会考虑“是否涉及实质性的对价”这一因素，但仍然是会采取不同的思路并给出不同的分寸和方向的判决。简而言之，**Facebook Patents license 并不涉及实质性的对价，所以司法层面不会随便基于这种许可而使有关方承担与对价不相匹配的重大义务。**

总之，还是不确定性较大，尽管笔者还是对各国实际判例缺少一手研究，但从法理和情理上仍倾向于 Facebook Patents license 因不存在实质性对价，相关方带来重大义务或损失的可能性较低，即利于开源免费。

背景因素 3 已经融合在以上讨论之中了。

综合以上背景因素的讨论，**可知 Facebook Patents license 对开源还是比较友好的，至少不会造成重大损害。**

### Facebook，面子大于里子

再审视 Facebook Patents license 的两个关键点，其对“默认许可”是否仍能成立各有微妙影响。笔者的观点是，很可能使情形确实反而不如没有这个 Facebook Patents license，不过负面影响有限。

就关键点 1，Facebook 对免费专利许可设了限制条件：你不可以诉我知识产权侵权。

明示的效力当然优于默认的效力，所以笔者倾向认为默认许可的效力被破坏了。但以下三个因素将对开源有利：

* 用户对 Facebook 发起诉讼时，许可终止，但用户此前的使用仍享受免费许可。所以，主动权还是在用户手里，可以选择有利形势。当用户认为自己更多的知识产权为 Facebook 所使用，份量重于自己所使用的 Facebook 开源软件的知识产权时，才发起诉讼，并在诉讼前做好调整和准备；如果自己用的 Facebook 的知识产权比较多，而被 Facebook 使用的知识产权少，自己还是在赚便宜，何必去找 Facebook 麻烦呢？更应当指出，Facebook 所设的这个条件较容易做被规避：可以将专利转移给第三人，也就是白手套，由白手套去诉 Facebook。这样，即可以继续享受免费许可，又可以搞 Facebook。这在法理上是成立的。
* 对单一用户来讲，出现要诉 Facebook 而会破坏免费许可这一情况的现实可能性较低。
* Facebook 此条件有构成滥用知识产权的风险。

以上第 1 条实际上已经能够让 Facebook 的关键点 1 形同虚设，达不成实际意义了。以上第 3 条，不确定性很大。

就关键点 2，专利许可所涉及的专利，仅限于所涉及的软件本身，对于软件修改后或与其他技术共同使用而可能侵犯的专利，不在许可之列。

关键点 2 实际上暗藏杀机，比形同虚设的关键点 1 凶险些，但实际威力也还有限。重点在于：

* Facebook 明示不予许可的专利：软件修改后或与其他技术共同使用而可能侵犯的专利，实际上照样可能将开源软件捆死。这是其心机最凶险之处。
* 尽管 Facebook 明示排除了软件修改后或与其他技术共同使用而可能侵犯的专利，但只是泛泛而论。实际上，用户修改软件或将之与其他技术共同使用是必然普遍发生的情况，如果 Facebook 没有及时向用户提示这些具体专利的存在，并对收费有明确具体要求，笔者倾向于默认许可的效力仍应成立。当然，不确定性仍然较大。“及时向用户提示”指对于软件交付之前已经持有的专利，应在软件交付前明确提示；对于软件交付之后获得的专利，应在专利获得后马上提示。

综上，尽管复杂的不确定性仍较多，笔者倾向于认为 Facebook Patents license 总体上对开源较为友善，与不涉及专利的许可证相比较，没有带来实质性变劣。**对 Facebook 而言，可能象征意义更大于实质意义，即面子大于里子。**

### Apache 潜在风险

另外，还有一个潜在风险因素，使 Apache 踢掉 FB+PL 之后使自己处在更为不利的境地。

Apache的风险控制措施是：“Apache 项目中将不能够包含或依赖于 Facebook Patents license 的代码；而已经发布的代码，涉 及FB+PL 许可证的，需要在 8 月 31 号前完成替换。”这一措施理论上说说还好，但在可操作性上问题很多。笔者认为，剔除 FB+PL 版权许可证所涉及的内容比较好操作：只要剔除相关的代码，替之以其他来源或自编的代码就好了。因为其他来源或自编的代码，基本就能确保在表达方式上的不同，从而规避版权侵权。这是现实的操作方式。

而规避侵犯 Facebook 专利权，上述方式很可能并不奏效。简单而言，版权保护表达形式，专利保护构想。规避表达形式，也就是从表述方式上加以实质调整就可以做到了。而规避构想，确实很难。实际上，Facebook 到底有哪些专利与之相关恐怕也很不清晰，还要加以规避，就更是难上加难了。分析工作和代码的重新设计对专利的专业性要求非常高，工作很复杂，工作量也很大。

**这种情况下，Apache 可能面对的最坏情况是：放弃了 FB+PL 的开源代码，仍存在侵犯 Facebook 专利的高风险，又不会得到 Facebook 明示、默认许可。**

### Apache 的激进开源

所以，笔者认为，Apache 的表态很干脆地捍卫了开源情怀，踢掉 FB+PL 的行事方式有可能略偏强硬激进，尽管从规避不确定的风险而言，也不是完全没有道理。

（题图：HuffPost）

---

作者简介：

**李可**

集慧智佳知识产权咨询公司，李可。江湖人称“可哥”，老牌专利代理人，知识产权高级咨询师。70 后文艺理工男，属牛，性子慢但踏实稳妥。


独家专访 MIT 2017 年度 TR35 吴翰清

Summary: 上月在北京举办的网络安全生态峰会上，我与吴翰清有过一次深入的独家专访。本文特别采用问答形式，希望还原这位最新的 TR35 获奖者在技术领域的深度思考。

![](/data/attachment/album/201708/16/221057uqfdqlb886zv8dbz.jpeg)

**先分享一个好消息：今天<ruby> 《麻省理工学院科技评论》 <rp>  （ </rp> <rt>  MIT Technology Review </rt> <rp>  ） </rp></ruby>杂志揭晓 [2017 年全球青年科技创新人才榜（TR35）](https://www.technologyreview.com/lists/innovators-under-35/2017)评选结果，阿里巴巴人工智能实验室首席科学家王刚、[阿里云首席安全科学家吴翰清脱颖而出](https://www.technologyreview.com/lists/innovators-under-35/2017/pioneer/hanqing-wu/)，获此殊荣。**

![](/data/attachment/album/201708/16/220349ylk277eaiphq0272.jpeg)

*TR 35 获奖者 吴瀚清*

TR35 是一个针对 35 岁以下青年科技才俊，为找出最有可能改变世界的牛人而设立的奖项。

自 1999 年以来，该杂志每年会在全球 IT（计算机、通信、网络）和生物医药、商业等领域内，从影响力、创新力、进取力、未来潜力、沟通力五个维度进行评估，挖掘学术界和工业界的 35 位科技创新精英。

从以往的上榜者来看，说 TR 35 是预言人类进程的先知也不为过。Google 联合创始人拉里·佩奇（2002 年）和谢尔盖·布林（2002 年），Linux 之父林纳斯·托瓦兹（1999 年），Facebook创始人马克·扎克伯格（2007 年），Yahoo 创始人杨致远（1999 年），Apple 设计总监乔纳夫·伊森（1999 年）等，都曾是该奖的座上宾。如今，他们正在改变我们所处的世界，甚至影响人类进步的方向。

正因如此，TR35 的门槛极高。据统计，从 1999 年到 2016 年，共评选出 820 名 TR35，中国入选者仅 17 人。今年，阿里巴巴有两位科学家同时入选，创下中国互联网科技企业的先例。

非常荣幸，上月在北京举办的网络安全生态峰会上，我与吴翰清有过一次深入的独家专访。本文特别采用问答形式，希望还原吴翰清在技术领域的深度思考。

### **一、云计算终极目标：实现飞机那样的技术普惠**

**老王**：

网络攻击和渗透行为日益增多，给社会和企业带来巨大危害。但并不是每个企业都有足够的预算和技术能力来迎接安全风险的威胁。

安全服务也能像水、电、网这样的基础服务一样，可以随时购买、随时使用，而不用关心很多引擎盖下面的技术细节？

**吴瀚清**：

我自己觉得这个问题得分成两部分来看。

首先，今天整个云端团队，或者阿里云安全团队希望成为互联网安全的一种基础设施。既然它是基础设施，它对于很多的人来说，就应该是普惠的，如同今天的水、电、网一样。在这个层面上来讲，我们希望把安全服务做的更加的透明一些，更加的无感知一些。

从技术的角度来讲，有一些问题通过弹性安全网络就有可能解决掉。

但网络安全服务其实是一个研究对抗的问题，只要是人与人之间的对抗，只要还要有坏人存在，就一定有新的安全问题会涌现出来，只是会随着技术发展不断更新。

比如，过去从 PC 走向了互联网、移动互联网，再走向 IoT，所有的安全问题也是跟随着 PC 的发展，然后到互联网，再到移动互联网的安全问题，到未来是研究 IoT 的安全问题。

另一方面，其实我觉得云计算的安全方面，或者云计算本身，它非常像飞机。比如说你要造一架飞机，用到的技术是极其复杂的，但是今天我们每个人都能够用非常便宜的价格，去享受这个航班的服务。所以我觉得这就是里面的差别。

就是说，我们要重新去发明一项技术，把它做到足够成熟是需要非常专业的人，花非常大的代价去把它做出来的。但是，最后我们要把这个非常复杂的技术，做到每个人都能够用。每个人都能够用最低的成本、最低的门槛去使用。

我觉得这个就是云计算所要追求的目标。就是要让技术变的普惠。让每个人都能够非常简单的去用非常复杂的技术。

对于普通客户，他并不需要理解一架飞机的原理，它只要能乘坐就好。

### **二、安全边界将会越来越模糊**

**老王**：

怎么样才能让用户，在需要时能够感知到安全，没有遇到安全问题的时候实现隐形。这个安全边界是怎么确定比较好？

**吴瀚清**：

AWS 提出了责任共担模型，他们认为操作系统之下的都是他们来负责；操作系统之上的都是客户自己来负责的，比如客户自己写的应用，比如自己管理的一些系统，比如客户配置出现了问题，都是要客户自己来负责的。但是操作系统之下，进程本身的安全，包括底层基础设施的安全，这些都是由 AWS 来负责。他们把这个边界划在这里。

但是我觉得这个边界，也不是一成不变的，它会随着软件架构的演进而不断发生变化。

边界会越来越模糊，而且我们整个技术是在进步的，所以在我的理解里，云计算是不需要像 Windows 跟 Linux 这样的 PC 时代的操作系统的。

因为今天大量的云时代的应用，或者互联网时代的应用，实际上就是用代码直接操作数据，其实并不需要关心底层操作系统。从这个角度来讲，今天这些程序员写代码的方式将来都是需要变化的。当计算时代真正到来的时候，比如说现在 AWS 就在推 serverless 这样的一些东西，谷歌也有 GCE，类似这些东西，实际上它真正代表的是未来我们写代码操作数据的方式。

所以回到未来来看，今天你所关心的很多的软件问题，在那个时候已经不再是一个问题了。因为都被云计算公司封装到了它的责任范围之内，所以我觉得这条线、这个边界是在不断地演进的，而且它的封装是越来越完整的。

### **三、未来五年，安全看** **IoT** **和** **AI**

**老王**：

你们现在有没有考虑到三年、五年以后的安全势态会怎么样，会不会研发相应的产品和技术？

**吴瀚清**：

我觉得未来要抓的两件事情，还是相对比较明确。

在战略思考方面，第一个就是抓 IoT。可能在整个 IoT 这方面，最根本的一个东西就是认证体系，它应该是从一个硬件芯片开始，通过证书做硬件的加密和认证，然后通过信任链的传递，在整个 IoT 里面我们就会有一个可信的计算环境。我们今天在 IoT 的安全方面，已经有一些解决方案。

另外一件，我觉得 AI 是我们这个时代接下来需要重点去抓的事情，它带来的这个变化，可能会超过我们所有人的想象，它可能会像手机出现的时候，会对这个世界带来这么大的影响和变化。所以今天如何把 AI 应用在我们安全技术本身，这个是我们今天要去思考的。

### **四、对网络暴力斗争到底**

老王：

在安全圈子里，有没有攻击者和厂商互相勾结？

**吴瀚清**：

从这个行业乱象来讲，今天一定存在你刚才说的这种黑与白的互相勾结，或者收取保护费的事情。

特别在我所了解的高防这个产业，实际上有一些这样的乱象的，就是攻击者和收保护费的实际上是同一波人。但是今天从其他的一些我所了解的一些厂商来说，比如说像今天的阿里，或者我们的一些友商，他们是绝对不会做这种事情。

因为对于阿里自己来说，对我们来说每一次大的攻击的挑战，实际上都是一次磨炼我们技术的机会，如果我们不去正面迎接这种挑战，我们的技术就不会进步。错过了我们技术进步的这个机会，我觉得这才是对阿里来说更大的一个损失。所以面对这种网络暴力，实际上我们更加采取的是这种绝不宽容的这种态度，一定会去斗争到底的。

### **五、安全和开源、闭源没有关系**

**老王**：

你对开源与安全是怎么看的？它们之间有没有必然联系？有什么样的联系？

**吴瀚清**：

我觉得安全不安全，跟开源还是闭源没有直接的关系。但是它跟这个软件背后的这个运营方是有关系的。

比如就开源软件来讲，有很多很多的开源软件，确实对整个互联网作出了不可磨灭的贡献。但是也有很多开源软件，它的软件开发者是非常、非常缺乏安全意识的。

像 Linux 这种，它本身有一个非常好的基金会，它的开发者都是非常资深的软件工程师，本身又有非常好的安全意识和非常完善的机制。从这个角度来讲，Linux 本身的安全，我觉得是做的非常不错的，而且它也在持续的、不断推出一些新的安全功能。

回到闭源软件这一边，比如微软本身就建立了非常好的一个应急响应机制，它本身建立了非常大的安全团队来做安全这个事情。从这个角度来讲，微软的安全也做的不错。

在我看来，更重要的应该去关注应急响应，这应该是整个安全机制里面最重要的一些事情。甚至我觉得，应该占到整个安全工作的 50%。另外 50% 的工作就是检测，所以安全实际上就是做两件事情，就是检测和响应。

所以在这里面我们做的很多工作，都可以看成应急响应的一部分。比如说你发现问题之后，你去做这个漏洞的修补，以及定期检查之后做的加固。包括通知机制，实际上都是应急响应需要去做的。应急响应不仅仅是解决具体某一个漏洞的问题，它还包括一系列的问题，包括安全的分析，以及产品能力本身的提升，比如说这次响应没有做好，下一次你的产品是不是有更强的能力来提升？

同时这还涉及到一个对外舆情的问题。这种应急响应是不是会带来恐慌？比如说有一些安全问题，完全是炒作漏洞，很多客户就会引发恐慌，这时候你能不能通过技术分析出来拨乱反正？所以有很多这样的问题，综合起来就会变成一个体系。

我们觉得今天可能更多的东西，应该是从实践中来的。所以几乎阿里云每周都在进行安全响应，每周都在响应两到三次。所以就会把我们的一套非常高效的流程给逼出来。

在未来我们也希望在这一块能够帮到更多的企业，我们在应急响应这块，也希望能够推出更多的产品和服务。

### **六、坚持产品的使命是最根本的东西**

**老王**：

你是阿里云的初创成员之一，也是阿里云安全团队初创成员。是否可以分享一下如何规划团队的技术和发展？

**吴瀚清**：

阿里本身也是一家使命驱动的公司。所以这两点，造成我们的做事方式实际上还是有迹可循的。

今天在所有的战略思考和所有的坚持上面，我们的使命一直是建设互联网安全的基础设施。

从这个角度来讲，我们会做很多、很多的东西。我们现在的产品，不管这个产品的形态如何发生变化，可能会经历一些阶段性的失败，但是我们的产品，最终它要去的那个地方，是始终没有动摇过的。

像我们的高防产品，我们第一天就打出一个使命，就是我们要消灭互联网的 DDoS，这是我们和其他所有做高防产品厂商的区别。他们都是希望 DDoS 存在的，因为这个能带来业务收入。

但是我们今天不在乎靠这个反 DDoS 产品赚钱，虽然今天我们的主要收入确实来自这个产品。这是一个现状，但是未来我们要去的地方-------我们是希望消灭整个互联网的 DDoS 的。我也觉得，只有真正到了那一天，我们对这个互联网和对这个社会的贡献的价值足够大，才会有足够大的商业空间诞生出来。我觉得这是我对整个商业的一个理解。

所以我觉得，今天在整个使命愿景的坚持上面，是我们最根本的东西，今天经历的所有的波折，实际上都是可以根据时间随着来调整的。

### **七、给年轻从业者的建议**

**老王**：

现在有很多年轻人想从事安全服务行业。作为一个资深的网络安全专家，有什么建议？

**吴瀚清**：

我觉得主要是三件事情。第一件就是多看一些书；第二件是多去见一些真正优秀的人；第三件是多经历一些事情。

回到安全服务这个行业，我觉得除了多看书之外，动手能力是最重要的。我觉得这个对于所有从事计算机产业的年轻人，都是非常重要的一个建议。就是动手远比从书本上看东西要重要------当然看书也很重要。

再就是能够多接触一些行业里面真正优秀的顶尖人物，我觉得这是需要他自己不断去找机会去拓展的。

安全这个行业，我觉得跟其他产业不太一样的地方，就是在于今天我们是在里面有一个对抗存在，涉及到正义与邪恶的，我希望未来的年轻人不要走上邪路，要站在正义的这一方，真正成为光明的守护者，去保护我们人民财产的安全。

### **采访后记**

对吴瀚清的采访就到这里，**从和吴瀚清的交谈中，我能体会到真正纯粹的技术专家的赤子之心，也能感受到吴瀚清和他的团队对安全的热爱和社会责任感，其所一直践行的，或许就是他的“道”吧。**

采访者：老王，Linux 中国开源社区的创始人，曾任职亚信旗下的玛赛系统安全公司的华东区技术总监，中国电信系统集成公司网络安全事业部高级专家。


Debian 庆祝 24 岁生日

生日快乐

来自山西吕梁的 Chrome Mobile 58.0|Android 5.0 用户

Debian用戶前來報道～

我是debian系用户，也来报道一个～

Deepin 用户也来报报个到

Debian用户发来贺电

来自福建泉州的 Chrome Mobile 60.0|Android 7.1 用户

红帽用户发来贺电

发来贺电！！！恭贺自由开源演进的Debian Gnu/Linux

我也来表示一下

纪念Ian

北方光棍 发来贺电。

南方独狼，发来贺电！

恭喜! 没有你, <br />
哪会有 Ubuntu 的诞生.

我去，跟我同岁。

**![](/data/attachment/album/201708/17/100307bblrl5ty5h55r9bl.jpg)**

2017 年 8 月 16 日，Debian 操作系统度过了它的第 24 个生日，这个由 Linux 内核所驱动的操作系统，由其创始人 Ian Murdock 发布于 1993 年的同一天。

每年的 8 月 16 日这一天，被 [Debian Project](https://www.debian.org/) 确定为 Debian 日，全世界各地的 Debian 爱好者会在这一天[举办各种庆祝活动](https://wiki.debian.org/DebianDay/2017)。

“如果你附近有城市在举办 2017 Debian 日 ，非常欢迎你前往参加，”Laura Arjona Reina 在[博文](https://bits.debian.org/2017/08/debian-turns-24.html)中说到，“如果没有的话，你来组织一个也很好！”

Debian GNU/Linux 是 Linux 社区里最受欢迎的 Linux 操作系统之一，也有大量的发行版衍生自此，这包括 Ubuntu 和 Linux Mint。

Debian GNU/Linux 的最新发布版本是 9.1.0 （Stretch），你可以从 Debian 官方网站下载安装镜像或者现场版镜像。这个操作系统支持十种之多的硬件架构。

我们对 Debian 的生日送上我们的良好祝福，我们已经迫不及待地想要看到即将来到的 Debian GNU/Linux 10 "Buster" 了。

生日快乐！ Debian！


用 R 收集和映射推特数据的初学者向导

>
> 学习使用 R 的 twitteR 和 leaflet 包, 你就可以把任何话题的推文定位画在地图上。
>
>
>

![用 R 收集和映射推特数据的初学者向导](/data/attachment/album/201708/17/150211n9wjnx9pk91f4wtk.png "用 R 收集和映射推特数据的初学者向导")

当我开始学习 R ，我也需要学习如何出于研究的目的地收集推特数据并对其进行映射。尽管网上关于这个话题的信息很多，但我发觉难以理解什么与收集并映射推特数据相关。我不仅是个 R 新手，而且对各种教程中技术名词不熟悉。但尽管困难重重，我成功了！在这个教程里，我将以一种新手程序员都能看懂的方式来攻略如何收集推特数据并将至展现在地图中。

### 创建应用程序

如果你没有推特帐号，首先你需要 [注册一个](https://twitter.com/signup)。然后，到 [apps.twitter.com](https://apps.twitter.com/) 创建一个允许你收集推特数据的应用程序。别担心，创建应用程序极其简单。你创建的应用程序会与推特应用程序接口（API）相连。 想象 API 是一个多功能电子个人助手。你可以使用 API 让其它程序帮你做事。这样一来，你可以接入推特 API 令其收集数据。只需确保不要请求太多，因为推特数据请求次数是有[限制](https://dev.twitter.com/rest/public/rate-limiting) 的。

收集推文有两个可用的 API 。你若想做一次性的推文收集，那么使用 **REST API**. 若是想在特定时间内持续收集，可以用 **streaming API**。教程中我主要使用 REST API。

创建应用程序之后，前往 **Keys and Access Tokens** 标签。你需要 Consumer Key (API key)、 Consumer Secret (API secret)、 Access Token 和 Access Token Secret 才能在 R 中访问你的应用程序。

### 收集推特数据

下一步是打开 R 准备写代码。对于初学者，我推荐使用 [RStudio](https://www.rstudio.com/)，这是 R 的集成开发环境 (IDE) 。我发现 RStudio 在解决问题和测试代码时很实用。 R 有访问该 REST API 的包叫 **[twitteR](https://cran.r-project.org/web/packages/twitteR/twitteR.pdf)**。

打开 RStudio 并新建 RScript。做好这些之后，你需要安装和加载 **twitteR** 包:

```
install.packages("twitteR")
#安装 TwitteR
library (twitteR)
#载入 TwitteR

```

安装并载入 **twitteR** 包之后，你得输入上文提及的应用程序的 API 信息：

```
api_key <- ""
 #在引号内放入你的 API key
api_secret <- ""
 #在引号内放入你的 API secret token
token <- ""
 #在引号内放入你的 token
token_secret <- ""
 #在引号内放入你的 token secret

```

接下来，连接推特访问 API：

```
setup_twitter_oauth(api_key, api_secret, token, token_secret)

```

我们来试试让推特搜索有关社区花园和农夫市场：

```
tweets <- searchTwitter("community garden OR #communitygarden OR farmers market OR #farmersmarket", n = 200, lang = "en")

```

这个代码意思是搜索前 200 篇 `(n = 200)` 英文 `(lang = "en")` 的推文, 包括关键词 `community garden` 或 `farmers market` 或任何提及这些关键词的话题标签。

推特搜索完成之后，在数据框中保存你的结果：

```
tweets.df <-twListToDF(tweets)

```

为了用推文创建地图，你需要收集的导出为 **.csv** 文件:

```
write.csv(tweets.df, "C:\Users\YourName\Documents\ApptoMap\tweets.csv")
 #an example of a file extension of the folder in which you want to save the .csv file.

```

运行前确保 **R** 代码已保存然后继续进行下一步。.

### 生成地图

现在你有了可以展示在地图上的数据。在此教程中，我们将用一个 R 包 **[Leaflet](https://rstudio.github.io/leaflet)** 做一个基本的应用程序，这是一个生成交互式地图的热门 JavaScript 库。 Leaflet 使用 [magrittr](https://github.com/smbache/magrittr) 管道运算符 (`%>%`)， 因为其语法自然，易于写代码。刚接触可能有点奇怪，但它确实降低了写代码的工作量。

为了清晰起见，在 RStudio 打开一个新的 R 脚本安装这些包：

```
install.packages("leaflet")
install.packages("maps")
library(leaflet)
library(maps)

```

现在需要一个路径让 Leaflet 访问你的数据：

```
read.csv("C:\Users\YourName\Documents\ApptoMap\tweets.csv", stringsAsFactors = FALSE)

```

`stringAsFactors = FALSE` 意思是保留信息，不将它转化成 factors。 (想了解 factors，读这篇文章["stringsAsFactors: An unauthorized biography"](http://simplystatistics.org/2015/07/24/stringsasfactors-an-unauthorized-biography/)， 作者 Roger Peng）

是时候制作你的 Leaflet 地图了。我们将使用 **OpenStreetMap**基本地图来做你的地图：

```
m <- leaflet(mymap) %>% addTiles()

```

我们在基本地图上加个圈。对于 `lng` 和 `lat`，输入包含推文的经纬度的列名，并在前面加个`~`。 `~longitude` 和 `~latitude` 指向你的 **.csv** 文件中与列名：

```
m %>% addCircles(lng = ~longitude, lat = ~latitude, popup = mymap$type, weight = 8, radius = 40, color = "#fb3004", stroke = TRUE, fillOpacity = 0.8)

```

运行你的代码。会弹出网页浏览器并展示你的地图。这是我前面收集的推文的地图：

![推文定位地图](/data/attachment/album/201708/17/150211us845om3tpz3l4mz.jpg "推文定位地图")

带定位的推文地图，使用了 Leaflet 和 OpenStreetMap [CC-BY-SA](https://creativecommons.org/licenses/by-sa/2.0/)

虽然你可能会对地图上的图文数量如此之小感到惊奇，通常只有 1% 的推文记录了地理编码。我收集了总数为 366 的推文，但只有 10（大概总推文的 3%）是记录了地理编码的。如果你为得到记录了地理编码的推文而困扰，改变搜索关键词看看能不能得到更好的结果。

### 总结

对于初学者，把以上所有碎片结合起来，从推特数据生成一个 Leaflet 地图可能很艰难。 这个教程基于我完成这个任务的经验，我希望它能让你的学习过程变得更轻松。

（题图：[琼斯·贝克](https://opensource.com/users/jason-baker). [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/). 来源: [Cloud](https://pixabay.com/en/clouds-sky-cloud-dark-clouds-1473311/), [Globe](https://pixabay.com/en/globe-planet-earth-world-1015311/). Both [CC0](https://creativecommons.org/publicdomain/zero/1.0/).）

---

作者简介：

Dorris Scott - Dorris Scott 是佐治亚大学的地理学博士生。她的研究重心是地理信息系统（GIS）、 地理数据科学、可视化和公共卫生。她的论文是在一个 GIS 系统接口将退伍军人福利医院的传统和非传统数据结合起来，帮助病人为他们的健康状况作出更为明朗的决定。

---

via: <https://opensource.com/article/17/6/collecting-and-mapping-twitter-data-using-r>

作者：[Dorris Scott](https://opensource.com/users/dorrisscott) 译者：[XYenChi](https://github.com/XYenChi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


使用 Snapcraft 构建、测试并发布 Snap 软件包

这玩意本身不是个自由开源软件

![](/data/attachment/album/201708/17/222938ba28a8i27q99ifa9.jpg)

snapcraft 是一个正在为其在 Linux 中的地位而奋斗的包管理系统，它为你重新设想了分发软件的方式。这套新的跨发行版的工具可以用来帮助你构建和发布 snap 软件包。接下来我们将会讲述怎么使用 CircleCI 2.0 来加速这个过程以及一些在这个过程中的可能遇到的问题。

### snap 软件包是什么？snapcraft 又是什么？

snap 是用于 Linux 发行版的软件包，它们在设计的时候吸取了像 Android 这样的移动平台和物联网设备上分发软件的经验教训。snapcraft 这个名字涵盖了 snap 和用来构建它们的命令行工具、这个 [snapcraft.io](https://snapcraft.io/) 网站，以及在这些技术的支撑下构建的几乎整个生态系统。

snap 软件包被设计成用来隔离并封装整个应用程序。这些概念使得 snapcraft 提高软件安全性、稳定性和可移植性的目标得以实现，其中可移植性允许单个 snap 软件包不仅可以在 Ubuntu 的多个版本中安装，而且也可以在 Debian、Fedora 和 Arch 等发行版中安装。snapcraft 网站对其的描述如下：

>
> 为每个 Linux 桌面、服务器、云端或设备打包任何应用程序，并且直接交付更新。
>
>
>

### 在 CircleCI 2.0 上构建 snap 软件包

在 CircleCI 上使用 [CircleCI 2.0 语法](https://circleci.com/docs/2.0/) 来构建 snap 和在本地机器上基本相同。在本文中，我们将会讲解一个示例配置文件。如果您对 CircleCI 还不熟悉，或者想了解更多有关 2.0 的入门知识，您可以从 [这里](https://circleci.com/docs/2.0/first-steps/) 开始。

### 基础配置

```
version: 2
jobs:
  build:
    machine: true
    working_directory: ~/project
    steps:
      - checkout
      - run:
          command: |
            sudo apt update && sudo apt install -y snapd
            sudo snap install snapcraft --edge --classic
            /snap/bin/snapcraft

```

这个例子使用了 `machine` 执行器来安装用于管理运行 snap 的可执行程序 `snapd` 和制作 snap 的 `snapcraft` 工具。

由于构建过程需要使用比较新的内核，所以我们使用了 `machine` 执行器而没有用 `docker` 执行器。在这里，Linux v4.4 已经足够满足我们的需求了。

### 用户空间的依赖关系

上面的例子使用了 `machine` 执行器，它实际上是一个内核为 Linux v4.4 的 [Ubuntu 14.04 (Trusty) 虚拟机](https://circleci.com/docs/1.0/differences-between-trusty-and-precise/)。如果 Trusty 仓库可以满足你的 project/snap 构建依赖，那就没问题。如果你的构建依赖需要其他版本，比如 Ubuntu 16.04 (Xenial)，我们仍然可以在 `machine` 执行器中使用 Docker 来构建我们的 snap 软件包 。

```
version: 2
jobs:
  build:
    machine: true
    working_directory: ~/project
    steps:
      - checkout
      - run:
          command: |
            sudo apt update && sudo apt install -y snapd
            docker run -v $(pwd):$(pwd) -t ubuntu:xenial sh -c "apt update -qq && apt install snapcraft -y && cd $(pwd) && snapcraft"

```

这个例子中，我们再次在 `machine` 执行器的虚拟机中安装了 `snapd`，但是我们决定将 snapcraft 安装在 Ubuntu Xenial 镜像构建的 Docker 容器中，并使用它来构建我们的 snap。这样，在 `snapcraft` 运行的过程中就可以使用在 Ubuntu 16.04 中可用的所有 `apt` 包。

### 测试

在我们的[博客](https://circleci.com/blog/)、[文档](https://circleci.com/docs/)以及互联网上已经有很多讲述如何对软件代码进行单元测试的内容。搜索你的语言或者框架和单元测试或者 CI 可以找到大量相关的信息。在 CircleCI 上构建 snap 软件包，我们最终会得到一个 `.snap` 的文件，这意味着除了创造它的代码外我们还可以对它进行测试。

### 工作流

假设我们构建的 snap 软件包是一个 webapp，我们可以通过测试套件来确保构建的 snap 可以正确的安装和运行，我们也可以试着安装它或者使用 [Selenium](http://www.seleniumhq.org/) 来测试页面加载、登录等功能正常工作。但是这里有一个问题，由于 snap 是被设计成可以在多个 Linux 发行版上运行，这就需要我们的测试套件可以在 Ubuntu 16.04、Fedora 25 和 Debian 9 等发行版中可以正常运行。这个问题我们可以通过 CircleCI 2.0 的工作流来有效地解决。

工作流是在最近的 CircleCI 2.0 测试版中加入的，它允许我们通过特定的逻辑流程来运行离散的任务。这样，使用单个任务构建完 snap 后，我们就可以开始并行的运行 snap 的发行版测试任务，每个任务对应一个不同的发行版的 [Docker 镜像](https://circleci.com/docs/2.0/building-docker-images/) (或者在将来，还会有其他可用的执行器)。

这里有一个简单的例子：

```
workflows:
  version: 2
  build-test-and-deploy:
    jobs:
      - build
      - acceptance_test_xenial:
          requires:
            - build
      - acceptance_test_fedora_25:
          requires:
            - build
      - acceptance_test_arch:
          requires:
            - build
      - publish:
          requires:
            - acceptance_test_xenial
            - acceptance_test_fedora_25
            - acceptance_test_arch

```

在这个例子中首先构建了 snap，然后在四个不同的发行版上运行验收测试。如果所有的发行版都通过测试了，那么我们就可以运行发布 `job`，以便在将其推送到 snap 商店之前完成剩余的 snap 任务。

### 留着 .snap 包

为了测试我们在工作流示例中使用的 .snap 软件包，我们需要一种在构建的时候持久保存 snap 的方法。在这里我将提供两种方法：

1. **artifact** —— 在运行 `build` 任务的时候我们可以将 snaps 保存为一个 CircleCI 的 artifact（LCTT 译注：artifact 是 `snapcraft.yaml` 中的一个 `Plugin-specific` 关键字），然后在接下来的任务中检索它。CircleCI 工作流有自己处理共享 artifact 的方式，相关信息可以在 [这里](https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-artifacts-among-jobs) 找到。
2. **snap 商店通道** —— 当发布 snap 软件包到 snap 商店时，有多种通道可供我们选择。将 snap 的主分支发布到 edge 通道以供内部或者用户测试已经成为一种常见做法。我们可以在 `build` 任务中完成这些工作，然后接下来的的任务就可以从 edge 通道来安装构建好的 snap 软件包。

第一种方法速度更快，并且它还可以在 snap 软包上传到 snap 商店供用户甚至是测试用户使用之前对 snap 进行验收测试。第二种方法的好处是我们可以从 snap 商店安装 snap，这也是 CI 运行期间的测试项之一。

### snap 商店的身份验证

[snapcraft-config-generator.py](https://gist.github.com/3v1n0/479ad142eccdd17ad7d0445762dea755) 脚本可以生成商店证书并将其保存到 `.snapcraft/snapcraft.cfg` 中（注意：在运行公共脚本之前一定要对其进行检查）。如果觉得在你仓库中使用明文来保存这个文件不安全，你可以用 `base64` 编码该文件，并将其存储为一个[私有环境变量](https://circleci.com/docs/1.0/environment-variables/#setting-environment-variables-for-all-commands-without-adding-them-to-git)，或者你也可以对文件 [进行加密](https://github.com/circleci/encrypted-files)，并将密钥存储在一个私有环境变量中。

下面是一个示例，将商店证书放在一个加密的文件中，并在 `deploy` 环节中使用它将 snap 发布到 snap 商店中。

```
- deploy:
    name: Push to Snap Store
    command: |
      openssl aes-256-cbc -d -in .snapcraft/snapcraft.encrypted -out .snapcraft/snapcraft.cfg -k $KEY
      /snap/bin/snapcraft push *.snap

```

除了 `deploy` 任务之外，工作流示例同之前的一样， `deploy` 任务只有当验收测试任务通过时才会运行。

### 更多的信息

* Alan Pope 在 [论坛中发的帖子](https://forum.snapcraft.io/t/building-and-pushing-snaps-using-circleci/789)：“popey” 是 Canonical 的员工，他在 snapcraft 的论坛上写了这篇文章，并启发作者写了这篇博文。
* [snapcraft 网站](https://snapcraft.io/)： snapcraft 官方网站。
* [snapcraft 的 CircleCI Bug 报告](https://bugs.launchpad.net/snapcraft/+bug/1693451)：在 Launchpad 上有一个开放的 bug 报告页面，用来改善 CircleCI 对 snapcraft 的支持。同时这将使这个过程变得更简单并且更“正式”。期待您的支持。
* 怎么使用 CircleCI 构建 [Nextcloud](https://nextcloud.com/) 的 snap：这里有一篇题为 [“复杂应用的持续验收测试”](https://kyrofa.com/posts/continuous-acceptance-tests-for-complex-applications) 的博文，它同时也影响了这篇博文。

这篇客座文章的作者是 Ricardo Feliciano —— CircleCi 的开发者传道士。如果您也有兴趣投稿，请联系 [ubuntu-iot@canonical.com](mailto:ubuntu-iot@canonical.com)。原始文章可以从 [这里](https://circleci.com/blog/build-test-publish-snap-packages?utm_source=insightsubuntu&utm_medium=syndicatedblogpost) 找到。

---

via: <https://insights.ubuntu.com/2017/06/28/build-test-and-publish-snap-packages-using-snapcraft/>

译者简介：

>
> 常年混迹于 snapcraft.io，对 Ubuntu Core、snaps 和 snapcraft 有浓厚的兴趣，并致力于将这些还在快速发展的新技术通过翻译或原创的方式介绍到中文世界。有兴趣的小伙伴也可以关注译者个人的公众号： `Snapcraft`
>
>
>

作者：Ricardo Feliciano 译者：[Snapcrafter](https://github.com/Snapcrafter) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Fedora 26 助力云、服务器、工作站系统

全组件镜像才是真正的方便用户，版本应该只要一个，在单一版本中保持软件的多样性，这点应该向Debian Gnu/Linux学习

来自陕西西安的 Chrome Mobile 59.0|Android 7.0 用户

已经用上了，还不错。

![](/data/attachment/album/201708/18/152112rz5lszn4l3ll73ms.png)

[Fedora 项目](https://getfedora.org/) 7 月份宣布推出 Fedora 26, 它是全面开放源代码的 Fedora 操作系统的最新版本。

Fedora Linux 是 Red Hat Enterprise Linux（RHEL）的社区版本。Fedora 26 包含一组基础包，形成针对不同用户的三个不同版本的基础。

Fedora <ruby> 原子主机版 <rt>  Atomic Host Edition </rt></ruby> 是用于运行基于容器的工作的操作系统。Fedora <ruby> 服务器版 <rt>  Server </rt></ruby>将 Fedora Server OS 安装在硬盘驱动器上。Fedora <ruby> 工作站版 <rt>  Workstation </rt></ruby>是一款用于笔记本电脑和台式机的用户友好操作系统，它适用于广泛的用户 - 从业余爱好者和学生到企业环境中的专业人士。

所有这三个版本都有共同的基础和一些共同的优点。所有 Fedora 版本每年发行两次。

Fedora 项目是创新和新功能的测试基地。Fedora 项目负责人 Matthew Miller 说，有些特性将在即将发布的 RHEL 版本中实现。

他告诉 LinuxInsider：“Fedora 并没有直接参与这些产品化决策。Fedora 提供了许多想法和技术，它是 Red Hat Enterprise Linux 客户参与并提供反馈的好地方。”

### 强力的软件包

Fedora 开发人员更新和改进了所有三个版本的软件包。他们在 Fedora 26 中进行了许多错误修复和性能调整，以便在 Fedora 的用例中提供更好的用户体验。

这些安装包包括以下改进：

* 更新的编译器和语言，包括 GCC 7、Go 1.8、Python 3.6 和 Ruby 2.4；
* DNF 2.0 是 Fedora 下一代包管理系统的最新版本，它与 Yum 的向后兼容性得到改善；
* Anaconda 安装程序新的存储配置界面，可从设备和分区进行自下而上的配置；
* Fedora Media Writer 更新，使用户可以为基于 ARM 的设备（如 Raspberry Pi）创建可启动 SD 卡。

[Endpoint Technologies Associates](http://www.ndpta.com/) 的总裁 Roger L. Kay 指出，云工具对于使用云的用户必不可少，尤其是程序员。

他对 LinuxInsider 表示：“Kubernetes 对于在混合云中编程感兴趣的程序员来说是至关重要的，这可能是目前业界更重要的发展之一。云，无论是公有云、私有云还是混合云 - 都是企业计算未来的关键。”

### Fedora 26 原子主机亮相

Linux 容器和容器编排引擎一直在普及。Fedora 26 原子主机提供了一个最小占用的操作系统，专门用于在裸机到云端的环境中运行基于容器的工作任务。

Fedora 26 原子主机更新大概每两周发布一次，这个时间表可以让用户及时跟上游创新。

Fedora 26 原子主机可用于 Amazon EC2 。OpenStack、Vagrant 镜像和标准安装程序 ISO 镜像可在 [Fedora 项目](https://getfedora.org/)网站上找到。

最小化的 Fedora 原子的容器镜像也在 Fedora 26 上首次亮相。

### 云托管

最新版本为 Fedora 26 原子主机提供了新功能和特性：

* 容器化的 Kubernetes 作为内置的 Kubernetes 二进制文件的替代品，使用户更容易地运行不同版本的容器编排引擎；
* 最新版本的 rpm-ostree，其中包括支持直接 RPM 安装，重新加载命令和清理命令;
* 系统容器，它提供了一种在容器中的 Fedora 原子主机上安装系统基础设施软件（如网络或 Kubernetes）的方法；
* 更新版本的 Docker、Atomic和 Cockpit，用于增强容器构建，系统支持和负载监控。

根据 Fedora 项目的 Miller 所言，容器化的 Kubernetes 对于 Fedora 原子主机来说是重要的，有两个重要原因。

他解释说：“首先，它可以让我们从基础镜像中删除它，减小大小和复杂度。第二，在容器中提供它可以轻松地在不同版本中切换，而不会破环基础，或者为尚未准备好进行改变的人造成麻烦。”

### 服务器端服务

Fedora 26 服务器版为数据中心运营提供了一个灵活的多角色平台。它还允许用户自定义此版本的 Fedora 操作系统以满足其独特需求。

Fedora 26 服务器版的新功能包括 FreeIPA 4.5，它可以改进容器中运行的安全信息管理解决方案，以及 SSSD 文件缓存，以加快用户和组查询的速度。

Fedora 26 服务器版月底将增加称为 “Boltron” 的 Fedora 模块化技术预览。作为模块化操作系统，Boltron 使不同版本的不同应用程序能够在同一个系统上运行，这实质上允许将前沿运行时与稳定的数据库配合使用。

### 打磨工作站版

对于一般用户的新工具和功能之一是更新的 GNOME 桌面功能。开发将获得增强的生产力工具。

Fedora 26 工作站版附带 GNOME 3.24 和众多更新的功能调整。夜光根据时间细微地改变屏幕颜色，以减少对睡眠模式的影响。[LibreOffice](http://www.libreoffice.org/) 5.3 是开源办公生产力套件的最新更新。

GNOME 3.24 提供了 Builder 和 Flatpak 的成熟版本，它为开发人员提供了更好的应用程序开发工具，它可以方便地访问各种系统，包括 Rust 和 Meson。

### 不只是为了开发

根据 [Azul Systems](https://www.azul.com/) 的首席执行官 Scott Sellers 的说法，更新的云工具将纳入针对企业用户的 Linux 发行版中。

他告诉 LinuxInsider：“云是新兴公司以及地球上一些最大的企业的主要开发和生产平台。”

Sellers说：“鉴于 Fedora 社区的前沿性质，我们预计在任何 Fedora 版本中都会强烈关注云技术，Fedora 26 不会不令人失望。”

他指出，Fedora 开发人员和用户社区的另一个特点就是 Fedora 团队在模块化方面所做的工作。

Sellers 说：“我们将密切关注这些实验功能。”

### 支持的升级方式

Sellers 说 Fedora 的用户超过其他 Linux 发行版的用户，很多都有兴趣升级到 Fedora 26，即使他们不是重度云端用户。

他说：“这个发行版的主要优点之一就是能提前看到先进的生产级别技术，这些最终将被整合到 RHEL 中。Fedora 26 的早期评论表明它非常稳定，修复了许多错误以及提升了性能。”

Fedora 的 Miller 指出，有兴趣从早期 Fedora 版本升级的用户可能比擦除现有系统安装 Fedora 26 更容易。Fedora 一次维护两个版本，中间还有一个月的重叠。

他说：“所以，如果你在用 Fedora 24，你应该在下个月升级。幸运的 Fedora 25 用户可以随时升级，这是 Fedora 快速滚动版本的优势之一。”

### 更快的发布

用户可以安排自己升级，而不是在发行版制作出来时进行升级。

也就是说，Fedora 23 或更早版本的用户应该尽快升级。社区不再为这些版本发布安全更新

---

作者简介：

Jack M. Germain 自 2003 年以来一直是 ECT 新闻网记者。他的主要重点领域是企业IT、Linux、和开源技术。他撰写了许多关于 Linux 发行版和其他开源软件的评论。发邮件联系 Jack

---

via: <http://www.linuxinsider.com/story/84674.html>

作者：[Jack M. Germain](jack.germain@newsroom.ectnews.comm) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


极客漫画：没特别的理由，别用 SIGKILL

Summary: 为线程们想想吧，不要随便用 SIGKILL！

系统还没那么脆弱，试想如果服务器突然断电了啦？多数情况下，在电力恢复后，无需做太多处理，还是继续正常工作的。

zan赞

为线程们想想吧，不要随便用 SIGKILL！

![Adopt a good cause, DON'T SIGKILL](/data/attachment/album/201708/18/160842xixj4rxjdnrs4jix.png)

为线程们想想吧，不要随便用 SIGKILL！

---

via: <http://turnoff.us/geek/dont-sigkill-2/>

作者：[Daniel Stori](http://turnoff.us/about/) 点评：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


混合云的那些事

Summary: 了解混合云的细节，包括它是什么以及如何使用它

了解混合云的细节，包括它是什么以及如何使用它

>
> 了解混合云的细节，包括它是什么以及如何使用它
>
>
>

![](/data/attachment/album/201708/19/100305e4394gzfgb4vi3v9.jpg)

在过去 10 年出现的众多技术中，云计算因其快速发展而引人注目，从一个细分领域的技术而成为了全球热点。就其本身来说，云计算已经造成了许多困惑、争论和辩论，而混合了多种类型的云计算的"混合"云计算也带来了更多的不确定性。阅读下文可以了解有关混合云的一些最常见问题的答案。

### 什么是混合云

基本上，混合云是本地基础设施、私有云和公共云（例如，第三方云服务）的灵活和集成的组合。尽管公共云和私有云服务在混合云中是绑定在一起的，但实际上，它们是独立且分开的服务实体，而可以编排在一起服务。使用公共和私有云基础设施的选择基于以下几个因素，包括成本、负载灵活性和数据安全性。

高级的特性，如<ruby> 扩展 <rt>  scale-up </rt></ruby>和<ruby> 延伸scale-out</ruby>，可以快速扩展云应用程序的基础设施，使混合云成为具有季节性或其他可变资源需求的服务的流行选择。(<ruby> 扩展 <rt>  scale-up </rt></ruby>意味着在特定的 Linux 实例上增加计算资源，例如 CPU 内核和内存，而<ruby> 延伸scale-out</ruby>则意味着提供具有相似配置的多个实例，并将它们分布到一个集群中)。

处于混合云解决方案中心的是开源软件，如 [OpenStack](https://opensource.com/resources/openstack)，它用于部署和管理虚拟机组成的大型网络。自 2010 年 10 月发布以来，OpenStack 一直在全球蓬勃发展。它的一些集成项目和工具处理核心的云计算服务，比如计算、网络、存储和身份识别，而其他数十个项目可以与 OpenStack 捆绑在一起，创建独特的、可部署的混合云解决方案。

### 混合云的组成部分

如下图所示，混合云由私有云、公有云注成，并通过内部网络连接，由编排系统、系统管理工具和自动化工具进行管理。

![混合云模型图](/data/attachment/album/201708/19/100320nl4if9qpjihhpsk7.jpg "Hybrid cloud model diagram")

*混合云模型*

#### 公共云基础设施

* <ruby> 基础设施即服务 <rt>  Infrastructure as a Service </rt></ruby>（IaaS） 从一个远程数据中心提供计算资源、存储、网络、防火墙、入侵预防服务（IPS）等。可以使用图形用户界面（GUI）或命令行接口（CLI）对这些服务进行监视和管理。公共 IaaS 用户不需要购买和构建自己的基础设施，而是根据需要使用这些服务，并根据使用情况付费。
* <ruby> 平台即服务 <rt>  Platform as a Service </rt></ruby>（PaaS）允许用户在其上开发、测试、管理和运行应用程序和服务器。这些包括操作系统、中间件、web 服务器、数据库等等。公共 PaaS 以模板形式为用户提供了可以轻松部署和复制的预定义服务，而不是手动实现和配置基础设施。
* <ruby> 软件即服务 <rt>  Software as a Service </rt></ruby>（SaaS）通过互联网交付软件。用户可以根据订阅或许可模型或帐户级别使用这些服务，在这些服务中，他们按活跃用户计费。SaaS 软件是低成本、低维护、无痛升级的，并且降低了购买新硬件、软件或带宽以支持增长的负担。

#### 私有云基础设施

* 私有 **IaaS** 和 **PaaS** 托管在孤立的数据中心中，并与公共云集成在一起，这些云可以使用远程数据中心中可用的基础设施和服务。这使私有云所有者能够在全球范围内利用公共云基础设施来扩展应用程序，并利用其计算、存储、网络等功能。
* **SaaS** 是由公共云提供商完全监控、管理和控制的。SaaS 一般不会在公共云和私有云基础设施之间共享，并且仍然是通过公共云提供的服务。

#### 云编排和自动化工具

要规划和协调私有云和公共云实例，云编排工具是必要的。该工具应该具有智能，包括简化流程和自动化重复性任务的能力。此外，集成的自动化工具负责在设置阈值时自动扩展和延伸，以及在发生任何部分损坏或宕机时执行自修复。

#### 系统和配置管理工具

在混合云中，系统和配置工具，如 [Foreman](https://github.com/theforeman)，管理着私有云和公共云数据中心提供的虚拟机的完整生命周期。这些工具使系统管理员能够轻松地控制用户、角色、部署、升级和实例，并及时地应用补丁、bug 修复和增强功能。包括Foreman 工具中的 [Puppet](https://github.com/theforeman/puppet-foreman)，使管理员能够管理配置，并为所有供给的和注册的主机定义一个完整的结束状态。

### 混合云的特性

对于大多数组织来说，混合云是有意义的，因为这些关键特性：

* **可扩展性：** 在混合云中，集成的私有云和公共云实例共享每个可配置的实例的计算资源池。这意味着每个实例都可以在需要时按需扩展和延伸。
* **快速响应：** 当私有云资源超过其阈值时，混合云的弹性支持公共云中的实例快速爆发增长。当需求高峰对运行中的应用程序需要显著的动态提升负载和容量时，这是特别有价值的。（例如，电商在假日购物季期间）
* **可靠性：** 组织可以根据需要的成本、效率、安全性、带宽等来选择公共云服务提供商。在混合云中，组织还可以决定存储敏感数据的位置，以及是在私有云中扩展实例，还是通过公共基础设施跨地域进行扩展。另外，混合模型在多个站点上存储数据和配置的能力提供了对备份、灾难恢复和高可用性的支持。
* **管理：** 在非集成的云环境中，管理网络、存储、实例和/或数据可能是乏味的。与混合工具相比，传统的编排工具非常有限，因此限制了决策制定和对完整的端到端进程和任务的自动化。使用混合云和有效的管理应用程序，您可以跟踪每个组件的数量增长，并通过定期优化这些组件，使年度费用最小化。
* **安全性：** 在评估是否在云中放置应用程序和数据时，安全性和隐私是至关重要的。IT 部门必须验证所有的合规性需求和部署策略。公共云的安全性正在改善，并将继续成熟。而且，在混合云模型中，组织可以将高度敏感的信息存储在私有云中，并将其与存储在公共云中的不敏感数据集成在一起。
* **定价：** 云定价通常基于所需的基础设施和服务水平协议（SLA）的要求。在混合云模型中，用户可以在计算资源(CPU/内存)、带宽、存储、网络、公共 IP 地址等粒度上进行比较，价格要么是固定的，要么是可变的，可以按月、小时、甚至每秒钟计量。因此，用户总是可以在公共云提供商中购买最好的价位，并相应地部署实例。

### 混合云如今的发展

尽管对公共云服务的需求很大且不断增长，并且从本地到公共云的迁移系统，仍然是大多数大型组织关注的问题。大多数人仍然在企业数据中心和老旧系统中保留关键的应用程序和数据。他们担心在公共基础设施中面临失去控制、安全威胁、数据隐私和数据真实性。因为混合云将这些问题最小化并使收益最大化，对于大多数大型组织来说，这是最好的解决方案。

### 预测五年后的发展

我预计混合云模型将在全球范围内被广泛接受，而公司的“无云”政策将在短短几年内变得非常罕见。这是我想我们会看到的：

* 由于混合云作为一种共担的责任，企业和公共云提供商之间将加强协作，以实施安全措施来遏制网络攻击、恶意软件、数据泄漏和其他威胁。
* 实例的爆发性增长将会很快，因此客户可以自发地满足负载需求或进行自我修复。
* 此外，编排或自动化工具（如 [Ansible](https://opensource.com/life/16/8/cloud-ansible-gateway)）将通过继承用于解决关键问题的能力来发挥重要作用。
* 计量和“量入为出”的概念对客户来说是透明的，并且工具将使用户能够通过监控价格波动，安全地销毁现有实例，并提供新的实例以获得最佳的可用定价。

---

作者简介：

Amit Das 是一名 Red Hat 的工程师，他对 Linux、云计算、DevOps 等充满热情，他坚信新的创新和技术，将以一种开放的方式的让世界更加开放，可以对社会产生积极的影响，改变许多人的生活。

---

via: <https://opensource.com/article/17/7/what-is-hybrid-cloud>

作者：[Amit Das](https://opensource.com/users/amit-das) 译者：[LHRchina](https://github.com/LHRchina) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出