<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ucloudcn (UCloud)</title>
    <link>https://ruby-china.org/ucloudcn</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>URTC 来了！支持万人直播的一站式实时音视频解决方案</title>
      <description>&lt;p&gt;有人说：2G 看文字，3G 看图片，4G 看视频，那么对于已经开启序幕的 5G 时代呢？随着短视频、在线课堂、互动直播等音视频应用的崛起，如何适配差异化的网络环境，为用户提供更流畅高清的实时音视频服务成为关注重点。而当前的音视频技术依然无法避免各种卡顿丢包、网络覆盖问题，也无法提供聊天、存储、转码、AI 处理等全栈式的解决方案。&lt;/p&gt;

&lt;p&gt;在此背景下，UCloud 于近日新推出一款基于 RTC 技术的实时音视频产品 URTC，依托 UCloud 强大的计算能力和网络覆盖，可以为用户提供&lt;strong&gt;就近接入 (全球 500 + 加速节点)、高质量（可用性达 99.99%）、抗弱网 (30% 视频丢包、70% 音频丢包仍可正常通信)、低延迟 (国内平均时延 70ms、国际平均时延不超过 300ms) 的网络音视频通信，并支持万人直播推送。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;全球实时传输，抗弱网低延时&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;基于 UCloud 在全球部署的 30 个可用区、28 条专线、500 + 加速节点，URTC 可提供全球覆盖的音视频服务，国内平均时延 70ms，国际平均时延不超过 300ms。通过全球接入点就近接入、自研 HTTPDNS 调度算法、丢包重传，实现弱网高质量通信，30% 视频丢包、70% 音频丢包仍可正常通信。70% 丢包下 URTC 经过网络传输后播放出来的音频效果如下，凭借其抗丢包能力仍可较完整地展现人声：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e2b9076cac1?w=1080&amp;amp;h=316&amp;amp;f=jpeg&amp;amp;s=32103" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;URTC 底层网络全部覆盖 BGP 线路，利用边缘节点就近接入，通过数据报文 AES 加密传输、端到端链路质量探测、多点接入线路容灾等保障其可用性达 99.99%。针对传输网络，UCloud 做了以下优化。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;抗网络抖动：&lt;/strong&gt; URTC 通过智能动态缓冲区策略，根据网络的变化动态调整缓冲区大小，抵抗网络抖动，最大支持 800ms 网络抗抖动。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;抗网络丢包：&lt;/strong&gt; URTC 通过 NACK+FEC+ARQ 智能重传策略抵抗丢包，通过动态调整重传和冗余数据比例，实现在通话质量和网络延时之间达到很好的平衡。同时 URTC 会对数据进行重要分类，保证重要数据优先，稳定传输，同时实现传输的公平性和稳定性。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;避免网络拥塞：&lt;/strong&gt; 利用线性回归方式，通过延时的斜率变化预测拥塞的发生和网络的变化，URTC 能做到更早发现网络拥塞、更早避免网络丢包、更早适应网络变化。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;多功能一体化，简单易用&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;传统方式下，要在 APP 应用上自研音视频功能，不仅需要开发人员具备基础的音视频编码、解码技术，还需要应对复杂的网络架构问题。从服务器设备的部署、开发到后期的运维都耗时耗力，且难以保障服务质量，因此对企业自身的技术门槛要求越来越高，这对于很多初创企业用户而言无疑是巨大的挑战。&lt;/p&gt;

&lt;p&gt;URTC 以 SDK 包的形式一键集成了音视频采集、编码、传输、解码、渲染、前后处理（如美颜、滤镜、回声消除、噪声抑制）功能，且可以扩展服务端、客户端的全部应用例如互动白板、转码、混流、录制等。由于其 SDK 接口接近主流 RTC 两级 SDK 快速模式，开发者只需要很少的代码就可以实现快速接入，简单易上手。&lt;/p&gt;

&lt;p&gt;同时 URTC 支持 Android、iOS、Mac OS、Windows、Electron、WEB 多平台的接入，能满足不同客户端的接入需求。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e31aa63526b?w=640&amp;amp;h=430&amp;amp;f=jpeg&amp;amp;s=20375" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;支持万人直播推送&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e3592a74b4e?w=640&amp;amp;h=308&amp;amp;f=jpeg&amp;amp;s=23640" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;URTC 利用 RTC 实时集群、RTC 直播集群，实现音视频连麦互动可以同时推送万人直播，具体原理如下。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;业务服务&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;URTC 在实现上主要包括控制流通信服务、实时互动集群（15 人以内房间）、低延时直播集群（万人大群）3 种服务集群。&lt;/p&gt;

&lt;p&gt;控制流通信服务提供流状态、流位置汇报，以及流订阅和发布的控制；实时互动集群主要负责 15 人以内的双向实时互动服务；低延时直播集群提供单向的万人低延时直播观看。媒体服务之间以及和转码录制集群通过自研私有 UDP 协议进行传输。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;底层网络&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;依托于 UCloud 全球加速网络 Rome，通过专线服务，优化跨区域、跨洋通信问题，提供更低的延时，更优质的传输质量和通话体验。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e39ae80d306?w=831&amp;amp;h=216&amp;amp;f=jpeg&amp;amp;s=15728" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;（图：Rome 公网加速）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;服务灾备&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;基于 Rome 的多线多云灾备能力，同时在单点服务故障时实现故障自动转移，提供更稳定的服务。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;打破地域限制，助力在线教育&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;随着互联网技术的高速发展，不受地域和时间限制的在线教育逐渐成为很多人学习、进修的选择。为了保障不同地域学生的在线学习体验，提升在线课堂的品质，在线教育对音视频应用服务的质量也提出了更高的要求。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e3e383b2e94?w=1080&amp;amp;h=315&amp;amp;f=jpeg&amp;amp;s=30779" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;URTC 高质量、抗弱网、低延迟的优异性能，能满足在线教育对于音视频服务的基本需求。通过 UCloud 自研和优化的 webrtc 架构，URTC 具有一对一、一对多、多对多的音视频通话功能。既能满足 1V1、小班课、双师课堂，也能满足视频互动大班课、万人直播课。&lt;/p&gt;

&lt;p&gt;互动演示文稿、互动白板，为师生学习、讨论提供交流的平台，且老师、学生可以在各自的白板内实时批注交流。白板内容支持录制、存储、回放，满足课堂教学、实时讨论、课后复习的需要。IM 聊天室支持老师设置全员禁言，让学生们集中注意听讲也可以发布讨论话题，让学生们畅所欲言。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e41c0d44efb?w=640&amp;amp;h=415&amp;amp;f=jpeg&amp;amp;s=33914" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;（图：互动白板界面）&lt;/p&gt;

&lt;p&gt;除了在线教育外，URTC 还可以广泛应用于智能家居、远程医疗、视频会议、娱乐直播、安防监控等场景。在实时音视频领域，UCloud 将围绕用户的场景和痛点不断丰富 URTC 产品特性，提供低延时、高可靠、安全稳定的音视频解决方案。为了让每个视频的通信质量、实时状态能够实时监测，也便于快速定位排障，URTC 近期将支持可视化运维面板，敬请期待。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;免费体验 URTC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为了帮助开发者更直观体验 URTC 在弱网环境下的抗丢包效果，这里给大家介绍一个网损测试方法，具体操作步骤如下：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;开源弱网模拟软件（网损软件）Clumsy 下载：&lt;a href="https://github.com/jagt/clumsy/releases" rel="nofollow" target="_blank"&gt;https://github.com/jagt/clumsy/releases&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;URTC demo 下载：&lt;a href="https://github.com/ucloud/urtc-win-demo" rel="nofollow" target="_blank"&gt;https://github.com/ucloud/urtc-win-demo&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;编译 URTC demo: 需要 Visual Studio 2015 以及 Windows10 SDK&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;运行两个 demo 客户端：一个订阅和一个发布&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;打开并设置网损软件 如下图：&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e45cfcbe462?w=584&amp;amp;h=346&amp;amp;f=jpeg&amp;amp;s=26897" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;设置网损方向（sending 代表上传丢包 receiving 代表下载丢包）&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e765f190d08?w=385&amp;amp;h=110&amp;amp;f=jpeg&amp;amp;s=11162" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;设置丢包：确认 drop 选项被选中，一遍开启丢包功能，后面设置丢包为 70%（取值 0.0 – 100.0）&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e846fa715d6?w=603&amp;amp;h=52&amp;amp;f=jpeg&amp;amp;s=7062" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;点击开始，启动网损设置，软件开始运行：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e8776cd0fcf?w=240&amp;amp;h=50&amp;amp;f=jpeg&amp;amp;s=2892" title="" alt=""&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;测试效果&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;依靠人耳去听；
实现 UCloudRtcAudioFrameCallback，通过 onRemoteMixAudioFrame 接口获取远端音频 pcm 数据，然后进行波形对比。
目前 URTC 每月 1 万分钟内免费，超出配额范围的计费方式如图所示，欢迎点击 &lt;a href="http://ucloudtml.mikecrm.com/C3aLi69" rel="nofollow" target="_blank"&gt;http://ucloudtml.mikecrm.com/C3aLi69&lt;/a&gt; 申请试用！&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e8c0bcbf42d?w=640&amp;amp;h=611&amp;amp;f=jpeg&amp;amp;s=27272" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;欢迎扫码入群，零距离交流最新产品和技术！&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/18/16d42e90630d5b52?w=640&amp;amp;h=851&amp;amp;f=jpeg&amp;amp;s=65825" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Wed, 18 Sep 2019 14:20:54 +0800</pubDate>
      <link>https://ruby-china.org/topics/39062</link>
      <guid>https://ruby-china.org/topics/39062</guid>
    </item>
    <item>
      <title>基于 NVMe SSD 的分布式文件存储 UFS 性能提升技术解析</title>
      <description>&lt;p&gt;UFS (UCloud File System) 是一款 UCloud 自主研发的分布式文件存储产品，此前已推出容量型 UFS 版本。UFS 以其弹性在线扩容、稳定可靠的特点，为众多公有云、物理云、托管云用户提供共享存储方案，单文件系统存储容量可达百 PB 级。&lt;/p&gt;

&lt;p&gt;为了应对 IO 性能要求很高的数据分析、AI 训练、高性能站点等场景，UFS 团队又推出了一款基于 NVMe SSD 介质的性能型 UFS，以满足高 IO 场景下业务对共享存储的需求。性能型 UFS 的 4K 随机写的延迟能保持在 10ms 以下，4K 随机读延迟在 5ms 以下。&lt;/p&gt;

&lt;p&gt;性能的提升不仅仅是因为存储介质的升级，更有架构层面的改进，本文将从协议、索引、存储设计等几方面来详细介绍性能型 UFS 升级改造的技术细节。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;协议改进&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;此前容量型 UFS 设计时支持的协议为 NFSv3，其设计理念是接口无状态，故障恢复的逻辑简单。此外 NFSv3 在 Linux 和 Windows 上被广泛支持，更易于跨平台使用。但是 NFSv3 的设计缺点导致的高延迟在高 IO 场景下是不可接受的，所以在性能型 UFS 中，我们选择仅支持性能更好、设计更先进的 NFSv4 协议。&lt;/p&gt;

&lt;p&gt;NFSv4 与 NFSv3 相比，更先进的特性包括：支持有状态的 lock 语义、多协议间的 compound 机制等。特别是 compound 机制，可以让多次 NFS 协议交互在一个 RTT 中完成，很好地解决了 NFSv3 性能低效的问题。一次典型的 open for write 操作，在 NFSv3 和 NFSv4 上分别是这样的：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfae3a9aa57527?w=502&amp;amp;h=286&amp;amp;f=jpeg&amp;amp;s=15141" title="" alt=""&gt;
&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfae3e0c37362e?w=509&amp;amp;h=275&amp;amp;f=jpeg&amp;amp;s=16516" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以看到，在关键的 IO 部分，NFSv4 比 NFSv3 节省一半的交互次数，可以显著降低 IO 延迟。除了协议以外，性能型 UFS 的核心由业务索引和底层存储两部分组成，由于底层 IO 性能的提升，这两部分都需要进行深度改造以适应这种结构性的改变。下面我们将分别介绍这两部分的改造细节。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;业务索引&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;索引服务是分布式文件系统的核心功能之一。相比对象存储等其它存储服务，文件存储的索引需要提供更为复杂的语义，所以会对性能产生更大影响。&lt;/p&gt;

&lt;p&gt;索引服务的功能模块设计是基于单机文件系统设计思路的一种『仿生』，分为两大部分：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;• 目录索引：&lt;/strong&gt; 实现树状层级目录，记录各个目录下的文件和子目录项&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;• 文件索引：&lt;/strong&gt; 记录文件元数据，包含数据块存储信息和访问权限等&lt;/p&gt;

&lt;p&gt;索引服务各模块的功能是明确的，主要解决两个问题：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;• 业务特性：&lt;/strong&gt; 除了实现符合文件系统语义的各类操作外，还要保证索引数据的外部一致性，在各类并发场景下不对索引数据产生静态修改从而产生数据丢失或损坏&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;• 分布式系统特性：&lt;/strong&gt; 包括系统拓展性、可靠性等问题，使系统能够应对各类节点和数据故障，保证系统对外的高可用性和系统弹性等&lt;/p&gt;

&lt;p&gt;虽然功能有区别，目录索引和文件索引在架构上是类似的，所以我们下面只介绍文件索引 (FileIdx) 架构。在以上的目标指导下，最终 FileIdx 采用无状态设计，依靠各索引节点和 master 之间的租约（Lease）机制来做节点管理，实现其容灾和弹性架构。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfae7389ad25ff?w=533&amp;amp;h=357&amp;amp;f=jpeg&amp;amp;s=20580" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;租约机制和悲观锁&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;master 模块负责维护一张路由表，路由表可以理解成一个由虚节点组成的一致性哈希环，每个 FileIdx 实例负责其中的部分虚节点，master 通过心跳和各个实例节点进行存活性探测，并用租约机制告知 FileIdx 实例和各个 NFSServer 具体的虚节点由谁负责处理。如果某个 FileIdx 实例发生故障，master 只需要在当前租约失效后将该节点负责的虚节点分配给其他实例处理即可。&lt;/p&gt;

&lt;p&gt;当 NFSServer 需要向文件服务请求具体操作 (比如请求分配 IO 块) 时，会对请求涉及的文件句柄做哈希操作确认负责该文件的虚节点由哪个 FileIdx 处理，将请求发至该节点。每个节点上为每个文件句柄维持一个处理队列，队列按照 FIFO 方式进行执行。本质上这构成了一个悲观锁，当一个文件的操作遇到较多并发时，我们保证在特定节点和特定队列上的排队，使得并发修改导致的冲突降到最低。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;更新保护&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;尽管租约机制一定程度上保证了文件索引操作的并发安全性，但是在极端情况下租约也不能保持并发操作的绝对互斥及有序。所以我们在索引数据库上基于 CAS 和 MVCC 技术对索引进行更新保护，确保索引数据不会因为并发更新而丧失外部一致性。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IO 块分配优化&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在性能型 UFS 中，底层存储的 IO 延迟大幅降低带来了更高的 IOPS 和吞吐，也对索引模块特别是 IO 块的分配性能提出了挑战。频繁地申请 IO 块导致索引在整个 IO 链路上贡献的延迟比例更高，对性能带来了损害。一方面我们对索引进行了读写分离改造，引入缓存和批量更新机制，提升单次 IO 块分配的性能。&lt;/p&gt;

&lt;p&gt;同时，我们增大了 IO 块的大小，更大的 IO 数据块降低了分配和获取数据块的频率，将分配开销进行均摊。后续我们还将对索引关键操作进行异步化改造，让 IO 块的分配从 IO 关键路径上移除，最大程度降低索引操作对 IO 性能的影响。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;底层存储&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;设计理念&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;存储功能是一个存储系统的重中之重，它的设计实现关系到系统最终的性能、稳定性等。通过对 UFS 在数据存储、数据操作等方面的需求分析，我们认为底层存储 (命名为 nebula) 应该满足如下的要求:・简单：简单可理解的系统有利于后期维护・可靠：必须保证高可用性、高可靠性等分布式要求・拓展方便：包括处理集群扩容、数据均衡等操作・支持随机 IO・充分利用高性能存储介质&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nebula: append-only 和中心化索引&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;基于以上目标，我们将底层存储系统 nebula 设计为基于 append-only 的存储系统 (immutable storage)。面向追加写的方式使得存储逻辑会更简单，在多副本数据的同步上可以有效降低数据一致性的容错复杂度。更关键的是，由于追加写本质上是一个 log-based 的记录方式，整个 IO 的历史记录都被保存，在此之上实现数据快照和数据回滚会很方便，在出现数据故障时，更容易做数据恢复操作。&lt;/p&gt;

&lt;p&gt;在现有的存储系统设计中，按照数据寻址的方式可以分为去中心化和中心化索引两种，这两者的典型代表系统是 Ceph 和 Google File System。去中心化的设计消除了系统在索引侧的故障风险点，并且降低了数据寻址的开销。但是增加了数据迁移、数据分布管理等功能的复杂度。出于系统简单可靠的设计目标，我们最终选择了中心化索引的设计方式，中心化索引使集群扩容等拓展性操作变得更容易。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfae79f9b968e1?w=713&amp;amp;h=186&amp;amp;f=jpeg&amp;amp;s=25996" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;数据块管理：extent-based 理念&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;中心化索引面临的性能瓶颈主要在数据块的分配上，我们可以类比一下单机文件系统在这方面的设计思路。早期文件系统的 inode 对数据块的管理是 block-based，每次 IO 都会申请 block 进行写入，典型的 block 大小为 4KB，这就导致两个问题：1、4KB 的数据块比较小，对于大片的写入需要频繁进行数据块申请操作，不利于发挥顺序 IO 的优势。2、inode 在基于 block 的方式下表示大文件时需要更大的元数据空间，能表示的文件大小也受到限制。&lt;/p&gt;

&lt;p&gt;在 Ext4/XFS 等更先进的文件系统设计中，inode 被设计成使用 extent-based 的方式来实现，每个 extent 不再被固定的 block 大小限制，相反它可以用来表示一段不定长的磁盘空间，如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfae7fd948f666?w=593&amp;amp;h=549&amp;amp;f=" title="jpeg&amp;amp;s=34026" alt=""&gt;
显然地，在这种方式下，IO 能够得到更大更连续的磁盘空间，有助于发挥磁盘的顺序写能力，并且有效降低了分配 block 的开销，IO 的性能也得到了提升，更关键的是，它可以和追加写存储系统非常好地结合起来。我们看到，不仅仅在单机文件系统中，在 Google File System、Windows Azure Storage 等分布式系统中也可以看到 extent-based 的设计思想。我们的 nebula 也基于这一理念进行了模型设计。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfae842960d786?w=510&amp;amp;h=178&amp;amp;f=jpeg&amp;amp;s=18035" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;存储架构&lt;/strong&gt;
&lt;strong&gt;Stream 数据流&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在 nebula 系统中存储的数据按照 stream 为单位进行组织，每个 stream 称为一个数据流，它由一个或多个 extent 组成，每次针对该 stream 的写入操作以 block 为单位在最后一个 extent 上进行追加写，并且只有最后一个 extent 允许写入，每个 block 的长度不定，可由上层业务结合场景决定。而每个 extent 在逻辑上构成一个副本组，副本组在物理上按照冗余策略在各存储节点维持多副本，stream 的 IO 模型如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfae89810c8922?w=618&amp;amp;h=300&amp;amp;f=jpeg&amp;amp;s=29860" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;streamsvr 和 extentsvr&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;基于这个模型，存储系统被分为两大主要模块：・streamsvr：负责维护各个 stream 和 extent 之间的映射关系以及 extent 的副本位置等元数据，并且对数据调度、均衡等做管控・extentsvr：每块磁盘对应一个 extentsvr 服务进程，负责存储实际的 extent 数据存储，处理前端过来的 IO 请求，执行 extent 数据的多副本操作和修复等&lt;/p&gt;

&lt;p&gt;在存储集群中，所有磁盘通过 extentsvr 表现为一个大的存储池，当一个 extent 被请求创建时，streamsvr 根据它对集群管理的全局视角，从负载和数据均衡等多个角度选取其多副本所在的 extentsvr，之后 IO 请求由客户端直接和 extentsvr 节点进行交互完成。在某个存储节点发生故障时，客户端只需要 seal 掉当前在写入的 extent，创建一个新的 extent 进行写入即可，节点容灾在一次 streamsvr 的 rpc 调用的延迟级别即可完成，这也是基于追加写方式实现带来的系统简洁性的体现。&lt;/p&gt;

&lt;p&gt;由此，存储层各模块的架构图如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfae8dcd376284?w=640&amp;amp;h=395&amp;amp;f=jpeg&amp;amp;s=34988" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;至此，数据已经可以通过各模块的协作写入到 extentsvr 节点，至于数据在具体磁盘上的存储布局，这是单盘存储引擎的工作。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;单盘存储引擎&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;前面的存储架构讲述了整个 IO 在存储层的功能分工，为了保证性能型 UFS 的高性能，我们在单盘存储引擎上做了一些优化。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;线程模型优化&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;存储介质性能的大幅提升对存储引擎的设计带来了全新的需求。在容量型 UFS 的 SATA 介质上，磁盘的吞吐较低延迟较高，一台存储机器的整体吞吐受限于磁盘的吞吐，一个单线程 / 单进程的服务就可以让磁盘吞吐打满。随着存储介质处理能力的提升，IO 的系统瓶颈逐渐从磁盘往处理器和网络带宽方面转移。&lt;/p&gt;

&lt;p&gt;在 NVMe SSD 介质上由于其多队列的并行设计，单线程模型已经无法发挥磁盘性能优势，系统中断、网卡中断将成为 CPU 新的瓶颈点，我们需要将服务模型转换到多线程方式，以此充分发挥底层介质多队列的并行处理能力。为此我们重写了编程框架，新框架采用 one loop per thread 的线程模型，并通过 Lock-free 等设计来最大化挖掘磁盘性能。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;block 寻址&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;让我们思考一个问题，当客户端写入了一片数据 block 之后，读取时如何找到 block 数据位置？一种方式是这样的，给每个 block 分配一个唯一的 blockid，通过两级索引转换进行寻址：&lt;/p&gt;

&lt;p&gt;・第一级：查询 streamsvr 定位到 blockid 和 extent 的关系&lt;/p&gt;

&lt;p&gt;・第二级：找到 extent 所在的副本，查询 blockid 在 extent 内的偏移，然后读取数据&lt;/p&gt;

&lt;p&gt;这种实现方式面临两个问题，（1）第一级的转换需求导致 streamsvr 需要记录的索引量很大，而且查询交互会导致 IO 延迟升高降低性能。（2）第二级转换以 Facebook Haystack 系统为典型代表，每个 extent 在文件系统上用一个独立文件表示，extentsvr 记录每个 block 在 extent 文件中的偏移，并在启动时将全部索引信息加载在内存里，以提升查询开销，查询这个索引在多线程框架下必然因为互斥机制导致查询延迟，因此在高性能场景下也是不可取的。而且基于文件系统的操作让整个存储栈的 IO 路径过长，性能调优不可控，也不利于 SPDK 技术的引入。&lt;/p&gt;

&lt;p&gt;为避免上述不利因素，我们的存储引擎是基于裸盘设计的，一块物理磁盘将被分为几个核心部分：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfae95678a7efb?w=693&amp;amp;h=200&amp;amp;f=jpeg&amp;amp;s=14188" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;•superblock: *&lt;/em&gt; 超级块，记录了 segment 大小，segment 起始位置以及其他索引块位置等&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;•segment: *&lt;/em&gt; 数据分配单位，整个磁盘除了超级块以外，其他区域全部都是 segment 区域，每个 segment 是定长的 (默认为 128MB)，每个 extent 都由一个或多个 segment 组成&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;•extent index / segment meta region: extent/segment *&lt;/em&gt; 索引区域，记录了每个 extent 对应的 segment 列表，以及 segment 的状态 (是否可用) 等信息&lt;/p&gt;

&lt;p&gt;基于这个设计，我们可以将 block 的寻址优化为无须查询的纯计算方式。当写完一个 block 之后，将返回该 block 在整个 stream 中的偏移。客户端请求该 block 时只需要将此偏移传递给 extentsvr，由于 segment 是定长的，extentsvr 很容易就计算出该偏移在磁盘上的位置，从而定位到数据进行读取，这样就消除了数据寻址时的查询开销。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;随机 IO 支持：FileLayer 中间层&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;我们之前出于简单可靠的理念将存储系统设计为 append-only，但是又由于文件存储的业务特性，需要支持覆盖写这类随机 IO 场景。&lt;/p&gt;

&lt;p&gt;因此我们引入了一个中间层 FileLayer 来支持随机 IO，在一个追加写的引擎上实现随机写，该思路借鉴于 Log-Structured File System 的实现。LevelDB 使用的 LSM-Tree 和 SSD 控制器里的 FTL 都有类似的实现，被覆盖的数据只在索引层面进行间接修改，而不是直接对数据做覆盖写或者是 COW (copy-on-write)，这样既可以用较小的代价实现覆盖写，又可以保留底层追加写的简单性。&lt;/p&gt;

&lt;p&gt;FileLayer 中发生 IO 操作的单元称为 dataunit，每次读写操作涉及的 block 都在某个 dataunit 上进行处理，dataunit 的逻辑组成由如下几个部分：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfae9b68885321?w=491&amp;amp;h=262&amp;amp;f=jpeg&amp;amp;s=18994" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;dataunit 由多个 segment 组成 (注意这和底层存储的 segment 不是一个概念)，因为基于 LSM-Tree 的设计最终需要做 compaction, 多 segment 的划分类似于 LevelDB 中的多层 sst 概念，最下层的 segment 是只读的，只有最上层的 segment 允许写入，这使得 compaction 操作可以更简单可靠地进行甚至回滚，而由于每次 compaction 涉及的数据域是确定的，也便于我们检验 compaction 操作的 invariant：回收前后数据域内的有效数据必须是一样的。&lt;/p&gt;

&lt;p&gt;每个 segment 则由一个索引流和一个数据流组成，它们都存储在底层存储系统 nebula 上，每次写入 IO 需要做一次数据流的同步写，而为了提升 IO 性能，索引流的写入是异步的，并且维护一份纯内存索引提升查询操作性能。为了做到这一点，每次写入到数据流中的数据是自包含的，这意味着如果索引流缺失部分数据甚至损坏，我们可以从数据流中完整构建整个索引。&lt;/p&gt;

&lt;p&gt;客户端以文件为粒度写入到 dataunit 中，dataunit 会给每个文件分配一个全局唯一的 fid，fid 作为数据句柄存储到业务索引中 (FileIdx 的 block 句柄)。&lt;/p&gt;

