基于Nginx搭建一个安全的、快速的微服务架构
StewartWill
8年前
<p>本文改编自Chris Stetson发表在nginx.conf 2016上的一个有关如今的微服务以及如何使用Nginx构建一个快速的、安全的网络系统的演讲,大家可以在YourTube上回看此次演讲。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/7b738e239f9cfa454bf6319100cd7950.png"></p> <p>今天我们要谈论微服务以及如何使用Nginx构建一个快速的、安全的网络系统。在我们谈话的最后,我们将与我们在Zokets的合作伙伴向您展示一个使用Fabric模式如何非常快速和轻松地构建一个微服务的demo。</p> <p>在我们探讨Fabric模式之前,我想谈一谈微服务并且从Nginx的角度来看这意味着什么。</p> <p><strong>大转变</strong></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/69112273acfbb80066fb3528483eccc2.png"></p> <p>微服务已经引起了应用程序架构的重大转变。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/4fa4206a9f225dabdc3da1641471cbea.png"></p> <p>当我第一次开始构建应用程序时,他们都是差不多的。幻灯片中所展示的单体架构也象征了应用程序的构造方式。</p> <p>目前存在着某种类型的虚拟机(VM),对我来说,就是通常的Java。在虚拟机中应用的功能组件以对象的形式存在,这些对象是在内存中相互通讯的,它们将来来回回处理并进行方法调用。偶尔,你会采用诸如通知等机制来接触到其他系统以便获取数据或传递信息。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/de0f00615bc0a6ccbe3f3b76caedcba9.png"></p> <p>有了微服务之后,应用程序如何构建的范式是完全不同的了。你的功能组件会从在同一个主机的内存中通过虚拟机相互通讯转变到部署在容器中,并且使用Restful API调用通过HTTP来相互连接。</p> <p>这是非常强大的,因为它赋予了你功能隔离。它为您提供了更细粒度的可伸缩性,并且你可以获得更好地处理故障的弹性。很多情况下这是简单的事实,你只需要使用HTTP进行跨网络调用。</p> <p>现在,这种方法也有一些缺点。</p> <p><strong>一件轶事</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/2e601d50206192458bb1e2dc2fdf3a6b.png"></p> <p>我有一个暗黑的秘密,我是一个微软的员工并且从事.Net开发已经很多年了。当我在那儿的时候,我搭建了一个他们的名为Showcase的视频发布平台。</p> <p>Showcase是一个用来将微软内部发布的所有视频发布到网上的工具。人们可以观看这些视频并进行学习,比如Microsoft Word的使用提示和技巧。这是一个非常受欢迎的平台,我们有很多人使用它,并且其中很多人都会在我们发布的视频上发表评论。</p> <p>Showcase从一开始就是一个.Net单体应用,随着它日益受欢迎,我们决定应该将它更换为SOA架构。转换是相对容易的。Visual Studio提供了本质上的翻转开关的能力,也就是将你的DLL调用转变为Restful API调用。随着一些小的重构,我们能够让我们的代码运行得相当好。我们也为这些评论和应用内的社区功能使用智能社区服务。</p> <p><strong>紧密的回路问题</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/ca1faf22604afa066df8f45a148cf49c.png"></p> <p>看起来我们是SOA可行的,在我们的首次测试中,一切都工作正常,直到我们将系统切换到我们的Staging环境并开始使用生产环境数据时,我们就会看到一些严重的问题。这些问题在在页面上有很多评论.。</p> <p>这是一个非常受欢迎的平台,其中的一些页面已经有多达2000条评论了。当我们深入这些问题时,我们意识到这些页面需要花费一分钟进行渲染的原因是因为智能社区服务首先需要填充用户名,然后对每一个用户名都需要发起一个对于用户数据库的网络调用来获得用户详细信息并且填充在渲染页面上。这是非常低效的,需要一到两分钟来渲染页面,而在内存中进行通常只需要5到6秒钟。</p> <p><strong> 缓解</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/72fc6a823b2e98371233c0e3b5b44426.png"></p> <p>当我们经历了发现和解决问题的过程后,我们最终通过一些措施来调整优化系统,比如对所有的请求进行分组。我们缓存了一些数据,最终我们优化了网络来真正的提高性能。</p> <p>所以,这与微服务有什么关系呢?对的,借助于微服务,你基本上是采用SOA架构的,并且会将其放入超光速引擎中。在SOA架构中所有的对象都是包含在单个虚拟机中并且在其内部管理,在内存中相互通讯,而现在微服务中是使用HTTP进行数据交换的。</p> <p>当这样做没有问题时,你会获得很好的性能和线性可伸缩性。</p> <p><strong>Nginx能够很好地与微服务工作</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/2e1358f1f867bb07783574c3d357d0dc.png"></p> <p>Nginx是一个你可以用来过渡到微服务的最佳工具之一。</p> <p>关于Nginx和微服务的一些历史。我们从一开始就参与了微服务运动,还是第一个从Docker Hub下载应用的,我们的客户以及那些拥有一些世界上最大的微服务安装量的最终用户广泛地在他们的基础设施使用Nginx。</p> <p>原因是Nginx很小、很快并且很可靠。</p> <p><strong>Nginx微服务参考架构</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/0625c24c1fde541a4dccb8865c4d04cb.png"></p> <p>我们还致力于在Nginx内部使用微服务工作已经有一段时间了。这是一个我们已经搭建的程式化的Nginx微服务参考架构,目前正在AWS上运行。</p> <p>我们拥有6个核心的微服务,它们都运行在Docker容器里。我们决定建立一个多语种的应用,所以每个容器都可以运行不同的语言,我们目前使用了Ruby、Python、PHP、Java和Node.js。</p> <p>我们搭建了这个使用十二要素应用的系统,稍加修改,就会使其更好地为微服务工作从而可以替代Roku平台。稍后,我们将向您展示一个实际上运行在demo里的应用。</p> <p><strong>MRA的价值</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/161c5df29ed13f126a7295fdda4e6acf.png"></p> <p>为什么我们要建立这样一个参考的微服务架构呢?</p> <p>我们建立这个参考架构是因为我们需要给我们的客户提供构建微服务的蓝图,我们也想在微服务上下文中测试Nginx和Nginx Plus的功能,弄清楚如何才能更好地利用它的优势。最后,我们要确保我们对于微服务生态系统以及其可以给我们提供什么有一个深入的理解。</p> <p><strong>网络问题</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/77be43a026158ad8e815ebac2104f94c.png"></p> <p>让我们回到我们讨论的大转变。</p> <p>从将运行在内存里并且被虚拟机管理的你的应用的所有功能组件迁移到通过网络进行工作并且相互通讯的方式,你会本质上引入一系列为了应用有效工作需要你解决的问题。</p> <p>第一你需要服务发现,第二,你需要在架构中为所有不同的实例进行负载均衡,然后还有第三个,你需要操心性能和安全。</p> <p>无论是好是坏,这些问题密不可分,你必须做权衡,有希望的是我们有一个可以解决所有这些问题的解决方案。</p> <p>让我们更深入地看待每一个问题。</p> <p><strong>服务发现</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/6beb5c38cd835c9d89807c9957e2cdbf.png"></p> <p>让我们来谈谈服务发现。在单体应用中,APP引擎会管理所有的对象关系,你永远不必担心一个对象与另一个对象的相对位置,你只需要简单的调用一个方法,虚拟机会连接到对象实例,然后在调用完毕后销毁。</p> <p>然后有了微服务,你需要考虑那些服务的位置。不幸的是,这不是一个普遍的标准流程。您正在使用的各种服务注册中心,无论是Zookeeper、Consul、etcd或者其它的,都会以不同的方式进行工作。在这个过程中,你需要注册你的服务,还需要能够读取这些服务在哪里并且可以被连接。</p> <p><strong>负载均衡</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/f07ec571ccdec942c831fc835acd17cb.png"></p> <p>第二个问题是关于负载均衡的。当您拥有多个服务实例时,您希望能够轻松地连接到它们,将您的请求在它们中高效地分发,并以最快的方式执行,所以不同实例之间的负载均衡是非常重要的问题。</p> <p>不幸的是,最简单形式的负载均衡是非常低效的。当你开始使用不同的更加复杂的方案做负载均衡时,它也变得更加复杂并且不易于管理。理想情况下,您希望您的开发人员能够基于他们的应用程序的需求决定何种负载均衡方案。例如,如果你连接到一个有状态的应用程序,你需要拥有持久化,这样可以确保你的Session信息会被保留。</p> <p><strong>安全和快速通讯</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/dce1305bf1d66670ce4133075d30a6f8.png"></p> <p>也许微服务最令人生畏的领域是性能和安全。</p> <p>当在内存中运行时,一切都很快。现在,运行在网络上就会慢了一个数量级。</p> <p>被安全地包含在一个系统中的信息,通常是二进制格式的,现在会被用文本格式在网络上传输。现在是比较容易在网络上布置嗅探器并能够监听你的应用正在被移动的所有数据。</p> <p>如果要在传输层加密数据,那么会在连接速率和CPU使用率方面引入显著的开销。SSL/TLS在其全面实施阶段需要九个步骤来初始化一个请求。当你的系统每天需要处理成千上万、几万、数十万或数百万的请求时,这就成为性能的一个重要障碍了。</p> <p><strong>一个解决方案</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/78b90ca32b5825143367ed7aafb835d5.png"></p> <p>我们已经在Nginx开发的一些解决方案,我们认为,会解决所有的这些问题,它赋予你健壮的服务发现、非常棒的用户可配置负载均衡以及安全和快速加密。</p> <p><strong>网络架构</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/b0f492cc3a057b5799b98bd8253da6c6.png"></p> <p>让我们来谈谈你可以安装和配置你的网络架构的各种方法。</p> <p>我们提出了三种网络模型,它们本身并不相互排斥,但我们认为它们属于多种格式的。这三种模式是Proxy模式、Router Mesh模式和Fabric模式——这是最复杂的,并在许多方面在其头部进行负载均衡。</p> <p><strong>Proxy模式</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/4dfd015877a9597591d037bda8c9ebcf.png"></p> <p>Proxy模式完全聚焦于你的微服务应用的入站流量,并且事实上忽略内部通讯。</p> <p>你会获得Nginx提供的所有的HTTP流量管理方面的福利。你可以有SSL/TLS终止、流量整形和安全,并且借助于最新版本的Nginx Plus和ModSecurity,你可以获得WAF能力。</p> <p>你也可以缓存,你可以将Nginx提供给你的单体应用的所有东西添加到你的微服务系统里,并且借助于Nginx Plus,你可以实现服务发现。当你的API实例上下浮动时,Nginx Plus可以在负载均衡工具里动态地添加和减去它们。</p> <p><strong>Router Mesh模式</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/c32dcb6747382b1f13c96390764eb363.png"></p> <p>Router Mesh模式类似于Proxy模式,在其中我们有一个前端代理服务来管理接入流量,但它也在服务之间添加了集中式的负载均衡。</p> <p>每个服务连接到集中式的Router Mesh,它管理不同服务之间的连接分发。Router Mesh模式还允许你在熔断器模式中搭建,以便可以对你的应用添加弹性并允许你采取措施来监控和拉回你的失效的服务实例。</p> <p>不幸的是,因为该模式增加了一个额外的环节,如果你不得不进行SSL/TLS加密,它事实上加剧了性能问题。这就是引入Fabric模式的原因。</p> <p><strong>Fabric模式</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/39bb1e76fd65406a36c47174596852cf.png"></p> <p>Fabric模式是将其头部的所有东西翻转的模式。</p> <p>就像之前的另外两个模式一样,在前面会有一个代理服务器来管理流入流量,但与Router Mesh模式不同的地方就是你用运行在每个容器里的Nginx Plus来替代了集中式的Router。</p> <p>这个Nginx Plus实例对于所有的HTTP流量作为反向和正向代理,使用这个系统,你可以获得服务发现、健壮的负载均衡和最重要的高性能加密网络。</p> <p>我们将探讨这是如何发生的,以及我们如何处理这项工作。让我们先来看看一个服务如何连接和分发他们的请求结构的正常流程。</p> <p><strong>正常的流程</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/1a052b07c45442e2cad9f1e299900d6f.png"></p> <p>在这个图中,你可以看到投资管理器需要跟用户管理器通讯来获取信息。投资管理器创建了一个HTTP客户端,该客户端针对服务注册中心发起了一个DNS请求并获得返回的一个IP地址,接着初始化了一个到用户管理器的SSL/TLS连接,该连接需要通过九阶段的协商或者是”握手”过程。一旦数据传输完毕,虚拟机会关闭连接并进行HTTP客户端的垃圾回收。</p> <p>整个过程就是这样。这是相当简单和易于理解的。当你把它分解成这些步骤时,您可以看到该模式是如何真正完成请求和响应过程的。</p> <p>在Fabric模式中,我们已经改变了这一点。</p> <p><strong>Fabric模式的细节</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/68298d55e202d80092c11b3ede6a9b98.png"></p> <p>你会注意到的第一件事是Nginx Plus是运行在每一个服务里的,并且应用程序代码是在本地与Nginx Plus通信的。因为这些是本地连接,你不需要担心加密问题。它们可以是从Java或者PHP代码到Nginx Plus实例的HTTP请求,并且都是在容器内的本地HTTP请求。</p> <p>你也注意到Nginx Plus会管理到服务注册中心的连接,我们有一个解析器,通过异步查询注册中心的DNS实例来获取所有的用户管理器实例,并且预先建立连接,这样当Java服务需要从用户管理器请求一些数据的时候,可以使用预先建立的连接。</p> <p><strong>持久的SSL/TLS连接</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/225adc3e73c48a616980255d58dd4ceb.png"></p> <p>微服务之间的有状态的、持久化的并且可以加密的连接是真正的益处。</p> <p>记得在第一个图中服务实例是如何通过一些流程的吧,比如创建HTTP客户端、协商SSL/TLS连接、发起请求并关闭的吗?在这里,Nginx预先建立了微服务之间的连接,并使用Keepalive特性,保持调用之间的持续连接,这样你就不必为每一个请求处理SSL/TLS协商了。</p> <p>本质上,我们创建了一个迷你的从服务到服务的V*N连接。在我们最初的测试中,我们发现连接速度增加了77%。</p> <p><strong>熔断器Plus</strong></p> <p></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/27a923c96114faf7db5a0fb173aa865c.png"></p> <p>在Fabric模式以及Router Mesh模式中,你也可以从创建和使用熔断器模式中获得好处。</p> <p>本质上,您定义了一个在服务内部的活跃的健康检查,并设置缓存,以便在服务不可用的情况下保留数据,从而获得完整的熔断器功能。</p> <p>所以,现在我可以确定你认为Fabirc模式听起来很酷,并且想在实际环境中跃跃欲试。</p> <p><strong>结论</strong></p> <p>对于那些有兴趣学习更多关于如何构建这些类型的网络架构的小伙伴,我强烈推荐我们的博客系列文章,上面讨论了微服务参考架构,涵盖了每一个模式:Proxu模式、Router Mesh模式和Fabric模式。</p> <p> </p> <p>来自:http://dockone.io/article/1938</p> <p> </p>