亚马逊AWS官方博客

by AWS Team | on |

程序员的深度学习入门指南    07 Nov

如何在AWS上构建基于 OpenSwan 的软件 VPN 解决方案    01 Nov

AWS的在线云计算专家,你用了吗?    31 Oct

利用S3fs在Amazon EC2 Linux实例上挂载S3存储桶    26 Oct

CloudFront常见错误配置及解决方法    25 Oct

使用DMT工具迁移北京区域的数据库    18 Oct

VPC中NAT的那点事     17 Oct

CloudWatch Events监控您应用的安全    8 Oct

Oracle数据库迁移到AWS云的方案    28 Sep

使用AWS的数据库迁移DMS服务    28 Sep

手把手教你使用Amazon EMR进行交互式数据查询    27 Sep

使用Oracle Data Pump将数据库迁移到AWS的RDS Oracle数据库    26 Sep

手把手教你快速部署流量压测工具 – Bees with Machine Guns    26 Sep

优秀的领导者如何更进一步迈向伟大?    24 Sep

现代IT高管已然化身首席变革管理官    24 Sep

利用云方案进行实验时的四要与四不要    24 Sep

来自成功云企业的十项诀窍    24 Sep

助你决胜云时代的人才其实近在眼前    13 Sep

手把手教你如何用Lambda + Alexa调用echo设备    01 Sep

AWS Kinesis的Javascript交互方法    25 Aug

基于AWS 平台跳板机配置    08 Aug

如何使用AWS 命令行分段上传大文件    02 Aug

我喜欢我的Amazon WorkSpaces    02 Aug

算法改变世界 - 从Prisma 的走红说开去    02 Aug

为员工进行云培训时的11条箴言    07 Jul

畅谈CIO该如何合并业务和技术    07 Jul

协同合作伙伴 合力加速上云战略    07 Jul

在云端试验时的“有所为和有所不为”    07 Jul

专线直连AWS建立混合IT环境实务指南    01 Jul

手把手教你调校AWS PB级数据仓库    20 Jun

Token Vending Machine:移动应用客户端安全访问AWS服务的解决方案    20 Jun

分布式神经网络框架 CaffeOnSpark在AWS上的部署过程    16 Jun

打造DIY版Echo:树莓派+ Alexa 语音服务    01 Jun

使用Docker封装IPSec安全网关    30 May

将VMware 中的Ubuntu 12.04 映像导入成Amazon EC2 AMI    30 May

如何使用AWS Auto-reboot和Auto-recovery进一步提升单机高可用    16 May

AWS CTO对过去十年的经验总结 – 十条军规    12 Apr

AWS上的游戏服务:Lumberyard + Amazon GameLift + Twitch    12 Apr

为AWS北京区管理控制台集成ADFS访问    12 Apr

AWS的十年创新之路    12 Apr

空荡的数据中心,120种妙用!    12 Apr

媒体洞察 | 让企业自由发展的云时代    12 Apr

亚马逊 风力发电厂在福勒岭启动了!    12 Apr

程序员的深度学习入门指南

by AWS Team | on |

本文根据费良宏在2016QCon全球软件开发大会(上海)上的演讲整理而成。

今天我想跟大家分享的话题与深度学习有关。事实上,深度学习本身是一个非常庞大的知识体系。今天的内容,不会涉及深度学习的理论知识,更多想从程序员的视角出发,让大家观察一下深度学习对我们程序员意味着什么,以及我们如何能够利用这样一个高速发展的学科,来帮助程序员提升软件开发的能力。

前言

1973年,美国上映了一部热门的科幻电影叫做《Westworld》,三年之后又有一个续集叫做《Futureworld》。这部电影在80年代初被引进到中国叫《未来世界》。那部电影对我来讲简直可以说得上是震撼。影片中出现了很多机器人,表情丰富的面部下面都是集成电路板。这让那时候的我觉得未来世界都是那么遥远、那么样的神秘。时间转到了2016年,很多朋友可能都在追看HBO斥巨资拍摄的同一个题材的系列剧《Westworld》。如果前两部电影还是局限在机器人、人工智能这样的话题,2016年的新剧则在剧情、以及对于人工智能的思考方面有了很大的突破。不再渲染机器人是否会威胁到人类,而是在探讨 “Dreams are mainly memories“这一类更具哲理的问题。记忆究竟如何影响了智能这个话题非常值得我们去思考,也给我们一个很好的启示 – 今天,人工智能领域究竟有了怎样的发展和进步。

今天我们探讨的话题不仅仅是简单的人工智能。如果大家对深度学习感兴趣,我相信各位一定会在搜索引擎上搜索过类似相关的关键字。我在Google上以deep learning作为关键字得到了2,630万个搜索的结果。这个数字比一周之前足足多出了300多万的结果。这个数字足以看得出来深度学习相关的内容发展的速度,人们对深度学习的关注也越来越高。

从另外的一个角度,我想让大家看看深度学习在市场上究竟有多么热门。从2011年到现在一共有140多家专注人工智能、深度学习相关的创业公司被收购。仅仅在2016年这种并购就发生了40多起。其中最疯狂的是就是Google,已经收购了 11 家人工智能创业公司,其中最有名的就是击败了李世石九段的 DeepMind。排名之后的就要数 Apple、Intel以及Twitter。以Intel 公司为例,仅在今年就已经收购了 3 家创业公司,Itseez、Nervana 和 Movidius。这一系列大手笔的并购为了布局人工智能以及深度学习的领域。

当我们去搜索深度学习话题的时候,经常会看到这样的一些晦涩难懂的术语:Gradient descent(梯度下降算法)、Backpropagation(反向传播算法)、Convolutional Neural Network(卷积神经网络)、受限玻耳兹曼机(Restricted Boltzmann Machine)等等。如你打开任何一篇技术文章,你看到的通篇都是各种数学公式。大家看到下面左边的图,其实并不是一篇高水准的学术论文,而仅仅是维基百科关于玻耳兹曼机的介绍。维基百科是科普层面的内容,内容复杂程度就超过了大多数数学知识的能力。

右边的那张图则是深度学习很流行的深度学习框架Theano 的一个简单的例子。对于大多数程序员而言学习这一类框架和程序代码的时候更让人抓狂,大段代码我们完全不明就里。我们看到的很多概念,对很多程序员来说觉得非常陌生,所以这确实是对程序员的一个很大的挑战。

在这样的背景之下,我今天的的话题可以归纳成三点:第一,我们为什么要学习深度学习;第二,深度学习最核心的关键概念就是神经网络,那么究竟什么是神经网络;第三,作为程序员,当我们想要成为深度学习开发者的时候,我们需要具备怎样的工具箱,以及从哪里着手进行开发。

为什么要学习深度学习

首先我们谈谈为什么要学习深度学习。在这个市场当中,最不缺乏的就是各种概念以及各种时髦新技术的词汇。深度学习有什么不一样的地方?我非常喜欢Andrew Ng(吴恩达)曾经用过的一个比喻。他把深度学习比喻成一个火箭。这个火箭有一个最重要的部分,就是它的引擎,目前来看在这个领域里面,引擎的核心就是神经网络。大家都知道,火箭除了引擎之外还需要有燃料,那么大数据其实就构成了整个火箭另外的重要组成部分——燃料。以往我们谈到大数据的时候,更多是强调存储和管理数据的能力,但是这些方法和工具更多是对于以往历史数据的统计、汇总。而对于今后未知的东西,这些传统的方法并不能够帮助我们可以从大数据中得出预测的结论。如果考虑到神经网络和大数据结合,我们才可能看清楚大数据真正的价值和意义。Andrew Ng就曾经说过“我们相信(神经网络代表的深度学习)是让我们获得最接近于人工智能的捷径”。这就是我们要学习深度学习的一个最重要的原因。

其次,随着我们进行数据处理以及运算能力的不断提升,深度学习所代表的人工智能技术和传统意义上人工智能技术比较起来,在性能上有了突飞猛进的发展。这主要得益于在过去几十间计算机和相关产业不断发展带来的成果。在人工智能的领域,性能是我们选择深度学习另一个重要的原因。

这是一段Nvidia 在今年公布的关于深度学习在无人驾驶领域应用的视频。我们可以看到,将深度学习应用在自动驾驶方面,仅仅经历了3千英里的训练,就可以达到什么样的程度。在今年年初进行的实验上,这个系统还不具备真正智能能力,经常会出现各种各样的让人提心吊胆的状况,甚至在某些情况下还需要人工干预。但经过了3千英里的训练之后,我们看到在山路、公路、泥地等各种复杂的路况下面,无人驾驶已经有了一个非常惊人的表现。请大家注意,这个深度学习的模型只经过了短短几个月、3千英里的训练。如果我们不断完善这种模型的话,这种处理能力将会变得何等的强大。这个场景里面最重要的技术无疑就是深度学习。我们可以得出一个结论:深度学习可以为我们提供强大的能力,如果程序员拥有了这个技术的话,无异于会让每个程序员如虎添翼。

神经网络快速入门

如果我们对于学习深度学习没有任何疑虑的话,接下来就一定会关心我需要掌握什么样的知识才能让我进入到这个领域。这里面最重要的关键技术就是“神经网络”。说起“神经网络”,容易混淆是这样两个完全不同的概念。一个是生物学神经网络,第二个才是我们今天要谈起的人工智能神经网络。可能在座的各位有朋友在从事人工智能方面的工作。当你向他请教神经网络的时候,他会抛出许多陌生的概念和术语让你听起来云里雾里,而你只能望而却步了。对于人工智能神经网络这个概念,大多数的程序员都会觉得距离自己有很大的距离。因为很难有人愿意花时间跟你分享神经网络的本质究竟是什么。而你从书本上读的到的理论和概念,也很让你找到一个清晰、简单的结论。

今天就我们来看一看,从程序员角度出发神经网络究竟是什么。我第一次知道神经网络这个概念是通过一部电影—1991年上映的《终结者2》。男主角施瓦辛格有一句台词:“My CPU is a neural-net processor; a learning computer.“(我的处理器是一个神经处理单元,它是一台可以学习的计算机)。从历史来看人类对自身智力的探索,远远早于对于神经网络的研究。1852年,意大利学者因为一个偶然的失误,将人类的头颅掉到硝酸盐溶液中,从而获得第一次通过肉眼关注神经网络的机会。这个意外加速了人对人类智力奥秘的探索,开启了人工智能、神经元这样概念的发展。

生物神经网络这个概念的发展,和今天我们谈的神经网络有什么关系吗?我们今天谈到的神经网络,除了在部分名词上借鉴了生物学神经网络之外,跟生物学神经网络已经没有任何关系,它已经完全是数学和计算机领域的概念,这也是人工智能发展成熟的标志。这点大家要区分开,不要把生物神经网络跟我们今天谈到的人工智能有任何的混淆。

神经网络的发展并不是一帆风顺的,这中间大概经历了三起三折的过程。