&lt;p&gt;dataunit 本身则由 fileserver 服务进程负责，每个 fileserver 可以有多个 dataunit，coordinator 根据各节点的负载在实例间进行 dataunit 的调度和容灾。整个 FileLayer 的架构如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfaea1d9122a77?w=626&amp;amp;h=359&amp;amp;f=jpeg&amp;amp;s=20080" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;至此，存储系统已经按照设计要求满足了我们文件存储的需求，下面我们来看一看各个模块是如何一起协作来完成一次文件 IO 的。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Big Picture：一次文件写 IO 的全流程&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;从整体来说，一次文件写 IO 的大致流程是这样的：&lt;/p&gt;

&lt;p&gt;①用户在主机上发起 IO 操作会在内核层被 nfs-client 在 VFS 层截获 (仅以 Linux 系统下为例)，通过被隔离的 VPC 网络发往 UFS 服务的接入层。&lt;/p&gt;

&lt;p&gt;②接入层通过对 NFS 协议的解析和转义，将这个操作分解为索引和数据操作。&lt;/p&gt;

&lt;p&gt;③经过索引模块将这个操作在文件内涉及的 IO 范围转化为由多个 file system block (固定大小，默认 4MB) 表示的 IO 范围。&lt;/p&gt;

&lt;p&gt;④NFSServer 拿到需要操作的 block 的句柄 (bid) 后去请求 FileLayer 进行 IO 操作 (每个 bid 在 FileLayer 中代表一个文件)。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfaea62a4982a1?w=640&amp;amp;h=486&amp;amp;f=jpeg&amp;amp;s=28947" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;请求会被 NFSServer 发往负责处理该 bid 对应的文件的 fileserver 上，fileserver 获取该文件所在的 dataunit 编号 (此编号被编码在 bid 中) 后，直接往该 dataunit 当前的数据流 (stream) 中进行追加写，完成后更新索引，将新写入的数据的位置记录下来，本次 IO 即告完成，可以向 NFSServer 返回回应了。类似地，当 fileserver 产生的追加写 IO 抵达其所属的 extentsvr 的时候，extentsvr 确定出该 stream 对应的最后一个 extent 在磁盘上的位置，并执行一次追加写落地数据，在完成多副本同步后返回。&lt;/p&gt;

&lt;p&gt;至此，一次文件写 IO 就完成了。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;性能数据&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;经过前述的设计和优化，性能型 UFS 的实际性能数据如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/9/4/16cfaeac94b459fb?w=685&amp;amp;h=190&amp;amp;f=jpeg&amp;amp;s=18345" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;本文从 UFS 性能型产品的需求出发，详细介绍了基于高性能存储介质构建分布式文件系统时，在协议、业务架构、存储引擎等多方面的设计考虑和优化，并最终将这些优化落实到产品中去。性能型 UFS 的上线丰富了产品种类，各类对 IO 延迟要求更高的大数据分析、AI 训练等业务场景将得到更好的助力。&lt;/p&gt;

&lt;p&gt;后续我们将在多方面继续提升 UFS 的使用体验，产品上会支持 SMB 协议，提升 Windows 主机使用文件存储的性能；底层存储会引入 SPDK、RDMA 等技术，并结合其它更高性能的存储介质；在冷存数据场景下引入 Erasure Coding 等技术；使用户能够享受到更先进的技术带来的性能和价格红利。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;产品最新优惠：性能型 UFS 原价 1.0 元 /GB/ 月，现在福建可用区优惠价 0.6 元 /GB/ 月，国内其他可用区 0.8 元 /GB/ 月，欢迎联系客户经理申请体验！&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如您有本篇文章相关问题，欢迎添加作者微信咨询。WeChat ID：cheneydeng&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Wed, 04 Sep 2019 14:54:43 +0800</pubDate>
      <link>https://ruby-china.org/topics/39015</link>
      <guid>https://ruby-china.org/topics/39015</guid>
    </item>
    <item>
      <title>高考填志愿的上亿流量高峰，看 MongoDB 如何应对</title>
      <description>&lt;p&gt;&lt;em&gt;随着用户规模的增长，数据库的压力也在成倍增加。面对大流量、高并发，UCloud MongoDB 做到了高效，并展现出了更好的性能体验。&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;—— 优志愿 CTO 张海鹏&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;每年 6 月下旬到 8 月下旬期间是高考填志愿的高峰期，也是优志愿后端面临大流量高并发请求的业务高峰期。优志愿 APP 旨在为 3000 万高中生提供专业的自主招生、志愿填报、留学、游学等升学规划服务，通过四年技术的不断创新和研发，凭借“省控线差值法”等专利级核心算法，目前已累计服务 400 多万考生，实现录取成功率高达 99.2%，最大浪费分仅 6 分的成绩。而要为如此多考生提供服务，面对上亿条检索依然稳定，并不是简单的事。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd46be1cb5656?w=202&amp;amp;h=88&amp;amp;f=jpeg&amp;amp;s=4121" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面临的痛点&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;优志愿原先基于物理机自建的 MSSQL（Microsoft SQL Sever）数据库，面对大流量高并发的业务高峰，暴露了以下问题：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. 跟不上业务弹性扩容的节奏&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;自建 MSSQL 在做读写分离、AlwaysOn 配置、给每台 windows 客户端配置域名帐户等操作时十分繁琐，且随着业务流量的增长需要不定时的增加服务器及应用配置，从硬件采购、机器部署到应用配置整个周期也较长。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. 性能遭遇瓶颈，DBA 耗时耗力&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;另外，由于优志愿的业务场景主要是以查询、索引操作为主，读写比例大概 7:3，之前自建的 MSSQL 在数据达到千万条时检索速度大幅下降，需要及时更新索引目录，不仅影响考生的用户体验，且耗费大量的 DBA 人力成本。&lt;/p&gt;

&lt;p&gt;经过一番调研对比后，优志愿选择了使用 UCloud MongoDB 产品来解决以上问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;为什么选择 UCloud MongoDB？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCloud MongoDB 是基于成熟云计算技术的高可用、高性能的数据库服务，无缝兼容开源的 MongoDB 版本；除了底层采用高可用主从架构外，还提供满足数据分片场景的配置节点和路由节点功能；同时提供灾备、备份、监控等全套解决方案。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd470ca5aa860?w=640&amp;amp;h=224&amp;amp;f=jpeg&amp;amp;s=14856" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;（图：在 UCloud 控制台 UDB 产品界面可选择创建 MongoDB 实例）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;●一键创建副本集实现读写分离&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCloud MongoDB 默认构建三节点的副本集：Primary 节点 + 一个 Secondary 节点 + 一个 Arbiter 节点构成。通过副本集中创建节点操作可支持扩展更多节点的副本集（例如：五节点、七节点或者更多个节点）。对于优志愿读多写少的场景及其业务高峰期，用户可以按需增删 Secondary 节点，更好地实现读取性能的扩展。利用 UCloud MongoDB 副本集读写分离解决了大部分读取的请求，即使数据到达上亿条时检索速度依然很快。副本集架构如图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd4763799a9d2?w=640&amp;amp;h=361&amp;amp;f" title="=jpeg&amp;amp;s=18106" alt=""&gt;
&lt;strong&gt;●灵活高可用集群架构&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为了解决随着数据量增多而导致的性能瓶颈，MongoDB 还支持分片集群，即多个分片可以组成一个集群对外提供服务。分片集群（MongoDB3.4 及以上版本），由 Config Server 三副本 + N 个 Mongos +N 个 shard 数据分片构成，MongoDB 集群设置好分片规则，通过 mongos 操作数据库就能自动把对应的数据操作请求转发到对应的分片机器上。MongoDB 采用“分片”能够快速搭建一个高可用可扩展的的分布式集群，具有大数据量、高扩展性、高性能、灵活数据模型、高可用性等特性。分片集群架构如图：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd47b826f2dfa?w=640&amp;amp;h=344&amp;amp;f=jpeg&amp;amp;s=25093" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;●弹性扩缩容更省成本&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;用户依据业务实际流量可以弹性扩展 MongoDB 资源，满足不同业务阶段数据库性能和存储空间的需求。在业务高峰期可即时开通所需数据库资源，无需在业务初期采购高成本硬件，从而有效减少硬件成本投入。在业务低峰期可随时删除释放，避免数据库资源的闲置浪费。&lt;strong&gt;正如优志愿 CTO 张海鹏所说：“使用 UCloud MongoDB 数据库后，运维成本节省了 80%，硬件采购成本减少 55%。”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;查询索引优化，打破性能瓶颈&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;卡顿现象&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在今年高考前夕，优志愿新版业务上线后业务出现小高峰的第一天，用户反馈他们的 APP 登陆界面非常卡顿，经运维排查发现瓶颈出现在数据库层，并邀请了 UCloud 云数据库团队介入解决相关性能问题。&lt;/p&gt;

&lt;p&gt;团队首先查看了一些常见的会引起 MongoDB 出现卡顿的性能指标，发现大多数指标正常。随着排查深入进行，发现实例全局写锁的加锁比例异常高。如下图所示。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd48fd3241af4?w=640&amp;amp;h=254&amp;amp;f=jpeg&amp;amp;s=19299" title="" alt=""&gt;
&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd492eea088ff?w=640&amp;amp;h=255&amp;amp;f=jpeg&amp;amp;s=16496" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图中加锁百分比达到 100%，意味着所有全局写操作全部卡住，大量的请求在排队等待加锁，性能急剧下降。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;语句优化&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCloud 云数据库团队针对当时用户所有慢查询的总体情况，以及相关慢查询的查询计划，并结合用户的索引情况进行了详细分析。经过分析后，团队首先发现用户的相关表当中一些索引可以优化，从而提升查询的效率，因此为用户添加了相关的索引。在添加了索引之后，团队结合监控指标，发现情况有所改善，但是依旧没有从根本上解决问题。&lt;/p&gt;

&lt;p&gt;然后，团队仔细分析了用户耗时最长的典型查询语句，并模拟执行查看执行计划。在执行过程中，团队发现虽然相关集合已经加上了索引，但是用户的查询语句的执行计划中并没有使用最优的索引。进一步分析后，团队发现用户的最慢的语句基本都是 aggregate 操作，结合加锁异常的性能指标，团队仔细查看了用户的具体 aggregate 的语句内容。最后发现耗时长的这些 aggregate 操作当中没有用到分组功能 ($group)。这样的话其实也可以通过 MongoDB 最普通的 find 操作来达到同样的效果。例如原语句：&lt;/p&gt;

&lt;p&gt;db.this_collection.aggregate([ {$match: { UserId: 12345}}, {$match: { $or: [{FieldA: 1}, {FieldB: 2}]}}, {$sort: {_id: -1}}, {$skip: 0}, {$limit: 1}])
这条语句做的事情，其实是在 this_collection 这个集合中，查找 UserId = 12345 并且 还满足 FieldA = 1 或者 FieldB = 2 的文档记录。查找到记录之后，对所有结果的_id 进行倒序排列，并且拿出第一条结果。团队用下面的 find 语句达到同样的效果。改造后语句：&lt;/p&gt;

&lt;p&gt;db.this_collection.find( { UserId: 12345, {$or: [{FieldA: 1}, {FieldB: 2}]} }).sort({_id: -1}).skip(0).limit(1)
MongoDB 的 find () 进行了更加高程度的查询优化，并且使用 find () 操作还有一个额外的好处，就是用户可以在 find () 最后接上 hint () 操作，可以强制指定使用的索引，使查询性能大幅提升。比如上面的例子中，如果在 this_collection 这个集合中，对 UserId 有索引，我们可以直接强制查询使用这个索引。具体语句可以变成：&lt;/p&gt;

&lt;p&gt;db.this_collection.find( { UserId: 12345, {$or: [{FieldA: 1}, {FieldB: 2}]} }).sort({_id: -1}).skip(0).limit(1).hint({UserId: 1})
团队尝试改造其中的一条典型耗时语句，并且在模拟环境中执行并查看改造后的执行计划。结果惊喜地发现，即使在没有使用 hint 操作的情况下，find () 操作已经能够使用我们认为的最优索引了，经过改造后的查询性能有了大幅的提升。&lt;/p&gt;

&lt;p&gt;当天晚上，UCloud 云数据库团队立即帮助用户改造了他们最慢的查询中所有可以被改造的查询语句，并且把改造建议同步给用户。用户的研发当晚收到改造建议后，紧急修改代码并发布。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;瓶颈解除&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;发布后的第二天，用户通过监控界面，可以看到慢查询显著减少，并且加锁队列显著降低，数据库的负载也明显降低，整个系统能更高效的提供服务，改造后的监控图如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd49d764f12dc?w=640&amp;amp;h=315&amp;amp;f=jpeg&amp;amp;s=17744" title="" alt=""&gt;
&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd4a01ac2fa1c?w=640&amp;amp;h=341&amp;amp;f" title="=jpeg&amp;amp;s=23332" alt=""&gt;
可以看到，在改造之后，全局写锁的加锁等待百分比大大减少，慢查询也大大减少。改造取得了非常好的效果，用户的 APP 后期再也没有出现过 DB 层面的性能瓶颈。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prometheus 全方位实时监控及告警&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为了帮助用户提供更实时的大盘监控，UCloud 在后台搭建了一套 Prometheus 监控系统，将所有数据库实例的关键性能指标全列出来，相比普通的监控平台，借助 Prometheus 可以更清晰的看到所有数据库实例当前的情况，掌握数据库当前的状态，也可以更好的发现数据库的运行趋势。&lt;/p&gt;

&lt;p&gt;例如连接数情况：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd4a4d41c909d?w=640&amp;amp;h=225&amp;amp;f=jpeg&amp;amp;s=25756" title="" alt=""&gt;
对于每一个实例，提供更详细的监控。例如 WTcache 的状态：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd4a852e5df89?w=1080&amp;amp;h=301&amp;amp;f=jpeg&amp;amp;s=23215" title="" alt=""&gt;
加锁的状态：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd4acbd7743ae?w=640&amp;amp;h=313&amp;amp;f=jpeg&amp;amp;s=19211" title="" alt=""&gt;
监控系统和告警系统相结合，可以在大于阀值时，直接告警出来，有利于问题的提前发现。借助 UCloud 搭建的 Prometheus，用户无需自行搭建监控系统，也无需关心底层数据存储、数据展示、系统运维等问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCloud 云数据库 UDB 自 2013 年正式商用后，一直紧跟开源社区的步伐，目前已经广泛支持业内主流的数据库类型，除了 MongoDB, 还支持例如 MySQL、PostgreSQL 以及 SQLServer。在开源的基础上，UCloud 数据库团队还自研了分布式架构、读写分离、存储计算分离等特性。同时，为了更贴近用户的使用场景，UCloud 数据库团队近期将推出 Cloud DBA 新产品，在控制台提供 Prometheus 监控入口、界面管理巡检和 SQL 分析等功能，以更加智能的方式提高 DBA 运维效率。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd4affe19aaaf?w=640&amp;amp;h=356&amp;amp;f=jpeg&amp;amp;s=33019" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 23 Aug 2019 15:19:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/38969</link>
      <guid>https://ruby-china.org/topics/38969</guid>
    </item>
    <item>
      <title>云原生时代，Kubernetes 让应用落地的 N 种招式 (附 PPT)</title>
      <description>&lt;p&gt;放眼望去，容器、Kubernetes 和云原生技术正在被越来越多的企业青睐，Kubernetes 已经为一种大规模部署容器化应用程序的标准。随着它不断的快速迭代发展，企业在实际的应用部署过程中也面临着各种复杂的问题和挑战。如何克服 K8S 技术难关，使其更好的服务于容器化应用成为大家关注的重点。&lt;/p&gt;

&lt;p&gt;8 月 17 日 UCan 下午茶上海站 ——《云原生 Kubernetes 的开发和运维》技术沙龙现场，六位资深技术专家围绕 K8S 的落地实践进行了充分的探讨。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd3af7821760f?w=640&amp;amp;h=427&amp;amp;f=jpeg&amp;amp;s=72150" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;张苗磊：Kubernetes 集群在云平台的实践与应用&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;K8S 自 2014 年推出，目的就是作为集群内容器管理调度的平台，用户只需关心将内容放进容器，而把调度和运行交给 K8S。为了让 K8S 在生产环境上运行得更加顺畅和完善，UCloud 作为公有云厂商推出的 UK8S，除了通用性，还提供了很多拓展能力。&lt;/p&gt;

&lt;p&gt;例如 Pod 的网络方案上，借助云厂商的底层网络能力，通过提供 SecondIP 的方式，和云上其它产品打通，避免采用封包方案造成的性能损失。又如在服务接入上，公有云的 UK8S 能通过插件很好地提供，用户在集群内部创建一个 loadbalancer 类型的 service，就能自动化地和 ULB 产品关联并使用。同时还支持非 SNAT 形式的 loadbalancer，让 Pod 可以直接拿到源 IP 地址。&lt;/p&gt;

&lt;p&gt;存储方面，K8S 原生态里 PV 需要集群管理员或第三方来实现。UK8S 也结合 UCloud 存储产品提供了自动化的实现，有块存储和文件存储两种形式。用户只需要在集群内创建一个 PVC，预设好的 StorageClass 就会自动创建相应 PV 并关联到 UDisk/UFS 上，实现快速接入。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd3b5a278ff8f?w=562&amp;amp;h=349&amp;amp;f=jpeg&amp;amp;s=21082" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;张鹏波：UK8S 打造稳定易用的 Kubernetes 服务&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;K8S 本质上是弱租户概念，要通过 namespace 做隔离。但 UCloud 在 2018 年推出的 UK8S，作为公有云 K8S 服务，面临着租户隔离的强需求，否则用户是不接受的。为此我们提出 K8S 中所有资源对用户应该是专享的想法。&lt;/p&gt;

&lt;p&gt;这个首先体现在 VPC 网络，不同用户的 K8S 集群分布在不同的 VPC 里，网络是完全强制性隔离。其次是资源的租户隔离，包括 UHost 等计算资源隔离，Node 和 Master 隔离，以及存储插件包括块存储、文件存储的完全隔离。UK8S 为了提升易用性和可维护性，也针对性的给出了解决方案，例如提供一键创建 / 删除集群功能，支持集群规模自动拓展，支持 API Service 通过外网访问，提供跨可用区健壮性等。集群管理高可用架构如图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd3bbfa36e842?w=640&amp;amp;h=308&amp;amp;f=jpeg&amp;amp;s=22003" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;此外，还介绍了 UK8S 和 UCloud 裸金属产品金翼物理机的结合。物理机租赁的 TCO 非常有竞争力，而如果用户想运行 K8S，上面能提供预装好的 K8S 服务，存储和负载均衡也可以配套部署好。UK8S 下半年预计将服务扩展到 30 多个可用区，并提供新版应用商店等功能。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;乐心医疗 韦飞龙：Kubernetes 在乐心健康的探索与实践&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;乐心医疗的一个主要产品乐心手环，其后端服务通过 App 和用户交互。该服务自 2016 年起就已经全面运行在 K8S 上，当时是自建的集群。自建过程中遇到很多问题，比如要在测试、开发、生产三个环境中运行同一个镜像，按传统方式把服务配置打包成镜像是个问题。此外安装过程中，早先是手动依次安装二进制文件，需要逐个下载软件包并配置验证，非常耗费时间，近期开始使用 kubeadm 工具实现了快速安装。自建 K8S 集群时 kubernetes-sigs 工具的镜像下载不到，需要修改镜像地址再安装。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd3c0f75a98ae?w=640&amp;amp;h=287&amp;amp;f=jpeg&amp;amp;s=21427" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;考虑到种种维护的成本较高，现在已将业务全部迁移到 UK8S 上，好处是不需要再关心此前安装的组件，网络、存储的管理也变得容易。韦飞龙最后还介绍了 Apollo 配置中心的使用，相比此前另一个开源配置中心，启动时间节省十几秒。以及运用 Jenkins 进行 Pipeline 的并行发布，只要有一个发布失败就终止运行，节省了开发等待的时间。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;刘拓：K8S 在 StepFlow 项目中的运用&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;StepFlow 全称工作流引擎，它能把微服务 API 用流程的方式编排起来，不写任何代码的情况下即可构建应用。StepFlow 架构设计时采用了微服务的理念，因此自然而然想到容器化部署。但团队在容器化道路上遇到不少挑战，例如资源如何合理规划、高可用如何解决、服务间怎样互联等。头痛医头并不是个好办法，而 UCloud 面向内部的 K8S 平台 KUN（中文名：鲲）恰好能解决这些问题。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd3c64a08bf90?w=640&amp;amp;h=318&amp;amp;f=jpeg&amp;amp;s=18412" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;资源管理上 KUN 可以轻松做到高可用和跨可用区分布，也对业务完全透明。通过配置 service 可以让服务互联，此外还有配置管理、日志监控等能力。在社区支持上也更好，CNCF 中很多云原生的组件都可以直接使用。KUN 平台解放了业务方的生产力，使其可以专注于上层的镜像制作、自动化测试集、灰度系统等工作。StepFlow 整个项目都基于 KUN，短时间内就实现了一个 CI/CD 的 Pipeline，达到一键部署的效果，可以说是一次成功的基于云原生标准来打造应用程序的实践。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;蔡书：基于 Kong 的服务网格方案&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kong 是目前最受欢迎的 API 网关之一。它的特点一是智能易用，可以和微服务做集成，处理动态路由，底层对微服务做细粒度的分析统计。二是简单灵活，支持容器化的部署，且提供安装包。管理类功能都通过插件提供，插件非常丰富，形成了社区。另外吞吐率和延迟也都不错。&lt;/p&gt;

&lt;p&gt;Kong 的应用场景：一是做入口，流量都可从网关进来；二是微服务的可视化；三是黑色 / 灰色流量清洗，依赖特征识别；四是微服务支持，和服务注册中心绑定后使用方便，此外还有流量可视化、微服务质量管理等。技术实现上底层是 Nginx，上面是 OpenResty，其上还有 Clustering，保证水平扩展时配置实时生效。再上面是 RESTful 接口，不再需要修改 Nginx 配置文件，而是通过代码调用的方式完成。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd3cbb0331f9c?w=640&amp;amp;h=392&amp;amp;f=jpeg&amp;amp;s=26434" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;元年科技 王海峰：中小团队的 K8S 落地之路&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;K8S 技术相对复杂，受限于人力时更需了解如何能简单落地。王海峰认为首先是把要点思考清楚，比如一共需要哪些基础服务来保证大应用落地、如何构建一套简单的外部程序、线下线上如何采用统一的 K8S 环境来保证开发测试的一致性、统一的 K8S 接口该如何设计等。&lt;/p&gt;

&lt;p&gt;在元年科技的实践中，首先出于实际情况使用 Windows 服务器，主要是为了利用它账户凭证的特性。其次利用 Jenkins 来完成外部浏览器端 DevOps 流程的触发，通过批处理和脚本简单的搞定流程线。线下用 Rancher 在三台物理机上部署环境，线上环境为了减少运维人力，直接用 UCloud 镜像库和 UK8S，省去集群维护精力。线上线下采用蒲公英第三方服务打通，提供 DevOps 通信。而在 K8S 集群的通信上，采用了 REST 风格的 API，用 Curl 的 Post、Delete 等方法，可以设计部署、删除 API 等。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd3d12ea6ede4?w=640&amp;amp;h=427&amp;amp;f=jpeg&amp;amp;s=34218" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;关于本次演讲的更多技术内容，敬请关注“UCloud 技术”公众号回复“K8S”即可获取讲师演讲 PPT。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/23/16cbd3d576128750?w=640&amp;amp;h=355&amp;amp;f=jpeg&amp;amp;s=32528" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 23 Aug 2019 14:56:08 +0800</pubDate>
      <link>https://ruby-china.org/topics/38968</link>
      <guid>https://ruby-china.org/topics/38968</guid>
    </item>
    <item>
      <title>镜像即代码：使用 Packer 实现自动化构建镜像</title>
      <description>&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;云主机是用户使用最高频的云产品之一。随着云主机数量的增多，如何在云主机中保证版本化部署的一致性，成为用户常见的难题。在现有情况下，用户首先需要手动或使用脚本连接主机，然后再进行部署安装，操作流程复杂且对环境要求苛刻，难以保证一致性和可用性。&lt;/p&gt;

&lt;p&gt;为了解决此类问题，UCloud 开发了相关代码，并被自动化构建镜像工具 Packer 的官方仓库所采纳。通过 Packer 创建自定义镜像，可以减少部署时间并提高可靠性，提高了用户自动化部署的能力。8 月 14 日，Hashicorp 官方正式发布了版本 1.4.3，其中包括了 UCloud Packer Builder。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/7b158dc7e1de4533966a3f063fc3fc6d" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Packer 是什么？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Packer 是 Hashicorp 公司推出的自动化打包镜像的轻量级开源工具，云厂商通过构建自己的 Builder 集成到 Packer 中去，即可凭借单一配置文件，高效并行的为多云平台创建一致性的镜像。目前 Packer 已经形成完整生态，并与多家主流云厂商建立合作。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/da2328d41da0487dbf898912b2d9441b" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;UCloud Packer 可以运行在常用的主流操作系统上，它不是 Chef、Puppet 等软件的替代品，而是集成并使用这些自动化配置工具在镜像上预装软件等。再配合 UCloud Terraform、UCloud CLI 等工具，可以在多云的 DevOps 场景下，实现基础设施即代码（IaC）、持续集成和快速交付。&lt;/p&gt;

&lt;p&gt;如下图所示，Packer 通过在 Provisioner 中集成 Chef、Shell、Puppet 等工具，制作包含各类软件的不可变镜像，供多云平台的云主机、Docker 等使用。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/b1b333d1fe9946b9942e62a97686e182" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hashicorp 官方将 Packer 的优势描述如下：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.    基础架构迅速部署：&lt;/strong&gt;Packer 镜像可以在几秒钟内启动完全配置的云主机，有利于生产和开发；&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.    多提供商可移植性：&lt;/strong&gt;Packer 可以为多云平台创建了相同的镜像，每个环境都能运行相同的机器镜像，提供最终的可移植性；&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.    稳定性高：&lt;/strong&gt;Packer 在构建镜像时会为机器安装和配置所有软件。如果脚本中存在错误，可以被提前捕获，而不是在启动计算机几分钟后；&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.    可测试性高：&lt;/strong&gt;Packer 在构建机器镜像后，可以快速启动该机器镜像并进行冒烟测试，以验证镜像是否正常工作。如果是正常工作，则可以确信从该镜像启动的任何其他计算机都能正常运行；&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.    可扩展性高：&lt;/strong&gt; Packer 的插件机制使得它能够自如的根据需求集成工具和拓展功能。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Packer 与传统控制台创建镜像的对比：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/594125f05b1947b497c130ebdd0110ad" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;生命周期&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;利用 Packer 打包镜像的完整周期如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/f107044574964c59a146b4ababf2be2e" title="" alt=""&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;用户通过构建 JSON 模版，执行 packer build 命令调用 UCloud Builder；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;参数提前校验保证可用性；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;创建云主机、EIP 等相关临时资源（若配置为内网环境则无需 EIP）；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;通过 SSH 或 WinRM 等连接主机，执行 Provisioner 进程；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;关闭云主机，并创建镜像；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;复制镜像；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;删除主机、EIP 等临时资源；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;执行后处理进程（如本地镜像导入等）。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;使用演示&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;下面通过一个视频来形象地展示 Packer 的使用方式。目标是构建一个装有 nginx 应用的镜像，我们首先创建一个 test.json 文件，然后执行如下命令一键构建镜像：&lt;/p&gt;

