如何配置 aws-sdk-java fastjson sdkcn-north-1

快速使用AWS的14个经验分享
你好,游客
快速使用AWS的14个经验分享
来源:AWS中文博客&
  在今天的文章中,我整理出了大量当初曾经错过、而至今仍将我追悔莫及的Amazon Web Services(简称AWS)使用心得。在几年来的实践当中,我通过在AWS之上新手构建及部署各类应用程序而积累到了这些经验。虽然内容有些杂乱,但相信仍然能给各位带来一点启示。
  从物理服务器向&云环境&转移的过程不仅仅是一项技术任务,同时也意味着我们的思维方式需要作出针对性的转变。总体而言,在物理环境下我们需要关注的只是每一台独立主机; 它们各自拥有自己的静态IP,我们能够对其分别加以监控。而一旦其中一台发生故障,我们必须尽最大可能让其快速恢复运转。大家可以以为只要将基础设施转移到AWS环境之下,就能直接享受到&云&技术带来的种种收益了。遗憾的是,事情可没那么简单(相信我,我亲身尝试过了)。在AWS环境之下,我们必须转变思维,而且这方面的任务往往不像技术难题那么容易被察觉。因此,受到了SehropeSarkuni最近一篇帖子的启发,我将自己几年来积累得出的AWS 使用心得汇总于此,而且说实话、我真希望自己当初刚刚接触AWS时能有人告诉我这些宝贵经验。这些心得总结自我在AWS之上部署个人及工作应用程序时的亲身感受,其中一部分属于需要高度关注的&疑难杂症&(我自己就是直接受害者),而另一部分则是我听其他朋友说起过、并随后亲自确认有效的解决方案。不过总体而言,为了积累这些经验,我确实付出了相当惨痛的代价:)
  应用程序开发
  千万不要把应用程序状态保存在自己的服务器上。
  之所以这么说,是因为一旦我们的服务器发生故障,那么应用程序状态很可能也随之彻底消失。有鉴于此,会话应当被存储在一套数据库(或者其它某些集中式存储体系、memcached或者redis当中)而非本地文件系统内。日志信息应当通过系统日志(或者其它类似方案)进行处理,并被发送至远程位置加以保存。上传内容应当直接指向S3(举例来说,不要将其存储在本地文件系统内,并通过其它流程随后迁移到S3)。再有,任何已经处理过或者需要长期运行的任务都应该通过异步队列(SQS非常适合处理此类任务)来实现。
  编辑点评:对于S3上传内容而言,HN用户Krallin指出,我们可以彻底避免其与自有服务器的接触,并利用预签名URL保证用户的上传数据被直接发送至S3当中。
  将额外信息保存在日志当中。
  日志记录通常包含有时间戳以及pid等信息。大家也可能希望将实例id、服务区域、可用区以及环境(例如分步环境或者生产环境等)添加进来,而这些都能在日后的调试工作中作为参考。大家可以从instance metadata service当中获取到这些信息。我所采用的方法是将这些信息作为引导脚本的组成部分,并将其以文件形式存储在文件系统当中(例如/env/az或者 /env/region等)。这样一来,我就用不着持续查询元数据服务来获取这些信息了。大家应当确保这些信息能够在实例重新启动时得到正确更新,毕竟我们都不希望在保存AMI时发现其中的数据还跟上次完全一样,这肯定属于非正常状况。
  如果我们需要与AWS进行交互,请在当前语言中使用对应SDK。
  千万不要试图自己动手。我当初就犯过这个错误,因为我认为自己只是单纯需要向S3上传内容,但随着后续服务的持续增加、我发现自己的决定简直愚蠢至极。AWS SDK的编写质量很高,能够自动处理验证、处理重试逻辑,而且由Amazon官方负责维护与迭代。此外,如果大家使用EC2 IAM角色(大家绝对应该这么做,这一点我们后面会进一步提到),那么该SDK将帮助我们自动获取到正确的证书。
  利用工具查看应用程序日志。
  大家应当采用管理员工具、系统日志查看器或者其它方案,从而帮助自己在无需在运行中实例内使用SSH的方式查看当前实时日志信息。如果大家拥有集中式日志记录系统(我强烈建议大家使用此类系统),那么当然希望能在不使用SSH的情况下完成日志内容查看任务。很明显,将SSH引入正处于运行状态的应用程序实例会引发诸多弊端。
  运营心得
  如果将SSH引入自己的服务器,那么自动化机制恐怕将无法生效。
  在全部服务器上禁用SSH访问。
  这听起来确实有点疯狂,我知道,但在大家的安全组当中、请务必确保端口22不向任何人开放。如果各位想从今天的文章中获得什么启示,那请千万牢记以下一点:如果将SSH引入自己的服务器,那么自动化机制恐怕将无法生效。从防火墙级别(而非服务器本身)禁用SSH有助于整套框架实现思维转变,因为这样一来我们就能了解到哪些区域需要进行自动化改造,同时大家也能更轻松地恢复访问来解决当前面临的问题。在意识到再也不必将SSH引入实例之后,大家肯定会像我一样感到浑身轻松。没错,这是我在实践中了解到的最惊世骇俗、但也却具实用性的心得。
  编辑点评:很多人对这项心得表现出了高度关注(HackerNews网站上还出现了不少值得一读的评论意见),因此我们要在这里多说几句。我个人也会通过禁用入站SSH来蒙骗自动化机制(哦,我只是SSH一下来修复某个问题,马上就撤)。当然,如果我需要在某个实例中进行主动调试,那么我仍然可以在安全组中将其重新启用,因为有时候我们确实没有其它办法来调试特定问题。另外,具体情况还取决于我们实际使用的应用程序类型:如果大家应用程序的正常运行要求各位能力通过SSH将信息传递至服务器,那么将其禁用肯定不是什么好主意。这种阻断进站SSH的办法确实适合我,也迫使我对自己的自动化机制加以精心打理,不过必须承认、这种方式并不适合每一位用户。
  服务器只是暂时性手段,没必要太过关注。我们要关注的仅仅是服务本身。
  如果某台服务器出现了故障,大家完全没必要对其太过关注。这是我在利用AWS来替代物理服务器之后,亲身获得的最直接的便利成效。一般来讲,如果一台物理服务器无法正常工作,技术人员总会暂时陷入恐慌。但在AWS当中,大家就完全不必担心了,因为自动伸缩机制会很快帮我们建立起新的实例。 Netflix公司在此基础之上还跨出了更具前瞻意义的步伐,他们组建了Simian Army团队,并尝试Chaos Monkey等极为激进的测试项目&&它会随机关闭生产环境下的某些实例(他们还利用Chaos Gorilla项目随机关闭可用区。我甚至得到消息,说是Chaos Kong项目会直接关闭基础设施大区&&)。总而言之,我想表达的意思是:服务器总会发生故障,但这不该影响到我们的应用程序。
  不要为服务器提供静态/弹性IP。
  对于一款典型的Web应用程序,大家应当将一切部署在负载均衡机制之下,并在不同可用区之间对资源使用情况加以平衡。虽然我也遇到过一些需要使用弹性IP机制的情况,但为了尽可能提高自动伸缩效果,大家还是应该利用负载均衡机制取代在每个实例中使用独有IP的作法。
  将自动化普及到各个角落。
  不只是AWS,自动化机制应该作为整体运营工作中的通用性指导方针,其中包括恢复、部署以及故障转移等等。软件包与操作系统更新都应该由自动化方案所管理,具体可表现为bash脚本或者Chef/Puppet等。我们不该把主要精力放在这些琐碎的杂事上。正如前文中所提到,大家还需要确保禁用SSH 访问,从而快速了解到自己的执行流程中还有哪些方面没有实现自动化改造。请记住前面提到的重要原则:如果将SSH引入自己的服务器,那么自动化机制恐怕将无法生效。
  每位员工都要拥有一个IAM账户。永远不要登录主账户。
  通常情况下,我们会为服务设置一个&运营账户&,而整个运营团队都将共享登录密码。但在AWS当中,大家当然不希望遵循同样的处理方式。每位员工都要拥有一个IAM账户,其中提供与其需求相符的操作权限(也就是最低权限)。IAM用户已经可以控制基础设施中的一切。截至本文撰写时,IAM用户惟一无法访问的就是计费页面中的部分内容。
  如果大家希望进一步保护自己的账户,请确保为每位员工启用多因素验证机制(大家可以使用谷歌Authenticator)。我听说有些用户会将MFA令牌交付给两名员工,并将密码内容交付给另外两名员工,这样主账户在执行任意操作时、都至少需要两名员工的同意。对我来说这种作法有点小题大做,但也许您所在的企业确实需要如此高强度的控制机制。
  我最后一次从CloudWatch收到操作警告大约是在一年之前&&
  将警告信息转化为通知内容。
  如果大家已经将一切步骤正确部署到位,那么运行状态检查机制应该会自动清除故障实例并生成新的实例。在收到CloudWatch警告信息时,我们一般不需要采取任何行动,因为所有应对措施都能以自动化方式实现。如果大家得到警告称相关问题需要手动干预,那么请做好事后检查、看看能不能找到一种可以在未来通过自动化方式将其解决的途径。我最后一次从CloudWatch收到操作警告大约是在一年之前,而且对于任何一位运营人员来说、能够不再被警告消息打扰了清梦都应该算是天大的好消息。
  计费机制
  建立起细化计费警告机制。
  大家应当始终设定至少一套计费警告机制,但其内容却可以非常简单&&例如只在我们超出了当月资源用量限额时发出提醒。如果大家希望早点掌握计费指数的动向,则需要一套更为完备的细化方案。我解决这个问题的办法是以星期为单位设定预期使用量。如此一来,假如第一周的警告额度为1000美元,那么第二周应该为2000美元,第三周为3000美元,依此类推。如果第二周的警告在当月的14号或者15号之前就被触发,那么我就能推定肯定发生了什么异常状况。如果想更进一步地实现细化控制,大家可以为每项服务设置独立的警告方案,这样就能快速了解到底是哪项服务把我们的资源预算早早耗尽了。如果大家每个月都在固定使用某几项服务,而且其中一些非常稳定、另一些则起伏较大,那么这种方法能够收到良好的成效。在此类情况下,我们不妨为稳定服务设置每周独立警告,同时为起伏较大的服务设置周期更长的整体警告。当然,如果各项服务的资源使用量都很稳定,那么上述方法就有点过分谨慎了,毕竟只要看一眼 CloudWatch、大家就能马上了解到底是哪项服务出了问题。
  安全性保障
  使用EC2角色,不要为任何应用程序提供IAM账户。
  如果大家在应用程序当中内置有AWS证书,那么肯定属于&处理失当&的状况了。前面之所以强调在开发语言中使用AWS SDK,最重要的理由之一就是我们能够轻松借此使用EC2 IAM角色。角色的设计思路在于,允许大家为特定角色指定其所必需的恰当权限,而后将该角色分配至对应EC2实例当中。而无论我们何时将AWS SDK应用至实例当中,都不必再指定任何验证凭证。相反,该SDK将回收我们在设置当中为该角色指定权限所使用的任何临时性证书。整个流程都会以透明化方式处理,非常安全而且极具实用性。
  将权限分配至组,而非用户。
  管理用户往往是件令人头痛的事情,特别是在使用Active Directory或者其它一些已经与IAM相整合的外部验证机制时,而且这类作法的实际效果也不够理想(当然也有效果不错的情况)。不过我发现更轻松的办法,即只将权限分配至组而非个别用户,这将大大降低权限的管理难度。很明显,相较于面向每位独立用户来查看为其分配的权限,以组为单位进行权限交付能够帮助我们更好地把握系统整体概况。
  设置自动化安全审计机制。
  在日常工作中,很重要的一点是追踪基础设施内安全设置的各项变更。实现这一目标的办法之一在于首先建立起一套安全审计角色(即JSON模板)。这一角色会对账户之内与安全相关的各类设置进行只读访问。在此之后,大家就可以利用这一类似于Python脚本的方案达到目标了,它将能够对账户中的所有条目进行审查并生成一整套与配置相关的规范比对结果。我们可以设置一个cronjob来运行该脚本,并将输出结果与上一次的结果相比较。其中的差异之处就代表着我们安全配置方案当中所出现的变化。这种方式非常实用,而且能够通过电子邮件将变更信息通知给大家。
  使用CloudTrail来记录审计日志。
  CloudTrail通过通过API或者S3存储桶内的Web控制台记录所有执行过的操作活动。利用版本控制机制设置存储桶可以确保任何人都无法修改这些日志内容,而我们自己则可以随后对账户内的全部变更进行彻底审计。我们当然不希望遇到需要审计日志内容的状况,但正所谓有备无患,准备好这么一套方案还是很有必要的。
  在存储桶内的SSL名称中使用&-&而非&.&。
  如果大家希望在SSL之上使用自己的存储桶,那么使用&.&作为名称的组成部分将导致证书不匹配错误。一旦存储桶创建完成,我们将无法再对其名称进行更改,所以大家只能将一切复制到新的存储桶当中。
  我发现文件系统就像大型政府部门一样&可靠&。
  避免载入文件系统(例如FUSE)。
  我发现在被用于关键性应用程序时,这些文件系统就像大型政府部门那样&可靠&。总之,使用SDK作为替代方案更加明智。
  我们用不着在S3之前使用CloudFront(但这样确实能够起到助益)。
  编辑评论:根据Hacker News网站用户的最佳反馈内容,我们对这条心得作出了部分修改。
  如果大家对于可扩展能力比较看重,那么最好是将用户直接引导至S3 URL而非使用CloudFront。S3能够实现任意水平的容量扩展(虽然一部分用户报告称其无法实现实时规模扩展),因此这也是充分发挥这一优势的最佳思路。除此之外,更新内容在S3中的起效速度也够快,虽然我们仍然需要在使用CDN查看变更时等等TTL的响应(不过我相信大家现在已经能够在 CloudFront中获得0延迟TTL,所以这一点也许存在争议)。
  如果大家需要良好的速度表现,或者需要处理对传输带宽要求极高的数据(例如超过10TB),那么大家可能更希望使用像CloudFront这样的CDN方案与S3相配合。CloudFront能够极大提升全球各地用户的访问速度,因为它会将相关内容复制到各边缘位置。根据实际用例的不同,大家可以通过较低数量的请求实现高传输带宽(10TB以上),并借此降低使用成本&&这是因为相较于S3传输带宽,当传输总量高于10TB时CloudFront的传输成本每GB比其低0.010美元。不过CloudFront的单次请求成本较直接访问S3中的文件却要略高一点。根据具体使用模式,传输带宽的成本节约额度也许会超过单一请求所带来的额外成本。因为在直接访问S3存储内容时,我们只需以较低频度从S3获取数据(远较正常使用情况更低),所以成本也就更加低廉。AWS官方提供的CloudFront说明文档解释了如何将其与S3配合使用,感兴趣的朋友可以点击此处查看细节信息。
  在密钥开头使用随机字符串。
  这初看起来似乎有点难以理解,不过S3所采取的一大实现细节在于,Amazon会利用对象密钥来检测某个文件到底保存在S3中的哪个物理位置。因此如果多个文件使用同样的前缀,那么它们最终很可能会被保存在同一块磁盘当中。通过设置随机性密钥前缀,我们能够更好地确保自己的对象文件被分散在各个位置,从而进一步提升安全性。
  EC2/VPC
  别忘了使用标签!
  几乎每项服务都提供标签功能,别忘了善加利用!它们非常适用于进行内容归类,从而大大简化后续出现的搜索与分组工作。大家也可以利用这些标签在自己的实例中触发特定行为,例如env-debug标签可以确保应用程序在部署之后进入调试模式。
  我遇到过这类问题,感觉很不好,大家千万不要重蹈覆辙!
  在非自动伸缩实例中使用中止保护。以后你会感激我的建议的,绝对。
  如果大家拥有某些不具备自动伸缩机制的一次性实例,则应当尽可能同时使用中止保护,从而避免某些人无意中将这些实例给删除掉。我就遇到过这类问题,感觉很不好,大家千万不要重蹈覆辙。
  使用VPC。
  当初我刚刚开始接触AWS时,VPC要么还不存在、要么就是被我给忽视了。虽然刚开始上手感觉很糟糕,但一旦熟悉了它的特性并能够顺畅使用,它绝对能带来令人喜出望外的便捷效果。它能够在EC2之上提供各类附加功能,事实证明设置VPC花掉的时间完全物有所值&&甚至物超所值。首先,大家可以利用 ACL从网络层面上控制流量,此外我们还可以修改实例大小及安全组等等,同时无需中止当前实例。大家能够指定出口防火墙规则(在正常情况下,我们无法控制来自EC2的离站流量)。不过最大的助益在于,它能为我们的实例提供独立的私有子网,这就彻底将其他人排除在外,从而构成了额外的保护层。不要像我当初那样傻等着了,立刻使用VPC并让一切变得更加轻松。
  如果大家对于VPC抱有兴趣,我强烈建议各位观看《百万数据包的一日之期》这段资料。
  利用保留实例功能来节约大量成本。
  保留实例的本质就是将一部分资金节约下来,从而使其保持较低的资源耗费速率。事实证明,保留实例相较于按需实例能够帮助我们省下大量经费。因此,如果大家意识到只需要继续保持某个实例运行一到三年,那么保留实例功能将是各位的最佳选择。保留实例属于AWS当中的一类纯逻辑概念,大家用不着将某个实例指定为需保留对象。我们要做的就是设定好保留实例的类型与大小,接下来任何符合这一标准的实例都将处于低速运转加低成本支出的运行模式之下。
  锁定安全组。
  如果有可能,千万不要使用0.0.0.0/0,确保使用特定规则来限制用户对实例的访问。举例来说,如果大家的实例处于ELB之后,各位应该将安全组设定为只允许接受来自ELB的流量,而非来自0.0.0.0/0的流量。大家可以通过将&amazon-elb/amazon-elb-sg&写入 CIDR的方式实现这一目标(它会自动帮大家完成其余的工作)。如果大家需要为一部分来自其它实例的访问请求向特定端口放行,也不要使用它们的对应IP,而最好利用其安全组标识符来替代(只需要输入&sg-&,其它的部分将自动完成)。
  不要保留无关的弹性IP。
  我们所创建的任意弹性IP都会成为计费项目,无论其与实例是否相关,因此请确保在使用过后将其及时清理掉。
  在负载均衡器上中止SSL。
  大家需要将自己的SSL证书信息添加到ELB当中,但在服务器上中止SSL能够消除由此带来的常规资源消耗,从而提高运行速度。除此之外,如果大家需要上传自己的SSL证书,则可以经由HTTPS流量实现、而负载均衡器会为我们的请求添加额外的标头(例如x-forwarded-for等),这有助于我们了解最终用户究竟是何许人也。相比之下,如果我们经由TCP流量实现,那么这些标头将不会被添加进来、相关信息自然也就无从获取。
  如果打算执行高强度流量,请对ELB进行预热。
  对于ELB来说,容量扩展是需要一段时间周期才能完成的。如果大家意识到自己将会迎来流量峰值(例如销售门票或者召开大型活动等),则需要提前对 ELB进行预热。我们可以主动增加流量规模,这样ELB就会提前进行容量添加,从而避免实际流量来临时发生卡顿。不过AWS建议大家最好是与服务人员取得联系,而非自行对负载均衡器进行预热。或者,大家也可以在EC2实例当中安装自己熟悉的负载均衡软件并加以使用(例如HAProxy等)。
  ElastiCache
  使用配置端点而非独立节点端点。
  通常情况下,大家需要让应用程序识别出各可用Memcached节点的存在。但如果大家希望以动态方式实现容量扩展,那么这种作法可能会带来新的问题,因为我们将需要采取多种方式才能保证应用程序识别到容量的变化。比较简便的解决方案在于使用配置端点,这意味着使用Memcached库的AWS版本来对新节点自动发现机制加以抽象并剥离。AWS使用指南中提供了更多与缓存节点自动发现议题相关的解答,感兴趣的朋友可以点击此处查看细节信息。
  为故障转移设置事件订阅机制。
  如果大家正在使用多可用区方案,那么这可能是一种被各位所忽略、但在相关需求出现时却又悔之晚矣的重要解决方案。
  CloudWatch
  使用CLI工具。
  要利用Web控制台创建警报机制,我们可能需要面临大量繁的工作,特别是在设置众多内容类似的警报信息时,因为我们无法直接&克隆&现有警报并仅对其中一小部分作出修改。在这种情况下,利用CLI工具实现脚本化效果能够帮助各位节约大量宝贵时间。
  使用免费监测指标。
  CloudWatch监控工具以免费方式提供各类监测指标(包括传输带宽、CPU使用率等等),而且用户能够获取到最多两周的历史数据。有鉴于此,我们根本用不着花钱购置自己的工具来实现系统监控。但如果大家需要超过两周的历史数据记录,那没办法,只能使用第三方或者自行开发的监控方案了。
  使用自定义监测指标。
  如果大家希望监控免费指标之外的其它项目,则可以将自己的定制指标信息发送至CloudWatch,并使用相关警报与图形功能。这不仅可以用于追踪诸如磁盘空间使用量等状况,同时也可以根据实际需求自行设定应用程序监测方向。感兴趣的朋友可以点击此处查看AWS提供的发布自定义监测指标页面。
  使用详细监测机制。
  这项服务每月每实例的使用成本约为3.5美元,但其提供的丰富额外信息绝对能够值回票价。1分钟的细化监测甚至好过5分钟的粗放查看。大家可以借此了解到某次时长5分钟的崩溃到底是因何而起,同时以非常明确的方式将其以1分钟图表的方式显示出来。也许这项功能并不适用于每闰用户,但就我个人而言、它确保帮我弄清了不少原本神秘的疑难杂症。
  自动伸缩
  利用INSUFFICIENT_DATA以及ALARM进行规模缩减。
  对于规模缩减操作而言,大家需要确保能够在不具备指标数据甚至触发机制本身出现问题时仍能正常实现规模缩减。举例来说,如果大家的某款应用程序平时始终处于低流量状态,但突然迎来了流量峰值,大家肯定希望其能够在峰值结束且流量中止后将规模恢复至原有水平。如果没有流量作为参考,大家可以使用 INSUFFICIENT_DATA来替代ALARM作为低流量阈值情况下的规模缩减执行手段。
  使用ELB运行状态检查取代EC2运行状态检查。
  在创建扩展组时系统会提供这样一个配置选项,大家能够指定是否使用标准的EC2检查机制(当该实例接入网络时),或者使用自己的ELB运行状态检查机制。ELB运行状态检查机制能够提供更出色的灵活性。如果大家的运行状态检查机制发生故障,那么该实例将被移出负载均衡池,在这种情况下大家当然希望能够通过自动伸缩中止该实例并创建新的实例加以替代。如果大家没有利用ELB检查设置出扩展组,那么上述功能将无法实现。AWS在说明文档当中就添加运行状态检查机制作出了详尽说明,感兴趣的朋友可以点击此处进行查看。
  只使用ELB预先配置的可用区。
  如果大家将扩展组添加到多个可用区内,请确保自己的ELB配置能够正确使用全部可用区,否则在容量发生向上扩展时,负载均衡器将无法正确识别出这些可用区。
  不要在同一个组内使用多个扩展触发器。
  如果大家在同一个自动伸缩组内选择了多种用于触发规模调整的CloudWatch警报机制,那么它们可能无法如各位的预期那样正常起效。举例来说,假设大家添加的触发器会在CPU使用率过高或者入站网络流量强度过大时进行向上扩展,并在情况相反时对规模进行缩减。但在使用过程中,我们往往会发现 CPU使用率持续增加,但入站网络流量却保持不变。这时高CPU负载触发器会进行容量扩展操作,但低入站流量警报却会立即触发规模缩减操作。根据各自执行周期的不同,二者之间的作用很可能会被抵消,导致问题无法得到切实解决。因此,如果大家希望使用多种触发器方案,请务必选择多自动伸缩组的方式。
  使用IAM角色。
  不要面向应用程序创建用户,而尽可能使用IAM角色。它们能够简化所有相关工作,并保证业务环境的安全水平。创建应用程序用户只会带来故障点(如果有人不小心删除了API密钥),而且令管理工作更加难以完成。
  用户可以拥有多个API密钥。
  如果某些员工在同时处理多个项目,又或者大家希望能够利用一次性密钥对某些内容进行测试,那么这种方式将非常实用。我们完全不必担心真正的密钥被泄露出去。
  IAM用户可以使用多因素身份验证,请善加利用!
  启用多因素验证机制能够为我们的IAM用户提供额外的安全层。我们的主账户肯定应该引入这项机制,面只要有可能、普通IAM用户亦应当享受到由此带来的保障。
  Route53
  使用ALIAS(即别名)记录。
  ALIAS记录会将我们的记录组直接链接到特定AWS资源处(即可以将某个域映射至某个S3存储桶),但其关键在于我们用不着为了ALIAS查找而支付费用。因此与CNAME这类付费机制不同,ALIAS记录不会增加任何额外成本。另外,与CNAME不同,大家可以在自己的区索引当中使用ALIAS。感兴趣的朋友可以点击此处查看AWS官方提供的ALIAS资源记录集创建说明页面。
  弹性MapReduce
  在S3中为Hive结果指定一个目录。
  如果大家打算利用Hive将结果输出至S3,则必须在存储桶内为其指定一个目录&&而非存储桶根目录。否则我们很可能遭遇NullPointerException,而且完全找不到引发这一问题的理由。