大约在1904年,人类已经对人脑的神经元有了最初步的认识和了解。1943年的时候,心理学家麦卡洛克 (McCulloch) 和数学家 Pitts 参考了生物神经元的结构,发表了抽象的神经元模型M。这个概念的提出,激发了大家对人智力探索的热情。到了1949年,有一个心理学家赫布(Hebb)提出了著名的Hebb模型,认为人脑神经细胞的突触上的强度上是可以变化的。于是计算科学家们开始考虑用调整权值的方法来让机器学习,这就奠定了今天神经网络基础算法的理论依据。到了1958年,计算科学家罗森布拉特(Rosenblatt)提出了由两层神经元组成的神经网络,并给它起了一个很特别的名字—“感知器”(Perceptron)。人们认为这就是人类智能的奥秘,许多学者和科研机构纷纷投入到对神经网络的研究中。美国军方也大力资助了神经网络的研究,并认为神经网络是比“曼哈顿工程”更重要的项目。这段时间直到1969年才结束,这个时期可以看作神经网络的一次高潮。事实上感知器只能做简单的线性分类任务。但是当时的人们热情太过于高涨,并没有清醒的认识到这点不足。于是,当人工智能领域的巨擘明斯基(Minsky)指出个问题的时候,事态就发生了反转。明斯基指出,如果将计算层增加到两层,则计算量过大并且缺少有效的学习算法。所以,他认为研究更深层的网络是没有价值的。明斯基在1969年出版了一本叫《Perceptron》的书,里面通过数学证明了感知器的弱点,尤其是感知器对XOR(异或)这样的简单分类任务都无法解决。由于明斯基在人工智能领域的巨大影响力以及书中呈现的明显的悲观态度,这很大多数多学者纷纷放弃了对于神经网络的研究。于是神经网络的研究顿时陷入了冰河期。这个时期又被称为“AI Winter”。将近十年以后,神经网络才会迎来复苏。

时间到了1986年,Rumelhar和Hinton提出了划时代的反向传播算法(Backpropagation,BP)。这个算法有效的解决了两层神经网络所需要的复杂计算量问题,从而带动了使用两层神经网络研究的热潮。我们看到的大部分神经网络的教材,都是在着重介绍两层(带一个隐藏层)神经网络的内容。这时候的Hinton 刚刚初露峥嵘,30年以后正是他重新定义了神经网络,带来了神经网络复苏的又一个春天。尽管早期对于神经网络的研究受到了生物学的很大的启发,但从BP算法开始研究者们更多是从数学上寻求问题的最优解,不再盲目模拟人脑网络。这是神经网络研究走向成熟的里程碑的标志。

90年代中期,由Vapnik等人提出了支持向量机算法(Support Vector Machines,支持向量机)。很快这个算法就在很多方面体现出了对比神经网络的巨大优势,例如:无需调参、高效率、全局最优解等。基于这些理由,SVM算法迅速打败了神经网络算法成为那个时期的主流。而神经网络的研究则再次陷入了冰河期。

在被人摒弃的十个年头里面,有几个学者仍然在坚持研究。这其中的很重要的一个人就是加拿大多伦多大学的Geoffery Hinton教授。2006年,他的在著名的《Science》杂志上发表了论文,首次提出了“深度信念网络”的概念。与传统的训练方式不同,“深度信念网络”有一个“预训练”(pre-training)的过程,这可以方便的让神经网络中的权值找到一个接近最优解的值,之后再使用“微调”(fine-tuning)技术来对整个网络进行优化训练。这两个技术的运用大幅度减少了训练多层神经网络的时间。在他的论文里面,他给多层神经网络相关的学习方法赋予了一个新名词— “深度学习”。

很快,深度学习在语音识别领域崭露头角。接着在2012年,深度学习技术又在图像识别领域大展拳脚。Hinton与他的学生在ImageNet竞赛中,用多层的卷积神经网络成功地对包含一千个类别的一百万张图片进行了训练,取得了分类错误率15%的好成绩,这个成绩比第二名高了将近11个百分点。这个结果充分证明了多层神经网络识别效果的优越性。从那时起,深度学习就开启了新的一段黄金时期。我们看到今天深度学习和神经网络的火热发展,就是从那个时候开始引爆的。

可以说在过去十几年时间里,图中这四位学者引领了深度学习发展最。第一位就是Yann LeCun,他曾在多伦多大学随 Hinton攻读博士后,现在是纽约大学的教授,同时还是Facebook人工智能最重要的推动者和科学家。第二位就是是之前我们多次提到的Geoffrey Hinton,现在是Google Brain。第三位是Bengio,他是蒙特利尔大学的教授,他仍然坚持在学术领域里面不断探索。Benjio主要贡献在于他对RNN(递归神经网络)的一系列推动。第四位是Andrew Ng(吴恩达),大家在很多媒体上见到过他。上个月他还来到北京参加过一次技术大会。因为他的华人身份更容易被大家接受。在纯理论研究上面Andrew Ng 的光芒不如上述三位大牛,甚至可以说有不小的差距,但是在工程方面的应用他仍然是人工智能领域的权威。

神经网络究竟可以用来干什么?神经网络如果放到简单概念上,可以理解成帮助我们实现一个分类器。对于绝大多数人工智能需求其实都可以简化成分类需求。更准确的描述就是绝大多数与智能有关的问题,都可以归结为一个在多维空间进行模式分类的问题

例如,识别一封邮件,可以告诉我们这是垃圾邮件或者是正常的邮件;或者进行疾病诊断,将检查和报告输入进去实现疾病的判断。所以说,分类器就是神经网络最重要的应用场景。

究竟什么是分类器,以及分类器能用什么方式实现这个功能?简单来说,将一个数据输入给分类器,分类器将结果输出。曾经有人问过这样一个问题,如果对一个非专业的人士,你如何用通俗表达方法向他介绍神经网络的分类器。有人就用了水果识别做为例子。例如,我非常喜欢吃苹果,当你看到一个新苹果,你想知道它是不是好吃是不是成熟,你鉴别的依据是很多年里你品尝过的许许多多的苹果。你会通过色泽、气味或其它的识别方法加以判断。这样判断过程在深度学习和神经网络里面,我们就称之为训练过的分类器。这个分类器建立完成之后,就可以帮助我们识别食入的每个苹果是不是成熟。对于传统的人工智能方法,例如逻辑回归来说,它的决策平面是线性的。所以,这一类的方法一般只能够解决样本是线性可分的情况。如果样本呈现非线性的时候,我们可以引入多项式回归。隐层的神经元对原始特征进行了组合,并提取出来了新的特征,而这个过程是模型在训练过程中自动“学习”出来的。

利用神经网络构建分类器,这个神经网络的结构是怎样的?

其实这个结构非常简单,我们看到这个图就是简单神经网络的示意图。神经网络本质上就是一种“有向图”。图上的每个节点借用了生物学的术语就有了一个新的名词 – “神经元”。连接神经元的具有指向性的连线(有向弧)则被看作是“神经”。这这个图上神经元并不是最重要的,最重要的是连接神经元的神经。每个神经部分有指向性,每一个神经元会指向下一层的节点。节点是分层的,每个节点指向上一层节点。同层节点没有连接,并且不能越过上一层节点。每个弧上有一个值,我们通常称之为”权重“。通过权重就可以有一个公式计算出它们所指的节点的值。这个权重值是多少?我们是通过训练得出结果。它们的初始赋值往往通过随机数开始,然后训练得到的最逼近真实值的结果作为模型,并可以被反复使用。这个结果就是我们说的训练过的分类器。

节点分成输入节点和输出节点,中间称为隐层。简单来说,我们有数据输入项,中间不同的多个层次的神经网络层次,就是我们说的隐层。之所以在这样称呼,因为对我们来讲这些层次是不可见的。输出结果也被称作输出节点,输出节点是有限的数量,输入节点也是有限数量,隐层是我们可以设计的模型部分,这就是最简单的神经网络概念。

如果简单做一个简单的类比,我想用四层神经网络做一个解释。左边是输入节点,我们看到有若干输入项,这可能代表不同苹果的RGB值、味道或者其它输入进来的数据项。中间隐层就是我们设计出来的神经网络,这个网络现在有不同的层次,层次之间权重是我们不断训练获得一个结果。最后输出的结果,保存在输出节点里面,每一次像一个流向一样,神经是有一个指向的,通过不同层进行不同的计算。在隐层当中,每一个节点输入的结果计算之后作为下一层的输入项,最终结果会保存在输出节点上,输出值最接近我们的分类,得到某一个值,就被分成某一类。这就是使用神经网络的简单概述。

除了从左到右的形式表达的结构图,还有一种常见的表达形式是从下到上来表示一个神经网络。这时候,输入层在图的最下方,输出层则在图的最上方。从左到右的表达形式以Andrew Ng和LeCun的文献使用较多。而在 Caffe框架里则使用的则是从下到上的表达。

简单来说,神经网络并不神秘,它就是有像图,利用图的处理能力帮助我们对特征的提取和学习的过程。2006年Hinton的那篇著名的论文中,将深度学习总结成三个最重要的要素:计算、数据、模型。有了这三点,就可以实现一个深度学习的系统。

程序员需要的工具箱

对于程序员来说,掌握理论知识是为了更好的编程实践。那就让我们我们来看看,对于程序员来说,着手深度学习的实践需要准备什么样的工具。

硬件

从硬件来讲,我们可能需要的计算能力,首先想到的就是CPU。除了通常的CPU架构以外,还出现了附加有乘法器的CPU,用以提升计算能力。此外在不同领域会有DSP的应用场景,比如手写体识别、语音识别、等使用的专用的信号处理器。还有一类就是GPU,这是一个目前深度学习应用比较热门的领域。最后一类就是FPGA(可编程逻辑门阵列)。这四种方法各有其优缺点,每种产品会有很大的差异。相比较而言CPU虽然运算能力弱一些,但是擅长管理和调度,比如读取数据,管理文件,人机交互等,工具也丰富。DSP相比而言管理能力较弱,但是强化了特定的运算能力。这两者都是靠高主频来解决运算量的问题,适合有大量递归操作以及不便拆分的算法。GPU 的管理能力更弱一些,但是运算能力更强。但由于计算单元数量多,更适合整块数据进行流处理的算法。FPGA在管理与运算处理方面都很强,但是开发周期长,复杂算法开发难度较大。就实时性来说,FPGA是最高的。单从目前的发展来看,对于普通程序员来说,现实中普遍采用的计算资源就还是是CPU以及GPU的模式,其中GPU是最热门的领域。

为什么是GPU?简单来说就是性能的表现导致这样的结果。随着CPU的不断发展,工艺水平逐步提高,我们开始担心摩尔定律会不会失效。但是GPU的概念横空出世,NVIDIA 的CEO 黄仁勋得意的宣称摩尔定律没有失效。我们看到最近几年,GPU处理能力的提升是非常惊人的。今年发布的Nvidia P100的处理能力已经达到令人恐怖的效果。与CPU处理能力做一个对比,虽然CPU的主频要远远高过GPU的主频,例如目前GPU在主频在0.5GHz到1.4gHz,处理单元达到3584个;而且最常见的CPU,比如Intel的处理器,大约只有20几个处理单元。这种差别是仅仅在处理单元的数量上就已经存在了巨大的差别。所以深度学习具备大量处理能力计算要求的情况下,GPU无疑具有非常强大的优势。