&lt;p&gt;packer build test.json&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Packer 对多云管理的价值&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在此次 Hashicorp 官方发布前，UCloud 内部已经积累了一定的 Packer 使用经验。从中发现，如果需要管理多云环境，或者要在公有云与私有云间维护相同的系统，又或者构建的是虚拟机而不是容器，Packer 都是一个很好的选择。&lt;/p&gt;

&lt;p&gt;通过一个具体例子来说明。下面这段代码定义了一个 UCloud 公有云上的虚拟机镜像，Packer 利用 ucloud-uhost Builder 配置的参数，先创建一个干净的 CentOS 7 系统，再 ssh 执行 provisioner 定义中指定的三段 shell 脚本，最终成功创建镜像并返回镜像 ID。&lt;/p&gt;

&lt;p&gt;{ "variables": { "ucloud_public_key": "{{env &lt;code&gt;UCLOUD_PUBKEY&lt;/code&gt;}}", "ucloud_private_key": "{{env &lt;code&gt;UCLOUD_SECRET&lt;/code&gt;}}", "ssh_user": "root", "ssh_password": "password", "ucloud_project_id": "org-projectid", "image_id": "uimage-dpdgyw", "consul_version": "1.5.1", "region": "cn-bj2", "az": "cn-bj2-02" }, "builders": [ { "type": "ucloud-uhost", "public_key": "{{user &lt;code&gt;ucloud_public_key&lt;/code&gt;}}", "private_key": "{{user &lt;code&gt;ucloud_private_key&lt;/code&gt;}}", "project_id": "{{user &lt;code&gt;ucloud_project_id&lt;/code&gt;}}", "region": "{{user &lt;code&gt;region&lt;/code&gt;}}", "availability_zone": "{{user &lt;code&gt;az&lt;/code&gt;}}", "instance_type": "n-basic-2", "source_image_id": "{{user &lt;code&gt;image_id&lt;/code&gt;}}", "ssh_username": "{{user &lt;code&gt;ssh_user&lt;/code&gt;}}", "ssh_password": "{{user &lt;code&gt;ssh_password&lt;/code&gt;}}", "image_name": "consul-server-{{user &lt;code&gt;consul_version&lt;/code&gt;}}" } ], "provisioners": [ { "type": "shell", "scripts": [ "scripts/config-yum.sh", "scripts/consul-service.sh", "scripts/consul-server.sh" ], "environment_vars": [ "CONSUL_VERSION={{user &lt;code&gt;consul_version&lt;/code&gt;}}" ] } ] }&lt;/p&gt;

&lt;p&gt;此时若有额外需求，要求将其也部署到私有云的 Kubernetes 上，该怎么办？一种方法是把 shell 脚本改写成对应的 Dockerfile，但若是构建过程非常复杂，那么改写的过程也会很复杂，并且可能引入错误。&lt;/p&gt;

&lt;p&gt;但用 Packer，只需要修改一下 builder 配置的细节：&lt;/p&gt;

&lt;p&gt;{ "variables": { "consul_version": "1.5.1" }, "builders": [ { "type": "docker", "image": "centos:7", "commit": true, "changes": [ "CMD [\"tail -f /dev/null\"]", "ENTRYPOINT [\"\"]" ] } ], "provisioners": [ { "type": "shell", "scripts": [ "scripts/config-yum.sh", "scripts/consul-service.sh", "scripts/consul-server.sh" ], "environment_vars": [ "CONSUL_VERSION={{user &lt;code&gt;consul_version&lt;/code&gt;}}" ] } ], "post-processors": [ [ { "type": "docker-tag", "repository": "lonegunmanb/consulServer", "tag": "0.1" }, "docker-push" ] ] }
在公有云平台上已经过测试的构建脚本，就可以直接用来构建 Docker 镜像，并且在构建完成后，自动打上 tag，push 到 Docker Hub 仓库去。并且，由于 Packer 是执行完 provisioner 后，通过 docker commit 的方式构建镜像，所以 Packer 的构建只会增加额外的一个层，避免不恰当的 Dockerfile 增加多个层的问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Packer +Terraform, 1+1&amp;gt;2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Packer 配合 Git、Terraform、UCloud CLI 等使用，可以实现 DevOps 下的基础设施即代码（IaC），达到持续集成和快速交付。&lt;/p&gt;

&lt;p&gt;如下图，Packer 配合 Git 对镜像的配置文件做版本化控制，从而来实现服务的版本化，保证了实例的最终一致性，然后利用 Packer 和 Terraform 自动化构建服务的目的。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/8d9453aecae241658ff756c3a1cbd06a" title="" alt=""&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;在自动化流程中，首先变更镜像配置仓库，触发执行 Terraform 命令；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Terraform 执行 packer build 命令构建镜像；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;将制作成功的镜像查询给 Terraform 使用；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;最后由 Terraform 构建并启动新实例替换原有的旧实例，完成服务自动化部署。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;UCloud 此前已提供对 Terraform 的官方集成，可通过产品文档了解更多详情。文档链接：&lt;a href="https://docs.ucloud.cn/compute/terraform/index" rel="nofollow" target="_blank"&gt;https://docs.ucloud.cn/compute/terraform/index&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCloud 通过对 Packer 的接入，提供了一种在云主机中自动化配置环境的能力，而且它可以配合 cloud-init 及一些常用的自动化部署软件使用，进一步拓展功能。另外，通过配合 UCloud Terraform、UCloud CLI 等工具，可以实现对基础架构的版本化和代码化管理，达到精准交付和快速部署以及最终一致性。&lt;/p&gt;

&lt;p&gt;官方参考文档地址：&lt;a href="https://www.packer.io/docs/builders/ucloud-uhost.html" rel="nofollow" target="_blank"&gt;https://www.packer.io/docs/builders/ucloud-uhost.html&lt;/a&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Tue, 20 Aug 2019 14:26:41 +0800</pubDate>
      <link>https://ruby-china.org/topics/38958</link>
      <guid>https://ruby-china.org/topics/38958</guid>
    </item>
    <item>
      <title>巧用命令行工具 UCloud CLI，轻量操作 API 管理云资源</title>
      <description>&lt;p&gt;截止目前，UCloud 已提供 Python/Java/Golang 等不同语言的 API SDK。为进一步降低用户的运维人力投入，又推出了基于 Golang SDK 的命令行工具 CLI（Command Line Interface），提供轻量化的 API 命令行调用方式，并在 GitHub 开源（&lt;a href="https://github.com/ucloud/ucloud-cliCLI%E7%9A%84%E5%91%BD%E4%BB%A4%E8%A1%8C%E4%BA%A4%E4%BA%92%E6%96%B9%E5%BC%8F%E6%9B%B4%E7%AC%A6%E5%90%88%E7%A0%94%E5%8F%91%E8%BF%90%E7%BB%B4%E7%9A%84%E6%93%8D%E4%BD%9C%E4%B9%A0%E6%83%AF%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%B8%80%E4%BA%9B%E5%85%B8%E5%9E%8B%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E9%80%9A%E8%BF%87CLI%E4%B9%9F%E6%9B%B4%E5%AE%B9%E6%98%93%E4%BB%A3%E7%A0%81%E5%8C%96%E7%9A%84%E6%B2%89%E6%B7%80%E5%92%8C%E7%BB%B4%E6%8A%A4%E3%80%82" rel="nofollow" target="_blank"&gt;https://github.com/ucloud/ucloud-cliCLI的命令行交互方式更符合研发运维的操作习惯，并且一些典型使用场景通过CLI也更容易代码化的沉淀和维护。&lt;/a&gt;）。&lt;/p&gt;

&lt;p&gt;下面是一些用户遇到的实际场景，用 CLI 都能更好地解决，在此总结并给出使用示例。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;场景一：大批量创建和删除主机&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PingCAP 作为一家专业的分布式数据库供应商，使用 UCloud 时需要一次性批量创建 300 台云主机，进行分布式业务测试。而 UCloud 控制台一次最多允许创建 10 台云主机，因此需要用户进行傻瓜式操作 30 次。但是，主机 API 实际可以支持最多 1000 台并发创建。对于一次性 API 操作，花时间用 SDK 编写创建脚本的投入产出比很低。此类场景 PingCAP 便是通过 CLI 解决。&lt;/p&gt;

&lt;p&gt;该场景的示例命令如下：&lt;/p&gt;

&lt;p&gt;$ ucloud uhost create —cpu 1 —memory-gb 2 —image-id uimage-xxx —password test123 —count 300
&lt;img src="https://user-gold-cdn.xitu.io/2019/8/16/16c99c5ff0df8c87?w=640&amp;amp;h=279&amp;amp;f=jpeg&amp;amp;s=19030" title="" alt=""&gt;
（图：控制台页面主机创建一次性最多 10 台并发）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;场景二：集中化管理/清理资源，不易遗漏&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;用户经常购买多种产品，每种的数量不一，部分应临时需求而创建的资源，结束使用后常忘记及时删除，因为分布零散不易管理，不知不觉中花了不少钱。如 X.D. GLOBAL 等用户，则善于利用 CLI 快速创建并及时清理不用的资源。&lt;/p&gt;

&lt;p&gt;示例命令如下：&lt;/p&gt;

&lt;p&gt;$ ucloud uhost delete --uhost-id &lt;code&gt;ucloud uhost list --uhost-id-only --page-off&lt;/code&gt;
&lt;img src="https://user-gold-cdn.xitu.io/2019/8/16/16c99c6347dbb24b?w=640&amp;amp;h=325&amp;amp;f=jpeg&amp;amp;s=15366" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;（图：控制台零散的产品资源）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;场景三：全球动态加速 PathX 实例大量端口管理&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;海外游戏发行商为了提高玩家体验，经常使用 UCloud 全球动态加速服务 PathX 实现各地区玩家就近接入，有效规避跨国网络拥塞导致的响应慢、丢包等问题。&lt;/p&gt;

&lt;p&gt;某游戏公司也使用了 PathX，但其单条线路需要管理的端口数量超过 60 个。方法一，产品首先得在控制台非标支持 60 个端口管理，然后用户在页面对所有端口逐一添加配置。方法二是架构师编写脚本，用户通过参数更新调整端口。不过，伴随产品迭代、API 调整，脚本的升级成为一个问题，强依赖双方配合。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/16/16c99c76a90eae97?w=640&amp;amp;h=434&amp;amp;f=jpeg&amp;amp;s=24403" title="" alt=""&gt;
（图：控制台 PathX 支持 9 个端口协议管理）&lt;/p&gt;

&lt;p&gt;CLI 通过沉淀这样的场景，直接支持了 PathX 多端口管理，示例代码如下：# 给 PathX 指定的线路实例资源添加 80 个 TCP 端口&lt;/p&gt;

&lt;p&gt;$ ucloud pathx uga add-port --uga-id uga-kjkxxx --protocol tcp --port 3000-3079,8080&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;场景四：频繁批量切换 EIP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;某资讯行业用户由于业务场景需要，会频繁触发其服务切换外网 IP。投入研发人力以脚本实现该需求，已是行业内非常通用的做法。而使用 UCloud CLI 能以轻量的方式完成目标。&lt;/p&gt;

&lt;p&gt;示例代码如下：# 创建 eip 并绑定，然后解绑释放之前已绑定的 eip&lt;/p&gt;

&lt;p&gt;$ ucloud ext uhost switch-eip --create-eip-bandwidth-mb 2 --uhost-id xxx --unband-all --release-all
&lt;img src="https://user-gold-cdn.xitu.io/2019/8/16/16c99c7aef8473de?w=640&amp;amp;h=222&amp;amp;f=jpeg&amp;amp;s=14833" title="" alt=""&gt;
（图：控制台先解绑再绑定新 EIP）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UCloud CLI 的便捷之处&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.多维度支持命令补全功能&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在命令补全方面，通常每次发布新版本都需要终端用户再次生成补全脚本，功能局限并且使用成本较高。因此，UCloud CLI 扩展了 spf13/cobra 框架的功能（相关代码已开源&lt;a href="https://github.com/lixiaojun629/cobra" rel="nofollow" target="_blank"&gt;https://github.com/lixiaojun629/cobra&lt;/a&gt;），把命令补全功能集成到命令行工具内部，用户只需要一次配置，日后版本升级都不必再重新生成补全脚本，使用方便。&lt;/p&gt;

&lt;p&gt;补全功能包括：支持命令补全、命令参数补全、命令参数值静态补全以及命令参数值动态补全等。针对命令参数值动态补全，为了减少调用 API 次数、避免卡顿，UCloud CLI 还添加了动态补全本地缓存特性。&lt;/p&gt;

&lt;p&gt;命令参数值静态补全以及命令参数值动态补全的代码示例见下图所示，其中参数 line 的可选值 BGP 和 International 是固定在代码里的静态枚举值，参数 eip-id 的可选值是由 Tab 键触发的 API 请求得到的。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/16/16c99c7f2f5adbe6?w=1080&amp;amp;h=165&amp;amp;f=jpeg&amp;amp;s=13219" title="" alt=""&gt;
（图：命令参数值静态补全）&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/16/16c99c822c4a52b6?w=1080&amp;amp;h=58&amp;amp;f=jpeg&amp;amp;s=14438" title="" alt=""&gt;
（图：命令参数动态补全）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.命令编写更简单高效&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCloud CLI 批量操作资源时原生支持并发、UI 多线程渲染等，相比开启多进程执行命令行，占用系统资源更少，而且命令编写更加简单，降低运维代码成本。例如批量删除主机命令：&lt;/p&gt;

&lt;p&gt;#命令 1&lt;/p&gt;

&lt;p&gt;$ ucloud uhost list --uhost-id-only | xargs -P 32 -I {} ucloud uhost delete --yes --uhost-id {}
#命令 2&lt;/p&gt;

&lt;p&gt;$ ucloud uhost delete --uhost-id &lt;code&gt;ucloud uhost list --uhost-id-only --page-off&lt;/code&gt;
很明显命令 2 更加简单，可以有效减少运维人员的代码操作。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/16/16c99c8ad29dd9ee?w=1080&amp;amp;h=244&amp;amp;f=jpeg&amp;amp;s=19963" title="" alt=""&gt;
（图：并发创建主机时，UI 多线程渲染）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.稳定可靠&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;由于 UCloud CLI 使用了 spf13/cobra 命令行开发框架，它也是 Docker、Kubernetes 和 etcd 等著名开源项目的 CLI 使用框架，久经考验，稳定可靠。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.丰富的产品支持&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在产品支持方面，目前 UCloud CLI 已经支持主机、网络、存储和数据库等常用云产品服务，基本能够满足用户大部分使用场景下的日常操作需求，支持产品列表见下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/16/16c99c8f21168714?w=640&amp;amp;h=485&amp;amp;f=jpeg&amp;amp;s=38334" title="" alt=""&gt;
（图：CLI 支持产品）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;在 Docker 中运行 UCloud CLI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在 Docker 中也可以快速地使用 UCloud CLI，按下面的操作步骤示例，就可以体验了。&lt;/p&gt;

&lt;p&gt;1.首先安装 Docker，拉取我们为你准备好的镜像：uhub.service.ucloud.cn/ucloudcli/ucloud-cli:0.1.20&lt;/p&gt;

&lt;p&gt;$ docker pull uhub.service.ucloud.cn/ucloudcli/ucloud-cli:0.1.20
此镜像的构建脚本如下：&lt;/p&gt;

&lt;p&gt;FROM ubuntu:18.04RUN apt-get update &amp;amp;&amp;amp; apt-get install wget -yRUN wget &lt;a href="https://github.com/ucloud/ucloud-cli/releases/download/0.1.20/ucloud-cli-linux-0.1.20-amd64.tgzRUN" rel="nofollow" target="_blank"&gt;https://github.com/ucloud/ucloud-cli/releases/download/0.1.20/ucloud-cli-linux-0.1.20-amd64.tgzRUN&lt;/a&gt; tar -zxf ucloud-cli-linux-0.1.20-amd64.tgz -C /usr/local/bin/RUN echo "complete -C $(which ucloud) ucloud" &amp;gt;&amp;gt; ~/.bashrc #配置自动补全
2.执行以下命令，以 uhub.service.ucloud.cn/ucloudcli/ucloud-cli:0.1.20 为镜像启动一个容器，容器名字为 ucloud-cli：&lt;/p&gt;

&lt;p&gt;$ docker run --name ucloud-cli -it -d uhub.service.ucloud.cn/ucloudcli/ucloud-cli:0.1.20
3.执行如下命令连接到容器 ucloud-cli，连接成功后即可开始使用 ucloud-cli，建议先执行 ucloud init 命令初始化配置。&lt;/p&gt;

&lt;p&gt;$ docker exec -it ucloud-cli bash&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCloud CLI 的一个重要意义在于能够将 API、事务等有机组合，场景化支持用户的需求，把耗费人力的资源管理以标准化形式呈现，给用户提供便捷灵活的产品解决方案。未来，UCloud CLI 也将在更多的使用场景下帮助运维者摆脱操作难题，欢迎大家点击阅读原文链接下载试用并提出反馈意见。（安装使用指南：&lt;a href="https://docs.ucloud.cn/software/cli/intro" rel="nofollow" target="_blank"&gt;https://docs.ucloud.cn/software/cli/intro&lt;/a&gt;）。&lt;/p&gt;

&lt;p&gt;巧用命令行工具 UCloud CLI，轻量操作 API 管理云资源&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;活动推荐：8 月 17 日在上海原境界美术馆，【UCan 下午茶—云原生 Kubernetes 的开发和运维】技术沙龙将邀请六位资深技术专家进行深入的技术探讨和实践案例分享。欢迎扫描下方二维码报名参加！&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/8/16/16c99c9371e85f18?w=640&amp;amp;h=285&amp;amp;f=jpeg&amp;amp;s=24743" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 16 Aug 2019 17:51:57 +0800</pubDate>
      <link>https://ruby-china.org/topics/38948</link>
      <guid>https://ruby-china.org/topics/38948</guid>
    </item>
    <item>
      <title>PostgreSQL UDB，让 31 会议数据管理更高效可靠</title>
      <description>&lt;p&gt;“PostgreSQL UDB 用在大数据分析上，查询效率更高。相比自建，其可靠性更高，方便运维维护。”&lt;/p&gt;

&lt;p&gt;— 31 会议运维经理 汤雷&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;如何用好 PostgreSQL?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL 是业内一款十分流行的开源数据库，和 MySQL、MongoDB 等并列第一梯队。&lt;/p&gt;

&lt;p&gt;PostgreSQL 支持多种表关联算法，有丰富的统计函数和语法，面对多维度的复杂查询和分析场景性能表现优异。而 MySQL 和 MongoDB 也各有亮眼特性和众多拥趸。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/f32c76b77fea443ba0d792486baba91f" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;客观来说，这几种数据库各擅胜场，没有必要简单比较孰优孰劣，而是应该充分了解各自的特点，根据业务需求合理决策和巧妙搭配，从而获得最大化的效果。&lt;/p&gt;

&lt;p&gt;UCloud 用户 31 会议的实践案例，可以帮助说明 PostgreSQL 在解决大数据量快速查询上成功应用的法门。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;用户场景&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;31 会议是中国领先的场景营销科技服务商，隶属于上海八彦图信息科技有限公司。通过运用互联网、物联网、AI、大数据和云计算技术，并结合会议、展览、活动等面对面营销场景，其陆续推出了会议云、展览云、营销云三大产品体系以及 10 个行业场景方案。其中，31 会议云和 31 会展云作为一站式数字会务 SaaS 云平台，通过组件化、集成化、流程化实现会展全流程智慧化。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/ca2715d11e6243b2a1770730c2b28c0c" title="" alt=""&gt;
注：图片来自 31 会议&lt;/p&gt;

&lt;p&gt;可以想见，SaaS 化的会议平台，内部模块众多且关联紧密，对数据库的需求呈现多样化和精细化的特点，所以首要的是调研了解市面上可获取的主流数据库类型。UCloud 能提供的 UDB 子类型如下表：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/db12597d29cb4b9d8eb4df1f766b0c59" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;由于用户的业务特点，其对 OLTP 和 OLAP 都有重要的诉求，而截至目前累计服务 30 多万家客户、130 多万场会展的业务量，意味着数据库的存储量也很可观。&lt;/p&gt;

&lt;p&gt;经过审慎考虑，用户同时选用三种数据库，针对性的满足不同目标。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/60f4f9d5a06a4d0a967d1f0f94100773" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;其中，PostgreSQL 相比于 MySQL 在 OLAP 上的快速高效是其优势，也是用户选型 PostgreSQL 的重要砝码。在实际业务中，用户利用 PostgreSQL 来处理单表 500w 条记录规模的大数据量查询，并且快速流畅的将结果流转到下一业务环节。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;自建集群还是 PostgreSQL UDB?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;现在需要面对的选择，是利用云主机自己搭建 PostgreSQL 集群，还是直接使用 UCloud 现成的 PostgreSQL UDB 产品？&lt;/p&gt;

&lt;p&gt;PostgreSQL UDB 具备高安全性和高可用性，并有备份创建、自动回档等功能。数据层面来讲，高可用主备和底层数据存储，具备数据冗余，可以保证数据零丢失。&lt;/p&gt;

&lt;p&gt;基于产品层面提供的这些要素，31 会议选择了使用 PostgreSQL UDB 产品。让我们感到欣慰的是，在该用户使用 PostgreSQL 的一年多时间内，其实例没有发生过一次故障，后台对可靠性设计的机制抵御住了各种意外状况，没有影响用户正常使用，帮助其免去了紧急排障的烦恼。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;如何保证高可靠？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为了充分保证可靠性，PostgreSQL UDB 产品化方面做了多项工作，例如：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. 自动回档&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这个功能是指，当用户出现人为误操作造成数据删除或者丢失时，只要之前 7 天的备份存在，就可以利用“秒级回档”功能将数据恢复到过去 7 天内的任意一秒，可以说是为用户使用 PostgreSQL 产品提供了一颗“定心丸”。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/e537228895e24b9db077a15f913a4316" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;除了回档，用户也可通过“创建从库”功能来创建更多数据库的副本，进一步增加数据的安全性。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. 高可用部署，自动容灾&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL UDB 为确保服务的高可用性，采用主从复制架构，主数据库提供服务的同时，有另一套数据库服务不断同步数据并随时待命，UDB 后台的自动容灾模块可以在 PostgreSQL 实例服务出现问题时自动探测到，并自动容灾，保证数据库服务的稳定可靠。&lt;/p&gt;

&lt;p&gt;实例切换时，容灾模块会把待命的备用 PostgreSQL 服务提升为主库，并且在原来主服务启动之后回退到从库。整个过程中用户不需要任何人工干预和配置修改，真正做到自动容灾。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/80b09aef2d4b492ea40ac1cc9a3ee48e" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：PostgreSQL UDB 自动容灾示意图&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. 热升级，不停服在线扩容&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL UDB 可依据业务的需要，动态按需扩展数据库资源。用户只需在控制台上进行几次点击，就可以动态调整实例的内存和磁盘大小，满足不同业务阶段对于数据库性能和存储空间的弹性需求。&lt;/p&gt;

&lt;p&gt;PostgreSQL UDB 在资源扩容过程中，数据库服务可以做到基本不停服，只有秒级的闪断。这样大大减少了数据库扩容对于业务的影响时间，做到真正的“热升级”。&lt;/p&gt;

&lt;p&gt;目前，PostgreSQL UDB 在北京、上海、广州和香港等多地上线服务，具体部署情况如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/55f1dd36ba8f4caaa9de6df297baed04" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 26 Jul 2019 17:25:14 +0800</pubDate>
      <link>https://ruby-china.org/topics/38878</link>
      <guid>https://ruby-china.org/topics/38878</guid>
    </item>
    <item>
      <title>Kubernetes 如何加速 UCloud 内部代码部署的 CI/CD 流程</title>
      <description>&lt;p&gt;UCloud 内部长期使用 Gitlab 来管理代码。虽然 Gitlab 作为一套开源平台已很优秀，但我们对于其能为 CI/CD 提供的敏捷性并不十分满意，内部实践中的代码发布周期仍需按天计算。为此，我们打造了一个基于 Kubernetes 的内部容器服务平台（名为 KUN），用于托管内部服务，并将 Gitlab 对接到 KUN 平台，从而借助 Kubernetes 的云原生优势，获得更好的 CI/CD 效果。这套系统运行一年内，Gitlab 的 Pipeline 一共触发了 994 次，执行了约 20000+ 次 Job，在测试环境和正式环境一共进行了 7000+ 次部署，即每天部署约 20 次。以下是该项目的一些实践经验。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;我们对 CI/CD 的目标&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CI 即 Continuous Integration（持续集成），指代码集成到主干之前必须通过自动化测试，只要有一个测试用例失败，就不能集成。目的是让产品快速迭代的同时还能保持高质量。&lt;/p&gt;

&lt;p&gt;CD 有两种意思：&lt;/p&gt;

&lt;p&gt;Continuous Delivery，持续交付，指的是任何的修改都经过验证，可以随时实施部署到生产环境。
Continuous Deployment，持续部署，是持续交付的更高阶段，指的是任何修改后的内容都经过验证，自动化的部署到生产环境。
两者的区别，在于是否自动部署到生产环境。对 UCloud 而言，肯定要以后者，也就是持续部署为目标。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/13d31b0a90be431381999d5a4295d90b" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gitlab 分支管理&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;我们采用的 Gitlab 分支管理模型在接入 KUN 平台前后并未发生变化，故简述如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/4554ba8924ac4b92846a1ec22c3b402f" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;master：主分支，代码经过验证。从 master 创建 tag 进行 Release。
dev：研发主分支，用于合入特性分支和补丁分支，在此分支。&lt;/p&gt;

