前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微服务实现 - Netflix技术栈

微服务实现 - Netflix技术栈

作者头像
杜逸先
发布2018-06-25 16:09:04
9100
发布2018-06-25 16:09:04
举报

微服务实现 - Netflix技术栈

你好。今天我将讨论并解释如何实现基于微服务的系统。有很多用于实现微服务的工具和技术。我今天关注的是Netflix技术栈和SpringBoot。目前微服务是业内热门话题之一。每个人都需要了解微服务,每个人都需要在微服务体系结构上完成项目。

在实践微服务之前,我们必须清楚微服务体系结构的概念,为什么我们的项目需要微服务,在微服务体系结构中有什么优点和缺点。在这里, Krish正在做关于微服务的很好的系列教程。如果您想深入了解微服务架构,请在开始实施前仔细阅读这些教程。

主要议题

  1. 示例项目简介
  2. 核心服务
  3. 发现服务器
  4. 发现客户端
  5. 客户端负载平衡器
  6. API网关
  7. 安全流程
  8. 服务弹性和容错
  9. 无状态服务器
  10. 公共类库

示例项目简介

首先我将解释系统的高层体系结构,以了解我们要做什么。这只是一个便于解释的示例应用程序。只是一个假想的基于电子商务的Web应用程序。所有这些系统设计和实施说明都是基于我以前的项目经验。有时候您的系统设计可能会根据您的要求而有所不同。

核心服务

根据微服务架构,您可以在这里看到我们将整个应用程序划分为不同的服务。每种服务都是可销售的,可以独立部署,并且具有精确定义的范围。这些服务被构建为SpringBoot项目。我将在本文末尾提供源代码项目。所以,尝试理解这个概念,而不要担心代码。在这个例子中,我们有五个核心服务。

身份验证服务负责处理系统的认证过程,授权用户检索,和授权用户存储。它与用户,角色,权限数据库表连接。我在这里使用了MongoDB。

商品服务服务负责商品存储,商品列表等库存处理的流程。

订单服务负责处理买家为商品安排的订单。然后卖方处理为其商品获得的订单。

消息服务负责在系统内处理个每用户之间的实时消息。

搜索服务负责搜索产品,用户,类别。在这些类型的应用程序中,搜索是最苛刻的操作,因此在此我使用RedisSearchBox来提供高性能服务。但这只是一个示例项目,您可以选择任何适合的技术。

发现服务器

在上一节中,我们讨论了我们系统的核心服务。那些是独立的服务。其中一些部署在单台服务器机器中,或者其他部署可能部署另一台服务器机器。在某些情况下,某些服务需要与其他服务进行通信,稍后我会解释这些情况。但是如果我们不知道它的位置在哪里,我们如何与其他服务进行通信。这就像我们正试图打电话给某人而不知道他的电话号码。

解决方案是发现服务器。发现服务器有助于发现我们需要的服务。当某些服务需要访问其他服务时, 发现服务器提供所请求服务的所有端点详细信息以建立连接。发现服务器充当服务注册表。所有的服务都需要在发现服务器上注册,其他聪明的发现服务器也不知道该服务。发现服务器有多个实现: Netflix Eureka, Consul, Zookeeper。在这里, 我将讨论 Netflix Eureka。

我们可以轻松地将Netflix Eureka设置为我们的发现服务器。我不打算在这里深入每一段代码,我关注重要的配置和实施点。你可以在源项目中找到它。为了使Springboot应用程序成为Eureka Discovery服务器,您必须将@EnableEurekaServer注释放入应用程序的启动(main方法)中来提及它。