GPU并不是完全完美的方案!对于程序员来讲,我们也应该了解到它天生的不足。相比CPU,它仍然存在许多的局限。首先,比如:这种技术需要绑定特定的硬件、对编程语言的有一定的限制。简单来说,开发的灵活性不如CPU。我们习惯的CPU已经帮助我们屏蔽掉处理了许多的硬件上细节问题,而GPU则需要我们直接面对这些底层的处理资源进行编程。第二,在GPU领域不同厂商提供了不兼容的框架。应用的算法需要针对特定的硬件进行开发、完善。这也意味着采用了不同框架的应用对于计算环境的依赖。第三,目前GPU是通过PCIe外部配件的方式和计算机集成在一起。众所周知,PCIe连接的频宽是很大的瓶颈,PCIe 3.0 频宽不过7.877 Gbit/s。考虑到计算需求较大的时,我们会使用显卡构成GPU的集群(SLI),这个频宽的瓶颈对于性能而言就是一个很大的制约。最后,就是有限的内存容量的限制。现在Intel新推出的E7处理器的内存可以达到2TB。但是对于GPU而言,即使是Nvidia 的 P100 提供有16GB的内存,将四块显卡构成SLI(Scalable Link Interface)也只有64GB的显存容量。如果你的模型需要较大的内存,恐怕就需要做更好的优化才可以满足处理的需要。这些都是GPU目前的缺陷和不足。我们在着手使用GPU这种技术和资源的时候一定要意识到这一点。

GPU除了硬件上具备了一定的优势以外,Nvidia还为程序员提供了一个非常好的开发框架-CUDA。利用这个编程框架,我们通过简单的程序语句就可以访问GPUs中的指令集和并行计算的内存。对于这个框架下的并行计算内存,CUDA提供了统一管理内存的能力。这让我们可以忽略GPU的差异性。目前的编成接口是C语言的扩展,绝大多数主流编程语言都可以使用这个框架,例如C/C++、Java、Python以及.NET 等等。

今年的中秋节假期,我为自己DIY了一台深度学习工作站。起因是我买了一块GeForce GTX 1070显卡,准备做一些深度学习领域的尝试。因为我的老的电脑上PCIe 2.0 的插槽无法为新的显卡供电。不得已之下,只好更新了全部设备,于是就组装了一台我自己的深度学习工作站。这个过程是充满挑战的,这并不仅仅是需要熟悉各个部件的装配。最重要的是要考虑很多细节的的搭配的问题。比如说供电的问题,要计算出每个单元的能耗功率。这里面又一个重要的指标就是TDP( Thermal Design Power)。Intel 6850K的TDP值是140W,1070显卡的值是150W。于是,系统搭配的电源就选择了650W的主动电源。其次,如果我们用多块显卡(SLI),就必须考虑到系统频宽的问题。普通的CPU和主板在这方面有很大局限。就我的最基本的需求而言我需要的最大的PCI Expres Lanes 是 40。这样算下来,Intel i7-6850K就是我能找到最便宜而且可以达到要求的CPU了。

我在这两天的时间里面,走了很多弯路,所以就想跟大家分享一下我的经验。

第一,Linux在显卡驱动的兼容性方面有很多问题。大多数Linux 分发版本提供的 Nvidia显卡驱动是一个叫做Nouveau的开源版本的驱动。这个版本是通过逆向工程而开发的,对于新的Nvidia 的技术支持的很不好,所以一定要屏蔽这个驱动。第二,Nvida的驱动以及CUDA合cuDnn 的配置上也有很多搭配的问题。官方的版本只提供了针对特定Linux 分发版本的支持。相比较而言,Ubuntu 16.04 在这方面表现的更出色一些。再有就是CuDNN需要在Nvidia 官网注册以后才可以下载。第三,Nvidia 的驱动有很多版本。例如Nvidia P100架构的显卡需要最新的370版本才能支持,但是官网上可以下载的稳定版本只是367。最后,就是令人烦心的软件的依赖关系,安装的顺序等等。举一个例子,在GPU上编译Tensorflow 是不支持GCC 5.x的版本,只能自行安装 GCC 4.9并修改编译选项。另外,Bazel 也会对JDK 的版本有一定的要求。

除了自己去DIY一个深度学习工作站这个选项之外,另外一个选择就是采用云计算环境所提供的计算资源。不久之前 AWS 发布了最新一款深度学习的EC2实例类型,叫做p2。这个实例的类型使用了NVIDIA 的 K80的GPU,包括三种不同规格,第一种2xlarge,第二种是8xlarge,第三种是16xlarge。以p2.16xlarge为例,提供了16块K80 GPU ,GPU 显存达到了192G,并行处理单元的数量达到了惊人的39,936个。

当你在考虑去开发一个应用、去着手进行深度学习尝试的时候,我建议大家可以试试这种方式,这个选择可以很轻松的帮助我们计算资源以及硬件上各种麻烦的问题。

这是我前天为这次分享而准备的一个AWS 上p2的实例。仅仅通过几条命令就完成了实例的更新、驱动的安装和环境的设置,总共的资源创建、设置时间大概在10分钟以内。而之前,我安装调试前面提到的那台计算机,足足花了我两天时间。

另外,从成本上还可以做一个对比。p2.8xLarge 实例每小时的费用是7.2美元。而我自己那台计算机总共的花费了是¥16,904元。这个成本足够让我使用350多个小时的p2.8xLarge。在一年里使用AWS深度学习站就可以抵消掉我所有的付出。随着技术的不断的升级换代,我可以不断的升级我的实例,从而可以用有限的成本获得更大、更多的处理资源。这其实也是云计算的价值所在。

云计算和深度学习究竟有什么关系?今年的8月8号,在IDG网站上发表了一篇文章谈到了这个话题。文章中做了这样一个预言:如果深度学习的并行能力不断提高,云计算所提供的处理能力也不断发展,两者结合可能会产生新一代的深度学习,将带来更大影响和冲击。这个是需要大家考虑和重视的一个方向!

软件

深度学习除了硬件的基础环境之外。程序员会更关心与开发相关的软件资源。这里我罗列了一些自己曾经使用过的软件框架和工具。

  • Scikit-learn是最为流行的一个Python机器学习库。它具有如下吸引人的特点:简单、高效且异常丰富的数据挖掘/数据分析算法实现; 基于NumPy、SciPy以及matplotlib,从数据探索性分析,数据可视化到算法实现,整个过程一体化实现;开源,有非常丰富的学习文档。
  • Caffe专注在卷及神经网络以及图像处理。不过Caffe已经很久没有更新过了。这个框架的一个主要的开发者贾扬清也在今年跳槽去了Google。也许曾经的霸主地位要让位给他人了。
  • Theano 是一个非常灵活的Python 机器学习的库。在研究领域非常流行,使用上非常方便易于定义复杂的模型。Tensorflow 的API 非常类似于Theano。我在今年北京的QCon 大会上也分享过关于Theano 的话题。
  • Jupyter notebook 是一个很强大的基于ipython的python代码编辑器,部署在网页上,可以非常方便的进行交互式的处理,很适合进行算法研究合数据处理。
  • Torch 是一个非常出色的机器学习的库。它是由一个比较小众的lua语言实现的。但是因为LuaJIT 的使用,程序的效率非常出色。Facebook在人工智能领域主打Torch,甚至现在推出了自己的升级版框架Torchnet。

深度学习的框架非常之多,是不是有一种乱花渐欲迷人眼的感觉?我今天向各位程序员重点介绍的是将是TensorFlow。这是2015年谷歌推出的开源的面向机器学习的开发框架,这也是Google第二代的深度学习的框架。很多公司都使用了TensorFlow开发了很多有意思的应用,效果很好。

用TensorFlow可以做什么?答案是它可以应用于回归模型、神经网络以深度学习这几个领域。在深度学习方面它集成了分布式表示、卷积神经网络(CNN)、递归神经网络(RNN) 以及长短期记忆人工神经网络(Long-Short Term Memory, LSTM)。关于Tensorflow 首先要理解的概念就是Tensor。在辞典中对于这个词的定义是张量,是一个可用来表示在一些向量、标量和其他张量之间的线性关系的多线性函数。实际上这个表述很难理解,用我自己的语言解释Tensor 就是“N维数组”而已。

使用 TensorFlow, 作为程序员必须明白 TensorFlow这样几个基础概念:它使用图 (Graph) 来表示计算任务;在被称之为 会话 (Session) 的上下文 (context) 中执行图;使用 Tensor 表示数据;通过 变量 (Variable) 维护状态;使用 feed 和 fetch 可以为任意的操作(arbitrary operation) 赋值或者从其中获取数据。

一句话总结就是,TensorFlow 就是有状态图的数据流图计算环境,每个节点就是在做数据操作,然后提供依赖性和指向性,提供完整数据流。

TensorFlow安装非常简单,但官网提供下载的安装包所支持的CUDA 的版本是7.5。考虑到CUDA 8 的让人心动的新特以及不久就要正式发布的现状。或许你想会考虑立即体验CUDA 8,那么就只能通过编译Tensorflow源代码而获得。目前TensorFlow已经支持了Python2.7、3.3+。此外,对于使用Python 语言的程序员还需要安装所需要的一些库,例如:numpy、protobuf等等。对于卷积处理而言,cuDNN是公认的性能最好的开发库,请一定要安装上。常规的Tensorsorflow的安装很简单,一条命令足矣:

$ pip3 install —upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.11.0rc0-cp35-cp35m-linux_x86_64.whl

如果想评估一下或者简单学习一下,还可以通过Docker进行安装,安装的命令如下:

$ docker run -it -p 8888:8888 gcr.io/tensorflow/tensorflow

TensorFlow有很多优点。首先,目前为止,深度学习的开发框架里面TensorFlow的文档做的最好,对程序员学习而言是非常好的一点。第二,TensorFlow有丰富的参考实例,作为参考学习起来非常容易。第三,开发者社区活跃,在任何一个深度学习的社区里,都有大量关于TensorFlow的讨论。第四,谷歌的支持力度非常大,从2015年到现在升级速度非常快,这是其他开源框架远远达不到的结果。

参考TensorFlow的白皮书,我们会看到未来TensorFlow还将会有巨大的发展潜力。让我特别感兴趣是这两个方向。第一,支持跨多台机器的 parallelisation。尽管在0.8版本中推出了并行化的能力,但是目前还不完善。随着未来不断发展,依托云计算的处理能力的提升这个特性将是非常让人振奋的。第二,支持更多的开发语言,对于开发者来说这是一个绝大的利好,通过使用自己擅长的语言使用TensorFlow应用。这些开发语言将会扩展到Java、Lua以及R 等。

在这里我想给大家展示一个应用Tensorflow 的例子。这个例子的代码托管在这个网址上 https://github.com/anishathalye/neural-style。白俄罗斯的现代印象派艺术家Leonid Afremov善于用浓墨重彩来表现都市和风景题材,尤其是其雨景系列作品。他习惯用大色块的铺陈来营造光影效果,对反光物体和环境色的把握非常精准。于是我就找到了一张上海东方明珠电视塔的一张摄影作品,我希望通过Tensorflow 去学习一下Leonid Afremov 的绘画风格,并将这张东方明珠的照片处理成那种光影色彩丰富的作品风格。利用Tensorflow 以及上面提到的那个项目的代码,在一个AWS 的p2类型的实例上进行了一个一千次的迭代,于是就得到了下图这样的处理结果。

这个处理的代码只有350行里,模型使用了一个成名于2014年ImageNet比赛中的明星 VGG。这个模型非常好,特点就是“go depper”。

TensorFlow 做出这样的作品,并不仅仅作为娱乐供大家一笑,还可以做更多有意思的事情。将刚才的处理能力推广到视频当中,就可以看到下图这样的效果,用梵高著名的作品”星月夜“的风格就加工成了这样新的视频风格。