&lt;p&gt;临时分支：
特性分支：用于开发某个特性；
补丁分支：用于修复线上 bug。
下面以一个实例来介绍 CI/CD 开发流程。StepFlow 是 UCloud 新近推出的一款可视化工作流产品，通过 StepFlow 用户可以灵活便捷地定义自己的工作流，快速实现业务功能。整套 StepFlow 系统由多个模块组成，并全部部署在 Kubernetes 集群上。&lt;/p&gt;

&lt;p&gt;在实例中，我们需要开发其中名为 optimize-allocate 的一个 feature：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/e8ca9619513e4503a434d64af3129a16" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;则开发流程为：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;首先，在 Gitlab 上创建了编号为 80 的 Issue，跟进这个 optimize-allocate 的 feature；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;从 dev 分支创建一个新分支，名为 feature/80-optimize-allocate，在该分支上进行开发；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在 feature/80-optimize-allocate 上开发完成，进行 commit，此时会触发静态测试、单元测试、Review 等 Pipeline Job；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;测试通过后，创建一个从 feature/80-optimize-allocate 到 dev 的 merge request，由负责人进行审核。审核通过并且 merge 成功后，触发静态测试、单元测试、镜像构建、镜像部署、集成测试等 Pipeline Job；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;测试通过后，创建一个从 dev 到 master 的 mergerequest，由负责人进行审核。审核通过并且 merge 成功后，负责人创建 tag v1.1.1，然后触发静态测试、单元测试、镜像构建、镜像部署、集成测试等 Pipeline Job；&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;注：版本号 tag 是有命令规范的，v{x}.{y}.{z}代表着 v{主版本}.{次版本}.{小修订版本}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gitlab CI/CD Pipeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Gitlab 8.0 版本以后，默认集成并开启了 Gitlab-CI，是可以提供一定 CI 能力的，我们以此搭建持续集成的流水线，其中有 Pipeline、Stage 和 Job 三个层级需要设计。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pipeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Gitlab 会检测一个项目的根目录下的 .Gitlab-CI.yml 文件，用户可在该文件中定义 CI/CD Pipeline，一个 Pipeline 代表了 CI/CD 的整个过程。代码发生变化时（比如 push、tag、merge 等），将触发一个 Pipeline 的运行。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;一个 Pipeline 包含多个 Stage，比如“静态检查”、“单元测试”、“构建镜像”等等，这些 Stage 一个接一个顺序执行。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/6f29421cc8b542b88807fdf27e063b0a" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Job&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;每一个 Stage 可以包含多个 Job，同一个 Stage 的所有 Job 同时执行。每个 Job 需指定若干个重要属性如 image, stage, tags, service 等。&lt;/p&gt;

&lt;p&gt;在 StepFlow 例子中，针对要开发的 feature，其 Pipeline 设计如下，包括静态检查、单元测试和最后的两个手动 Code Review：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/613ff47bf16347deab503c7045d69931" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;当其需要发布到公共测试环境（类似预发布环境），则设计另一个 Pipeline，包括：执行完整的静态检查，单元测试，预发布镜像 build, 预发布部署，预发布集成测试。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/ff2e4652baa44086a44b0f883c31b254" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;而合并 master 之后触发 prod 环境的另一个 Pipeline，包括静态检查、生产环境镜像的 build、生产环节的部署、最后集成测试：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/9a22c243e6434b3c80985c35ad3f2b85" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gitlab Runner&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/a9d50e17f9fd410c93ddb246ac4c811d" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;我们将 Gitlab Runner 和 Gitlab-CI 配合使用，负责具体 Job 的运行。Gitlab Runner Kubernetes Executor 提供了在 Kubernetes 中运行 Job 的能力。运行原理如下：&lt;/p&gt;

&lt;p&gt;Gitlab Runner 需要事先部署并注册到 Gitlab 上；
当代码发生更新时，Gitlab 根据用户的配置，通知 runner 来运行 Job；
Gitlab Runner 使用某个镜像来创建一个 Pod，然后在其中运行某些命令；
Gitlab Runner 将整个运行过程以及运行结果告诉 Gitlab。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kaniko 集成和改造：在容器中构建 Docker 镜像&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为了使用 CI/CD 将代码变成最终运行在 Kubernetes 中的服务，必不可少的一步就是容器镜像的构建。由于 CI Job 本身就是以容器的形式运行的，所以需要在容器中构建出 Docker 镜像。&lt;/p&gt;

&lt;p&gt;已有的方法，包括把 Host 上的 Docker Socket 挂载到 Pod 里面去（Docker Socket Mounting），或者是在 Pod 再启动一个 Docker Daemon（Docker-in-Docker），然而，前者有安全风险，后者需要 Pod 具备特权，两种方法都不适合。&lt;/p&gt;

&lt;p&gt;Kaniko（&lt;a href="https://github.com/GoogleContainerTools/kaniko" rel="nofollow" target="_blank"&gt;https://github.com/GoogleContainerTools/kaniko&lt;/a&gt;）是 Google 开源的一个工具，可以实现在 docker 容器里面制作 docker 镜像，并且不需要任何特权。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/c2a68571a52d4b838b8c81ce7e7aa79c" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;但是原生的 Kaniko 镜像由于缺少一些必要的工具，无法和 Gitlab CI 集成。为此我们修改了 Kaniko 镜像，添加了整个 busybox 工具包进去，以支持其作为一个 CI Job 来运行。然后就可以把 Gitlab 往内部容器服务平台 KUN 对接了。代码示例如下：&lt;/p&gt;
&lt;h2 id="use Docker:$ cd /path/to/project &amp;amp;&amp;amp; \ docker build -t uhub.service.ucloud.cn/myimage:0.0.1 -f deploy/Dockerfile &amp;amp;&amp;amp; \ docker push uhub.service.ucloud.cn/myimage:0.0.1# use Kaniko:$ /kaniko/executor -c /path/to/project -f deploy/Dockerfile -d uhub.service.ucloud.cn/myimage:0.0.1"&gt;use Docker:$ cd /path/to/project &amp;amp;&amp;amp; \ docker build -t uhub.service.ucloud.cn/myimage:0.0.1 -f deploy/Dockerfile &amp;amp;&amp;amp; \ docker push uhub.service.ucloud.cn/myimage:0.0.1# use Kaniko:$ /kaniko/executor -c /path/to/project -f deploy/Dockerfile -d uhub.service.ucloud.cn/myimage:0.0.1&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;KUN+Gitlab：基于 Kubernetes 的 CI/CD 流程&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/3871cad4379c4700af4d0553b1b9eca5" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;KUN 中 CI/CD 的整个流程如上图所示。从图中我们可以看到，CI 部分是一个单元测试，预发布部署，集成测试，Debug，提交代码的循环过程。在 CI 过程中预发布的部署是通过 CD 系统来实现的，CI 其中一个步骤是生成部署文件，然后按照项目、资源集、版本等参数提交到 CD 后端系统。CD 系统提供了页面入口，当部署文件推送到 CD 系统后，用户可以在页面查找对应的部署文件。如果需要部署，在页面点击“部署”按钮即可实现部署。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YAML 编辑器&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为方便用户使用，我们为 KUN 开发了专门的 YAML 编辑器，相比用普通的文本编辑器写 YAML，可以提供智能模板补全、搜索替换等能力。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/e7dbb916cfc849548ff4ea0c147cad62" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;上图展示了一个使用案例，目前页面编辑器支持的功能有：&lt;/p&gt;

&lt;p&gt;Snippet：模版补全，用户编辑文档时，会提示相关模版，可选择直接模版输入&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/c5ad0d77fd3c40de8e8fa7188f6de5d3" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;Hover：用户鼠标放置关键字，提示关键字含义和官方文档链接&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/f80dccbfaea942768eebd395eaf94f51" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;搜索替换：使用⌘+F/Ctrl+F 打开页面搜索支持页面直接查询&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/0bdf027b7f6242d1a95cfacc7942e088" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;部署系统&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为了在 Gitlab CI Job 中把服务部署到 Kubernetes 上，我们研发了部署系统。在 CI Pipeline 的最后一步，用户生成一个 YAML 文件，定义需要部署到 Kubernetes 上的资源，然后使用部署系统提供的一个工具镜像，该镜像会调用部署系统的 API，将 YAML 提交给部署系统。接下来部署系统将使用用户的权限，调用 Kubernetes API 实现真正的部署。&lt;/p&gt;

&lt;p&gt;目前部署系统主要包含两部分功能：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. 资源集管理：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;资源集是用户项目下一个或多个资源的集合，资源指 Kubernetes 的 object 的描述文件，一般为 YAML 文件；
资源集分为多个版本，不同的版本对应资源的不同的描述文件；
用户可以选择某个版本，然后指定集群执行部署。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/dfba5fdb577c4690a5827aa1f120acc2" title="" alt=""&gt;
&lt;img src="http://p3.pstatp.com/large/pgc-image/3a36c896669a4799b6648a64fd013990" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. 部署任务&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;用户每次部署都会生成一个 job，就是部署任务
执行部署后，用户可在任务详情页直接查看部署任务日志。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/51c49c81f63e4af3aeb0868b0e5a17d2" title="" alt=""&gt;
&lt;img src="http://p1.pstatp.com/large/pgc-image/94783fa7fc754b2ca51d36f8990d0a59" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;当完成上述所有工作，Gitlab 能很好嵌入 KUN 平台，运行在 Kubernetes 上的各模块就可像齿轮一样有序运转，从而获得 CI/CD 上的良好效果。&lt;/p&gt;

&lt;p&gt;前面提到的 StepFlow 项目，从一开始就实施了这样一套 CI/CD，效率获得了很大提升，每个编译Job耗时约3分钟，其他Job耗时在1分钟以内。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CI/CD是提供高质量互联网服务必不可少的一环。Gitlab和Kubernetes都是非常优秀的开源软件，在此基础上，我们根据自己的实际情况，结合两者打造了一套高效的CI/CD平台，努力提升研发效率，为用户提供更优质的服务。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/ecb645700b2a4352ae0f3dda05b820cd" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 19 Jul 2019 14:36:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/38860</link>
      <guid>https://ruby-china.org/topics/38860</guid>
    </item>
    <item>
      <title>一键调用 API，UAPI 助力 BBGame 高效运维管理</title>
      <description>&lt;p&gt;&lt;strong&gt;“接入 UAPI 之后，可以方便的将 UCloud 上的一些资源和常用操作集成在自己公司的运维平台上，可以按照自己的方式展示数据、操作资源，为运维工作带来了很大的便利。”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;–黑胡子游戏 运维工程师 - 黄智星&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;用户痛点&lt;/strong&gt;
BBGame 黑胡子游戏开发有限公司是一家专业的全球化手游发行平台公司。目前在港台、韩国发行多款 MMPORPG、SLG 游戏产品。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/7/4/16bbc0f1c17ae50e?w=640&amp;amp;h=481&amp;amp;f=jpeg&amp;amp;s=23262" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;为了满足业务需求，BBGame 使用了多家云厂商的产品。虽然解决了很多问题，随之而来的弊端也浮现出来。由于各个厂商的产品设计思维、计费方式等方面的不同，导致对资源的管理难度较大。因此，他们希望通过构建一个统一的管理平台，对所有资源进行高效管理。对云资源的 API 调用是其中的重要一环，而 API 学习成本高、使用复杂的现状也成为一个困扰。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;管理平台负责人在将 UCloud 资源管理模块嵌入平台时，使用了 UCloud 控制台提供的 UAPI 产品进行 API 调用。通过交互式的方式，而非传统的、枯燥的文档阅读方式，快速学习和使用 UCloud API。通过在 UAPI 中一键调用，轻松掌握每个 API 实现的功能及具体返回情况，综合业务需求场景，高效编排出平台所需的调用逻辑。&lt;/p&gt;

&lt;p&gt;由于需要同时运维三家云厂商的资源，若不通过 UAPI 集成进平台，在管理上的工作量估计为现在的两倍。并且 UAPI 也支持批量购买资源并打 tag，考虑到日常少则十台多则数十台的批量数，这也可帮助将操作时间降为单独操作的数分之一。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/7/4/16bbc0f5d3514f03?w=640&amp;amp;h=367&amp;amp;f=jpeg&amp;amp;s=22254" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UAPI 优势：一键调用，简单使用 API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;更浅显易懂的阅读方式&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UAPI 交互式的方式，更有利于用户理解 API 的每个字段含义，更直观的发起请求和查看返回结果。帮助用户更好地理解 API 的定义，快速学习和使用 UCloud API。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/7/4/16bbc0f9550e9867?w=640&amp;amp;h=342&amp;amp;f=jpeg&amp;amp;s=20622" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;更一目了然的参数设置&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;用户在使用 UAPI 填写 API 请求参数时，对于枚举类型的字段，可以通过可视化界面的操作，直接下拉列表选择参数，避免了跨文档查阅枚举值的问题，大大提高了调试效率。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/7/4/16bbc0fcac8e811c?w=640&amp;amp;h=342&amp;amp;f=jpeg&amp;amp;s=15919" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;更简单快捷的调用方式&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;用户只需根据自身需求填写相关内容，一键发送，就可以在零编码的情况下实现对 API 的请求，高效并准确地对 API 进行调用。同时，可以在界面直接查看请求返回结果及响应说明，快速调整参数，获取需求数据。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/7/4/16bbc1004c8cb580?w=640&amp;amp;h=308&amp;amp;f=jpeg&amp;amp;s=16622" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;一个简单的使用演示&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;下面通过一个简单的例子，来展示如何使用 UAPI。当用户需要查询某个地域的 EIP 时，可以根据网络产品中 API 描述，选择 DescribeEIP。然后根据需求，选择相应地域及项目，进行查询，查询结果将直接在控制台展示。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/7/4/16bbc10442bc1393?w=800&amp;amp;h=458&amp;amp;f=gif&amp;amp;s=2256745" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;只需以下三步，&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;填写：请求的参数信息&lt;/strong&gt;
&lt;strong&gt;执行：发送请求&lt;/strong&gt;
&lt;strong&gt;查看：实时获得响应结果&lt;/strong&gt;
&lt;strong&gt;便可以做到：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(1) 无需搭建环境 (2) 无需编写代码 (3) 无需处理签名即可发送请求&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;目前，UAPI 已支持 26 个产品，实现了对主流产品的 100% 覆盖。随着新功能的推出，更多 API 将会持续开放，敬请关注。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/7/4/16bbc10815339a52?w=640&amp;amp;h=587&amp;amp;f=jpeg&amp;amp;s=88033" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Thu, 04 Jul 2019 16:25:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/38785</link>
      <guid>https://ruby-china.org/topics/38785</guid>
    </item>
    <item>
      <title>Kubernetes 在混合云架构下的应用</title>
      <description>&lt;p&gt;&lt;strong&gt;“托管云物理机纳入 UK8S 集群统一管理后，可实现托管云物理机保障平峰时业务正常运行，高峰时期利用 UK8S 快速扩容公有云资源的理想应用场景，继而提升混合云的可用性。”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;——海豹他趣技术负责人 张嵩&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;混合云的业务模式&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;厦门海豹他趣信息技术股份有限公司于 2012 年 4 月成立，是一家基于 B2C 模式的综合性两性健康电商服务平台企业。目前采用混合云 (公有云 + 托管云) 的技术架构模式，在保证存量 IT 资源合理利用的同时，又能够与公有云产品内网高速安全互通，实现资源的弹性扩展。&lt;/p&gt;

&lt;p&gt;海豹他趣选择将部分数据敏感的业务部署在 UCloud 的托管云区域，通过租赁 UCloud 机房机柜的方式，托管自有设备，并依照自身电商业务特点进行高峰*冗余部署，但该模式下存在平峰时期物理机资源利用率低的现象。&lt;/p&gt;

&lt;p&gt;业务容器化改造的过程中，海豹他趣已在公有云场景下实现 UK8S 的资源统一纳管，故想进一步提高托管云的资源利用率，实现托管云物理机保障平峰时业务正常运行，高峰时期利用 UK8S 快速扩容公有云资源的应用场景。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;托管云中自建 K8S 集群的难题&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;起初，海豹他趣尝试在托管云中自建 K8S 集群，但运行后发现，同时在公有云和托管云中使用 K8S 集群，会存在网络互通、存储、负载均衡等方面的问题。与此同时，自行部署 K8S 集群需投入一支专业团队的人力成本，包含开发以及部署 K8S 网络、存储和负载均衡等工作，需自行挑选和部署第三方网络插件、搭建存储集群并适配 K8S 存储类型，以及维护一套负载均衡集群等。此外，集群搭建后的维护工作也费时费力。权衡之下，海豹他趣更希望将集群的管理和运维工作交给云厂商处理，从而自身精力能专注于业务研发之中。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;托管云物理机纳入 UK8S 集群&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCloud 已推出的 UK8S 能自动化实现公有云场景下的 K8S 集群部署以及运维工作，有效解决上述自行部署和维护 K8S 集群的难题。&lt;/p&gt;

&lt;p&gt;同时，由于公有云和托管云分属不同的环境，在网络、服务器资源管理、控制等各方面完全独立，彼此之间仅有三层网络打通，要实现两者场景下 K8S 集群的统一略为繁琐。目前市面上各家云厂商针对混合云下的 K8S 集群部署，给出的解决方案多是在公有云和托管云下分别部署一套 K8S 集群，提供支持多集群管理的服务。&lt;/p&gt;

&lt;p&gt;但考虑到该用户在跨集群模式下的困扰，UCloud 开始策划将托管云物理机纳入 UK8S 现有集群统一管理的方案，即在混合云架构下仅需部署管理一套 K8S 集群。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;解决三大技术问题&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;前文也提及，部署 K8S 集群需解决网络、存储以及负载均衡方案，UCloud 的 UK8S 团队尝试在三个问题上逐个击破。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;网络实现&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;K8S 本身并不提供网络能力，而是将网络接口开放，由外部插件来实现，其网络模型需要满足以下条件：&lt;/p&gt;

&lt;p&gt;1、Node 与 Node 节点之间可通过 IP 直接通信；&lt;/p&gt;

&lt;p&gt;2、不同节点的 Pod 之间可通过 IP 直接通信；&lt;/p&gt;

&lt;p&gt;3、Pod 与非宿主 Node 节点之间可通过 IP 直接通信。&lt;/p&gt;

&lt;p&gt;首先，针对 Node 节点之间的通信。UK8S 运行在公有云的 VPC 网络下，VPC 网络与托管云虽属于不同的网段，但彼此间已实现三层互通，因此 UK8S 公有云中的 Node 节点与托管云中的物理机之间可通过 IP 直接通信，该条件满足。&lt;/p&gt;

&lt;p&gt;其次是 Pod 之间以及 Pod 与 Node 节点间的通信问题，可具体描述为（1）公有云中的 Pod 与托管云中的 Pod 互通，（2）公有云中的 Pod 与托管云中的 Node 互通，或（3）公有云中的 Node 与托管云中的 Pod 互通。&lt;/p&gt;

&lt;p&gt;下图是 UK8S 在公有云场景下的网络模型，采用 Underlay 方案，Pod 与 Node 网络处于同一层面，CNI 插件会调用 UCloud API 为每个 Pod 分配一个 VPC IP。由于 VPC IP 已默认与托管云中的物理机互通，即代表公有云中的 Pod 已实现与托管云中的 Node 互通，此外公有云中 Pod 与 Node 网络同等，上述待解决问题可简化为公有云中的 Pod 与托管云中的 Pod 互通。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/6/13/16b5016087da1efe?w=640&amp;amp;h=325&amp;amp;f=jpeg&amp;amp;s=15271" title="" alt=""&gt;
图：公有云下的网络模型&lt;/p&gt;

&lt;p&gt;为实现 Pod 之间的互通，托管云的网络模型也同样采用 Underlay 模式。如下图所示，两者场景下所有的 Node 节点均采用 Underlay 模式的 CNI 插件，公有云中的 Node 已默认安装 CNI-VPC 插件，托管云中的 Node 可采用二层 Bridge 或自定义路由的 Underlay 模式 CNI 插件。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/6/13/16b50164581c5e99?w=640&amp;amp;h=324&amp;amp;f=jpeg&amp;amp;s=23883" title="" alt=""&gt;
图：混合云下的网络模型&lt;/p&gt;

&lt;p&gt;以自定义路由为例，托管云的网段为 172.16.0.0/16，安装 kubelet 后，将 Bridge 插件拷贝至/opt/cni/bin 下，再配置插件启动参数即可。CNI 插件会在 Node 上先创建一个网桥，当 Pod 启动时，通过 veth pair 连接该网桥到 pause 容器的网络命名空间，即可实现托管云中的 Pod 互通。由于 172.16.0.0/16 已在网关上配置完成，最后在交换机侧配置自定义路由，可最终完成公有云中的 Pod 与托管云中的 Pod 互通。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/6/13/16b50167ce95952c?w=640&amp;amp;h=464&amp;amp;f=jpeg&amp;amp;s=33627" title="" alt=""&gt;
图：交换机侧配置信息&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;存储实现&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;除去内置的存储插件，UK8S 在公有云中额外集成 UDisk、UFS 两种云储存产品。目前 UCloud 托管云中物理机尚不支持挂载云存储产品，因此 UK8S 中的存储插件需实现兼容，只支持挂载至公有云中的 Node 节点上。&lt;/p&gt;

&lt;p&gt;实现形式上，给公有云中的 Node 节点打上类似 nodetype: uhost 的标签即可。用户使用时，若 Pod 需要挂载单写模式的存储卷，在调度 Pod 时声明 nodeAffinity，就可指定 Pod 分配至公有云中的 Node 节点。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;负载均衡实现&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;最后需解决服务如何对外暴露的问题，K8S 提供了几种服务暴露的方案，其中 LoadBalancer 类型的 Service 最为通用，同时由于在托管云中维护一个可靠的负载均衡设备成本较高，故使用公有云中的 ULB 作为 K8S 的外部负载均衡器。&lt;/p&gt;

&lt;p&gt;业务流量入口由公有云的 ULB 和 Node 节点承载，通过在 K8S 集群中定义 LoadBalancer 类型的 Service，业务流量可先通过 ULB 转发到公有云 Node 节点上，再通过公有云节点上 kube-proxy 配置的 iptables 规则转发至整个集群中实际工作的 Pod。对于 ClusterIP 类型的 Service，与现有 K8S 集群无异，通过 kube-proxy 在集群内部通信。&lt;/p&gt;

&lt;p&gt;此外，也可在公有云节点部署 Ingress Controller，代理部署在托管云节点的业务流量。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/6/13/16b5016be24cac6f?w=640&amp;amp;h=356&amp;amp;f=jpeg&amp;amp;s=24487" title="" alt=""&gt;
图：流量转发链路&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;采用该方案实现的效果&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1、提高托管云物理机的利用率&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;托管云物理机纳入 UK8S 集群统一管理后，可实现托管云物理机保障平峰时业务正常运行，高峰时期利用 UK8S 快速扩容公有云资源的应用场景，无需原先的高峰*冗余部署，有效解决平峰时期资源利用率低的问题，从而节约资源成本。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2、减少公有云主机资源的冗余&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;实际业务中，遇到大型活动或突增的服务请求时，采用云主机自动服务扩容的方式处理速度较慢，通常需要五分钟左右的时间，而利用 UK8S 可以赚取云主机启动与容器启动速度的时差，做到资源的快速扩容，继而减少云主机日常冗余的数量。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3、无需 K8S 部署和维护的人力投入&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;用户可在 UK8S 上部署、管理以及扩展容器化应用，而无需关心 K8S 集群自身的搭建及维护等运维类工作，能够更加集中于业务实现。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4、加快服务上线速度&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;一方面，UK8S 中通过统一的镜像，可保证代码及部分配置在测试环境、预发布环境、正式环境中的一致性，避免环境不一致引发的异常状况；另一方面，UK8S 有其完善的 CI/CD 流程，可简化服务部署步骤，有效减少服务上线时的人工干预，实现效率的全面提升。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;随着 K8S 使用的逐步增多，运行部署 K8S 的环境也日趋复杂，对于企业 IT 人员而言，找到一种兼容现有业务环境的 K8S 配置、管理方式显得尤为重要，特别是在多云、IDC 与云并存等环境下如何配置 K8S。上述提供的针对 UCloud 混合云场景下的 K8S 部署方案，其思路同样适用于非 UCloud 混合云环境。&lt;/p&gt;

&lt;p&gt;欢迎加入 UCloud K8S 技术交流群，和我们共同探讨 Kubernetes 前沿技术。（由于群人数已超过 100 人，&lt;strong&gt;请添加群主微信 zhaoqi628543，备注 K8S 即可邀请入群&lt;/strong&gt;。）&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Thu, 13 Jun 2019 17:16:24 +0800</pubDate>
      <link>https://ruby-china.org/topics/38640</link>
      <guid>https://ruby-china.org/topics/38640</guid>
    </item>
    <item>
      <title>可实现 RSSD 云硬盘 120 万 IOPS 的 SPDK IO 路径优化实践</title>
      <description>&lt;p&gt;&lt;strong&gt;一 简介&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;用户对超高并发、超大规模计算等需求推动了存储硬件技术的不断发展，存储集群的性能越来越好，延时也越来越低，对整体 IO 路径的性能要求也越来越高。在云硬盘场景中，IO 请求从生成到后端的存储集群再到返回之间的 IO 路径比较复杂，虚拟化 IO 路径尤其可能成为性能瓶颈，因为虚机内所有的 IO 都需要通过它下发给后端的存储系统。我们使用了 SPDK 来优化虚拟化 IO 路径，提出了开源未解决的 SDPK 热升级和在线迁移方案，并且在高性能云盘场景中成功应用，取得了不错的效果，RSSD 云硬盘最高可达 120 万 IOPS。本文主要分享我们在这方面的一些经验。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;二 SPDK vhost 的基本原理&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SPDK（Storage Performance Development Kit ) 提供了一组用于编写高性能、可伸缩、用户态存储应用程序的工具和库，基本组成分为用户态、轮询、异步、无锁 NVMe 驱动，提供了从用户空间应用程序直接访问 SSD 的零拷贝、高度并行的访问。&lt;/p&gt;

&lt;p&gt;在虚拟化 IO 路径中，virtio 是比较常用的一种半虚拟化解决方案，而 virtio 底层是通过 vring 来通信，下面先介绍下 virtio vring 的基本原理，每个 virtio vring 主要包含了以下几个部分：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c856d0acf537?w=437&amp;amp;h=307&amp;amp;f=jpeg&amp;amp;s=12871" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;desc table 数组，该数组的大小等于设备的队列深度，一般为 128。数组中每一个元素表示一个 IO 请求，元素中会包含指针指向保存 IO 数据的内存地址、IO 的长度等基本信息。一般一个 IO 请求对应一个 desc 数组元素，当然也有 IO 涉及到多个内存页的，那么就需要多个 desc 连成链表来使用，未使用的 desc 元素会通过自身的 next 指针连接到 free_head 中，形成一个链表，以供后续使用。&lt;/p&gt;