你必须进行一些配置。在这种情况下,我配置到内置的application.yml(或者你可以使用application.properties

在这里我注明这个实例不是一个Discovery客户端,在这里服务器的端口是从maven属性获得的。但是你可以放任何你需要的端口号。默认端口是1111。

发现客户端

在服务发现部分,我告诉每个服务都必须在发现服务器上注册。因此,我们必须使用@EnableDiscoveryClient将每项服务标为Discovery客户端这个注解可以与在您的项目中实施的任何发现客户端实施(Eureka,Consul,Zookeeper)一起使用您也可以使用@EnableEurekaClient注解,但它仅适用于Eureka的发现客户端实现

你必须进行一些配置。

在这里你必须配置spring.application.name。因为该名称将是其他人用来访问此服务的Service-Id

我需要指出的其他事情,我们可以通过使用相同的Service-Id根据对服务的需求保持服务的集群。实际上,Eureka服务器通过使用Instance-Id保留了他的发现客户端的踪迹有人可以通过提供服务ID来请求Eureka获得特定服务的所有端点。然后,Eureka能够提供该服务客户端的所有服务端点列表。

Instance - Id =  { Server - Host }  +  ':'  { Service - Id }  +  ':'  +  { Server - Port }

你可以看到有一些简单的配置。你必须通过使用defaultZone属性来标明Eureka服务器的位置借助leaseRenewalIntervalInSeconds,您可以更改注册时间。注册需要30秒,因为这是默认的客户端刷新时间。

客户端负载平衡器

我已经告诉过你,在某些情况下,某些服务需要从其他服务获取服务或数据。在这种情况下,一个服务将成为另一个服务的客户。客户服务(client-server)可以使用Service-Id调用所需的服务。但假设所需的服务组成了集群。然后Eureka为所请求的服务提供所有的端点。现在,客户端服务如何决定哪个端点需要选择来建立连接。这是客户端负载平衡器入场的时间。

根据负载均衡算法,客户端负载均衡器将从列表中选择最佳端点来建立连接。在我们的案例中,我使用Netflix Ribbon作为客户端负载均衡器。

根据您的要求,您可以选择最佳的负载平衡算法。在Ribbon中有几个实现。简单循环负载均衡(Simple Round Robin LB),加权响应时间负载均衡(Weighted Response Time LB),区域感知循环均衡(Zone Aware Round Robin LB)和随机负载均衡(Random LB)。 或者你可以实现你自己的负载均衡实现。默认的是简单循环。

Spring框架为访问REST端点提供了使用RestTemplate类的简单的方法。

在使用RestTemplate之前,您必须在spring上下文中创建实例。@LoadBalanced注解将有助于将Ribbon配置设置到RestTemplate中。这是如何通过使用RestTemplate访问另一项服务。

我希望你现在知道我们如何通过使用Ribbon和Eureka来进行服务间通信。

API网关

现在我们要实现系统的入口。外部用户(Web应用程序,移动应用程序)如何访问我们的服务,或者换句话说,我们如何为外部用户公开微服务。是的,解决方案是API网关。系统的外部用户通过API网关访问我们的核心服务。在这里我们使用Netflix Zuul API网关。我们可以使用Zuul作为代理和请求过滤器。我将通过查看配置来解释更多细节。

您可以在这里看到,我们必须提及Eureka服务器的细节,就像我们在Discovery Client部分中所做的一样。原因是当请求进入Zuul时,它将通过使用Service-Id访问特定的核心服务。就像以前我们做的一样。我们不需要担心客户端负载平衡,Zuul通过使用功能区进行负载平衡。

在Zuul属性的另一边,我们可以注明URL前缀是什么。在路由属性部分,我们必须标明每个核心服务具有相同的名称。在里面我们可以标明访问核心服务的url路径。最后,我们必须标明特定服务的Service-Id。

例如,如果外部用户需要访问核心的商品服务。他请求的端点URL可能与这些结构类似。假设Zuul在8080上运行。

http://localhost:8080/api/product-service/{ core-product-service-end-point }

http://localhost:8080/api/product-service/products

http://localhost:8080/api/product-service/products/10

安全流程

在本节中,我将讨论我们的应用程序中安全处理的方式。为此,我主要使用JWT(JSON Web Token)和Spring Security。

登录

您可以在这里看到登录请求进入auth服务。让我们看看auth令牌(auth-token)是如何生成的。

header = {"alg": "HS256", "typ": "JWT"}
payload = {
              "exp": "2017-08-09 12:00:00",
              "user_name": "user",
              "authorities": [
                   "ROLE_SELLER"
               ],
               ...
              }
secret_key = "quebic_secret"
Token = HMAC( base64(header) + "." + base64(payload) , secret_key)

服务检查用户名和密码是有效的,如果证书正确,auth-service会创建有效负载。有效负载包含用户名,权限和令牌到期时间。密钥存储在每个服务的配置(application.yml)中。

在另一边的jwt配置中,我们可以设置包含auth-token的请求头是什么。为此我们使用Authorization标头。并且您可以根据您的要求更改密码和到期时间。在这种情况下,web-app将生成的auth令牌存储在浏览器存储中。

授权

根据我们的示例项目,商品存储操作仅适用于卖家(USER_SELLER)。您可以在这里看到网络应用程序发送产品服务的新产品详细信息。

product_service不知道任何关于传入用户的信息,所以他要求auth-service获取auth-object。auth-service能够解密auth令牌,如果token是有效的auth-service返回auth-object。auth-object包含userId,用户名和权限。现在根据授权的的商品服务将继续这个过程。

在这里您了解我们安全流程的主要要点。首先,我们的核心服务不去维护关于日志用户的会话。所有的服务都是无状态的。第二件事是商品服务,订单服务,消息服务和搜索服务委托认证服务进行认证过程。获得auth对象后,他们可以处理授权过程,因为每个核心服务都包含使用Spring Security实现的权限规则。

身份验证委派过滤器(Authentication Delegating Filter)

CommonAuthenticationTokenFilter是Authentication Delegating的实现。这包含在我们的common-lib依赖中。您可以在com.quebic.common.security包中找到此过滤器类。通过覆盖OncePerRequestFilter类的doFilterInternal()方法,我实现了Auth委托逻辑。

使用Spring Security进行授权

您可以从WebSecurityConfig类中找到授权规则。每个服务都包含它自己的实现,这个类位于security.config包下。

登出

当以无状态进行时,不可能在授权令牌过期之前使授权令牌失效。所以当退出时,从客户端扔掉令牌。作为一个例子,如果客户端是一个Web应用程序,我们可以从浏览器存储中释放auth令牌。

服务弹性和容错

当我们设计基于微服务的项目时,我们必须考虑服务弹性和容错机制的实现。有几种方法可以实现这一点,断路器模式是处理这个问题的好方法。Netflix Hystrix是电路断路器模式的一个实现。

如果readList()方法在其执行过程中失败,则后退方法将立即触发而不会中断主进程。

无状态服务器

正如我在前面提到的,所有核心服务都必须是可销售的,并且可以独立部署。根据需求,我们可以保留来自同一服务的多个实例。但是如果我们保持基于服务器的会话,那么当我们部署新实例时,我们必须共享这些会话数据,它将杀死微服务架构的自由。所以所有的服务都被设计成无状态服务器。

不要将会话数据或缓存保存在服务器内存中,将它们存储在分布式内存中。有很多很好的解决方案。例如:Hazelcast,Redis,Memcache。

公共类库

如果您对所有服务都有共同点,请不要在每个服务中复制它。把这些放在公共场所。在这个例子中,我保存了一个名为common-lib的独立项目。每个核心服务都必须添加common-lib作为依赖项。

好吧,现在我们来到了讨论的最后。我认为你对微服务架构的实现有相当的了解。我希望这将有助于您未来的项目。这是GitHub源代码项目,请按照我在README中给出的说明运行该项目。您可以将微服务托管在AWS EC2,Pivotal WebServices或heroku中。我将在以后的文章中解释更多关于托管的内容。谢谢阅读。祝你好运。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 微服务实现 - Netflix技术栈
    • 主要议题
    • 示例项目简介
    • 核心服务
    • 发现服务器
    • 发现客户端
    • 客户端负载平衡器
    • API网关
    • 安全流程
    • 服务弹性和容错
    • 无状态服务器
    • 公共类库
    相关产品与服务
    负载均衡
    负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档