可以想象一下,如果这种处理能力在更多领域得以应用,它会产生什么样的神奇的结果?前景是美好的,让我们有无限遐想。事实上我们目前所从事的很多领域的应用开发都可以通过使用神经网络和深度学习来加以改变。对于深度学习而言,掌握它并不是难事。每一个程序员都可以很容易的掌握这种技术,利用所具备的资源,让我们很快成为深度学习的程序开发人员。

结束语

未来究竟是什么样,我们没有办法预言。有位作家Ray Kurzweil在2005年写了《奇点临近》一书。在这本书里面他明确告诉我们,那个时代很快到来。作为那个时代曙光前的人群,我们是不是有能力加速这个过程,利用我们学习的能力实现这个梦想呢?

作者介绍:

费良宏

亚马逊AWS首席云计算技术顾问,拥有超过20年在IT行业以及软件开发领域的工作经验。在此之前他曾经任职于Microsoft、Apple等知名企业,任职架构师、技术顾问等职务,参与过多个大型软件项目的设计、开发与项目管理。目前专注于云计算以及互联网等技术领域,致力于帮助中国的开发者构建基于云计算的新一代的互联网应用。

如何在AWS上构建基于 OpenSwan 的软件 VPN 解决方案

by AWS Team | on |

概述

随着云的普及以及即用即付的模式,正在被大家逐渐接受,那么在初期从原始数据中心到云迁移的过程中,为了保证数据的平稳迁移,并不推荐将应用以及数据库一次性的迁移到云中。所有项目都应该分阶段来进行,阶段迁移的情况下就必须要将云资源与本地数据中心的资源互连互通。

要做到互连互通,有三种备选方案,互联网,专线直连(DX)和 VPN。从三个方面比较下这三种解决方案,安全,稳定性以及费用。DX 服务无疑是最优的一种解决方案,提供安全稳定的网络性能,高吞吐量。由于国内专线铺设所带来的高昂费用,所以在初期阶段,DX 并不是一个最优的。这里面互联网是最便宜的,因为本身数据中心就已经支付了这部分费用,只要保证云中的资源可以上互联网就可以了,但互联网面临的问题是网络依赖互联网,互联网的网络性能并不是可控的,另外一方面是互联网的安全性。VPN 呢是基于互联网的服务,虽然不能保证网络性通的可控,但可以做到数据的安全。

就以上比较而言,在初期阶段,VPN 无疑是一种高性比的安全以及节约成本的方案。考虑到目前北京区域并不支持硬件VPN的服务,即Global区域的VPN Connection。那么有没有可以替代的方案呢?答案是肯定的,一切问题都难不倒我们伟大的开源组织,开源方案如 OpenSwan (今天的主角),StrongSwan,Raccoon等等了。除了开源的解决方案外,还有一些商业解决方案,比如Sanfor 深信服,Hillstone 山石,Checkpoint , Cisco CSR1000v等也可以部署,有兴趣的可以与相应的软件提供商联系。

前面说了那么多关于VPN的各种软件,那么该如何选择呢?这里我们从使用上来划分下吧,将VPN主要划分为两类,一类是工作于客户端到服务端的模式,像OpenVPN,SSL VPN,L2TP,PPTP这些都是需要客户端主动发起连接,拨到Server端在两者之间建立一个逻辑上的隧道 (tunnel)进行通信。这种方式一般适用于个人到总部场景。服务器是无法主动发起连接到客户端。

另外一种就是站点到站点(site-to-site)的模式,像OpenSwan,StrongSwan, Raccoon 等软件,这种情况下两端会各有一个设备负责来建立两个站点之间安全通信的隧道,任何需要到对端的通信都会触发设备来建立安全隧道通信。

那么公司原有数据中心与云通信都是双向通信,所以站点到站点更合理。

实际上这里说的 VPN 即是指 IPsec VPN,IPsec 是一种工业标准,只要支持这种标准的设备都可以互相协商建立一个安全的隧道出来,比如支持的硬件设备有路由器,防火墙以及专业的 VPN 设备。

说了这么多,下面我们就以 AWS 端为 OpenSwan 与 Cisco 的路由器之间的配置为例。

场景及拓扑

拓扑如上图,AWS端建立一个VPC(CIDR:192.168.0.0/16),包含两个子网,一个可以上互联网的Public子网192.168.1.0/24以及私有子网Private 192.168.2.0/24。在公有子网上会配置一台OpenSwan实例与公司的Cisco设备做VPN连接。

OpenSwan的EIP地址为54.223.152.218 子网:192.168.1.0/24

Cisco设备的公网地址为54.223.170.5 子网:10.1.2.0/24

目标:实现AWS上私有子网192.168.2.0/24和数据中心10.1.2.0/24双向互通

详细配置步骤

1.配置 VPC 基础环境

1.1 创建 VPC

在AWS console界面点击VPC,在左侧点击“您的VPC”, 创建VPC

名称标签: MyVPC

CIDR块: 192.168.0.0/16

租赁:默认

1.2 创建子网

将鼠标点到子网,选择创建子网

标签名称:Public

VPC:选择第一步创建好的VPC

可用区:保持默认

CIDR块:192.168.1.0/24

以同样的方法创建一个192.168.2.0/24的子网

1.3 创建路由表

点击路由表,创建路由表

名称标签:PrivateRoute

VPC:选择1.1创建好的VPC

创建完成以后,点到刚刚创建好的路由表,在页面下列点击子网关联,点击编辑

在192.168.2.0/24的路由前打勾,点击保存。

1.4 创建 IGW

点击Internet网关,创建Internet网关

名称标签:MyIGW

创建完成,点击附加到VPC

选择新创建好的VPC

2. 启动并配置 VPN 实例

2.1 启动实例

到EC2页面,点击启动实例。选择Amazon Linux

在详细信息页中,网络请选择新创建的VPC

子网选择192.168.1.0/24

点击下一步,存储标签等按需配置

配置安全组,选择创建一个新的安全组

添加规则

自定义的UDP规则,端口500 来源任何位置

自定义的UDP规则,端口4500 来源任何位置

自定义协议, 协议 50 来源任何位置

所有流量 来源为 192.168.2.0/24

注意:一定要放行来自于192.168.2.0/24的流量,否则无法通信。

最后审核启动,启动时指定一个用于登陆实例的key文件,如果没有创建一个新的。

2.2 配置弹性 IP (EIP)

在EC2页面,左侧导航栏找到弹性IP,申请分配新地址,并将其关联到新创建的OpenSwan实例。这里申请到的为 54.223.152.218。

2.3 关闭源/目的检查

在EC2页面点击OpenSwan实例,右键选择联网,更改源/目标检查,点“是,请禁用”

3. 安装配置 OpenSwan

3.1 登录到实例安装 OpenSwan

如何登陆实例请参考如下文档:

https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/putty.html

登陆完成以后,运行如下命令安装OpenSwan

$ sudo yum -y install openswan

3.2 根据Cisco 参数来配置 OpenSwan