&lt;p&gt;available 数组，该数组是一个循环数组，每一项表示一个 desc 数组的索引，当处理 IO 请求时，从该数组里拿到一个索引就可以到 desc 数组里面找到对应的 IO 请求了。&lt;/p&gt;

&lt;p&gt;used 数组，该数组与 avail 类似，只不过用来表示完成的 IO 请求。当一个 IO 请求处理完成时，该请求的 desc 数组索引就会保存在该数组中，而前端 virtio 驱动得到通知后就会扫描该数据判断是否有请求完成，如果完成就会回收该请求对应的 desc 数组项以便下个 IO 请求使用。&lt;/p&gt;

&lt;p&gt;SPDK vhost 的原理比较简单，初始化时先由 qemu 的 vhost 驱动将以上 virtio vring 数组的信息发送给 SPDK，然后 SPDK 通过不停的轮寻 available 数组来判断是否有 IO 请求，有请求就处理，处理完后将索引添加到 used 数组中，并通过相应的 eventfd 通知 virtio 前端。&lt;/p&gt;

&lt;p&gt;当 SPDK 收到一个 IO 请求时，只是指向该请求的指针，在处理时需要能直接访问这部分内存，而指针指向的地址是 qemu 地址空间的，显然不能直接使用，因此这里需要做一些转化。&lt;/p&gt;

&lt;p&gt;在使用 SPDK 时虚机要使用大页内存，虚机在初始化时会将大页内存的信息发送给 SPDK，SPDK 会解析该信息并通过 mmap 映射同样的大页内存到自己的地址空间，这样就实现了内存的共享，所以当 SPDK 拿到 qemu 地址空间的指针时，通过计算偏移就可以很方便的将该指针转换到 SPDK 的地址空间。&lt;/p&gt;

&lt;p&gt;由上述原理我们可以知道 SPDK vhost 通过共享大页内存的方式使得 IO 请求可以在两者之间快速传递这个过程中不需要做内存拷贝，完全是指针的传递，因此极大提升了 IO 路径的性能。&lt;/p&gt;

&lt;p&gt;我们对比了原先使用的 qemu 云盘驱动的延时和使用了 SPDK vhost 之后的延时，为了单纯对比虚拟化 IO 路径的性能，我们采用了收到 IO 后直接返回的方式：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.单队列（1 iodepth, 1 numjob）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;qemu 网盘驱动延时：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c85d1a6fb222?w=747&amp;amp;h=123&amp;amp;f=jpeg&amp;amp;s=23805" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;SPDK vhost 延时：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c86d77961bf4?w=711&amp;amp;h=81&amp;amp;f=jpeg&amp;amp;s=20399" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可见在单队列情况下延时下降的非常明显，平均延时由原来的 130us 下降到了 7.3us。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.多队列（128 iodepth，1 numjob）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;qemu 网盘驱动延时：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c870efc168b3?w=788&amp;amp;h=120&amp;amp;f=jpeg&amp;amp;s=26373" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;SPDK vhost 延时：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c874c61a4045?w=703&amp;amp;h=79&amp;amp;f=jpeg&amp;amp;s=19647" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;多队列时 IO 延时一般会比单队列更大些，可见在多队列场景下平均延时也由 3341us 下降为 1090us，下降为原来的三分之一。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;三 SPDK 热升级&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在我们刚开始使用 SPDK 时，发现 SPDK 缺少一重要功能——热升级。我们使用 SPDK 并基于 SPDK 开发自定义的 bdev 设备肯定会涉及到版本升级，并且也不能 100% 保证 SPDK 进程不会 crash 掉，因此一旦后端 SPDK 重启或者 crash，前端 qemu 里 IO 就会卡住，即使 SPDK 重启后也无法恢复。&lt;/p&gt;

&lt;p&gt;我们仔细研究了 SPDK 的初始化过程发现，在 SPDK vhost 启动初期，qemu 会下发一些配置信息，而 SPDK 重启后这些配置信息都丢失了，那么这是否意味着只要 SPDK 重启后重新下发这些配置信息就能使 SPDK 正常工作呢？我们尝试在 qemu 中添加了自动重连的机制，并且一旦自动重连完成，就会按照初始化的顺序再次下发这些配置信息。开发完成后，初步测试发现确实能够自动恢复，但随着更严格的压测发现只有在 SPDK 正常退出时才能恢复，而 SPDK crash 退出后 IO 还是会卡住无法恢复。从现象上看应该是部分 IO 没有被处理，所以 qemu 端虚机一直在等待这些 IO 返回导致的。&lt;/p&gt;

&lt;p&gt;通过深入研究 virtio vring 的机制我们发现在 SPDK 正常退出时，会保证所有的 IO 都已经处理完成并返回了才退出，也就是所在的 virtio vring 中是干净的。而在意外 crash 时是不能做这个保证的，意外 crash 时 virtio vring 中还有部分 IO 是没有被处理的，所以在 SPDK 恢复后需要扫描 virtio vring 将未处理的请求下发下去。这个问题的复杂之处在于，virtio vring 中的请求是按顺序下发处理的，但实际完成的时候并不是按照下发的顺序的。&lt;/p&gt;

&lt;p&gt;假设在 virtio vring 的 available ring 中有 6 个 IO，索引号为 1，2，3，4，5，6，SPDK 按顺序的依次得到这个几个 IO，并同时下发给设备处理，但实际可能请求 1 和 4 已经完成，并返回了成功了，如下图所示，而 2，3，5，6 都还没有完成。这个时候如果 crash，重启后需要将 2，3，5，6 这个四个 IO 重新下发处理，而 1 和 4 是不能再次处理的，因为已经处理完成返回了，对应的内存也可能已经被释放。也就是说我们无法通过简单的扫描 available ring 来判断哪些 IO 需要重新下发，我们需要有一块内存来记录 virtio vring 中各个请求的状态，当重启后能够按照该内存中记录的状态来决定哪些 IO 是需要重新下发处理的，而且这块内存不能因 SPDK 重启而丢失，那么显然使用 qemu 进程的内存是最合适的。所以我们在 qemu 中针对每个 virtio vring 申请一块共享内存，在初始化时发送给 SPDK，SPDK 在处理 IO 时会在该内存中记录每个 virtio vring 请求的状态，并在意外 crash 恢复后能利用该信息找出需要重新下发的请求。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c87b4a12eca7?w=262&amp;amp;h=152&amp;amp;f=jpeg&amp;amp;s=4608" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;四 SPDK 在线迁移&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SPDK vhost 所提供的虚拟化 IO 路径性能非常好，那么我们有没有可能使用该 IO 路径来代替原有的虚拟化 IO 路径呢？我们做了一些调研，SPDK 在部分功能上并没有现有的 qemu IO 路径完善，其中尤为重要的是在线迁移功能，该功能的缺失是我们使用 SPDK vhost 代替原有 IO 路径的最大障碍。&lt;/p&gt;

&lt;p&gt;SPDK 在设计时更多是为网络存储准备的，所以支持设备状态的迁移，但并不支持设备上数据的在线迁移。而 qemu 本身是支持在线迁移的，包括设备状态和设备上的数据的在线迁移，但在使用 vhost 模式时是不支持在线迁移的。主要原因是使用了 vhost 之后 qemu 只控制了设备的控制链路，而设备的数据链路已经托管给了后端的 SPDK，也就是说 qemu 没有设备的数据流 IO 路径所以并不知道一个设备那些部分被写入了。&lt;/p&gt;

&lt;p&gt;在考察了现有的 qemu 在线迁移功能后，我们觉着这个技术难点并不是不能解决的，因此我们决定在 qemu 里开发一套针对 vhost 存储设备的在线迁移功能。&lt;/p&gt;

&lt;p&gt;块设备的在线迁移的原理比较简单，可以分为两个步骤，第一个步骤将全盘数据从头到尾拷贝到目标虚机，因为拷贝过程时间较长，肯定会发生已经拷贝的数据又被再次写入的情况，这个步骤中那些再次被写脏的数据块会在 bitmap 中被置位，留给第二个步骤来处理，步骤二中通过 bitmap 来找到那些剩余的脏数据块，将这些脏数据块发送到目标端，最后会 block 住所有的 IO，然后将剩余的一点脏数据块同步到目标端迁移就完成了。&lt;/p&gt;

&lt;p&gt;SPDK 的在线迁移原理上于上面是相同的，复杂之处在于 qemu 没有数据的流 IO 路径，所以我们在 qemu 中开发了一套驱动可以用来实现迁移专用的数据流 IO 路径，并且通过共享内存加进程间互斥的方式在 qemu 和 SPDK 之间创建了一块 bitmap 用来保存块设备的脏页数量。考虑到 SPDK 是独立的进程可能会出现意外 crash 的情况，因此我们给使用的 pthread mutex 加上了 PTHREAD_MUTEX_ROBUST 特性来防止意外 crash 后死锁的情况发生，整体架构如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c88113d4b799?w=449&amp;amp;h=352&amp;amp;f=jpeg&amp;amp;s=14489" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;五 SPDK IO uring 体验&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IO uring 是内核中比较新的技术，在上游内核 5.1 以上才合入，该技术主要是通过用户态和内核态共享内存的方式来优化现有的 aio 系列系统调用，使得提交 IO 不需要每次都进行系统调用，这样减少了系统调用的开销，从而提供了更高的性能。&lt;/p&gt;

&lt;p&gt;SPDK 在最新发布的 19.04 版本已经包含了支持 uring 的 bdev，但该功能只是添加了代码，并没有开放出来，当然我们可以通过修改 SPDK 代码来体验该功能。&lt;/p&gt;

&lt;p&gt;首先新版本 SPDK 中只是包含了 io uring 的代码甚至默认都没有开放编译，我们需要做些修改：&lt;/p&gt;

&lt;p&gt;1.安装最新的 liburing 库，同时修改 spdk 的 config 文件打开 io uring 的编译；&lt;/p&gt;

&lt;p&gt;2.参考其他 bdev 的实现，添加针对 io uring 设备的 rpc 调用，使得我们可以像创建其他 bdev 设备那样创建出 io uring 的设备；&lt;/p&gt;

&lt;p&gt;3.最新的 liburing 已经将 io_uring_get_completion 调用改成了 io_uring_peek_cqe，并需要配合 io_uring_cqe_seen 使用，所以我们也要调整下 SPDK 中 io uring 的代码实现，避免编译时出现找不到 io_uring_get_completion 函数的错误：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c886103f10dc?w=640&amp;amp;h=240&amp;amp;f=jpeg&amp;amp;s=25457" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;4.使用修改 open 调用，使用 O_SYNC 模式打开文件，确保我们在数据写入返回时就落地了，并且比调用 fdatasync 效率更高，我们对 aio bdev 也做了同样的修改，同时添加读写模式：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c88a963339f2?w=848&amp;amp;h=202&amp;amp;f=jpeg&amp;amp;s=33035" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;经过上述修改 spdk io uring 设备就可以成功创建出来了，我们做下性能的对比：&lt;/p&gt;

&lt;p&gt;使用 aio bdev 的时候：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c88d86a5f9af?w=639&amp;amp;h=81&amp;amp;f=jpeg&amp;amp;s=19933" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;使用 io uring bdev 的时候：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/5/31/16b0c8908cf46e9c?w=632&amp;amp;h=84&amp;amp;f=jpeg&amp;amp;s=18427" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可见在最高性能和延时上 io uring 都有不错的优势，IOPS 提升了约 20%，延迟降低约 10%。这个结果其实受到了底层硬件设备最大性能的限制，还未达到 io uring 的上限。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;六 总结&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SPDK 技术的应用使得虚拟化 IO 路径的性能提升不再存在瓶颈，也促使 UCloud 高性能云盘产品可以更好的发挥出后端存储的性能。当然一项技术的应用并没有那么顺利，我们在使用 SPDK 的过程中也遇到了许多问题，除了上述分享的还有一些 bug 修复等我们也都已经提交给了 SPDK 社区，SPDK 作为一个快速发展迭代的项目，每个版本都会给我们带来惊喜，里面也有很多有意思的功能等待我们发掘并进一步运用到云盘及其它产品性能的提升上。&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 31 May 2019 14:28:46 +0800</pubDate>
      <link>https://ruby-china.org/topics/38594</link>
      <guid>https://ruby-china.org/topics/38594</guid>
    </item>
    <item>
      <title>利用 UK8S 落地微服务，加速元年科技业务迭代</title>
      <description>&lt;p&gt;“使用 UK8S，开发者可以像使用普通云服务器一样迅速搭建 K8S 环境。在享受 K8S 带来的便利的同时，能够让开发人员集中注意力在业务实现的细节，而不必在基础架构搭建上浪费太多的精力。UCloud 为此提供的专业、快速的服务和响应机制帮助我们成功的将整个环境从自建 K8S 平滑迁移到 UK8S。UCloud 的 UK8S 如同其它的基础服务一样稳定，使我们相信‘让专业的人做专业的事’，选择 UCloud 作为我们的云服务提供商是我们在技术选型上做出的正确选择之一。”&lt;/p&gt;

&lt;p&gt;—元年科技 CTO 杨熠&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;写在开始&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;本文主要介绍 UK8S 在公有云场景中的实践案例，后续即将推出在混合云模式下的案例分享。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;元年科技业务使用 UK8S 的效果&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;业务上引入 UK8S 落地微服务，目的并非是节约云主机资源，而是节省人工成本，使得开发人员可更专注于业务实现；可降低系统耦合度、研发难度，从而更高效合理的调度主机集群资源；提高团队整体交付效率，实现时间成本的节约，最终转化为业务迭代的加速。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;关于元年科技&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;自 2000 年成立起，一直专注于以管理会计为核心的管理咨询和管理信息化领域，致力于成为“中国管理会计领航者”，帮助中国企业实现财务转型和管理精细化。&lt;/p&gt;

&lt;p&gt;元年科技的专业服务和软件平台涵盖企业运营以及管理的四个层面：以管理会计为核心，支持企业分析模拟、决策支持和管理控制；以财务共享为核心，推动财务转型、提升企业运营效率；基于商业智能平台和大数据，实现客户分析、销售分析、运营分析；以企业信息化规划和互联网转型为核心，提供集团管控体系、组织和流程优化等咨询服务。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/721df0068e3949ac8f14fb694f03f00c" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;云快报的业务场景和架构&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;云快报是元年科技旗下一款商旅及支出管理 SaaS 产品。采用云计算和移动互联网技术开发，凝聚了众多行业、企业费用管理的最佳实践，满足广大企业提升业务能力、规范业务行为、管控业务费用的核心需求，&lt;strong&gt;同时集成了同程、艺龙、滴滴、京东等互联网消费平台，&lt;/strong&gt; 将差旅申请、消费和报销流程打通，此外还整合发票查验、智能记账、多种财务接口，让企业的费用管控更高效，更清晰透明。&lt;/p&gt;

&lt;p&gt;该产品中的 &lt;strong&gt;商城业务采用巨石与微服务结合的架构模式&lt;/strong&gt; ，包含商城端以及商城服务端两部分内容。&lt;strong&gt;商城端目前仍使用传统巨石结构，&lt;/strong&gt; 也正在改造中，主要负责买卖双方的管理，涵盖商户管理、购物商城、管理后台等服务。由于云快报中接入的商户并未实际在商城中开店，遂引入对接端的概念，完成对远端商户的真实下单操作。&lt;/p&gt;

&lt;p&gt;商城用户在购物商城中下单并完成支付后，对接端将订单通过 API 服务提交至商城服务端进行真实下单，&lt;strong&gt;商城服务端采用微服务架构，&lt;/strong&gt; 每类服务之间既相互独立又维持协作的关系。此外，针对搜索服务，云快报选择将微服务架构与 Solr 结合的方式，实现供应电商系统中商品的定时同步，以及推送至 Solr 中提供搜索服务。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/383cfa36f1a84f3c89aee87519b16054" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：云快报商城业务架构图&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;引入 K8S，解决业务痛点&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;微服务架构下，元年科技开发人员发现使用 K8S 比原先云主机部署模式在如下场景中可更为有效的解决问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;痛点一：新服务的上线以及原有服务的更新过程繁杂&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;一方面，若要在既有云主机上发布全新的服务，需考虑不同类型语言要求不一致的问题，从基础环境到启动脚本，内容十分零散，整个发布过程相当复杂；另一方面，若要更新已存在的服务，脚本语言可使用热更新，但编译类语言又面临同样的困境。&lt;/p&gt;

&lt;p&gt;常规做法是由 nginx 在服务前面做一个负载的代理，人工操作切换负载来保证非中断服务方式的更新，但当服务数量较多时，人工操作负担大。&lt;/p&gt;

&lt;p&gt;K8S 下可利用容器技术的自包含自描述解决多种编程语言更新的问题，并实现零散发布内容的整合；此外，使用 K8S 的应用编排能力进行发布，可解决微服务架构下复杂的多应用依赖发布的问题，同时还可降低误操作概率。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;痛点二：动态服务迁移操作难度大&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/ad88d1f5f1474f8fb00509fde5528e1a" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：动态服务迁移示意图&lt;/p&gt;

&lt;p&gt;由于云主机资源的限制，为了给特定服务提供资源升级的空间，常常需要动态的将其余正在执行的服务迁移至新的云主机。如上图所示，服务 11 要由 0.5 核 CPU 升级为 1 核 CPU，此时需要把服务 07 和 12 迁移至别的节点中，再对服务 11 进行升级操作。&lt;/p&gt;

&lt;p&gt;未使用 K8S 的情况下，为了防止业务中断，通常会将服务 07 和服务 12 在节点 05 中进行部署，更改服务发现后再将节点 02 中资源清除。而 K8S 中只需更改服务 07 和 12 的 nodeSelector，即可将服务 07 和 12 实现迁移，在保障服务不中断的前提下快速满足服务 11 的扩容需求。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;痛点三：线上服务健康检查复杂度高&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为了保证线上服务的存活，需安装多类别的检测监控软件，安装软件工作量大，并且只能作为报警提醒，无法协助后续处理。&lt;/p&gt;

&lt;p&gt;利用 K8S 的健康检查机制，可以通过请求服务的健康检查接口来检测服务的工作状态，并根据响应码判识状态是否正常，若处于非正常状态，K8S 会自动执行 Pod 的销毁重建，保障服务正常工作。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;痛点四：服务之间的调用和发现配置工作多&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/01348b3d3f8d4d1398d9e3291d05e860" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：服务调用与发现示意图&lt;/p&gt;

&lt;p&gt;实际应用中，会需要服务之间的内部调用。但不同环境下，调用相同的服务由于内部 IP 无法固定，需要额外增加多个配置文件，且每个环境下对应一套，服务数量较多时，配置工作繁重。&lt;/p&gt;

&lt;p&gt;而 K8S 的服务发现基于 Service 加 DNS 解析实现，完成服务发现的同时具备负载。如上图所示，服务 16 访问服务 18 的时候会先由 K8S 内部的 DNS 来获取服务 18 的 Service 代理 IP，再访问服务 18-proxy。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;痛点五：单个服务完全消耗云主机资源&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;原有的部署模式下，单台云主机上同时运行多个服务，并且没有对每个服务的 CPU、内存以及磁盘 IO 进行限制，导致出现单个服务负载过高，将整台主机资源耗尽，从而主机卡住的情况，此时再扩展新的资源部署服务，整个恢复过程较为漫长。&lt;/p&gt;

&lt;p&gt;K8S 中可对服务的 CPU、内存使用量进行限制，有效减少运行在同一台主机上服务资源争抢问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;由自建 K8S 迁移至 UK8S&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;元年科技业务中共有两套 K8S 集群，一套是运行在线下内网环境中的自建 K8S 集群，直接使用 Rancher 搭建和管理，另一套运行在 UCloud 公有云环境中，先前也是自建的 K8S 集群。考虑到 UK8S 相较于自建 K8S 集群有如下几点优势，最终选择从自建 K8S 集群迁移至 UK8S。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/605194018cc1452eb0e196f92ea508c7" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;表：UK8S 与自建 K8S 对比&lt;/p&gt;

&lt;p&gt;—END —&lt;/p&gt;

&lt;p&gt;欢迎扫描下方二维码，加入 UCloud K8S 技术交流群，和我们共同探讨 Kubernetes 前沿技术。（如显示群人数已加满，可添加群主微信 zhaoqi628543，备注 K8S 即可邀请入群。）&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/6c1ebe5c31514f01966d2f3a52c0dccb" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;TIC 2019 报名火热进行中，欢迎加入我们共同探讨 Kubernetes 的技术实践！UCloud 实验室负责人叶理灯将于 &lt;strong&gt;技术专场 A&lt;/strong&gt; 带来更多 Kubernetes 技术干货。除此之外，技术专场还汇集了 &lt;strong&gt;Serverless、微服务、分布式技术等&lt;/strong&gt; 热门话题，诚邀广大技术开发者扫描下方二维码参与报名，共享技术盛宴！&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/1d565139af9847dcae186271adf4fbed" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 17 May 2019 18:36:19 +0800</pubDate>
      <link>https://ruby-china.org/topics/38547</link>
      <guid>https://ruby-china.org/topics/38547</guid>
    </item>
    <item>
      <title>轻松上手 UAI-Train，拍拍贷人脸识别算法优化效率提升 85.7%</title>
      <description>&lt;p&gt;“UAI-Train 平台可以让我们方便地在短时内使用大量的 GPU 资源，用较低的成本训练海量的数据集，提高算法模型迭代优化的效率。” — 拍拍贷算法研究员 朱运&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UAI-Train 是什么&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UAI-Train 是面向 AI 训练任务的大规模分布式计算平台，基于 P40、V100 等 GPU 云主机集群，通过分布式扩展，最高可实现 192TFlops 的单精度计算能力。提供一站式训练任务托管服务，可自动化解决计算节点调度、训练环境准备、数据上传下载以及任务容灾等问题，并支持按需收费、成本可控，无需担心资源浪费。在视频图像识别、自然语言处理、语音处理等领域均已有诸多实践。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;拍拍贷接入 UAI-Train 的效果&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;通过使用分布式 GPU 训练平台，700W 人脸数据的模型训练所需时长可从原先的一周缩短至一天，&lt;strong&gt;整体算法优化效率提升 85.7%，&lt;/strong&gt; 相应的迭代频率也提高数倍，为更深层次的模型结构试验提供了可能。同时 UAI-Train 平台备有大量 GPU 资源，拍拍贷的算法工程师可以同时探索多种算法模型结构，极大缩短初期算法结构探索的时间。最重要的是 UAI-Train 平台具备按需收费的特性，拍拍贷人脸识别算法的 &lt;strong&gt;GPU 资源成本可由原先的上万元/月，下降至数千元/月，&lt;/strong&gt; GPU 资源的有效利用率也达到了 100%。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/ffdb91cb07d9401aacca8d2c0564b300" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;表：UAI-Train 与购买 GPU 资源的特性对比&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;关于拍拍贷&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;拍拍贷是一家行业领先的金融科技公司，同时也是一家非常注重技术驱动、强调自主研发的高科技公司。一直以来非常重视 AI 技术的探索和应用，涉及到计算机视觉、语音分析和建模、自然语言处理、复杂网络分析等针对特定非结构化数据的领域，并将迁移学习、主动学习、强化学习、多任务学习、在线学习、非监督半监督等各种机器学习算法应用至多种业务场景。尤其是人脸识别、OCR、不良中介识别和欺诈团伙挖掘、智能对话机器人、社交文本挖掘等项目，在实际的业务实践中取得了不俗的效果，极大地提升了风险反欺诈水平和运营效率。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/a3d757cbb2d047928f77cee0e6a19f84" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;人脸识别&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;人脸识别是拍拍贷 AI 技术的一个重要研究方向，它通过算法识别人的脸部特征，从而可以做到实时地从图片或者视频流中检测和追踪特定的人。&lt;/p&gt;

&lt;p&gt;目前拍拍贷自研人脸识别算法，在 700W 规模多年龄段、多姿态、多表情、多环境的人脸图片上进行训练。通过尝试不同的网络结构，包含 Inception-v3、优化后的 resnet 等，以及多种损失函数，例如 triplet_loss、sphere、cosine、arc_loss 等来优化人脸识别算法，从而提升 1:1 人脸认证、1:N 人脸搜索、N:N 人脸交叉比对、人脸聚类等场景的识别精度，并将此类技术应用于拍拍贷的风险监控、反欺诈等业务，并发挥了重要作用。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/29bf5acf4ca148fe9865a9b770c3a34b" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：人脸识别业务场景&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面临的问题&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;算法人员在优化人脸识别算法的过程中发现&lt;strong&gt;使用单台 GPU 机器迭代一次算法需要一周左右的时间，&lt;/strong&gt;效率过低影响研发进度，但是采购更多的 GPU 机器来探索不同算法会导致资源成本线性增长；此外由于算法调优工作涉及诸多研究内容，例如算法效果分析、新算法调研、开发等，实际的资源使用率不高。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;接触 UAI-Train&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在一次线下技术交流活动中，拍拍贷技术人员了解到 UCloud 提供一种面向人工智能算法训练的 UAI-Train 平台，并支持 GPU 资源的按需租售服务，同时该平台上还可执行多机多卡的分布式训练任务。&lt;/p&gt;

&lt;p&gt;为了提升模型训练的效率，充分高效地利用更多的新数据来进一步提高其准确率，拍拍贷抉择后选择尝试 UAI-Train 平台。UCloud AI 团队在 GitHub 上发布了适配 UAI-Train 平台的 Insightface 开发案例，用于协助拍拍贷的算法工程师很方便地将单机的人脸识别算法转化成支持分布式训练的人脸识别算法，并成功在 UAI-Train 平台上进行算法的快速优化。&lt;/p&gt;