相关新闻 & & &
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款中国领先的IT技术网站
51CTO旗下网站
经验分享:Amazon AWS 中国区的那些坑
使用AWS 中国区有一段时间了, 期间踩过了一些坑. 简单写一下, 希望对别人有帮助。文中很可能有错误或者AWS 已经升级了, 还是用他们的 support 服务最靠谱。
作者:佚名来源:简书| 14:11
使用AWS 中国区有一段时间了, 期间踩过了一些坑. 简单写一下, 希望对别人有帮助。文中很可能有错误或者AWS 已经升级了, 还是用他们的 support 服务最靠谱。
所有坑中, 最数 S3 坑多. 原因很简单: EC2的服务大不了大家在web console 里面点击鼠标, S3 更多时候肯定是用SDK访问. 因此SDK的各种问题都会提前暴露.
Hadoop Over S3
问题: 去年12月份左右(具体jets3t 什么时候fix的这个问题不记得了), hadoop 中使用的library jets3t 不支持中国区(cn-north-1) , 原因很简单: S3 的signature 已经升级到V4. 但是因为兼容问题, AWS的其他region都兼容V2版本, 中国区是新的region, 没有兼容问题, 因此仅仅支持V4. 详情参见 jets3t 的这个issue
折腾了各种解决办法, 流水账的形式写一下吧.
第一个法子: copy EMR 集群中的emrfs
emrfs 就是 EMR 集群中hadoop使用的访问S3 的方式. 是 Amazon
官方提供的, 不开源. 使用的法子也很简单: 启动一个emr 集群, 随便登陆一台服务器, 在 hadoop-env.sh 中可以看到添加了emrfs 的classpath:
#!/bin/bash
export HADOOP_CLIENT_OPTS=&$HADOOP_CLIENT_OPTS -XX:MaxPermSize=128m&
export HADOOP_CLASSPATH=&$HADOOP_CLASSPATH:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/lib/*&
export HADOOP_DATANODE_HEAPSIZE=&384&
export HADOOP_NAMENODE_HEAPSIZE=&768&
export HADOOP_OPTS=&$HADOOP_OPTS -server&
if [ -e /home/hadoop/conf/hadoop-user-env.sh ] ; then
. /home/hadoop/conf/hadoop-user-env.sh
注意: EMR 可能会发布新的版本, 这里仅仅是提供一个思路, 列出的文件也是当时版本的emr的实现
将 /usr/share/aws/emr/emrfs 下面的所有文件copy出来, 部署到自己的集群并在 core-sites.xml 中添加如下内容:
fs.s3n.implcom.amazon.ws.emr.hadoop.fs.EmrFileSystem
fs.s3.implcom.amazon.ws.emr.hadoop.fs.EmrFileSystem
fs.s3.buffer.dir/mnt/var/lib/hadoop/s3,/mnt1/var/lib/hadoop/s3
fs.s3.buckets.create.regioncn-north-1
fs.s3bfs.implorg.apache.hadoop.fs.s3.S3FileSystem
fs.s3n.endpoint<-north-.cn
设置 EMRFS_HOME 并且把 $EMRFS_HOME/bin 添加到PATH中(后面会用到)
这样可以保证hadoop 尽快运行起来. 但使用 emrfs 也有一些问题:
没有源代码. 官方没有计划将这个东西开源. 因此除了问题只有反编译jar包. 还好官方编译的jar包没有混淆并且带着 lineNumber 等信息. 曾经遇到他代码里面吃掉异常的情况, 不知道现在是否更新
S3 rename 操作非常耗时. 众所周知Hadoop Mapreduce 为了保证一致性, 结果文件都是先写临时文件, 最后 rename 成最终输出文件. 在 HDFS 上这种模式没有问题, 但是 S3 就会导致最后 commit job 时非常慢, 因此默认的committer 是单线程rename文件. 结果文件大并且多文件的情况下S3 非常慢. 因此 emrfs 做了一个hack: 结果仅仅写本地文件, 到 commit 的时候再一次性上传结果文件. 但如果你输出的一个结果文件太大会导致本地磁盘写满! 不知道哪里是否有参数配置一下这个最大值.
S3 由于不是FileSystem, 仅仅是一个KV存储. 因此在list dir 时会很慢, emrfs 为了优化, 用dynamodb做了一层索引.但在某些情况下(我们遇到过)mr job fail 会导致索引和 S3 数据不一致. 极端情况下需要使用 emrfs sync path 来同步索引
暂时记得的关于 emrfs 就有这么多.
第二个法子: hadoop-s3a
An AWS SDK-backed FileSystem driver for Hadoop
这是github上有人用 AWS-java-SDK 开发的一个 FileSystem 实现, 虽说是试验情况下, 修改一下还是可以用的. &;&
但是, 这个直接用也是不行的!~~~
中国区 Amazon S3 Java SDK 有一个神坑: 如果不显示设置region的 endpoint , 会一直返回 Invalid Request(原因后面解释), 需要在代码中添加如下几行:
// 这里获取配置文件中的region name的设置
如果获取不到, 强烈建议获取当前系统所在region
AmazonS3Client s3 = new AmazonS3Client(credentials, awsConf);
String regionName = XXXX;
Region region = Region.getRegion(Regions.fromName(regionName));
s3.setRegion(region);
final String serviceEndpoint = region.getServiceEndpoint(ServiceAbbreviations.S3);
// 关键是下面这一行, 在除了中国外的其他region, 这行代码不用写
s3.setEndpoint(serviceEndpoint);
(&setting s3 region: & + region + &, : & + serviceEndpoi
S3 rename 操作慢!
需要在 hadoop-s3a 中需要修改rename 方法的代码, 使用线程池并行rename 一个dir.
需要写一个 committer, 在MR job 完成的时候调用并行rename操作.
hadoop-s3a 没有设置 connect timeout. 仅仅设置了socket timetout
block size计算错误.
需要在社区版本上添加一个 block size 的配置项(跟 hdfs 类似), 并且在所有创建 S3AFileStatus 的地方添加 blockSize 参数. 现在情况下会导致计算 InputSplit 错误(blocksize默认是0).
通常情况下, hadoop 集群使用IAM role 方式获取accessKey 访问S3, 这样会导致之前在 hdfs 中基于用户的权限管理失效. 比如, 用户A 是对一些Table 有读写权限, 但是用户B 只有只读权限. 但EC2 不支持一个instance 挂载两个不同的 IAM role. 我们的解决方案是在S3FileSystem中判断当前的用户, 根据不同的用户使用不同的AccessKey, 实现HDFS的权限管理.
S3 api/client
使用S3 api 或者aws client, 还有一个容易误导的坑:
你有可能在 cn-north-1 的region 访问到AWS 美国的S3 !
现象: 比如你按照doc 配置好了aws client(access key 和secret都配置好), 简单执行 aws --debug s3 ls s3://your-bucket/ 确返回如下错误:
20:54:25,622 - botocore.endpoint - DEBUG - Sending http request:
20:54:27,770 - botocore.response - DEBUG - Response Body: b'\nInvalidAccessKeyIdThe AWS Access Key Id you provided does not exist in our records.AAABBBBAAAAAA111B1ABCFEA8D30AfPehbRNkUmZyI6/O3kL7s+J0zCLYo/8U6UE+Hv7PSBFiA6cB6CuLXoCT4pvyiO7l'
20:54:27,783 - botocore.hooks - DEBUG - Event needs-retry.s3.ListObjects: calling handler
20:54:27,783 - botocore.retryhandler - DEBUG - No retry needed.
20:54:27,784 - botocore.hooks - DEBUG - Event after-call.s3.ListObjects: calling handler
20:54:27,784 - awscli.errorhandler - DEBUG - HTTP Response Code: 403
20:54:27,784 - awscli.clidriver - DEBUG - Exception caught in main() Traceback (most recent call last):
File &/usr/share/awscli/awscli/clidriver.py&, line 187, in main
return command_table[mand](remaining, parsed_args)
File &/usr/share/awscli/awscli/customizations/s3/s3.py&, line 165, in __call__
remaining, parsed_globals)
File &/usr/share/awscli/awscli/customizations/s3/s3.py&, line 276, in __call__
return self._do_command(parsed_args, parsed_globals)
File &/usr/share/awscli/awscli/customizations/s3/s3.py&, line 358, in _do_command
self._list_all_objects(bucket, key)
File &/usr/share/awscli/awscli/customizations/s3/s3.py&, line 365, in _list_all_objects
for _, response_data in iterator:
File &/usr/lib/python3/dist-packages/botocore/paginate.py&, line 147, in __iter__
**current_kwargs)
File &/usr/lib/python3/dist-packages/botocore/operation.py&, line 82, in call
parsed=response[1])
File &/usr/lib/python3/dist-packages/botocore/session.py&, line 551, in emit
return self._events.emit(event_name, **kwargs)
File &/usr/lib/python3/dist-packages/botocore/hooks.py&, line 158, in emit
response = handler(**kwargs)
File &/usr/share/awscli/awscli/errorhandler.py&, line 75, in __call__
http_status_code=http_response.status_code) awscli.errorhandler.ClientError: A client error (InvalidAccessKeyId) occurred when calling the ListObjects operation: The AWS Access Key Id you provided does not exist in our records.
20:54:27,877 - awscli.clidriver - DEBUG - Exiting with rc 255 A client error (InvalidAccessKeyId) occurred when calling the ListObjects operation: The AWS Access Key Id you provided does not exist in our records.
上面的错误信息非常有误导性的一句话是:
A client error (InvalidAccessKeyId) occurred when calling the ListObjects operation: The AWS Access Key Id you provided does not exist in our records.
然后你打电话给 support(记住一定要提供request id), 那边给的答复是你本机的时间不对
WTF! 服务器肯定开启了NTP, 怎么会时间不对!
其实你使用 aws s3 --region cn-north-1 ls s3://your-bucket 就不会出错. 或者在 ~/.aws/config 中 配置:
region = cn-north-1
support为什么会说我的时间不对?
为什么 aws client 报错是 The AWS Access Key Id you provided does not exist in our records
因为你的请求到了AWS 的美国区(或者准确说是非cn-north-1区)!
简单猜测一下原因(纯猜测, 猜对了才奇怪!):
AWS S3 要高可用, 必须要存储多份数据, 而中国区只有一个availability zone(现在已经有多个了), 因此数据必须存储到其他region, 也就是说在内部, AWS cn-north-1 去跟其他region网络是通的!
默认情况下aws s3 的endpoint url 是其他region. 因此那个ls 操作直接请求了非cn-north-1 region.
但是aws cn-north-1 的账户系统跟其他region不通, 因此美国区返回错误: The AWS Access Key Id you provided does not exist in our records
support 之所以根据request id 告诉你错误是因为请求时间不对, 也很简单: server端验证了请求的发起时间, 由于时差, 导致时间肯定是非法的. 因此support 告诉你说你的时间有问题
感觉客户端跟support告诉你的错误不一致是吧? 我当时就是因为他们的误导, 折腾了2天啊!!! 最后加一行代码解决了问题, 想死的&#10084;&#65039;都有
因此结论很简单:
使用awscli 操作 S3 时, 记得带上 --region cn-north-1
写代码访问S3 时, 显示调用 setEndpoint 设置api地址
// 关键是下面这一行, 在除了中国外的其他region, 这行代码不用写
s3.setEndpoint(serviceEndpoint);
S3 一个理解错误的坑
S3 是一个KV 存储, 不存储在文件夹的概念. 比如你存储数据到 s3://yourbucket/a/b/c/d.txt, S3 仅仅是将s3://yourbucket/a/b/c/d.txt 作为key, value就是文件的内容. 如果你想ls s3://yourbucket/a/b 是不存在的key!
S3 定位错误的tips
调试模式下, 可以考虑关闭ssl, 并使用 tcpdump 抓包查看数据是否正确, 非常实用
aws 客户端可以添加 --debug 开启调试日志, 出错后开case时最好带着 Request ID 和 Extended Request ID . AWS 几乎所有服务的每次请求都是带有 Request ID 的, 非常便于定位问题. 至于为什么, 建议看Google早年的论文: Dapper, a Large-Scale Distributed Systems Tracing Infrastructure
聊完了 S3, 其他的基本上坑不多, 走过路过也记不得了. 但最深刻的一个关于 IAM 的要注意.
Amazon IAM 坑
AWS Identity and Access Management (IAM) 使您能够安全地控制用户对 Amazon AWS 服务和资源的访问权限。您可以使用 IAM 创建和管理 AWS 用户和群组,并使用各种权限来允许或拒绝他们对 AWS 资源的访问。
唯一大坑: IAM policy file 中 arn 的写法
Amazon Resource Names (ARNs) uniquely identify AWS resources. We require an ARN when you need to specify a resource unambiguously across all of AWS, such as in IAM policies, Amazon Relational Database Service (Amazon RDS) tags, and API calls.
具体参加这里
简单来说, arn 就是AWS中资源的uri. 任何AWS资源都可以用 arn 标识, 因此对于资源的访问控制配置文件也要使用 arn 来写.
arn 的格式如下:
arn:partition:service:region:account:resource
arn:partition:service:region:account:resourcetype/resource
arn:partition:service:region:account:resourcetype:resource
上面这行代码据说 在AWS 其他region 都可以使用
唯独中国区不能用! 因为AWS 中国区非常特殊, 上述文件中的 aws 要修改成 aws-cn !!!!
这样写在中国区就可以用:
&Version&: &&,
&Statement&: [
&Effect&: &Allow&,
&Action&: &s3:*&,
&Resource&: [&arn:aws:s3:::your-bucket&, &arn:aws:s3:::your-bucket/*&]
不要小看这一点小区别, 由于AWS 其他region 都是用 aws 就可以, 因此很多开源项目中, 将 arn:aws: XXXX hard code 在代码里, 导致这些项目用到中国区会失败!
BTW, 一个小坑: 上面的配置文件中的 &Version&: &&, 这个日期是必须写成这个的, 估计是AWS 的码农 hard code 的版本, 不能修改其他任何值 , 千万别用这个值来作为自己的版本控制(偷笑)
建议程序访问AWS 资源时, 使用IAM role的方式, 不要使用配置文件中写入AccessKey/Secret 的方式, 非常不安全.
EC2 就是虚拟主机. AWS 有两个概念: Reserved Instance 和 Spot Instance
Reserved Instance
简单来说就是包年购买节点. 优点肯定是便宜. 缺点就是买了就不能退货. 但这里最坑(不容易理解)的是:
购买N个T类型的RI后, 其实仅仅是在RI有效期限内计费的时候, 该类型的节点中的N 个 T 类型节点按照打折价格计费.
即使你在RI 期限内没有使用任何该类型的 EC2 节点, 费用照常收取, RI 过期后价格恢复原价
其他节点已久按照正常价格按小时收费
RI 仅仅是计费单元, 节点销毁后重新启动, 只要不超过 RI 数量, 都按照打折计费
例如: 购买了3个 t2.micro 类型的RI, 但是你再次期间最多同时开启了5个 t2.micro 节点, 那么这其中的3个是按照打折价格计费, 2个节点按照正常价格. 如果发现三台 t2.micro 配置错误, 直接 terminate 后启动新的instance , 依旧是按照 RI 的价格计费
Spot Instance
这个就是可以以非常便宜的价格买到 EC2 节点. 不过迄今未知() 中国区没有该项业务.
今天太晚了, 回家睡觉去了. 有时间继续写.
再次重申一下, AWS 是在升级的, 这些问题我肯定是遇到过, 但对于原因很多都是猜测, 毕竟AWS 是个非常复杂的系统, 也不开源, 内部如何实现我也无从得知。
原文链接:
【编辑推荐】
【责任编辑: TEL:(010)】
大家都在看猜你喜欢
热点聚焦关注聚焦热点
24H热文一周话题本月最赞
讲师:5581人学习过
讲师:14522人学习过
讲师:3914人学习过
精选博文论坛热帖下载排行
本书深刻揭示了Spring的技术内幕,对IoC、AOP、事务管理等根基性的技术进行了深度的挖掘。读者阅读本书后,不但可以熟练使用Spring的各项功...
订阅51CTO邮刊}

我要回帖

更多关于 aws java sdk s3 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信