修改/etc/ipsec.conf去掉最后一行include /etc/ipsec.d/*.conf 的注释

$ sudo vim /etc/ipsec.conf

include /etc/ipsec.d/*.conf

 

Cisco路由器的配置如下:

crypto isakmp policy 10

encr aes

authentication pre-share

group 2

crypto isakmp key aws123 address 54.223.152.218

!

!

crypto ipsec transform-set OpenSwan esp-aes esp-sha-hmac

mode tunnel

!

!

!

crypto map OpenSwan 10 ipsec-isakmp

set peer 54.223.152.218

set transform-set OpenSwan

match address 100

!

!

interface GigabitEthernet1

ip address 54.223.170.5 255.255.255.252

ip mtu 1400

ip tcp adjust-mss 1360

crypto map OpenSwan

!

access-list 100 permit ip 10.1.2.0 0.0.0.255 192.168.2.0 0.0.0.255

ip route 0.0.0.0 0.0.0.0 54.223.170.6

根据cisco的配置创建OpenSwan的配置如下:

$ sudo vim /etc/ipsec.d/cisco.conf

conn cisco

authby=secret

auto=start

leftid=54.223.152.218

left=%defaultroute

leftsubnet=192.168.2.0/24

leftnexthop=%defaultroute

right=54.223.170.5

rightsubnet=10.1.2.0/24

keyingtries=%forever

ike=aes128-sha1;modp1024

ikelifetime=86400s

phase2alg=aes128-sha1

salifetime=3600s

pfs=no

配置解释:

leftid 标明本地对应公网IP

letftsubnet为本地子网

right为对端公网地址

rightsubnet为对端子网

ike为第一阶段参数

ikelifetime为第一阶段的生存时间

phase2alg为第二阶段参数

salifetime为第二阶段生存时间

结果如下图:

配置预共享密钥:

$ sudo vim /etc/ipsec.d/cisco.secrets

54.223.152.218  54.223.170.5: PSK “aws123”

启动openswan服务并做配置检查

$ sudo service ipsec start

$ sudo ipsec verify

3.3 修改系统参数

更改系统参数做IP转发并关闭重定向功能

编辑/etc/sysctl.conf内核配置文件,做如下修改

$ vim /etc/sysctl.conf

$ vim /etc/sysctl.conf

net.ipv4.ip_forward = 1

net.ipv4.conf.all.accept_redirects = 0

net.ipv4.conf.all.send_redirects = 0

net.ipv4.conf.default.send_redirects = 0

net.ipv4.conf.eth0.send_redirects = 0

net.ipv4.conf.default.accept_redirects = 0

net.ipv4.conf.eth0.accept_redirects = 0

配置完成以后,启用新的配置

$ sudo sysctl –p

3.4 更改 OpenSwan 的网卡 MSS 值

$ sudo iptables -t mangle -A FORWARD -o eth0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1387

3.5 修改 VPC 私有子网路由表

找到VPC Console页面,在左侧点路由表,找到192.168.2.0/24关联的路由表(1.3中创建), 在页面下方点击路由,编辑

添加其他路由,

目标: 10.1.2.0/24

目标:OpenSwan实例ID (i-xxxxx)

4. 测试连通性

以上步骤都完成以后,就可以在192.168.2.0网段的实例进行测试了。使用 ping 测试到 10.1.2.x private 私有地址段的一个地址。

ping 10.1.2.3

检查 IPsec tunnel 状态:

$ sudo service ipsec status

IPsec running - pluto pid: 25674

pluto pid 25674

1 tunnels up

some eroutes exist

常见问题及排错

1.  IPsec Tunnel 没有正常建立

首先检查到对端 IP 是否可以通信,检查安全组是否放行 IKE 需要的端口 UDP 500。如果网络层没问题,检查各项参数配置是否有错误。

2. 隧道建立成功,但是无法进行通信

首先检查 IP forward 是否设置为 1?VPN 实例安全组是否放行了相应的策略?路由是否正确?NAT 是否影响?

3. NAT 问题

如果您的 CGW 配置了 NAT 与 VPN 工作,根据厂家不同对 VPN 包的处理顺序不一致,如果源 NAT 在 VPN 之前被处理了,因为源地址发生了改变,所以也就不会再被 VPN 处理,造成通信失败。像 Cisco 设备就需要做 NAT 的例外策略。主流的 Cisco ASA 就需要做相应修改,参考如下:

8.2 及以前的版本:

nat (inside) 0 access-list nat_exemption
access-list nat_exemption extended permit ip 192.168.1.0 255.255.255.0 10.0.0.0 255.255.255.0

8.3 及更新的版本:

object network obj-192.168.1.0

subnet 192.168.1.0 255.255.255.0

object network obj-10.0.0.0

subnet 10.0.0.0 255.255.255.0

nat (inside,any) source static obj-192.168.1.0 obj-192.168.1.0 destination static obj-10.0.0.0 obj-10.0.0.0 no-proxy-arp

如果您经过以上步骤还是不能成功搭建 VPN,AWS Support 提供专业化的技术支持,可根据您当前或计划的使用案例为您提供一套独特的工具和专业知识。建议您开案例联系Support 技术支持。

作者介绍:

侯晓鹏

亚马逊AWS云支持工程师,多年从事网络相关支持以及架构咨询工作,在加入 AWS 以前曾担任 Juniper 高级咨询专家,负责为企业网及运营商提供专业架构咨询及网络优化工作。现任亚马逊云支持工程师,AWS 认证 Direct Connect 服务专家。多次帮助大规模企业客户解决混合云复杂技术及架构问题。

AWS的在线云计算专家,你用了吗?

by AWS Team | on |

我们在享受AWS云计算带来的弹性、灵活、高可用、按需使用等优点的同时,相信运维开发人员及商务决策者们会越来越多地关注如何在云上实现成本、安全、性能和容错方面的优化。今天为大家隆重介绍一位就在你身边的AWS在线云计算专家,希望给大家一些最直接的帮助。

——-专家简介—-

AWS Trusted Advisor有着丰富的云计算疑难病症的临床经验,并总结了大量的最佳实践。他会实时帮你从成本优化、安全、性能和容错四个大的方面诊断AWS帐户的健康状况并推送检查结果和建议。

——–专家支招——-

第一招:免费检查项   对象:所有支持级别

1. 是否有过于宽松的端口安全组设置

2. 是否使用AWS Identity and Access Management (IAM)来进行用户身份和权限管理

3. 是否在根帐户上启动了Multi-Factor Authentication (MFA)加强帐户安全

4. 各服务当前使用量是否接近限额需要联系AWS小伙伴进行限额提升

注:北京区域目前提供服务限制和安全组 – 特定端口不受限制两项

第二招:全套检查项   对象:商用和企业级别支持服务

商用和企业级别支持服务客户可以享受全套检查项(截至到发文止,共54个检查项,还会不断增加),横跨成本优化、安全、性能和容错四个大类。

  • 9个成本优化检查项

  • 15个安全检查项

  • 19个容错检查项

  • 11个性能检查项

*为北京区域目前可用的检查项

第三招:支持API方式获取检查建议和数据 对象:商用和企业级别支持服务

这招比较适合技术咖了,可以用程序的方式获取Trusted Advisor的检查建议及数据。

戳以下链接了解Trusted Advisor (TA)以及AWS支持计划!

全球区域:

https://aws.amazon.com/premiumsupport/trustedadvisor/

https://aws.amazon.com/premiumsupport/compare-plans/

北京区域:

http://www.amazonaws.cn/support/trustedadvisor/

http://www.amazonaws.cn/support/support-plans/

 

利用S3fs在Amazon EC2 Linux实例上挂载S3存储桶

by AWS Team | on |

背景介绍

Amazon S3是互联网存储解决方案,能让所有开发人员访问同一个具备可扩展性、可靠性、安全性和快速价廉的数据存储基础设施。Amazon S3 提供了一个简单 Web 服务接口,可用于随时在 互联网上的任何位置存储和检索任何数量的数据。开发人员可以利用Amazon提供的REST API接口,命令行接口或者支持不同语言的SDK访问S3服务。

对于原来使用本地目录访问数据的应用程序,比如使用本地磁盘或网络共享盘保存数据的应用系统,如果用户希望把数据放到S3上,则需要修改数据的访问方式,比如修改为使用AWS SDK 或CLI访问S3中存储的数据。为了让用户原来的应用系统能在不做修改的情况下直接使用Amazon S3服务,需要把S3存储桶作为目录挂载到用户服务器的本地操作系统上。常用的挂载工具有S3fs和SubCloud等。本文主要介绍如何利用S3fs将S3存储桶挂载到Amazon EC2 Linux实例上。

S3fs介绍

S3fs是基于FUSE的文件系统,允许Linux和Mac Os X 挂载S3的存储桶在本地文件系统,S3fs能够保持对象原来的格式。关于S3fs的详细介绍,请参见:https://github.com/s3fs-fuse/s3fs-fuse

利用S3fs挂载S3存储桶

一、准备
1. 使用拥有足够权限的IAM账号登录AWS控制台。

2. 创建S3存储桶,给存储桶命名如“s3fs-mount-bucket”(如果使用已有存储桶,本步骤可略过)。

3. 创建具有该S3存储桶访问权限的 IAM 用户,并为该IAM用户创建访问密钥。

a)  关于如何创建IAM用户,请参见:http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_users_create.html#id_users_create_console

b)  关于如何为IAM用户创建访问密钥,请参见:http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html

c)  关于如何为IAM用户设置权限策略,请参见:http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/access_policies_create.html

https://aws.amazon.com/cn/blogs/security/writing-iam-policies-how-to-grant-access-to-an-amazon-s3-bucket/

4. 创建并启动Amazon EC2 Linux实例

具体过程请参见:http://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/launching-instance.html

二、安装和配置S3fs

1. 安装s3fs

a)  使用Amazon EC2默认用户“ec2-user”和对应的私钥文件登录启动的Linux实例(请注意将下边例子中的私钥文件和ec2实例域名替换为用户自己的值)

b)  安装必要的软件包

c) 下载,编译并安装s3fs

d) 检查s3fs是否安装成功

2. 创建IAM用户访问密钥文件

  • IAM用户访问密钥内容可以写入当前用户默认密钥文件比如“/home/ec2-user/.passwd-s3fs”或者用户自己创建的文件。
  •  命令格式:echo [IAM用户访问密钥ID]:[ IAM用户访问密钥] >[密钥文件名]
  • 命令举例:下面的例子将在当前用户默认路径创建密钥文件

请注意:访问海外AWS S3服务和中国 S3服务使用的是不同的IAM账号,对应不同的密钥。

3. 设置密钥文件只能够被当前用户访问

  • 命令格式:chmod 600  [密钥文件名]
  • 命令举例:下面的例子将设置密钥文件只能被当前用户访问

三、手动挂载S3存储桶

S3fs挂载存储桶使用的命令是s3fs

s3fs的命令格式是:

  • s3fs BUCKET MOUNTPOINT [OPTION]…
  • s3fs [S3存储桶名] [本地目录名] [OPTION]

OPTION是可选项,格式是 –o <option_name>=<option_value>,常用的options有:


手动挂载AWS海外区域S3存储桶

  • 命令格式:s3fs [S3存储桶名] [本地目录名] -o passwd_file=[密钥文件名] -o endpoint=[区域名]
  • 命令举例:下面的例子将名为“s3fs-mount-bucket”的新加坡区域S3存储桶挂载到指定的本地目录“/home/ec2-user/s3mnt”。

手动挂载AWS中国北京区域S3存储桶

  • 命令格式:s3fs [S3存储桶名] [本地目录名] -o passwd_file=[密钥文件名] -o url=http://s3.cn-north-1.amazonaws.com.cn -o endpoint=cn-north-1
  • 命令举例:下面的例子将名为“s3fs-mount-bucket”的北京区域S3存储桶挂载到本地目录“/home/ec2-user/s3mnt”。

检查挂载结果

  • 挂载操作执行结束后,可以使用Linux “df”命令查看挂载是否成功。出现类似下面256T的s3fs文件系统即表示挂载成功。用户就可以进入本地挂载目录去访问存储在S3存储桶中的对象。

卸载挂载的S3存储桶

  • 如果不再需要通过挂载方式访问S3存储桶,可以使用Linux “umount”命令卸载。

调试

如果遇到手动挂载不成功的问题,请尝试在执行的命令后面添加下面的参数,并检查输出日志中的错误提示信息:

  • 命令格式:[完整的s3fs挂载命令] -d -d -f -o f2 -o curldbg
  • 命令举例:下面的例子试图将名为“s3fs-mount-bucket”的S3存储桶挂载到指定的本地目录“/home/ec2-user/s3mnt”下,并输出挂载过程详细调试日志

四、设置开机自动挂载S3存储桶

A. 创建全局IAM用户访问密钥文件

切换Linux系统用户账号到“root”用户,把IAM用户访问密钥内容写入/etc/passwd-s3fs文件中,并限制该文件的访问权限。“/etc/passwd-s3fs”文件是s3fs保存IAM用户访问密钥的全局默认路径。

请注意:访问海外AWS S3服务和中国 S3服务使用的是不同的IAM账号,对应不同的密钥。

B. 修改/etc/fstab文件

编辑/etc/fstab文件,添加后面的自动挂载命令。

B.1自动挂载海外区域S3存储桶

  • 命令格式:s3fs#[S3存储桶名] [本地目录名] fuse _netdev,allow_other,endpoint=[区域名] 0 0
  • 命令举例:添加下面的语句到/etc/fstab后,Linux系统启动后将自动把名为“s3fs-mount-bucket”的新加坡区域S3存储桶挂载到本地目录“/home/ec2-user/s3mnt”,并允许其它操作系统用户(非root用户)访问。

B.2自动挂载中国北京区域S3存储桶

  • 命令格式:s3fs#[S3存储桶名] [本地目录名] fuse allow_other,url=http://s3.cn-north-1.amazonaws.com.cn,endpoint=cn-north-1 0  0
  • 命令举例:添加下面的语句到/etc/fstab后,Linux系统启动将自动把名为“s3fs-mount-bucket”的北京区域S3存储桶挂载到本地目录“/home/ec2-user/s3mnt”下,并允许其它操作系统用户(非root用户)访问。


局限性

利用S3fs可以方便的把S3存储桶挂载在用户本地操作系统目录中,但是由于S3fs实际上是依托于Amazon S3服务提供的目录访问接口,所以不能简单的把S3fs挂载的目录和本地操作系统目录等同使用。用户使用S3f3挂载S3存储桶和直接访问S3服务有类似的使用场景。适用于对不同大小文件对象的一次保存(上传),多次读取(下载)。不适用于对已保存文件经常做随机修改,因为每次在本地修改并保存文件内容都会导致S3fs上传新的文件到Amazon S3去替换原来的文件。从访问性能上来说,通过操作系统目录方式间接访问Amazon S3存储服务的性能不如直接使用SDK或CLI接口访问效率高。以本地配置文件方式保存访问密钥的安全性也不如使用EC2 IAM角色方式高。

关于S3fs使用时候需要注意的更多细节,请参考下面s3fs官网内容:

Generally S3 cannot offer the same performance or semantics as a local file system. More specifically:

  • random writes or appends to files require rewriting the entire file
  • metadata operations such as listing directories have poor performance due to network latency
  • eventual consistency can temporarily yield stale data
  • no atomic renames of files or directories
  • no coordination between multiple clients mounting the same bucket
  • no hard links

总结

利用S3fs可以把共享的Amazon S3存储桶直接挂载在用户服务器本地目录下,应用不需要做修改就可以直接使用Amazon S3存储服务,这种方式可以作为临时解决方案将传统应用快速迁移到AWS平台。

在已经提供了Amazon EFS(Elastic File System)服务的AWS区域,建议用户优先考虑使用Amazon EFS服务,因为它具有更高的性能。在目前还没有提供EFS服务的AWS区域,用户可以先暂时使用S3fs实现快速业务迁移。然后逐步调整S3数据访问实现方式,最终修改为使用AWS SDK或CLI方式高效并更加安全地访问S3存储服务。

作者介绍:

蒙维

亚马逊AWS解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,有超过十年以上电信行业和移动互联网行业复杂应用系统架构和设计经验,主要擅长分布式和高可用软件系统架构设计,移动互联网应用解决方案设计,研发机构DevOps最佳实施过程。

CloudFront常见错误配置及解决方法

by AWS Team | on |

很多的用户在最初使用CloudFront做Web类内容分发的时候遇到无法调通的情况,本文总结了用户在配置过程中遇到的常见错误,内容涵盖了大部分用户遇到的情况。

错误一  源访问权限未放开

这种错误常见于用S3做源的情况, 引起这种错误的原因是s3的访问控制没有对CloudFront开放。从浏览器中返回的错误通常类似于下图:

更具体些,可分为以下两个场景:

场景1. CloudFront使用了Restrict Bucket Access

在创建distribution的时候选择了Restrict Bucket Access 为yes, 但 Grant Read Permissions on Bucket, 选择的是”No, I Will Update Permissions”, 而用户事后却没有在s3的桶里更新policy。如下图所示。

解决方法:

方法1, 在S3中增加桶的策略,使该桶允许该CloudFront访问,以下是policy示例,其中标黄部分需要替换成用户自己的信息。

{

                "Version": "2008-10-17",

                "Id": "PolicyForCloudFrontPrivateContent",

                "Statement": [

                                {

                                                "Sid": "1",

                                                "Effect": "Allow",

                                                "Principal": {

                                                                "AWS": "arn:aws:iam::CloudFront:user/CloudFront Origin Access Identity E344H6KAFBMK0I"

                                                },

                                                "Action": "s3:GetObject",

                                                "Resource": "arn:aws:s3:::elastictcoutputthumb/*"

                                }

                ]

}

方法2, 重新创建distribution, 新建的distribution中Grant Read Permissions on Bucket选择yes, Update bucket policy, 这样当distribution创建完成后,s3桶的policy会被自动更新。

场景2. 普通的S3回源

CloudFront 并未使用Restrict Bucket Access, 这种情况下如果s3中的对象没有设置成可被公共访问,也会出现Access Denied的错误。

解决方法:

可以通过设置s3桶的bucket policy或者设置s3中对象的Object ACL来实现。 例如,通过 AWS 控制台设置存储桶的bucket policy:

通过 AWS 控制台设置S3对象的Object ACL:

注:如果想了解S3访问控制的详细内容,请参考:http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html

错误二 使用自定义域名但未在CloudFront中配置

用户有时不直接使用CloudFront的distribution产生的域名,而是使用了自定义的域名并用CNAME的方式指到CloudFront的域名, 例如使用cdn.mydomain.com  CNAME到d1cbzf61pdxxxx.CloudFront.net。此外,如果使用Route53作为DNS, 也可以不采用CNAME的方式,而是采用Alias的方式。

CloudFront规定当使用自定义域名并配置该域名使用CNAME或Alias的方式指向CloudFront distribution的域名的时候,需要在CloudFront相应的distribution中提供该自定义的域名,如果使用了多个自定义的域名,则提供多个自定义的域名。如果没有提供,就会出现类似下图的错误:

解决方法:

可以通过AWS控制台,对distribution中的Alternate Domain Names(CNAMEs)进行设置:

错误三 访问路径错误

配置完CloudFront的Behavior后,用户有时不能给出正确的url来访问想要的资源。 出现访问错误, 如果是回源s3, 返回的错误通常如下:

如果是回源的自定义网站,返回的错误根据网站的不同而不同,例如:返回”找不到相应的页面”等错误。

解决方法:

避免这种错误很简单,了解CloudFront Behavior的url与所访问的源站资源的对应方法,即可判别自己的url是否正确. 以下举例说明:

某Behavior如下,该Behavior对应的origin ID是S3-hxybucket/Picture:

进入到Origin查看,可知Origin Domain Name and Path是hxybucket.s3.amazonaws.com/Picture

如果通过d1cbzf61pdxxxx.CloudFront.net/dog.jpg访问的话, 对应的源站资源是hxybucket.s3.amazonaws.com/Picture/dog.jpg

如果通过d1cbzf61pdxxxx.CloudFront.net/jpg/dog.jpg访问的话,对应的源站资源是hxybucket.s3.amazonaws.com/Picture/jpg/dog.jpg

即: 将CloudFront域名后面的路径追加到Origin Domain Name and Path (注意,除了Domain Name之外,还有Path) 所对应的路径后面, 就是对应到源站的资源, 用户通过该路径即可判断所使用的url是否正确。

错误四 HTTP Method 设置不当

在创建Behavior的时候, allowed http methods选项的默认值是GET和HEAD, 有时用户会使用其他的HTTP method, 例如POST, 此时如果还是用默认值,就会出错,返回的错误通常如下:

“This distribution is not configured to allow the HTTP request method that was used for this request. The distribution supports only cachable requests.”

解决办法:

办法很简单,在Behavior中重新设定一下Allowed HTTP Methods选项,使其包含所用的HTTP Method.

错误五 设置了Restrict Viewer Access 却没有使用Signed URL或Signed Cookie

在创建Behavior的时候,Restrict Viewer Access (Use Signed URLs or
Signed Cookies)选项的默认值是No, 如果用户改成了Yes, 此时该Behavior对应的资源必须使用Signed URL 或者Signed Cookie的方式访问,如果使用普通的Url访问,返回的错误通常如下:

解决方法:

方法1.使用signed url 或signed Cookie进行访问,具体参考:http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html

方法2. 将Restrict Viewer Access (Use Signed URLs or
Signed Cookies)的值改为No。如图:

错误六  Object Caching 设置不当

虽然能够访问到源,但有时用户会反映使用了CloudFront并没有加速访问,有时甚至效果还不如未使用CloudFront时。 这很可能是由于Object Caching设置不当造成的。

解决方法:

Object Caching有两个选项,分别是Use Origin Cache Headers 和 Customize。默认选项是前者。但是,当默认选择了Use Origin Cache Headers,而源的HTTP header中却没有Cache-control的头,那返回内容就不被缓存了。 因此,用户需谨慎选择,当源的返回值中没有Cache-control头的情况下,选择Customize,Customize中的Default值将会成为TTL时间(时间单位是秒)。

另外,如果源的返回值中存在Cache-control,而Object Caching又选择了Customize, 这种情况下返回的内容肯定会在CloudFront边缘节点中被缓存。但CloudFront会使用哪个值作为TTL呢? 这个在CloudFront 文档中有详细的描述, 详见: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html

作者介绍:

韩小勇

亚马逊AWS解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,实施和推广,在加入AWS之前,从事电信核心网系统上云的方案设计及标准化推广 。

使用DMT工具迁移北京区域的数据库

by AWS Team | on |

在前面的blog《将Oracle数据库迁移到AWS云的方案》中谈到了多种将Oracle数据库从数据中心迁移到AWS云中的方法。其中 使用DMS服务迁移的方法简单实用,也支持异构数据库的迁移,很多朋友都想使用这种方法完成迁移。但是在北京区域不支持DMS服务,如何实现类似的迁移工作呢?其实在北京区域支持使用Database Migration Tool(DMT)来迁移数据库,DMT工具是DMS服务的前身,它是安装在Windows上的一个软件,迁移前只需要获取DMT工具的AMI,然后简单的配置后,就可以进行数据迁移了。本文主要讨论如何使用DMT将Oracle迁移到Amazon RDS数据库,示例的场景如下图所示:

在建立客户本地数据中心与AWS连接的时候,考虑到安全性问题,我们建议您通过VPN或者企业专线来建立数据库之间的连接,您只需确保您本地数据库端口(例如Oracle端口1521)对外可访问。如果您的业务对安全性要求较高,需要传输的数据量较大,同时,要求以较快速度传输的时候,可以采用专线迁移,但是这种方法成本较高,您需要根据您的业务需求来选择是通过VPN还是企业专线迁移。

在介绍DMT数据库迁移之前,我们首先介绍一下DMT迁移工具支持的数据库类型以及对源和目标数据库的限制:DMT目前支持将Oracle、SQL Server、MySQL、SAP Sybase以及PostgreSQL作为源或目标数据库,您也可以将Amazon Redshift作为您的目标数据库。同时,DMT也支持异构数据库的迁移,例如将Oracle迁移到MySQL。

DMT工具为我们迁移数据库提供了巨大的便利,然而,它也有一些限制条件,下表主要介绍DMT支持的三种常用关系型数据库版本以及相关限制条件。如果您需要了解更多有关DMT迁移数据库信息,请参考DMT用户手册:

https://s3.cn-north-1.amazonaws.com.cn/rdmt/RDS+Migration+Tool+User+Guide.pdf

使用DMT迁移主要有下面几个步骤:

(1)获取DMT的AMI

(2)启动DMT的AMI

(3)登陆DMT服务器

(4)配置服务器

(5)访问DMT工具

(6)迁移数据

1.获取DMT的AMI

如果您有数据库数据需要导出或者导入到AWS 北京区域中,首先您需要获取DMT的AMI镜像,然后根据镜像启动EC2服务器。获取DMT的镜像有两种方式:

(1)和支持您当前AWS账号的商务人员联系,他能帮您在后台申请访问DMT AMI的权限。

(2)您也可以自己在Support Center 中开case。在AWS Console中访问Support Center的方式如下图所示:

2.启动DMT的AMI

当您有能访问DMT的AMI以后,登陆您的AWS账号,进入Services->EC2->AMI的界面,选择“Private images”列表,就可以看到有一个Amazon_RDS_Migration_Tool的记录,这就是最新的迁移工具,如下图所示:

选择DMT点击上方的“Lunch”按钮,启动一个已经安装好DMT工具的服务器。接下来您需要配置您实例的类型、大小、实例所在VPC以及安全组和密钥等信息。具体配置步骤请参考官方文档:http://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/EC2_GetStarted.html

需要注意的是:

(1)在选择DMT服务器所在VPC的时候,尽量选择源或者目标数据库所在的VPC创建DMT服务器,这样可以加快迁移的速度。

(2)在配置安全组的时候,您的安全组应该允许RDP协议和https协议。由于DMT服务器是Windows Server服务器,因此您需要使用Windows远程桌面连接访问,此时需要RDP协议,source指定当前需要连接客户端的IP或者IP段。DMT工具可以通过浏览器来访问,因此需要设置https协议的安全组,如下图所示:

3.登陆DMT服务器

启动DMT服务器,并下载私钥后,就可以登陆DMT服务器了,如下图所示,当您的服务器状态显示为running,并且通过健康检查后,您的服务器就可以正常访问了。如下图所示:

选择您的DMT服务器,然后点击Connect,显示如下界面:

在此步骤中,您需要根据下载的私钥获取登陆Windows的密码。点击 get Password,显示如下图所示界面:

输入您前面下载的私钥的文件全部内容,点击 Decrypt Password后,您在界面上可以看到Administrator的密码,请记录下这个密码。下面就可以登陆服务器了。

本例中是使用MAC的Windows远程终端软件来访问DMT服务器,如果您使用Windows客户端,访问过程类似,输入远程DMT服务器的DNS名称,输入用户名和密码并连接。

连接上DMT终端后,您会看到Windows Server 2012的桌面如下图所示,桌面上有DMT工具。

连接到远程终端后,您可以根据需要修改访问Windows的密码,修改密码可以在控制面板中完成,界面如下:

4. 配置服务器

登陆到DMT服务器后,在界面上有Database Migration Tool Documentation的目录,进入目录并下载QuickStart Guide.下载过程中如果出现如下错误,请添加授信站点或者配置服务器解决错误。

下载Quick Start Guide和PDF阅读软件。

打开QuickStart Guide如下图所示,您可以按照您数据库的类型(Oracle, MySQL等)选择相应的驱动程序。

本例中由于迁移的是Oracle数据库,安装Oracle的驱动和客户端相对复杂,下面会详细解释如何安装Oracle驱动,其他驱动的安装请参考文档。点击Quick Start Guide中的Oracle Instant Client后面的链接后,出现如下界面(需要您有Oracle账号才能下载软件):

下载Instant Client Package-Basic: All files required to run OCI….的文件,也就是上图第一个黄色方框中的文件。

下载Instant Client Package-ODBC驱动,如上图第二个黄色方框。由于DMT安装在Windows Server上,因此有很多安全的限制,如果遇到禁止下载的错误,可以参照下图:

选择Internet,然后点击Customer level。

选择Downloads,然后Enable下载,就可以正常下载Oracle的软件了。

下载完成后,basic和odbc的包如上图所示。

创建 c:\oracle目录,将目录作为解压的目录,选中 basic-windows的文件,然后解压到oracle目录,如下图示:

选中odbc的压缩包,然后解压到c:\oracle

解压后的文件目录结构大致如下:

选中 odbc_install.exe并运行,如下图:

选择run,默认没有反应是正常状态 。

将变量 C:\oracle\instantclient_12_1添加到Path变量中,如下图所示:

增加TNS_ADMIN变量如下图所示:

在本例中,增加的变量TNS_ADMIN和变量Path的值相同。

5.访问DMT工具

先使用界面上的工具Stop Amazon RDS Migration Service停止DMT服务。这样避免刚才设置的环境变量没有应用DMT工具中。

在点击在桌面点击下面图标启动DMT服务。

启动后,如果见到下面的窗口:

表示启动成功。

选择图标就可以启动DMT的Web访问客户端,如下图所示:

见到Console的界面,表示DMT服务启动成功。DMT的console可以在服务器上访问,也可以在客户端访问,在外网访问只需要获取到DMT服务器的Public DNS,使用下面格式URL从外网访问DMT console。

https://your-public-dns/AmazonRDSMigrationConsole

访问console后,会弹出如下界面,输入访问windows的用户名和密码。

输入登陆系统的用户名和密码并登陆,显示如下界面:

在界面中使用Manage Database创建Source和Target数据库,创建Task就可以开始迁移您的数据库了。

6.使用DMT迁移数据

当您通过前面的步骤能够正确地访问DMT工具,说明配置基本成功,下面就可以通过DMT迁移您的数据库了。

Step1: 配置源数据库连接信息

点击上图中的Manage Databases->Add Database,输入数据库类型为Oracle,填好具体URL及数据库的Role信息,示例信息如下:

参数说明:

Name:给需要迁移的数据库定义一个名称,可以根据需要定义。

Description:给需要迁移的数据库一个详细的描述。

Role:需要迁移数据库的角色,如果是迁移中的源数据库,则选择SOURCE,如果是迁移中的目标数据库,则选择TARGET.

Connection String:对于传统Oracle数据库的格式为 ip:port/sid

User name:数据库连接的用户名

Password:数据库连接的密码

Step2: 配置目标RDS数据库连接信息

配置目标RDS数据库信息如下:

RDS的Connection String的格式为:

<database-name>.<rds-endpoint>:<port>/<sid>

Step 3:检查Source和Target数据库的归档模式和Supplemental Log

由于DMT工具可以捕捉数据库日志,将源数据库的变化复制到目标数据库,这种复制方式要求源和目标数据库都是归档的数据库,并且需要Supplemental Log的设置。

使用SQL PLUS连接源数据库,如果数据库处于非归档模式,则将数据库改为归档模式。

运行下面语句,修改Supplemental Log设置:

SQL> ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;

Database altered.

使用Oracle SQL Developer或者其他客户端工具连接RDS目标数据库,运行下面的语句:

exec rdsadmin.rdsadmin_util.alter_supplemental_logging(‘ADD’);

Step 4:创建Task

在主界面上点击“New Task”,如下图所示:

Task options: 定义复制的类型,Full Load表示将当前的表和数据拷贝到目标数据库。Apply Changes表示将当前时刻到停止复制前的日志变化同步到目标数据库。如果两个都选择,表示同步数据,并将捕捉到的数据库变化复制到目标数据库。

Step 5:定义Task

将Source和Target数据库的图标,拖入到左边的流程图中,如下图所示,我们定义了将OracleSourceDB复制到RDSDatabase中。

定义好流程后,点击Table Selection选择需要复制哪些表。如下图所示:

在此图中,我们复制的是TEST.T_USERS表。您也可以使用Patterns的方式匹配表名。

点击Task中的Run按钮,很快数据库就开始迁移了。

7. 错误诊断

(1)如果在测试数据库时出现oci.dll无法加载的错误,如下图所示:

这个错误一般说明你没有将instance client的路径配置到path变量中去。此时只需要配置好变量,然后停止并启动DMT服务就可以了。

(2)ORA-12170: TNS: Connect timeout occurred [122307] OCI error.

如果出现此错误,说明DMT工具连接数据库超时,此时请检查RDS数据库的Security Group是否开启了DMT服务器的1521端口的访问,或者检查数据库的防火墙等网络设置,确保DMT服务器能够正常访问Oracle服务器。

作者介绍:

蓝勇

AWS解决方案架构师,负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内的应用和推广,在DR解决方案、数据仓库、RDS服务、企业应用、自动化运维等方面有着广泛的设计和实践经验。在加入AWS之前,在甲骨文中国担任资深售前工程师,负责售前方案咨询和架构设计,在数据库,中间件,大数据及企业应用方面有丰富经验。

杨婉洁

亚马逊AWS解决方案架构师实习生,喜欢编程,熟悉Java、C++、JSP、HTML以及关系型数据库。曾在学校和企业参与数据分析项目,熟悉各类数据分析的算法。热爱大数据、云计算。

VPC中NAT的那点事

by AWS Team | on |

NAT就在那里

下图 是EC2实例通过IGW(Internet网关) 接入到Internet的示意图。熟悉AWS的读者会知道,这里EC2实例和Internet通信的两个方向上,实际上发生了如下的转换:

  • 从EC2实例发出的前往Internet的IP包,其源地址10.0.0.10在经过IGW时,会被转换为与实例关联的公网地址 54.232.0.1;
  • 从Internet发给54.232.0.1的IP包,经过IGW时其目的地址会转换为ENI对应的内网地址10.0.0.10并被送到 EC2实例;

可以看到,这里Internet网关就是起到实例的内网地址和公网地址一对一的基本 NAT(网络地址转换)的功能。

相比于没有NAT的场景,大部分的应用、软件不需要任何改变就能在基本NAT的场景下继续工作,例如基于HTTP协议的Web应用等;但是对于某些应用,例如FTP、VoIP等,网络地址转换会给应用带来一些意想不到的挑战。今天我们以历史悠久的FTP协议为例,来和大家探讨一下NAT给FTP这样的应用带来什么样的挑战,以及FTP应用和协议又是如何演进去适应它。

被动模式下的FTP

我们重温一下FTP的工作过程。客户端连接服务端TCP 21端口建立命令通道后,输入用户名密码完成登录;随后的每一次数据传输都需要另外建立数据通道进行; 如果数据通道由客户端发起,服务端接受,我们称之为被动模式;反之,如果数据通道由服务端发起,客户端接受,则称之为主动模式。

为简化讨论,我们以被动模式为例。

同一个私网内

我们在EC2实例10.0.0.10上搭建了一台FTP服务器,它监听在21端口。现在我们从同一个VPC里的另外一台EC2上运行FTP客户端;那么整个过程会很顺利。

从Internet访问

现在我们从位于Internet某处的一台PC上运行FTP客户端。

这里连接超时的原因显而易见,FTP服务端发送给客户端的IP地址是服务端的私有地址。位于Internet上的客户端无法建立与位于VPC内部的私有地址10.0.0.10直接通讯。

解决这个问题有多种方法,我们由简单到复杂分别叙述。

增强协议适配NAT

FTP协议针对NAT和其他因素,对协议进行了增强,提供了增强版的被动模式EPSV命令[1]。

下面的例子里,服务端不再显式指定IP地址,只提供数据通道的端口号。客户端默认与控制通道相同的IP地址建立数据通道。

可以看到,解决方案很优雅。实际上如果你在阅读本文的时候,绝大部分FTP服务端和客户端都已经实现了EPSV,而且优先使用它,所以FTP应用目前在EC2上是可以称之为开箱即用的。当然这需要客户端和服务端都支持增强的协议才能达成;如果我们不修改协议,能否解决这个问题呢。

放开那协议!我来!

有些时候,修改协议和实现需要多方协调和很长的时间才能完成。在RFC2428标准化之前,一些FTP实现就已经通过修改实现来适配基本NAT,而非修改协议。

以vsftpd为例,它允许通过配置文件vsftpd.conf中的配置项 pasv_address=54.232.0.1 告知服务端,在PASV被动模式下,应当指示客户端连接到配置项指定的IP(而不是服务端的私有IP)来适配基本NAT。

其他的一些常见应用例如VoIP类应用,也有类似的机制去适配基本NAT;例如引入STUN/TURN/ICE等方式[2]适配各种更加复杂的NAT穿越场景;但是针对部署在EC2上的基本NAT环境,也有通过实现上的简单调整,例如开源VoIP应用Asterisk就支持通过在配置文件/etc/asterisk/sip.conf里指定本机的公网地址和本地网段的方式来适配基本NAT。

nat=yes

externaddr=54.223.0.1

localnet=10.0.0.0/16

协议和实现我都不想动!

作为一枚任性的读者,如果您既不想动协议也不想动实现,这里笔者给读者介绍一种剑走偏锋的方式,读者若有兴趣,可以轻松愉快的在AWS上试一试,看看能否解决你的应用适配基本NAT。下面是一段shell脚本,当然是运行在Linux操作系统上的。

          #从EC2 实例元数据服务获取本实例的公网IP(如有)、私网IP

          public_ipv4=`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`

          local_ipv4=`curl -s http://169.254.169.254/latest/meta-data/local-ipv4`

          #配置私网地址段,这里应为EC2实例所在VPC的地址范围

          local_net=10.0.0.0/16

          if [ “x${public_ipv4}” == “x” ]

          then

          echo “No public IPv4 address available for this instance, abort.”

          exit 1

          else

           #如果EC2实例的公网IP不为空,则将该公网地址添加到eth0上

          ip address add ${public_ipv4}/32 dev eth0

          #本地接受的连接,如果来源不是本VPC,那么将IP包的目的地址改写为公网IP

          iptables -t nat -A PREROUTING ! -s ${local_net} -d ${local_ipv4} -i eth0 -j DNAT –to ${public_ipv4}

          #本地发起的连接,如果出方向流量的源IP地址是公网地址,那么需要改写为私网IP

          iptables -t nat -A POSTROUTING -s ${public_ipv4} -o eth0 -j SNAT –to ${local_ipv4}

          fi

正常情况下,脚本执行完毕后,可以通过如下方式验证效果。

首先检查本实例的公网IP是否已经正确配置到eth0上。

~ # ip addr show dev eth0

eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000

link/ether 02:c7:6b:9b:d2:b6 brd ff:ff:ff:ff:ff:ff

inet 10.0.0.10/24 brd 10.0.0.255 scope global eth0

valid_lft forever preferred_lft forever

                  inet 54.232.0.1/32 scope global eth0

valid_lft forever preferred_lft forever

inet6 fe80::c7:6bff:fe9b:d2b6/64 scope link

valid_lft forever preferred_lft forever

可以看到,公有IP地址(54.232.0.1/32)已经成功添加到eth0接口。

然后检查iptables的NAT规则是否正确配置

~ # iptables -t nat -nvL

 

Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)

pkts bytes target     prot opt in     out     source               destination

               0    0  DNAT       all  —  eth0   *       ! 10.0.0.0/16        10.0.0.10            to:54.223.74.106

Chain INPUT (policy ACCEPT 1 packets, 64 bytes)

pkts bytes target     prot opt in     out     source               destination

 

Chain OUTPUT (policy ACCEPT 3 packets, 222 bytes)

pkts bytes target     prot opt in     out     source               destination

 

Chain POSTROUTING (policy ACCEPT 3 packets, 222 bytes)

pkts bytes target     prot opt in     out     source               destination

              0     0 SNAT       all  —  *      eth0    54.223.74.106        0.0.0.0/0            to:10.0.0.1

从上面可以看到传入、传出数据包的数量以及IP地址在传入前,传出后的地址改写情况。

最后分别从VPC内部和Internet连接到服务,验证结果

~ $ ss -nt

State       Recv-Q Send-Q            Local Address:Port                       Peer Address:Port

ESTAB        0          72                   54.223.74.106:21                            119.xx.x.xx:52425

ESTAB        0      1272                   54.223.74.106:12081                      119.xx.x.xx:23710

ESTAB        0          72                   10.0.0.10:21                                     10.xx.x.xx:48361

ESTAB        0      1272                   10.0.0.10:12090                               10.xx.x.xx:32115

笔者在没有修改任何vsftpd的配置文件的前提下,通过上述脚本的运行和配置,同一个VPC内部的客户端和Internet客户端都能完成FTP被动模式的文件传输全流程。

值得一提的是,本方法仅供参考,不建议在生产环境中大规模使用,推荐的解决方案请参考前文关于协议适配和实现适配。

[1] FTP Extensions for IPv6 and NATs  https://tools.ietf.org/html/rfc2428
[2] NAT Traversal Practices for Client-Server https://tools.ietf.org/html/rfc6314
作者介绍:

丁成银

AWS 解决方案架构师,获得AWS解决方案架构师专业级认证和DevOps工程师专业级认证。负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云 服务在国内的应用和推广,在数字媒体、电信、互联网和游戏、企业混合IT等方面有着丰富的实践和设计经验。在加入AWS之前,历任数字媒体娱乐系统工程 师、宽带业务架构师、云解决方案架构师,负责数字媒体娱乐系统、云计算解决方案等服务的咨询和架构设计工作。

 

CloudWatch Events监控您应用的安全

by AWS Team | on | | Comments

每个应用程序时刻都在产生事件,Amazon CloudWatch Events能帮助您针对应用的事件进行有针对性的响应和处理,及时响应,并处理错误事件,存储和分析潜在的告警信息。在接下来的篇幅里,我将利用AWS的CloudWatch Events,Lambda,SNS,SQS等服务向您展示如何及时分析与处理应用事件。

在这个场景中,我将应用事件划分分三个等级(当然,在您的具体业务场景中,您可以根据实际情况划分任意多的等级),Green,Yellow,Red。Green代表应用正常,您不需要进行任何动作。Yellow表示您应用的健康检查失败,通过Lambda来处理该类型事件。Red表示您的应用在至少一台服务器上已经失败,立即通知运维部门处理。

以下是该场景中的架构示意图:

1. 最左边为您的应用服务器群,他们将各自的事件发送给CloudWatch Events;

2. 在CloudWatch Events中设置Rule来进行区分,并将对应的事件发送相应的目标,如Lambda,SNS,SQS;

3. 目标在收到事件后进行相应的处理;

具体步骤:

1.   创建3个目标,Lambda,SNS,SQS;

1.1, 目标1,创建Lambda函数,SampleAppDebugger;

1.2, 目标2,创建SNS主题,RedHealthNotifier;

1.3, 目标3,创建SQS消息队列,ReportInspectionQueue;

 

2.   创建CloudWatch Events Rule

2.1, 将以下内容保存为YellowPattern.json;

2.2, 使用以下命令创建名为myCustomHealthStatusYellow的规则;

2.3, 使用以下命令创建目标;

2.4, CloudWatch Event需要将事件发送给Lambda,所以需要给Lambda添加适当权限允许CloudWatch这么做;

3.   重复上面的步骤创建第2条规则,并设置目标为SQS和SNS,特别注意,不要忘记给SNS,SQS设置相应权限以允许CloudWatch发送事件过来;

3.1, 使用以下命令创建名为myCustomHealthStatusRed的规则,这里的RedPattern.json文件其实是将2.1步骤中的YellowPattern.json是一样的,只是将内容中的Yellow替换成了Red;

3.2, 创建两个目标,SQS,SNS;

3.3, 添加权限允许CloudWatch Events发送事件;

其他SNS,SQS权限设置相关,请参考该官方链接:http://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/events/resource-based-policies-cwe.html#sns-permissions

4.   进行测试,手动放入一些Red事件(我设置了个小脚本,每次运行都会放入61个事件),看看SQS及SNS情况;

这里我运行了三次脚本,所以SQS中有183条消息

看看邮箱中是否会收到邮件

5.   测试Yellow事件及Lambda反应;

Lambda被触发的次数

作者介绍:

郑进佳

亚马逊AWS解决方案架构师,在加入AWS之前,在多家跨国公司有着超过7年的架构设计和项目管理的经验,对AWS云端高可用架构有着深刻的理解,以及对企业级应用如何迁移到云端的架构设计有实战方面的经验。

使用Oracle Data Pump将数据库迁移到AWS的RDS Oracle数据库

by AWS Team | on |

1.Oracle数据库的迁移方法

如何将Oracle数据库从数据中心迁移到AWS云上是DBA经常遇到的问题,迁移Oracle数据库有多种方式:

(1)使用AWS DMS服务迁移

(2)使用Oracle SQL Developer迁移

(3)使用Oracle Data Pump迁移

(4)使用Oracle Export/Import迁移

(5)使用Oracle SQL Loader迁移

如果需要了解不同的迁移方法,可以参考 博客《Oracle数据库迁移到AWS云的方案》 。

2.使用Oracle Data Pump迁移

本文主要讨论使用Oracle Data Pump将Oracle数据库迁移到RDS数据库。示例数据库的信息如图。

 

下面是模拟在数据中心的Oracle11g源数据库中创建用户和表,并将源数据库迁移到AWS云中RDS Oracle 11g数据库的全过程。

步骤一:初始化源数据库并使用Data Pump导出

(1)使用SQL Plus登录源Oracle数据库

sqlplus / as sysdba

(2)创建用户test

create user test identified by welcome1;

(3)为新创建用户grant权限(实际使用请给用户grant合适的权限)

grant dba to test;

(4)为用户test创建表

create table test.aa(id varchar(20) not null primary key,name varchar2(30));

(5)为表插入数据并commit

SQL> insert into test.aa values(‘1111′,’1111name’);

1 row created.

SQL> insert into test.aa values(‘2222′,’2222name’);

1 row created.

SQL> commit;

Commit complete.

(6)在源数据库所在的Linux上逐级创建下面文件目录

mkdir /home/oracle/datapump/datafiles

(7)在SQLPlus中创建数据库Directory

create directory dpump_dir as ‘/home/oracle/datapump/datafiles’;

grant read,write on directory dpump_dir to test;

(8)使用expdp命令导出test用户的所有表

expdp test1/welcome123 directory=dpump_dir dumpfile=test.dmp

expdp test1/welcome123 directory=dpump_dir dumpfile=test1.dmp

步骤二:使用SQL Plus连接RDS数据库,并创建数据库目录对象

(1)在源数据库上配置RDS数据库的tnsnames

cd $ORACLE_HOME/network/admin

vi tnsnames.ora

输入tnsnames的内容如下:

ORARDS=(description=(address_list=(address = (protocol = TCP)(host =    RDS_HOST_NAME)(port = RDS_PORT)) )(connect_data =(SID=RDS_SID)))

(2)使用SQLPLUS连接远程RDS数据库

sqlplus oracle/welcome1@ORARDS

(3)使用tnsping检查RDS连接信息

如果连接有错误,可以使用下面命令查看通讯是否正常

tnsping “(description=(address_list=(address = (protocol = TCP)(host = RDS_HOST_NAME)(port = RDS_PORT)))(connect_data =(SID= RDS_SID)))”

tnsping应该返回“OK (xx msec)”类似文字。

如果tnsping不通请检查RDS对应的security group,RDS的security group中应当允许当前服务器通过TCP协议访问RDS数据库的端口。

(4)创建目标RDS的directory对象

exec rdsadmin.rdsadmin_util.create_directory(‘dpump_dir1’);

创建成功后退出连接RDS的SQL Plus客户端。

步骤三:将源数据库Data Pump导出的文件上传到RDS数据库

(1)连接源数据库并创建database link

create database link to_rds connect to oracle identified by welcome1 using ‘(description=(address_list=(address = (protocol = TCP)(host = RDS_HOST_NAME)(port = RDS_PORT)))(connect_data =(SID=RDS_SID)))’;

(2)运行DBMS_FILE_TRANSFER包将数据传输到RDS服务器的目录

BEGIN

DBMS_FILE_TRANSFER.PUT_FILE(

source_directory_object       => ‘dpump_dir1’,

source_file_name              => ‘test.dmp’,

destination_directory_object  => ‘dpump_dir1’,

destination_file_name         => ‘test.dmp’,

destination_database          => ‘to_rds’

);

END;

步骤四:通过impdp命令将远程的RDS数据库文件导入

(1)在源数据库服务器上运行impdp命令导入数据

impdp  oracle@ORARDS dumpfile=test.dmp directory=dpump_dir1 full=y

执行完毕检查test用户和相关的表。

3.    总结

从上面的过程我们可以看到,将一个Oracle数据库迁移到RDS的过程并不复杂,如果源数据库很大,由于需要导出数据、将数据上传到RDS的Data Pump目录、导入数据,迁移的过程也会比较长。上述过程假设了我们生产数据库的业务有足够的停机时间,在迁移过程中数据不会变化。如果迁移过程中,源数据库会发生变化,那么我们就需要同步数据中心和RDS数据库间的日志了。

如果源数据库很大,我们也可以在AWS上启动一台中间服务器,并在中间服务器上安装Oracle的客户端软件,将源数据库的Data Pump导出文件分片然后scp复制、Tsunami UDP加速上传等方式将文件上传到中间服务器,然后上传到RDS的Data Pump目录,这样能加速迁移的过程。

作者介绍:

蓝勇

AWS解决方案架构师,负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内的应用和推广,在DR解决方案、数据仓库、RDS服务、企业应用、自动化运维等方面有着广泛的设计和实践经验。在加入AWS之前,在甲骨文中国担任资深售前工程师,负责售前方案咨询和架构设计,在数据库,中间件,大数据及企业应用方面有丰富经验。