&lt;p&gt;Insightface 是 GitHub 上一个基于 MXNet 框架的开源人脸识别项目（&lt;a href="https://github.com/deepinsight/insightfaceUCloud%E5%9F%BA%E4%BA%8Einsightface%E5%BC%80%E5%8F%91%E4%BA%86%E4%B8%80%E6%95%B4%E5%A5%97%E8%83%BD%E6%94%AF%E6%8C%81%E5%88%86%E5%B8%83%E5%BC%8F%E8%AE%AD%E7%BB%83%E7%9A%84%E4%BA%BA%E8%84%B8%E8%AF%86%E5%88%AB%E8%AE%AD%E7%BB%83%E5%92%8C%E5%9C%A8%E7%BA%BF%E6%8E%A8%E7%90%86%E7%9A%84%E6%A1%88%E4%BE%8B%E4%BB%A3%E7%A0%81%EF%BC%8C%E5%B9%B6%E5%8F%91%E5%B8%83%E5%9C%A8GitHub%E4%B8%8A%EF%BC%88https://github.com/ucloud/uai-sdk/tree/master/examples/mxnet/insightface%EF%BC%89%EF%BC%8C%E5%85%B6%E4%B8%AD%E5%8C%85%E6%8B%AC%E5%9F%BA%E4%BA%8EMXNet%E6%A1%86%E6%9E%B6%E7%9A%84%E4%BB%A3%E7%A0%81%E5%8F%8A%E5%BC%80%E5%8F%91%E6%A1%88%E4%BE%8B%E3%80%82%E6%8B%8D%E6%8B%8D%E8%B4%B7%E7%9A%84%E5%B7%A5%E7%A8%8B%E5%B8%88%E5%9F%BA%E4%BA%8E%E8%AF%A5%E6%A1%88%E4%BE%8B%EF%BC%8C%E7%BB%93%E5%90%88%E8%87%AA%E8%BA%AB%E4%BA%BA%E8%84%B8%E8%AF%86%E5%88%AB%E7%AE%97%E6%B3%95%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%92%8C%E6%95%B0%E6%8D%AE%EF%BC%8C**%E4%B8%80%E5%91%A8%E6%97%B6%E9%97%B4%E5%86%85%E5%B0%B1%E5%AE%8C%E6%88%90%E4%BA%86%E5%BC%80%E5%8F%91%E5%92%8C%E8%B0%83%E8%AF%95%EF%BC%8C**" rel="nofollow" target="_blank"&gt;https://github.com/deepinsight/insightfaceUCloud基于insightface开发了一整套能支持分布式训练的人脸识别训练和在线推理的案例代码，并发布在GitHub上（https://github.com/ucloud/uai-sdk/tree/master/examples/mxnet/insightface），其中包括基于MXNet框架的代码及开发案例。拍拍贷的工程师基于该案例，结合自身人脸识别算法的实现和数据，**一周时间内就完成了开发和调试，**&lt;/a&gt;）。并顺利在 UAI-Train 平台上逐步展开人脸识别算法的训练迭代工作。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/feb206a9272b43c7a6d4168a1b00a2f5" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：人脸识别算法接入过程&lt;/p&gt;

&lt;p&gt;在多次算法优化迭代尝试后，拍拍贷通过利用高维向量表征人脸，余弦距离表达相似度，最终在开源测试集准确率表现为：&lt;strong&gt;lfw 99.8%, cfp_fp 97%, agedb_30 98.2%&lt;/strong&gt; ，实际业务应用中的准确率高达 &lt;strong&gt;99%&lt;/strong&gt; 以上，进一步提升了风险监管、反欺诈等业务的效率。&lt;/p&gt;

&lt;p&gt;后续拍拍贷和 UCloud 计划在更多算法场景和应用场景展开深入合作，更好地服务于金融领域客户。&lt;/p&gt;

&lt;p&gt;对人工智能更多应用场景和解决方案感兴趣的，欢迎扫描下方二维码进群交流。
&lt;img src="http://p1.pstatp.com/large/pgc-image/6f5b37bacc96424f99d1f596f0871050" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;TIC 2019 报名火热进行中，欢迎扫描下方二维码或点击阅读原文加入我们，共同探讨企业上云的更多落地案例！
&lt;img src="http://p3.pstatp.com/large/pgc-image/57db29c56723435cb0ddd9896b11fb0a" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 10 May 2019 15:16:37 +0800</pubDate>
      <link>https://ruby-china.org/topics/38505</link>
      <guid>https://ruby-china.org/topics/38505</guid>
    </item>
    <item>
      <title>分享一个无套路的读书日抽奖活动！是送礼包哦~</title>
      <description>&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2019/88ba9eb9-d53a-4d40-af88-f70320dfa76c.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4 月 22 日 -4 月 28 日持续抽奖&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;技术书籍 + 小米随身蓝牙音箱 + 定制笔记本&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;想要进群交流的，不要错过这班车哟！&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Mon, 22 Apr 2019 18:40:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/38440</link>
      <guid>https://ruby-china.org/topics/38440</guid>
    </item>
    <item>
      <title>USQL 如何帮爱普新媒降低 80%成本，提升 50%数据分析速度</title>
      <description>&lt;p&gt;&lt;strong&gt;“使用 USQL 产品，用户在原有的数据文件基础上进行数据建模，即可使用 SQL 进行业务数据的快速查询，此种方式对原有数据文件改动较小，用户不用关注大数据分布式处理的过程，业务迁移方便。对比我们现有的大数据处理方案，节省 80% 的服务器成本，提升 50% 数据分析速度，同时也缩短了新业务的开发周期，值得推荐。”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;——爱普新媒 CTO 牛德恒&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;USQL 是什么？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;数据湖分析（USQL）是一种可扩展性强、成本低廉的无服务器 SQL 分析计算引擎，可轻松完成面向海量数据的数据建模工作，SQL 即可完成数据查询和分析，极大降低使用大数据的门槛，且无需数据库管理员和运维人员，大幅度减少对大数据工程师的依赖。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;USQL 在爱普新媒案例中的表现&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;计算成本降低 97.5%&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;相较于爱普新媒现在每月花费在数据仓库 UDW（用于临时存放数据）的数千元，处理同样的数据，USQL 可将成本控制在每月几十元，因为 USQL 按照实际分析数据量计费，每 GB 数据分析价格极低，且不使用时不计费。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;任务周期缩短 55.6%&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;爱普新媒现有架构下，处理不固定的数据需求，数据导入与分析平均处理时长为 1.8 天，而 USQL 可省去数据导入的步骤，减少运维工作量，大幅度缩短每次任务完成时间。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;分析效率提升 5 倍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;爱普新媒所有真实业务 SQL 均已落地，其中最耗时的 SQL 分析时间可从 600 秒降至 118 秒，整体明显提高 SQL 分析效率。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;大数据工程师投入降为 0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;目前每月需投入大数据工程师 20 个人日，使用 USQL 产品，业务分析师可直接通过 SQL 在对象存储 UFile 中完成数据分析，极大减少对工程师的依赖，有限的人力资源可得到更好的利用。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;关于爱普新媒&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;成立于 2010 年，是一家专注于移动互联网产品研发和新媒体整合营销的高新技术型公司，旗下拥有 100 余款精品软件，内容涵盖日常生活、效率工具、文章资讯等多个方面，主营以天气预报、快游等综合自媒体矩阵为载体的推广业务和以云魔方 DSP 移动互联网广告分发平台为基础的广告投放业务。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/9a056251ff854931a3a100e13fb397be" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面临的数据挑战&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;爱普新媒广告业务数据规模达到数百 TB，日增长量为 1TB 左右，业务日常不固定的分析需求多，现有的大数据处理方案下，数据部门每月需投入大数据工程师 20 个人日，额外花费数千元维持一个数据仓库集群，且平均每次需求处理时长为 1.8 天。基于已有架构，数据部门将广告日志数据压缩后存放于对象存储 UFile 中，接收到业务分析师不固定的数据需求后，再将用于分析的原始数据，临时加载到数据仓库 UDW 中，完成 SQL 分析后实施清除操作。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/95fb082bbc604294a0c21887bb78f111" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：爱普新媒现有架构&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;业务分析师的抱怨&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;对于业务分析师而言，数据规模达到数百 TB，无法自主完成分析，必须极大程度依赖大数据工程师；并且每次任务处理周期长，若后续有需求变更或分析结果未达预期，还需重新走一遍处理流程；此外当对分析结果存有疑问时，无法查看原始数据进行校验。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;数据部门的烦恼&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;业务每月的不固定数据分析需求多，又无法自主完成，需要占用数据部门有限的技术人力资源；需求变动返工次数多，会导致大量重复性工作；并且随着数据规模日增长量的不断提升，用于临时存放不固定需求数据的 GreenPlum 成本一直在增加。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;产品诉求&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;基于现状，爱普新媒的产品需求清晰明确：&lt;/p&gt;

&lt;p&gt;支持数百 TB 规模的数据分析
业务分析师能够独立完成不固定需求分析工作
具有较强的 Ad-Hoc 能力
缩短每次需求处理时长
降低计算成本投入和运维投入&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;选择 USQL 产品&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;带着上述诉求，爱普新媒留意到 UCloud 推出的 USQL 产品，对其无运维、低成本、低门槛的产品理念产生浓厚兴趣，当即联系 UCloud 架构师表达试用的意愿。&lt;/p&gt;

&lt;p&gt;在与其数据部门沟通的过程中，UCloud 架构师发现对方务实且拥有开放的学习态度，对云计算也一直保持极大的好奇心，接触了解过数据湖以及 Serverless 的概念，为双方的交流奠定了良好的基础。此外现有架构中计算与存储是分离的状态，其原始数据并未与 GreenPlum 强耦合，这为更换分析引擎的方案实施提供了便利。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;USQL 替换 GreenPlum&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;新架构中使用 USQL 替换原先用于临时加载数据的 GreenPlum，省去数据从 UFile 导入到 GreenPlum 的过程，并使得业务分析师能够直接通过 SQL 分析 UFile 中海量数据，全程无需大数据工程师的参与。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/adeed23f7f4543779e16344f91b73da0" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：爱普新媒新架构&lt;/p&gt;

&lt;p&gt;此外，数据对接中发现，爱普新媒的数据格式为 JSON 并通过 GZIP 格式压缩，UCloud 了解后一周内完成 USQL 产品升级，得以支持这两种数据格式，减少对接上的障碍，并协助爱普新媒重新布局其现有数据，目前爱普新媒实际业务 SQL 已全部落地，同时完成产品培训以及现场演示。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/6bba666a49b24963a29db73c08a08d06" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：实际业务 SQL 示例&lt;/p&gt;

&lt;p&gt;结果显示分析效率可提高 5 倍，CTO 观看 USQL 的实例演示后，当场测算成本，对其在降低成本、提高效率、减少人力方面的表现感到超出预期，已决定将所有离线计算业务都放在 USQL 上。&lt;/p&gt;

&lt;p&gt;如果您也有大数据分析成本的困扰，欢迎加入我们的数据分析群共同探讨！&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/aa7730f7e50044de9c9b3539eee78d72" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Mon, 22 Apr 2019 17:33:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/38439</link>
      <guid>https://ruby-china.org/topics/38439</guid>
    </item>
    <item>
      <title>Kubernetes 源码探疑：Pod IP 泄露排查及解决</title>
      <description>&lt;p&gt;UK8S 是 UCloud 推出的 Kubernetes 容器云产品，完全兼容原生 API，为用户提供一站式云上 Kubernetes 服务。我们团队自研了 CNI（Container Network Interface）网络插件，深度集成 VPC，使 UK8S 容器应用拥有与云主机间等同的网络性能（目前最高可达 10Gb/s, 100 万 pps），并打通容器和物理云/托管云的网络。过程中，我们解决了开源 kubelet 创建多余 Sandbox 容器导致 Pod IP 莫名消失的问题，确保 CNI 插件正常运行，并准备将修复后的 kubelet 源码提交给社区。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;深度集成 VPC 的网络方案&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;按照我们的设想，开发者可以在 UK8S 上部署、管理、扩展容器化应用，无需关心 Kubernetes 集群自身的搭建及维护等运维类工作。UK8S 完全兼容原生的 Kubernetes API，以 UCloud 公有云资源为基础，通过自研的插件整合打通了 ULB、UDisk、EIP 等公有云网络和存储产品，为用户提供一站式云上 Kubernetes 服务。&lt;/p&gt;

&lt;p&gt;其中 VPC 既保障网络隔离，又提供灵活的 IP 地址定义等，是用户对网络的必备需求之一。UK8S 研发团队经过考察后认为，UCloud 基础网络平台具有原生、强大的底层网络控制能力，令我们能抛开 Overlay 方案，把 VPC 的能力上移到容器这一层，通过 VPC 的能力去实现控制和转发。UK8S 每创建一个 Pod 都为其申请一个 VPC IP 并通过 VethPair 配置到 Pod 上，再配置策略路由。原理如下图所示。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a108f5ce1ae05e?w=640&amp;amp;h=329&amp;amp;f=jpeg&amp;amp;s=18936" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;此方案具有以下优势：&lt;/p&gt;

&lt;p&gt;无 Overlay，网络性能高。50 台 Node 下的测试数据表明，容器与容器之间的网络性能，相对于云主机与云主机之间，只有轻微差异（小包场景下，pps 会有 3~5% 损耗），而且 Pod 网络性能各项指标 (吞吐量，包量，延迟等) 不会随着节点规模增大而削减。而 Flannel UDP，VXLan 模式和 Calico IPIP 的模式存在明显的性能消耗。
Pod 能直通公有云和物理云。对于使用公有云和物理云的用户而言，业务上 K8S 少了一层障碍，多了一份便利。而 Flannel 的 host gw 模式下，容器无法访问公有云和物理云主机。
而 CNI 的工作流程如下所示。&lt;/p&gt;

&lt;p&gt;创建 Pod 网络过程：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a1090fefbe989d?w=1080&amp;amp;h=282&amp;amp;f=jpeg&amp;amp;s=30577" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;删除 Pod 网络过程：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a10915a4c9436a?w=1080&amp;amp;h=216&amp;amp;f=jpeg&amp;amp;s=26319" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pod IP 消失问题的排查与解决&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为了测试 CNI 插件的稳定性，测试同学在 UK8S 上部署了一个 CronJob，每分钟运行一个 Job 任务，一天要运行 1440 个任务。该 CronJob 定义如下：&lt;/p&gt;

&lt;p&gt;apiVersion: batch/v1beta1 kind: CronJob metadata: name: hello spec: schedule: "*/1 * * * *" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date; echo Hello from the Kubernetes cluster restartPolicy: OnFailure&lt;/p&gt;

&lt;p&gt;每运行一次 Job 都要创建一个 Pod，每创建一个 Pod，CNI 插件需要申请一次 VPC IP，当 Pod 被销毁时，CNI 插件需要释放该 VPC IP。因此理论上，通过该 CronJob 每天需要进行 1440 次申请 VPC IP 和释放 VPC IP 操作。&lt;/p&gt;

&lt;p&gt;然而，经过数天的测试统计，发现通过该 CronJob，集群每天申请 IP 次数高达 2500 以上，而释放的的 IP 次数也达到了 1800。申请和释放次数都超过了 1440，而且申请次数超过了释放次数，意味着，部分分配给 Pod 的 VPC IP 被无效占用而消失了。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CNI：待删除的 IP 去哪儿了？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;仔细分析 CNI 插件的运行日志，很快发现，CNI 在执行拆除 SandBox 网络动作（CNI_COMMAND=DEL）中，存在不少无法找到 Pod IP 的情况。由于 UK8S 自研的 CNI 查找 Pod IP 依赖正确的 Pod 网络名称空间路径 (格式：/proc/10001/net/ns)，而 kubelet 传给 CNI 的 NETNS 环境变量参数为空字符串，因此，CNI 无法获取待释放的 VPC IP，这是造成 IP 泄露的直接原因，如下图所示。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a1092669077638?w=640&amp;amp;h=431&amp;amp;f=jpeg&amp;amp;s=25131" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;问题转移到 kubelet，为什么 kubelet 会传入一个空的 CNI_NETNS 环境变量参数给 CNI 插件？&lt;/p&gt;

&lt;p&gt;随后跟踪 kubelet 的运行日志，发现不少 Job Pod 创建和销毁的时候，生成了一个额外的 Sandbox 容器。Sandbox 容器是 k8s pod 中的 Infra 容器，它是 Pod 中第一个创建出来的容器，用于创建 Pod 的网络名称空间和初始化 Pod 网络，例如调用 CNI 分配 Pod IP，下发策略路由等。它执行一个名为 pause 的进程，这个进程绝大部分时间处于 Sleep 状态，对系统资源消耗极低。奇怪的是，当任务容器 busybox 运行结束后，kubelet 为 Pod 又创建了一个新的 Sandbox 容器，创建过程中自然又进行了一次 CNI ADD 调用，再次申请了一次 VPC IP。&lt;/p&gt;

&lt;p&gt;回到 UK8S CNI，我们再次分析重现案例日志。这一次有了更进一步的发现，所有 kubelet 传递给 NETNS 参数为空字符串的情形都发生在 kubelet 试图销毁 Pod 中第二个 Sandbox 的过程中。反之，kubelet 试图销毁第二个 Sandbox 时，给 CNI 传入的 NETNS 参数也全部为空字符串。&lt;/p&gt;

&lt;p&gt;到这里，思路似乎清晰了不少，所有泄露的 VPC IP 都是来自第二个 Sandbox 容器。因此，我们需要查清楚两个问题：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;为什么会出现第二个 Sandbox 容器？&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;为什么 kubelet 在销毁第二个 Sandbox 容器时，给 CNI 传入了不正确的 NETNS 参数？&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;第二个 Sandbox：我为何而生？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在了解的第二个 Sandbox 的前世今生之前，需要先交待一下 kubelet 运行的基本原理和流程。&lt;/p&gt;

&lt;p&gt;kubelet 是 kubernetes 集群中 Node 节点的工作进程。当一个 Pod 被 kube-sheduler 成功调度到 Node 节点上后，kubelet 负责将这个 Pod 创建出来，并把它所定义的各个容器启动起来。kubelet 也是按照控制器模式工作的，它的工作核心是一个控制循环，源码中称之为 syncLoop，这个循环关注并处理以下事件：&lt;/p&gt;

&lt;p&gt;Pod 更新事件，源自 API Server；
Pod 生命周期 (PLEG) 变化，源自 Pod 本身容器状态变化，例如容器的创建，开始运行，和结束运行；
kubelet 本身设置的周期同步（Sync）任务；
Pod 存活探测（LivenessProbe）失败事件；
定时的清理事件（HouseKeeping）。
在上文描述的 CronJob 任务中，每次运行 Job 任务都会创建一个 Pod。这个 Pod 的生命周期中，理想情况下，需要经历以下重要事件：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Pod 被成功调度到某个工作节点，节点上的 Kubelet 通过 Watch APIServer 感知到创建 Pod 事件，开始创建 Pod 流程；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;kubelet 为 Pod 创建 Sandbox 容器，用于创建 Pod 网络名称空间和调用 CNI 插件初始化 Pod 网络，Sandbox 容器启动后，会触发第一次 kubelet PLEG(Pod Life Event Generator) 事件。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;主容器创建并启动，触发第二次 PLEG 事件。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;主容器 date 命令运行结束，容器终止，触发第三次 PLEG 事件。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;kubelet 杀死 Pod 中残余的 Sandbox 容器。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sandbox 容器被杀死，触发第四次 PLEG 事件。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;其中 3 和 4 由于时间间隔短暂，可能被归并到同一次 PLEG 事件（kubelet 每隔 1s 进行一次 PLEG 事件更新）。&lt;/p&gt;

&lt;p&gt;然而，在我们观察到的所有 VPC IP 泄露的情况中，过程 6 之后“意外地”创建了 Pod 的第二个 Sandbox 容器，如下图右下角所示。在我们对 Kubernetes 的认知中，这不应该发生。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a109344cb2d40d?w=558&amp;amp;h=183&amp;amp;f=jpeg&amp;amp;s=16790" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;对 kubelet 源码 (1.13.1) 抽丝剥茧&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;前文提到，syncLoop 循环会监听 PLEG 事件变化并处理之。而 PLEG 事件，则来源 kubelet 内部的一个 pleg relist 定时任务。kubelet 每隔一秒钟执行一次 relist 操作，及时获取容器的创建，启动，容器，删除事件。&lt;/p&gt;

&lt;p&gt;relist 的主要责任是通过 CRI 来获取 Pod 中所有容器的实时状态，这里的容器被区分成两大类：Sandbox 容器和非 Sandbox 容器，kubelet 通过给容器打不同的 label 来识别之。CRI 是一个统一的容器操作 gRPC 接口，kubelet 对容器的操作，都要通过 CRI 请求来完成，而 Docker，Rkt 等容器项目则负责实现各自的 CRI 实现，Docker 的实现即为 dockershim，dockershim 负责将收到的 CRI 请求提取出来，翻译成 Docker API 发给 Docker Daemon。&lt;/p&gt;

&lt;p&gt;relist 通过 CRI 请求更新到 Pod 中 Sandbox 容器和非 Sandbox 容器最新状态，然后将状态信息写入 kubelet 的缓存 podCache 中，如果有容器状态发生变化，则通过 pleg channel 通知到 syncLoop 循环。对于单个 pod，podCache 分配了两个数组，分别用于保存 Sandbox 容器和非 Sandbox 容器的最新状态。&lt;/p&gt;

&lt;p&gt;syncLoop 收到 pleg channel 传来事件后，进入相应的 sync 同步处理流程。对于 PLEG 事件来说，对应的处理函数是 HandlePodSyncs。这个函数开启一个新的 pod worker goroutine，获取 pod 最新的 podCache 信息，然后进入真正的同步操作：syncPod 函数。&lt;/p&gt;

&lt;p&gt;syncPod 将 podCache 中的 pod 最新状态信息 (podStatus) 转化成 Kubernetes API PodStatus 结构。这里值得一提的是，syncPod 会通过 podCache 里各个容器的状态，来计算出 Pod 的状态 (getPhase 函数)，比如 Running，Failed 或者 Completed。然后进入 Pod 容器运行时同步操作：SyncPod 函数，即将当前的各个容器状态与 Pod API 定义的 SPEC 期望状态做同步。下面源码流程图可以总结上述流程。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a109396c864d36?w=640&amp;amp;h=522&amp;amp;f=jpeg&amp;amp;s=39641" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SyncPod：我做错了什么？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SyncPod 首先计算 Pod 中所有容器的当前状态与该 Pod API 期望状态做对比同步。这一对比同步分为两个部分：&lt;/p&gt;

&lt;p&gt;检查 podCache 中的 Sandbox 容器的状态是否满足此条件：Pod 中有且只有一个 Sandbox 容器，并且该容器处于运行状态，拥有 IP。如不满足，则认为该 Pod 需要重建 Sandbox 容器。如果需要重建 Sandbox 容器，Pod 内所有容器都需要销毁并重建。
检查 podCache 中非 Sandbox 容器的运行状态，保证这些容器处于 Pod API Spec 期望状态。例如，如果发现有容器主进程退出且返回码不为 0，则根据 Pod API Spec 中的 RestartPolicy 来决定是否重建该容器。
回顾前面提到的关键线索：所有的 VPC IP 泄露事件，都源于一个意料之外的 Sandbox 容器，被泄露的 IP 即为此 Sandbox 容器的 IP。刚才提到，SyncPod 函数中会对 Pod 是否需要重建 Sandbox 容器进行判定，这个意外的第二个 Sandbox 容器是否和这次判定有关呢？凭 kubelet 的运行日志无法证实该猜测，必须修改源码增加日志输出。重新编译 kubelet 后，发现第二个 Sandbox 容器确实来自 SyncPod 函数中的判定结果。进一步确认的是，该 SyncPod 调用是由第一个 Sandbox 容器被 kubelet 所杀而导致的 PLEG 触发的。&lt;/p&gt;

&lt;p&gt;那为什么 SyncPod 在第一个 Sandbox 容器被销毁后认为 Pod 需要重建 Sandbox 容器呢？进入判定函数 podSandboxChanged 仔细分析。&lt;/p&gt;

&lt;p&gt;podSandboxChanged 获取了 podCache 中 Sandbox 容器结构体实例，发现第一个 Sandbox 已经被销毁，处于 NOT READY 状态，于是认为 pod 中已无可用的 Sandbox 容器，需要重建之，源码如下图所示。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a1093d8ae25d53?w=1080&amp;amp;h=254&amp;amp;f=jpeg&amp;amp;s=36269" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;注意本文前面我们定位的 CronJob yaml 配置，Job 模板里的 restartPolicy 被设置成了 OnFailure。SyncPod 完成 Sandbox 容器状态检查判定后，认为该 Pod 需要重建 Sandbox 容器，再次检查 Pod 的 restartPolicy 为 OnFailure 后，决定重建 Sandbox 容器，对应源码如下。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a10941205a85a3?w=640&amp;amp;h=338&amp;amp;f=jpeg&amp;amp;s=24557" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以看出 kubelet 在第一个 Sandbox 容器死亡后触发的 SyncPod 操作中，只是简单地发现唯一的 Sandbox 容器处于 NOT READY 状态，便认为 Pod 需要重建 Sandbox，忽视了 Job 的主容器已经成功结束的事实。&lt;/p&gt;

&lt;p&gt;事实上，在前面 syncPod 函数中通过 podCache 计算 API PodStatus Phase 的过程中，kubelet 已经知道该 Pod 处于 Completed 状态并存入 apiPodStatus 变量中作为参数传递给 SyncPod 函数。如下图所示。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a10944f44706d3?w=1080&amp;amp;h=335&amp;amp;f=jpeg&amp;amp;s=30446" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;Job 已经进入 Completed 状态，此时不应该重建 Sandbox 容器。而 SyncPod 函数在判定 Sandbox 是否需要重建时，并没有参考调用者 syncPod 传入的 apiPodStatus 参数，甚至这个参数是被忽视的。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a109486b16c88d?w=1080&amp;amp;h=266&amp;amp;f=jpeg&amp;amp;s=31198" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;第二个 Sandbox 容器的来源已经水落石出，解决办法也非常简单，即 kubelet 不为已经 Completed 的 Pod 创建 Sandbox，具体代码如下所示。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a1094bc4dbff34?w=1080&amp;amp;h=289&amp;amp;f=jpeg&amp;amp;s=43010" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;重新编译 kubelet 并更新后，VPC IP 泄露的问题得到解决。&lt;/p&gt;

&lt;p&gt;下图可以总结上面描述的第二个 Sandbox 容器诞生的原因。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a1094f0c86279b?w=640&amp;amp;h=315&amp;amp;f=jpeg&amp;amp;s=21558" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;事情离真相大白还有一段距离。还有一个问题需要回答：&lt;/p&gt;

&lt;p&gt;为什么 kubelet 在删除第二个 Sandbox 容器的时候，调用 CNI 拆除容器网络时，传入了不正确的 NETNS 环境变量参数？&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;失去的 NETNS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;还记得前面介绍 kubelet 工作核心循环 syncLoop 的时候，里面提到的定期清理事件 (HouseKeeping) 吗？HouseKeeping 是一个每隔 2s 运行一次的定时任务，负责扫描清理孤儿 Pod，删除其残余的 Volume 目录并停止该 Pod 所属的 Pod worker goroutine。HouseKeeping 发现 Job Pod 进入 Completed 状态后，会查找该 Pod 是否还有正在运行的残余容器，如有则请理之。由于第二个 Sandbox 容器依然在运行，因此 HouseKeeping 会将其清理，其中的一个步骤是清理该 Pod 所属的 cgroup，杀死该 group 中的所有进程，这样第二个 Sandbox 容器里的 pause 进程被杀，容器退出。&lt;/p&gt;

&lt;p&gt;已经死亡的第二个 Sandbox 容器会被 kubelet 里的垃圾回收循环接管，它将被彻底停止销毁。然而由于之前的 Housekeeping 操作已经销毁了该容器的 cgroup, 网络名称空间不复存在，因此在调用 CNI 插件拆除 Sandbox 网络时，kubelet 无法获得正确的 NETNS 参数传给 CNI，只能传入空字符串。&lt;/p&gt;

&lt;p&gt;到此，问题的原因已经确认。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题解决&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;一切水落石出后，我们开始着手解决问题。为了能确保找到所删除的 Pod 对应的 VPC IP，CNI 需要在 ADD 操作成功后，将 PodName，Sandbox 容器 ID，NameSpace，VPC IP 等对应关联信息进行额外存储。这样当进入 DEL 操作后，只需要通过 kubelet 传入的 PodName，Sandbox 容器 ID 和 NameSpace 即可找到 VPC IP，然后通过 UCloud 公有云相关 API 删除之，无需依赖 NETNS 操作。&lt;/p&gt;

&lt;p&gt;考虑到问题的根因是出现在 kubelet 源码中的 SyncPod 函数，UK8S 团队也已修复 kubelet 相关源码并准备提交 patch 给 Kubernetes 社区。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kubernetes 依然是一个高速迭代中的开源项目，生产环境中会不可用避免遇见一些异常现象。UK8S 研发团队在学习理解 Kubernetes 各个组件运行原理的同时，积极根据现网异常现象深入源码逐步探索出问题根因，进一步保障 UK8S 服务的稳定性和可靠性，提升产品体验。&lt;/p&gt;

&lt;p&gt;2019 年内 UK8S 还将支持节点弹性伸缩 (Cluster AutoScaler)、物理机资源、GPU 资源、混合云和 ServiceMesh 等一系列特性，敬请期待。&lt;/p&gt;

&lt;p&gt;欢迎扫描下方二维码，加入 UCloud K8S 技术交流群，和我们共同探讨 Kubernetes 前沿技术。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-gold-cdn.xitu.io/2019/4/12/16a10952f22e13dd?w=640&amp;amp;h=851&amp;amp;f=jpeg&amp;amp;s=64446" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;如显示群人数已加满，可添加群主微信 zhaoqi628543，备注 K8S 即可邀请入群。&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 12 Apr 2019 16:45:35 +0800</pubDate>
      <link>https://ruby-china.org/topics/38389</link>
      <guid>https://ruby-china.org/topics/38389</guid>
    </item>
    <item>
      <title>使用 GlobalSSH 加速 Ansible 海外部署效率</title>
      <description>&lt;p&gt;&lt;strong&gt;什么是 Ansible&lt;/strong&gt;
Ansible 是一个简单高效、无 Agent 架构的自动化编排、部署及配置管理工具，通过 SSH 协议实现远程节点和管理节点之间的通信。&lt;/p&gt;

&lt;p&gt;Ansible 的目的是简化大量复杂重复的运维工作，以精简的技术思路建立公司内统一的自动化文化。无 Agent 的架构使其比其他工具更显简单，基于 SSH 可以做到的事 Ansible 都可以做的更好，超高的易用度使其可以简单集成到现有体系之中，因而被广泛使用。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/a23892f718bc4f368d41e3eb57347223" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UCloud Ansible 使用场景&lt;/strong&gt;
UCloud 内部也大量使用到了 Ansible。比如，机房产品部署系统，通过 Ansible 实现了部署效率的极大提升，目前已经成为 UCloud 机房部署的重要工具。又如，现网大规模灰度发布系统，通过集成 Ansible 的基础 API 和 Callback 功能，很好的解决了灰度发布、回滚、控制等难题，该系统已经在线上稳定运行 3 年以上，完成相关灰度发布任务上万个。&lt;/p&gt;

&lt;p&gt;下面将详细介绍 Ansible 在机房产品部署系统中的使用，相信对有多机房部署需求的读者会有帮助。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;海外多机房部署&lt;/strong&gt;
我们基于 Ansible 集中式地批量部署和管理服务，集中式管理中心位于北京/上海机房。当海外节点（如拉各斯、胡志明等）需要建设时，通过 Ansible 来远程部署云产品及内部服务。部分云产品是基于 UCloud 云主机作为 IaaS 层搭建的，所以也是通过 SSH 连到对应的海外云主机进行操作。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/45e00b015bee4c319fcb87290f0c070c" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;这和一般用户的使用场景有很多相似之处，无论其是自建 IDC 或用了公有云，甚至多云部署来同时管理不同云上的服务器，都有类似批量部署的需要。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/1b93ba32ec6f4e18937b8552224e3274" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;海外部署有个额外的痛点，就是部署效率的问题。Ansible 使用 SSH 协议进行通信，SSH 通道的创建和通信速度都较慢。当需要通过外网管理，而网络环境较差或带宽不足的情况下，执行时间基本上无法忍耐，体现在用 Ansible 部署时，经常会出现卡顿、连接失败、传输速度较慢等现象，使用 Copy 模块传输稍大的代码包/镜像文件时基本上要等到花儿都谢了。&lt;/p&gt;

&lt;p&gt;我们的解决方法，是把 UCloud 的 PaaS 产品 GlobalSSH，集成进 Ansible，用于提高跨国远程管理服务器效率。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GlobalSSH&lt;/strong&gt;
GlobalSSH 为了保障海外数据中心的运维而推出，采用了 UCloud 众多 IaaS 产品如 ULB4（四层负载均衡）、UDPN（洲际内网互联、0 丢包）及高包量云主机，引入智能 DNS 服务以提供就近接入的能力。网络转发基于成熟稳定的 GRE、NAT 技术，支持 TCP 端口（除 80、443）四层转发。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/2a0030e118cc48498746204747122626" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ansible Playbook 方式部署&lt;/strong&gt;
我们将 GlobalSSH 集成到 Ansible，做一个简单的软件包拷贝及安装，步骤如下所示。&lt;/p&gt;

&lt;p&gt;1）首先，我们通过 UCloud API 或控制台在北京二和拉各斯（尼日利亚）各创建一台云主机，带宽为 1Mb，其中拉各斯机房会自动开启 GlobalSSH 功能（所有 UCloud 海外机房均会自动开启），如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/63bbfcc61542432b8ac834275479f0e7" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;2）准备一个简单的 Ansible Playbook，分别完成 3 个步骤：gather facts、copy 代码包以及 yum 安装代码。相关的 playbook 如下所示：&lt;/p&gt;

&lt;p&gt;--- - hosts: all tasks: - name: copy test copy: src=/data/MySQL-devel-5.6.41-1.el6.x86_64.rpm dest=/data/test - name: install mysql-devel yum: name=/data/MySQL-devel-5.6.41-1.el6.x86_64.rpm state=present
3）准备一个 hosts 文件，用于配置 GlobalSSH 所生成的域名。Ansible 在对 GlobalSSH 的支持上非常简单，只要在主机变量里面添加 ansible_ssh_host=xxx.xxx.xxx.xxx.ipssh.net 即可。我们的机房部署系统会结合 Ansible 的 Dynamic Inventory 功能，直接在生成的 inventory 中将 GlobalSSH 的加速域名加到 ansible_ssh_host 变量中了，使用起来也是非常容易的，如下所示。&lt;/p&gt;

&lt;p&gt;[root@10-10-83-122 ~]# cat hosts_nrly [all] 152.32.140.39 ansible_ssh_pass=example [root@10-10-83-122 ~]# cat hosts_nrly_1 [all] 152.32.140.39 ansible_ssh_pass=example ansible_ssh_host=152.32.140.39.ipssh.net
4）使用 ansible-playbook 命令执行该 playbook，任务完成。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;测试对比&lt;/strong&gt;
前面提到，GlobalSSH 大幅提高了我们海外部署的效率。可以通过另写一个无 GlobalSSH 加速的 Playbook，来测试一下具体的加速效果。&lt;/p&gt;

&lt;p&gt;无 GlobalSSH 的 Playbook 写起来比较简单，和上文基本类似，区别在第三步的 hosts 文件里不使用加速域名，而是直接填写原有的外网 IP 地址。&lt;/p&gt;

&lt;p&gt;为防止单次测试结果的不准确，这里测试了 10 次，取平均值进行比较。&lt;/p&gt;

&lt;p&gt;测试命令：&lt;/p&gt;

&lt;p&gt;time for i in &lt;code&gt;seq 1 10&lt;/code&gt;; do ansible-playbook -i hosts_nrly test_playbook.yml; done time for i in &lt;code&gt;seq 1 10&lt;/code&gt;; do ansible-playbook -i hosts_nrly_1 test_playbook.yml; done
最终的结果如下所示，可以看到在简单的 Ansible Playbook 部署中，经过 GlobalSSH 加速后的效果提升了 32.23%.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/b83a22a2da4d4d12b514193b750688dc" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ansible Ad-hoc 方式&lt;/strong&gt;
GlobalSSH 在低速的带宽下可以提升整个网络传输的稳定性和速度，尤其是对 RTT (Round-Trip Time) 往返延迟的提升，更是有着外网弹性 IP 所不具备的速度优势。因此我们认为它对 Ansible Ad-hoc 方式也有很大帮助。&lt;/p&gt;

&lt;p&gt;运维人员经常会用 Ad-hoc 方式，它类似 pssh，却支持 Ansible 所有的 module 语法，通常的使用场景是批量执行命令并查看回显结果。为了验证假设，我们对 Ad-hoc 方式也做了类似测试，发现 GlobalSSH 后的优化效果更明显，优化速度超过 50%，详细结果如下所示。&lt;/p&gt;

&lt;p&gt;测试命令：&lt;/p&gt;

&lt;p&gt;time for i in &lt;code&gt;seq 1 10&lt;/code&gt;; do ansible -i hosts_nrly all -m shell -a "cat /var/log/messages"; done time for i in &lt;code&gt;seq 1 10&lt;/code&gt;; do ansible -i hosts_nrly_1 all -m shell -a "cat /var/log/messages"; done&lt;/p&gt;

&lt;p&gt;测试结果：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/3d69b10e003945dd977471aab0267360" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;
Ansible 是被大量使用的 DevOps 工具，我们在使用中根据需要，将 GlobalSSH 很容易地集成其中，避免了服务器部署中 SSH 卡顿造成的不良影响。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;更多深度技术内容，微信关注“UCloud 技术”。&lt;/strong&gt;&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Wed, 03 Apr 2019 16:00:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/38340</link>
      <guid>https://ruby-china.org/topics/38340</guid>
    </item>
    <item>
      <title>高可用数据库 UDB 主从复制延时的解决</title>
      <description>&lt;p&gt;MySQL 主从复制的延时一直是业界困扰已久的问题。延时的出现会降低主从读写分离的价值，不利于数据实时性较高的业务使用 MySQL。&lt;/p&gt;

&lt;p&gt;UDB 是 UCloud 推出的云数据库服务，上线已达六年，运营了数以万计的 UDB MySQL 实例。除了提供高可用、高性能、便捷易用的产品特性，团队还平均每天帮助用户解决 2-3 起 MySQL 实例主从复制延时的问题。从大量实践中我们总结了主从复制延时的各种成因和解决方法，现分享于此。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;延时问题的重要性&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;主从复制机制广泛应用在 UDB 的内部实现中：UDB 创建的从库和主库就采用了“主从复制”的数据复制；另外，UDB 的主打产品“UDB MySQL 高可用实例”，也是采用 2 个数据库互为主从的“双主模式”来进行数据复制，而双主模式的核心就是主从复制机制。&lt;/p&gt;

&lt;p&gt;如果主从复制之间出现延时，就会影响主从数据的一致性。&lt;/p&gt;

&lt;p&gt;在高可用复制场景下，我们在 UDB 高可用容灾设计上考虑到，若出现主备数据不一致的场景，默认是不允许进行高可用容灾切换的。因为在主备数据不一致的情况下，此时发生容灾切换，且在新的主库写入了数据，那么从业务角度上，会产生意想不到的严重后果。&lt;/p&gt;

&lt;p&gt;复制延时问题，不仅在 UDB 高可用中会带来不良后果，在只读从库的场景下，若从库产生复制延时，也可能会对业务造成一定影响，比如在业务上表现为读写不一致——新增/修改数据查不到等现象。&lt;/p&gt;

&lt;p&gt;由此可见，主从复制的延时问题在数据库运营中需要特别关注。一般来说，DBA 在库上执行’SHOW SLAVE STATUS’，并且观察&lt;/p&gt;

&lt;p&gt;‘Seconds_Behind_Master’的值，就能够了解当前某个数据库和它的主库之间的数据复制延时。这个值是如此的重要，因此在 UDB 的监控界面上，我们将这个值单独抽取来，设计了“从库同步延时”监控项，以便于运维人员能够直接在控制台上观察。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/84b63178e796424896149b113421b858" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;生产环境中延时问题的分析及解决&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;我们将最常见的主从复制延时案例总结为几类，以下是相关案例的现象描述、原因分析和解决方法汇总。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;◆ 案例一：主库 DML 请求频繁&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;某些用户在业务高峰期间，特别是对于数据库主库有大量的写请求操作，即大量 insert、delete、update 等并发操作的情况下，会出现主从复制延时问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;现象描述&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;我们通过观察主库的写操作的 QPS 的值，会看到主库的写操作的 QPS 值突然升高，伴随主从复制延时的上升，可以判断是由于主库 DML 请求频繁原因造成的。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/9b9ece56472641ad9b149418cd5a76da" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;如上图，可以看出，在 17:58 分左右 QPS 突增，查看控制台上的写相关 QPS，也有相应提升。而 QPS 突增的时间，对应的延时也在逐步上升，如下图所示。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/6913c3662b5e40cb9bb98c98bbde90ed" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;原因分析&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;经过分析，我们认为这是由于主库大量的写请求操作，在短时间产生了大量的 binlog。这些操作需要全部同步到从库，并且执行，因此产生了主从的数据复制延时。&lt;/p&gt;

&lt;p&gt;从深层次分析原因，是因为在业务高峰期间的主库写入数据是并发写入的，而从库 SQL Thread 为单线程回放 binlog 日志，很容易造成 relaylog 堆积，产生延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;解决思路&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如果是 MySQL 5.7 以下的版本，可以做分片 (sharding)，通过水平扩展 (scale out) 的方法打散写请求，提升写请求写入 binlog 的并行度。&lt;/p&gt;

&lt;p&gt;如果是 MySQL 5.7 以上的版本，在 MySQL 5.7，使用了基于逻辑时钟 (Group Commit) 的并行复制。而在 MySQL 8.0，使用了基于 Write Set 的并行复制。这两种方案都能够提升回放 binlog 的性能，减少延时。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/8f1c311a297f4508ac21365342afeac0" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;◆ 案例二：主库执行大事务&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;大事务指一个事务的执行，耗时非常长。常见产生大事务的语句有：&lt;/p&gt;

&lt;p&gt;使用了大量速度很慢的导入数据语句，比如：INSERT INTO $tb、SELECT * FROM $tb、LOAD DATA INFILE 等；
使用了 UPDATE、DELETE 语句，对于一个很大的表进行全表的 UPDATE 和 DELETE 等。
当这个事务在从库执行回放执行操作时，就有可能会产生主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;现象描述&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;我们从 SHOW SLAVE STATUS 的结果进行分析，会发现 Exec_Master_Log_Pos 字段一直未变，且 second_behinds_master 持续增加，而 Slave_SQL_Running_State 字段的值为”Reading event from the relay log”；同时，分析主库 binlog，看主库当前执行的事务，会发现有一些大事务，这样基本可以判定是执行大事务的原因导致的主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/6eb23f89803041f7a69f827447641617" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;原因分析&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;当大事务记录入 binlog 并同步到从库之后，从库执行这个事务的操作耗时也非常长，这段时间，就会产生主从复制延时。&lt;/p&gt;

&lt;p&gt;举个例子，假如主库花费 200s 更新了一张大表，在主从库配置相近的情况下，从库也需要花几乎同样的时间更新这张大表，此时从库延时开始堆积，后续的 events 无法更新。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;解决思路&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;对于这种情况引起的主从复制延时，我们的改进方法是：拆分大事务语句到若干小事务中，这样能够进行及时提交，减小主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;◆ 案例三：主库对大表执行 DDL 语句&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DDL 全称为 Data Definition Language，指一些对表结构进行修改操作的语句，比如，对表加一个字段或者加一个索引等等。当 DDL 对主库大表执行 DDL 语句的情况下，可能会产生主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;现象描述&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;从现象上，如果从库执行 SHOW SLAVE STATUS 的输出中，检查 Exec_Master_Log_Pos 一直未动，在排除主库执行大事务的情况下，那么就有可能是在执行大表的 DDL。这一点结合分析主库 binlog，看主库当前执行的事务就可以进行确认。&lt;/p&gt;

&lt;p&gt;DDL 语句的执行情况，可以进一步细分现象来更好地判断：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; DDL 未开始，被阻塞，这时 SHOW SLAVE STATUS 的结果能检查到 Slave_SQL_Running_State 为 waiting for table metadata lock，且 Exec_Master_Log_Pos 不变；&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/0537ce3ffa01411ab524a726488839fb" title="" alt=""&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; DDL 正在执行，SQL Thread 单线程应用导致延时增加。这种情况下观察 SHOW SLAVE STATU 的结果能发现 Slave_SQL_Running_State 为 altering table，而 Exec_Master_Log_Pos 不变。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/c59350bb17f14f699db6fcf7e079b680" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;如果有上述的现象，那么很有可能主库对大表执行 DDL 语句，同步到从库并在从库回放时，就产生了主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;原因分析&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DDL 导致的主从复制延时的原因和大事务类似，也是因为从库执行 DDL 的 binlog 较慢而产生了主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;解决思路&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;遇到这种情况，我们主要通过 SHOW PROCESSLIST 或对 information_schema.innodb_trx 做查询，来找到阻塞 DDL 语句，并 KILL 掉相关查询，让 DDL 正常在从库执行。&lt;/p&gt;

&lt;p&gt;DDL 本身造成的延时难以避免，建议考虑：&lt;/p&gt;

&lt;p&gt;避免业务高峰，尽量安排在业务低峰期执行；
set sql_log_bin=0 后，分别在主从库上手动执行 DDL（此操作对于某些 DDL 操作会造成数据不一致，请务必严格测试），这一条如果用户使用云数据库 UDB，可以联系 UCloud UDB 运维团队进行协助操作。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;◆ 案例四：主库与从库配置不一致&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如果主库和从库使用了不同的计算资源和存储资源，或者使用了不同的内核调教参数，可能会造成主从不一致。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;现象描述&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;我们会详细比对主库和从库的性能监控数据，如果发现监控数据差异巨大，结合查看主从的各个配置情况，即可作出明确判断。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;原因分析&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;各种硬件或者资源的配置差异都有可能导致主从的性能差异，从而导致主从复制延时发生：&lt;/p&gt;

&lt;p&gt;硬件上：比如，主库实例服务器使用 SSD 磁盘，而从库实例服务器使用普通 SAS 盘，那么主库产生的写入操作在从库上不能马上消化掉，就产生了主从复制延时；
配置上：比如，RAID 卡写策略不一致、OS 内核参数设置不一致、MySQL 落盘策略不一致等，都是可能的原因。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;解决思路&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;考虑尽量统一 DB 机器的配置（包括硬件及选项参数）。甚至对于某些 OLAP 业务，从库实例硬件配置需要略高于主库。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;◆ 案例五：表缺乏主键或合适索引&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如果数据库的表缺少主键或者合适索引，在主从复制的 binlog_format 设置为’row’的情况下，可能会产生主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;现象描述&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;我们进行数据库检查时，会发现：&lt;/p&gt;

&lt;p&gt;观察 SHOW SLAVE STATUS 的输出，发现 Slave_SQL_Running_State 为 Reading event from the relay log；
SHOW OPEN TABLES WHERE in_use=1 的表一直存在；
观察 SHOW SLAVE STATUS 的 Exec_Master_Log_Pos 字段不变；
mysqld 进程的 CPU 接近 100%（无读业务时），IO 压力不大。
这些现象出现的情况下，可以认为很可能有表缺乏主键或唯一索引。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;原因分析&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在主从复制的 binlog_format 设置为’row’的情况下，比如有这样的一个场景，主库更新一张 500 万表中的 20 万行数据。binlog 在 row 格式下，记录到 binlog 的为 20 万次 update 操作，也就是每次操作更新 1 条记录。如果这条语句恰好有不好的执行计划，如发生全表扫描，那么每一条 update 语句需要全表扫描。此时 SQL Thread 重放将特别慢，造成严重的主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;解决思路&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这种情况下，我们会去检查表结构，保证每个表都有显式自增主键，并协助用户建立合适索引。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;◆ 案例六：从库自身压力过大&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;有时候，从库性能压力很大的情况下，跟不上主库的更新速度，就产生了主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;现象描述&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;观察数据库实例时，会发现 CPU 负载过高，IO 利用率过高等现象，这些导致 SQL Thread 应用过慢。这样就可以判断是因为从库自身压力过大引起主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;原因分析&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;部分 UCloud 用户对于数据库的主从会使用读写分离模式，读请求大部分在从库上执行。在业务有大量读请求的场景下，从库会产生比主库大得多的性能压力。有的用户甚至会在从库运行十分耗费计算资源的 OLAP 业务，这也对从库造成了更高的性能挑战，这些都会造成主从复制的延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;解决思路&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这种情况下，我们会建议用户建立更多从库，打散读请求，降低现有从库实例的压力。对于 OLAP 业务来说，可以专门建立一个从库来做 OLAP 业务，并对这个从库，允许适当的主从复制延时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在使用 MySQL 的主从复制模式进行数据复制时，主从复制延时是一个需要考量的关键因素。它会影响数据的一致性，进而影响数据库高可用的容灾切换。&lt;/p&gt;

&lt;p&gt;在遇到数据库之间出现主从复制延时的情况下，我们团队基于过往经验，归纳出以下方法与流程来协助排查问题：&lt;/p&gt;

&lt;p&gt;通过 SHOW SLAVE STATUS 与 SHOW PROCESSLIST 查看现在从库的情况。（顺便也可排除在从库备份时的类似原因）；
若 Exec_Master_Log_Pos 不变，考虑大事务、DDL、无主键，检查主库对应的 binlog 及 position 即可；
若 Exec_Master_Log_Pos 变化，延时逐步增加，考虑从库机器负载，如 IO、CPU 等，并考虑主库写操作与从库自身压力是否过大。
UDB 的高可用、高性能、便捷易用，可以大量减轻使用者的运维负担。在使用过程中，UDB 团队也会利用多年累积的运营经验，帮助用户及时分析、排查问题原因，并给出合理的解决方法。&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 29 Mar 2019 16:38:00 +0800</pubDate>
      <link>https://ruby-china.org/topics/38312</link>
      <guid>https://ruby-china.org/topics/38312</guid>
    </item>
    <item>
      <title>UCloud 基于 Linux 内核新特性的下一代外网网关设计及相关开源工作</title>
      <description>&lt;p&gt;UCloud 外网网关是为了承载外网 IP、负载均衡等产品的外网出入向流量，当前基于 Linux 内核的 OVS/GRE tunnel/netns/iptables等实现，很好地支撑了现有业务。同时，我们也在不断跟踪开源社区的新技术发展，并将之用于下一代外网网关的设计。这些新特性可将系统性能和管理能力再提上一档，满足未来几年的需求。在方案设计研发过程中发现，新特性存在不少缺陷和Bug，为此我们向开源社区回馈了10多个patch，并融入到kernel 5.0 版本中，帮助完善 kernel 功能并提升稳定性。&lt;/p&gt;

&lt;p&gt;当前业界的多租户外网网关很多都是基于 OpenFlow 的 OpenvSwitch（OVS）方案，然而随着内核路由转发功能的不断完善，利用内核原生路由转发方式进行设计多租户外网网关系统成为一种可能。在这种方式下能有效的使用传统 iproute2 路由工具以及 iptables、nftables 等 Firewall 工具，并且随着 SwitchDev 技术的兴起，未来将网关系统迁移到 Linux Switch 上也成为一种可能。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;现有 kernel 3.x 的不足&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;当前广泛使用的内核版本为 3.x 系列，例如 CentOS 7 全系列标准支持的内核为 3.10 版本，Fedora/Ubuntu 等 Linux 发行版也有大量使用。在 3.x 系列内核下存在着 IP tunnel 管理复杂、租户隔离性能损耗等问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. IP tunnel 管理复杂&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Linux 内核创建 IP tunnel 设备来建立点对点的隧道连接，创建时需指定 tunnel dst 和 tunnel key。因为宿主机之间两两建立连接，面向宿主机的目的地址众多，这样就会导致网关节点上需要创建成千上万的 tunnel 设备，在大规模业务环境下，tunnel 的管理将变得及其复杂。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. 多租户隔离导致的性能下降&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;a. 公有云需要实现多租户隔离以确保用户间的安全和隐私。由于 VPC 网络下不同租户的内网地址可以重合，导致路由也有重合的可能性，此时需要通过大量的策略路由去隔离租户的路由规则，由于策略路由的链表属性，性能会随着链表长度的增加而急剧下降。&lt;/p&gt;

&lt;p&gt;b. 由于 Firewall 和 NAT 的实现基于同样链式的 iptables，性能损耗同样可观。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. netns 带来性能开销&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;通过 netns 实现租户路由和 Firewall 规则的隔离，但是 netns 会引入虚拟网卡和协议栈重入开销，使整体性能下降 20% 左右。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;三项内核新技术&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为了解决原有方案存在的困扰，我们调研了大量行业主流方案和内核上游的新动向，发现 Lightweight tunneling（轻量级隧道，简称 lwtunnel）、Virtual Routing Forwarding（虚拟路由转发，简称 VRF）以及 nftable &amp;amp; netfilter flow offload（流卸载）三项内核新技术的特性，可以帮助规避原方案存在的缺陷。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Lightweight tunneling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Linux 内核在 4.3 版本中引入了轻量级隧道 Lightweight tunneling，它提供了通过 route 方式设置 tunnel 属性的方法，这样可以避免管理大量的 tunnel 设备。&lt;/p&gt;

&lt;p&gt;创建隧道设备时指定 external 模式，利用路由设置的轻量级隧道通过 tun 设备发送报文。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/e13437c5dfdd4fffb3cd0bd8f7cda599" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Virtual Routing Forwarding&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Linux 内核在 4.3 版本中引入了 VRF 的初步支持，并在 4.8 版本形成完备版本。Virtual Routing Forwarding 虚拟路由转发，可以将一台 Linux Box 的物理路由器当多台虚拟路由器使用，能很好的解决租户路由隔离问题，避免直接使用策略路由。因此，可以将不同租户的网卡加入租户所属的虚拟路由器中来实现多租户的虚拟路由。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/e01c31ac8d524ed6b4ba4a66dedb6b4a" title="" alt=""&gt;
&lt;img src="http://p3.pstatp.com/large/pgc-image/4a74a4ae55904c9da744b1e0e5ab371a" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. flow offload&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nftables 是一种新的数据包分类框架，旨在替代现存的{ip,ip6,arp,eb}_tables。在 nftables 中，大部分工作是在用户态完成的，内核只知道一些基本指令（过滤是用伪状态机实现的）。nftables 的一个高级特性就是映射，可以使用不同类型的数据并映射它们。例如，我们可以映射 iif device 到专用的规则集合（之前创建的存储在一个链中）。由于是 hash 映射的方式，可以完美的避免链式规则跳转的性能开销。&lt;/p&gt;

&lt;p&gt;Linux 内核在版本 4.16 引入了 flow offload 功能，它为 IP forward 提供了基于流的卸载功能。当一条新建连接完成首回合原方向和反方向的报文时，完成路由，Firewall 和 NAT 工作后，在处理反方向首报文的 forward hook，根据报文路由、NAT 等信息创建可卸载 flow 到接收网卡 ingress hook 上。后续的报文可以在接收 ingress hook 上直接转发，不需要再进入 IP stack 处理。此外，将来 flow offload 还将支持 hardware offload 模式，这将极大提高系统转发性能。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/a36e38f0802a49e0b717732c99c619b1" title="" alt=""&gt;
&lt;img src="http://p1.pstatp.com/large/pgc-image/46f5a621ba60461b8310c4476613293f" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;方案设计与优化实践&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;通过对上述三项新技术的研究，我们发现可以尝试设计一套基于路由的方式，实现多租户 overlay 网络的外网网关。在方案设计过程中，我们也碰到了诸如 lwtunnel 和 flow offload 功能不足，以及 VRF 和 flow offload 不能一起有效的工作等问题。最终我们都设法解决了，并针对这些内核的不足提交 patch 给 Linux 开源社区。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. lwtunnel 发送报文 tunnel_key 丢失&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题描述：&lt;/strong&gt;我们利用 lwtunnel 路由方式发送报文时，创建了一个 external 类型的 gretap tunnel，我们将命令设置了 id 为 1000，但是发送成功报文中没有 tunnel_key 字段。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/19e93dbacca1451b823f114d805d32f9" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题定位：&lt;/strong&gt;我们研究 iproute2 代码，发现由于 TUNNEL_KEY flag 并没有开放给用户态，所以 iproute2 工具并没有对 lwtunnel 路由设置 TUNNEL_KEY，导致报文不会创建 tunnel_key 字段。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提交 patch：&lt;/strong&gt; 我们给内核和用户态 iproute2 分别提交 patch 来解决这一问题：&lt;/p&gt;

&lt;p&gt;iptunnel: make TUNNEL_FLAGS available in uapi&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/" rel="nofollow" target="_blank"&gt;https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/&lt;/a&gt;?
id=1875a9ab01dfa96b06cb6649cb1ce56efa86c7cb&lt;/p&gt;

&lt;p&gt;iproute: Set ip/ip6 lwtunnel flags&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=3d65cefbefc86a53877f1e6461a9461e5b8fd7b3" rel="nofollow" target="_blank"&gt;https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=3d65cefbefc86a53877f1e6461a9461e5b8fd7b3&lt;/a&gt;
提交 patch 后，可以通过以下方式设置路由。&lt;/p&gt;

&lt;p&gt;ip r r 2.2.2.11 via 1.1.1.11 dev tun encap ip id 1000 dst 172.168.0.1 key&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. lwtunnel 对指定 key 的 IP tunnel 无效&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题发现：&lt;/strong&gt;为了能有效隔离租户路由，我们给每个租户创建一个基于 tunnel_key 的 gretap tunnel 设备。如下图，创建一个 tunnel_key 1000 的 gretap tunnel 设备，把 tunnel 设备加入租户所属 VRF，tunnel 设备能有效地接收报文，但并不能发送报文。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/cae6d67a137d4b7d8a2ec8322f4c1c03" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;问题定位：研究内核发现，IP tunnel 在非 external 模式下即使指定了轻量级隧道路由，发送报文也没有使用它，导致报文路由错误被丢弃。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提交 patch：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ip_tunnel: Make none-tunnel-dst tunnel port work with lwtunnel&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d71b57532d70c03f4671dd04e84157ac6bf021b0" rel="nofollow" target="_blank"&gt;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d71b57532d70c03f4671dd04e84157ac6bf021b0&lt;/a&gt;
提交 patch 后，在未指定 tunnel_dst 的非 external 模式 IP tunnel 下，能使用轻量级隧道路由进行发送报文。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. external IP tunnel ARP 无法正常运行&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题描述：&lt;/strong&gt;邻居 IP tunnel 进行了 ARP 请求，但是本端的 ARP 回应报文的隧道头中并没带 tunnel_key 字段。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/062d7b0a4f54493fad7f534a7d28961b" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题定位：&lt;/strong&gt;研究代码发现，tunnel 收到了对端的 ARP 请求，在发送报文 ARP 回复的时候会复制请求报文的 tunnel 信息，但是遗漏了所有 tun_flags。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提交 patch：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;iptunnel: Set tun_flags in the iptunnel_metadata_reply from src&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7bdca378b2301b1fc6a95c60d6d428408ae4e39e" rel="nofollow" target="_blank"&gt;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7bdca378b2301b1fc6a95c60d6d428408ae4e39e&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Flow offload 不能与 DNAT 有效工作&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题描述：&lt;/strong&gt;Firewall 创建规则从 eth0 收到目的地址 2.2.2.11 的报文，DNAT 为 10.0.0.7，flow offload 无法工作。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/08622f9eb1f648e29cd65d31353bcff6" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题定位：&lt;/strong&gt;分析发现，客户端 1.1.1.7 —&amp;gt; 2.2.2.7 DNAT 到 server 10.0.0.7，第一个 reply 反向报文 (syc+ack) 使用了错的目的地址获取反向路由&lt;/p&gt;

&lt;p&gt;daddr = ct-&amp;gt;tuplehash[!dir].tuple.dst.u3.ip
此时 dir 为反方向，所以 daddr 获取为原方向的目的地址，这个值是 2.2.2.7, 但是由于被 DNAT 过，真正的路由不应该通过 2.2.2.7 去获取，而是应该根据 10.0.0.7 这个值去获取&lt;/p&gt;

&lt;p&gt;addr = ct-&amp;gt;tuplehash[dir].tuple.src.u3.ip&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提交 patch：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;netfilter: nft_flow_offload: Fix reverse route lookup&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a799aea0988ea0d1b1f263e996fdad2f6133c680" rel="nofollow" target="_blank"&gt;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a799aea0988ea0d1b1f263e996fdad2f6133c680&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Flow offload 不能与 VRF 有效工作&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;问题描述：&lt;/strong&gt; 将网卡 eth0 和 eth1 加入 VFR 后，flow offload 不起作用。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/2c798dc501014deeb866eccb3c20ee18" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题定位：&lt;/strong&gt;查看代码发现，原方向和反方向首报文进入协议堆栈后 skb-&amp;gt;dev 会设置为 vrf device user1，创建 flow offload 规则的 iif 就是 user1。但是 offload 规则下发在 eth0 和 eth1 的 ingress hook 上，所以后续报文在 eth0 和 eth1 的 ingress hook 上不能匹配 flow 规则。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提交 patch：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;netfilter: nft_flow_offload: fix interaction with vrf slave device&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=10f4e765879e514e1ce7f52ed26603047af196e2" rel="nofollow" target="_blank"&gt;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=10f4e765879e514e1ce7f52ed26603047af196e2&lt;/a&gt;
最终，我们根据两个方向查找路由的结果，设置 flow offload 规则的 iif 和 oif 信息来解决此问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. VRF PREROUTING hook 重入问题&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题描述：&lt;/strong&gt;配置网卡加入 VRF，firewall ingress 方向规则为接收目的地址 2.2.2.11、TCP 目的端口 22 的报文，egress 方向规则为丢弃 TCP 目的端口 22 的报文。出现异常结果：收到目的地址 2.2.2.11 TCP 22 目的端口的报文却被丢弃。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/f20a3d5dfa494caba4b3ef925204380b" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;问题定位：&lt;/strong&gt;研究发现网卡加入 VRF 后收到的报文会两次进入 PREROUTING hook，因为在进入 IP stack 时会进第一次 PREROUTING hook，然后被 VRF 设备接管后会再次进入 PREROUTING hook。上述规则第一次在 rule-1000-ingress chain 中 dst nat 为 10.0.0.7，第二次由于报文被 DNAT 后会错误的进入 rule-1000-egress，导致报文被丢弃。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提交 patch：&lt;/strong&gt;我们给内核加了一个支持判断网卡类型的 match 项目，让用户态避免可知的第二次无效重入，内核态和用户态 nftables 分别提交了如下的 patch：&lt;/p&gt;

&lt;p&gt;netfilter: nft_meta: Add NFT_META_I/OIFKIND meta type&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=0fb4d21956f4a9af225594a46857ccf29bd747bc" rel="nofollow" target="_blank"&gt;https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=0fb4d21956f4a9af225594a46857ccf29bd747bc&lt;/a&gt;
meta: add iifkind and oifkind support&lt;/p&gt;

&lt;p&gt;&lt;a href="http://git.netfilter.org/nftables/commit/?id=512795a673f999fb04b84dbbbe41174e9c581430" rel="nofollow" target="_blank"&gt;http://git.netfilter.org/nftables/commit/?id=512795a673f999fb04b84dbbbe41174e9c581430&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;使用方法：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;nft add rule firewall rules-all meta iifkind "vrf" counter accept&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;原型验证&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;最终，我们成功地利用 lwtunnel、VRF 和 flow offload 实现多租户外网网关的原型验证。验证过程如下：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. 首先创建原型环境。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;a. netns cl 模拟外网 client, 地址为 1.1.1.7，tunnel src 172.168.0.7，配置发送路由；&lt;/p&gt;

&lt;p&gt;b. netns ns1 模拟租户 1，内网地址为 10.0.0.7，外网地址为 2.2.2.11，tunnel src 172.168.0.11 tunnel_key 1000，配置发送路由；&lt;/p&gt;

&lt;p&gt;c. netns ns2 模拟租户 2，内网地址为 10.0.0.7，外网地址为 2.2.2.12，tunnel src 172.168.0.12 tunnel_key 2000，配置发送路由；&lt;/p&gt;

&lt;p&gt;d. Host 模拟外网网关，tunnel src 172.168.0.1，创建租户 VRF user1 和 use2，创建租户 IP tunnel tun1 和 tun2，配置转发路由。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;原型环境图如下：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/304f7ccccef94b73bb65b651dd4d32b0" title="" alt=""&gt;
&lt;img src="http://p1.pstatp.com/large/pgc-image/9d8bac8c417c4f4c809a957d7971df53" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. 创建 firewall 规则：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;a. 租户 1 入向允许 TCP 目的端口 22 和 ICMP 访问，出向禁止访问外部 TCP 22 目的端口；&lt;/p&gt;

&lt;p&gt;b. 租户 2 入向允许 TCP 端口 23 和 ICMP 访问，出向禁止访问外部 TCP 23 目的端口；&lt;/p&gt;

&lt;p&gt;c. 在租户 tun1 和 tun2 设备上支持 flow offload。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/cec54548227644f481261a7b08cb1b7e" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;最终，client 可以通过 2.2.2.11 成功访问 user1 tcp 22 端口服务，user1 不能访问 client tcp 22 端口服务；client 可以通过 2.2.2.12 成功访问 user2 tcp 23 端口服务，user1 不能访问 client tcp 23 端口服务。&lt;/p&gt;

&lt;p&gt;待后续 hardware offload 功能完善以及网卡厂商支持后，我们会做进一步的开发验证。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;以上是本项目涉及的部分核心问题，这些 patch 特性都可以在 Linux kernel 5.0 版本里获取。我们把这期间为 Linux kernel 社区贡献的 patch 整理成了一份列表，希望能为开发者提供帮助，读者可以点击&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?qt=author&amp;amp;q=wenxu%40ucloud.cn" rel="nofollow" target="_blank" title=""&gt;“阅读原文”&lt;/a&gt;阅览完整 patch list。&lt;/p&gt;

&lt;p&gt;Linux 作为成熟的开源套件，一直是云厂商使用的主流操作系统，但在技术的更新迭代过程中，一些新特性在实际应用上也会存在稳定性、兼容性等方面的问题。我们在研究使用上游技术的同时，也一直积极探索、丰富开源技术功能，帮助提高开源技术稳定性。并将产出持续回馈给社区，与社区共同构建一个繁荣的开源生态。&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Mon, 25 Mar 2019 17:55:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/38292</link>
      <guid>https://ruby-china.org/topics/38292</guid>
    </item>
    <item>
      <title>UCloud 可支撑单可用区 320,000 服务器的数据中心网络系统设计</title>
      <description>&lt;p&gt;2018 年 10 月份，UCloud 数据中心基础网络完成了 V4 新架构的落地，自此，新建的数据中心（下简称 DC）全面升级到 25G/100G 网络，极大提升了 DC 容量和 DC 间互联的性能。V4 架构下的单可用区可提供 320,000 个服务器接入端口，是此前 V3 架构的 4 倍。并且支持无损网络特性，提供可用区资源的水平扩展和滚动升级能力。上线以来，新架构有力保障了 UCloud 福建 GPU 可用区开放、北京二可用区 B/C/D 扩容等需求。&lt;/p&gt;

&lt;p&gt;对比云产品通过软件的灵活性来创造丰富的用户价值，公有云物理网络更注重规划的前瞻性与设计的合理性。其目标是简单、稳定、高效。通过对上层虚拟网络提供极度可靠的、一维寻址的逻辑连通面，来帮助实现上层产品“软件定义一切”的使命。下文就将详述我们秉承这种理念设计 DCN V4 架构的细节。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UCloud DCN V3 架构设计&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCloud 公有云以可用区（下简称 AZ）为最小资源池单位对外提供服务，一个可用区由一个或多个数据中心组成。UCloud 数据中心基础网络架构（下简称 DCN）在 2016 年升级到 V3 架构，如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/ea925f1c95a145f8b16aa3815c84c9a9" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：UCloud DCN V3 架构&lt;/p&gt;

&lt;p&gt;V3 架构的设计目的：&lt;/p&gt;

&lt;p&gt;全面升级到 10G 接入、40G 互连；
彻底拆掉了堆叠，避免了堆叠的种种弊端；
采用了两级 CLOS、Spine-Leaf 架构，实现了一定的水平扩展能力；
数据中心核心交换机为 Spine，提供标准的 BGP 路由接入，TOR/Border 为 Leaf；业务服务器的网关落在 TOR Leaf 上；DC 的 Border Leaf 连接城域网 POP 机房，实现 DC 到 DC 外的互通，一个 DC 即一个可用区。
V3 解决了 V2 时代堆叠和 MC-LAG 的弊端，CLOS 架构有水平扩展能力，全网统一接入方式提升了网络部署效率。&lt;/p&gt;

&lt;p&gt;V3 上线后，适逢 UCloud 发力建设海外节点，为首尔、东京、华盛顿、法兰克福等节点在短时间内的快速落地，提供了有效支撑。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/5ea9ef7a59b54195b9f9b8d41051bc91" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V3 架构的新挑战&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;近两年，随着 UCloud 业务高速发展，以及 25G/100G 网络设备的成熟，业务对网络的性能提出了全新需求，V3 架构逐渐显示出一些不足之处，主要如下：&lt;/p&gt;

&lt;p&gt;性能不足
分布式计算、实时大数据、NVMeoF 等的发展，要求网络提供更大的带宽和更低的时延，以及服务质量保证。&lt;/p&gt;

&lt;p&gt;以 NVMeoF 为例，网络存储比起传统存储，在网络设备转发、传输、TCP/IP 协议栈上有额外开销。近来 RDMA 技术的成熟，极大降低了 TCP/IP 协议栈开销，提升了 IO 性能。但我们在实践中发现，V3 架构下的轻微拥塞，可能造成大量 RMDA 报文重传，占用相当带宽并造成业务性能下降，这种网络性能上的瓶颈需要突破。&lt;/p&gt;

&lt;p&gt;容量不足
用户常希望在一个可用区有无限的资源可以扩容。V3 的两级 CLOS 架构水平扩容能力，最终受限于 Spine 设备端口数，一个 DC 网络大概能容纳的规模为一两万台服务器或一两千个机架。而一座机房可以有上万甚至上十万的机架，在 V3 架构下，需要做多个 DC 网络，DCN 之间通过 POP 互连互通，不但性能难以提升，而且成本巨大。&lt;/p&gt;

&lt;p&gt;灵活性不足
全网统一接入方式，便于大规模上架布线部署工作，确确实实提高了效率，但同时带了灵活性下降。比如有的业务要求集群服务器二层可达，有的业务要求经典网络做 Overlay……总之，整齐划一的网络规划不能满足所有主流的业务需求。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DCN V4 架构的设计与优化&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为了解决上面的问题，2017 年底开始，团队对 DCN 架构进行重新设计、硬件选型和标准化，并于 2018 年 10 月份完成 DCN V4 整套方案并在新建数据中心落地，整体架构如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p3.pstatp.com/large/pgc-image/3d98571b166b45749818244142c9f9a8" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：UCloud DCN V4 架构&lt;/p&gt;

&lt;p&gt;新架构中，我们主要做了如下优化：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. 硬件整体升级到 25G/100G 平台&lt;/strong&gt;
2017 年底到 2018 年上半年，各商用交换机大厂的 25G/100G 网络设备逐渐成熟，25G/100G 光模块价格也趋于合理，同时 GPU、实时大数据、NVMeoF 等业务需求爆发，IO 瓶颈从服务器内部转移到了网络上。因此，我们开始着手将硬件从 10G 升级到 25G 平台。&lt;/p&gt;

&lt;p&gt;我们从 2017 年底开始，对各主流交换机、光模块、光纤、服务器网卡厂商的主流 25G/100G 产品进行了选型、交叉测试、线上小批量，投入了 8 个月的时间，累计交叉测试超过 300 个产品组合，最终确定整套 25G/100G 硬件产品。&lt;/p&gt;

&lt;p&gt;本月已上线的福建 GPU 可用区，利用此架构，同时支持 10G/25G 物理网络。25G 网络带来更高的集群运算效率，和普通可用区提供的 GPU 云主机相比，整体性能翻倍，这对 AI 训练这样看重绝对性能的场景非常重要。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/cfb9a729be6d46c79948662f4924fc9a" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：GPU 物理云 10G/25G 网关集群&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. 3 级 CLOS 的设计&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/8a4791d00121460cb7bde020eb2c2b3d" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：2 级 CLOS&lt;/p&gt;

&lt;p&gt;CLOS 架构要求下一级设备需要跟上一级设备 full-mesh，因此在 V3 的 2 级 CLOS 架构下，Leaf 层的接入交换机（下简称 AS）必须连接到所有 Spine 层的核心交换机（下简称 DS），也就是 2 台 DS；如果设计为 4 台 DS，那么 AS 就必须四上连到每一台 DS，复杂度直线上升。因此 DCN 整体容量取决于 DS 设备的总端口数，DS 设备的槽位数越多、单槽位端口密度越大，那么一个 DCN 可接入服务器容量就越大。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/fb0e3a2345a0405188b1fc8933d17d99" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：3 级 CLOS&lt;/p&gt;

&lt;p&gt;V4 改用新的 3 级 CLOS 设计。Leaf 层的每一台汇聚交换机（下简称 CS）需要上连到所有 Spine 层的 DS。比如一台典型的 CS 是 32 端口 100G 设备，16 口上连 DS，16 口下联 AS：&lt;/p&gt;

&lt;p&gt;设计的 2 台 DS，1 台 CS 出 8 个口连到 DS1、8 个口连到 DS2，总共 16 个上连，每台 DS 消耗 8 个端口；
如果设计的是 4 台 DS，1 台 CS 的 16 个上连口分成 4 组，每组 4 个口分别上连到 DS1/2/3/4，每台 DS 消耗 4 个端口；
如果是 8 台 DS，那么 1 台 CS 只需要消耗 DS 的 2 个端口……
可以看到，设计的 Spine 层的设备越多，每台 CS 需要 DS 的端口数越少，可以接入的 CS 数量就越多，在其他条件不变的情况下，整个 DCN 接入容量就越大。&lt;/p&gt;

&lt;p&gt;我们通过 2 级 CLOS→3 级 CLOS 的架构变化，使得整个 DCN 的接入容量得以提升，理论上，随着硬件技术的发展，设计容量可以提升到无穷大。这就解决了 DCN 容量上的问题。&lt;strong&gt;按我们目前的设计，单 DC 容量最大可以提供 80,000 个服务器接入端口，单可用区可达到 320,000 个，是 DCN V3 时代的 4 倍，能满足 UCloud 所有地域未来几年平滑扩容的需要。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. POD 的引入&lt;/strong&gt;
2 级 CLOS 变为 3 级 CLOS 之后，多出了一个汇聚层，我们把一组汇聚交换机及其下连的接入交换机、以及接入交换机带的机架，总体称为一个 POD。单个 POD 提供一致的网络能力，包括：&lt;/p&gt;

&lt;p&gt;一致的连接方式。一个 POD 里，所有 AS 到 CS 的连接方式是一样的，比如都是 1*100G 单线互连或者都是 2*100G；所有服务器到 AS 的连接也是一致的，比如每台服务器 1*25G 连到 AS 或者 2*25G 连到 AS。
一致的网络特性。一个 POD 支持的网络特性是一样的，比如支持 ECMP、支持开启 QoS、支持直接接入到公网等。
这让我们可以根据业务对网络性能和特性的要求，针对性的开设 POD。&lt;/p&gt;

&lt;p&gt;例如，当前的业务分区有公有云区、物理云区、托管云区、网关区、管理区、IPv6 区等，其中公有云区、网关区、管理区、IPv6 区对基础网络的要求基本一致，在新的 POD 设计思路下，均合并为“内网 POD”。而大数据区、云存储区等网络 IO 极高的业务，则设置了“高性能内网 POD”，具有每台服务器 2*25G 全线速接入的网络能力，提供 QoS 和无损网络特性。此外，还有“综合 POD”应对要求公网/其他特殊网络需求的服务器接入，“混合云 POD”提供裸金属或用户私有云接入等，满足不同的业务需求，来解决灵活性问题。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/16ef3e9146414e7a924356f6727c4a67" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;总的来说，POD 是按照网络能力设计的，满足不同业务的需求，且能避免成本浪费，控制 CAPEX，并避免按业务分区导致过多的网络分区，控制维护的复杂度。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. DC Group&lt;/strong&gt;
UCloud 公有云资源池分为“地域”（一般是一个地理上的城市）和“可用区”（简称 AZ，两个可用区一般距离 10km 以上，基础设施隔离）两级。&lt;/p&gt;

&lt;p&gt;一个 AZ 可以包含多个 DC，但实际上，由于 V3 架构下 DC 都是连接到 POP、与其他 DC 互通，这就需要拉光缆、架设波分，带来带宽瓶颈和时延上升。所以即使两个 DC 距离非常近，作为一个 AZ 资源池也不合适，作为两个 AZ 则与 AZ 的距离要求相悖、也不合适。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/01c633a34e4b4e80a8787af4eafd85fe" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：DC Group 产生前后对比&lt;/p&gt;

&lt;p&gt;V4 架构提出了「DC Group」概念，将地理位置相近的 DC 间 full-mesh 连接起来，作为同一个 AZ 对外提供服务。带来的好处有：&lt;/p&gt;

&lt;p&gt;网络时延低。DC Group 内的 DC 之间距离非常近，通常不超过 10km，由此带来的时延在 0.1ms 以内；
增加冗余度和带宽。由于 DC 之间距离近，光缆成本也低，我们可以增加更多的光缆连接，一方面保证足够的冗余度，另一方面增加足够的带宽；
可滚动升级。可以通过新建新一代 DC 的方式，满足新业务在原 AZ 里上线的要求，且对运行中的 DC 基本无影响。
例如，前段时间我们发布了高性能 SSD 云盘产品。在业务部署阶段，恰逢北京二可用区 D 的空闲机柜不多，如果等申请到新机柜再部署，就浪费了宝贵的时间。而如果只把产品部署在新开的可用区，就无法照顾原可用区用户的需要。&lt;/p&gt;

&lt;p&gt;这个矛盾在 DC Group 架构下，就可以通过添加新 DC 得到良好解决。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p1.pstatp.com/large/pgc-image/6e6ae9dd4a304993a5dc5d25570a13ab" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCloud 总体网络设计中，基础网络的目标是「稳定」和「高效」。基础网络通过组织物理线路、经典网络设备和网络技术，形成了一张稳定而且高性能的网络底层，为上层业务提供 IP 连通性。基础网络下承机房基础设施、上接业务，需要解决「业务需求变化快」和「基础网络升级难」这一对永恒的矛盾。DCN 数据中心网络是基础网络最重要的一个组成部分。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://p9.pstatp.com/large/pgc-image/d5a16446de5b4fea89433f5e47db162e" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;图：UCloud 总体网络设计&lt;/p&gt;

&lt;p&gt;我们过去一年所重新设计的 DCN V4 架构，令新建的 DC 全面升级到 25G/100G、支持无损网络特性、提升了 DC 容量和 DC 间的性能、提供了 AZ 资源的水平扩展和滚动升级能力。总而言之，平衡了「新需求」和「老架构」之间的矛盾，可以满足数年的发展需求。未来，基础网络会继续紧跟技术发展潮流，为各公有云产品提供更稳定、更高效的底层网络。&lt;/p&gt;</description>
      <author>ucloudcn</author>
      <pubDate>Fri, 15 Mar 2019 18:33:23 +0800</pubDate>
      <link>https://ruby-china.org/topics/38237</link>
      <guid>https://ruby-china.org/topics/38237</guid>
    </item>
  </channel>
</rss>
