ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【微服务】认识微服务及Eureka注册中心

【微服务】认识微服务及Eureka注册中心 一、认识微服务1. 微服务架构演变单体架构将业务的所有功能集中在一个项目中开发打成一个包部署。优点项目架构简单前期开发成本低周期短小型项目的首选开发效率高各模块之间交互采用本地方法调用容易部署运维简单直接打包成一个jar、war包拷贝到web容器的目录下即可。缺点全部功能在一个工程中对于大项目不易开发不易扩展修改一个功能需要将整个项目全部编译、部署。无法按需伸缩如订单管理需要高可用性需要采用集群方式那么其他功能也要通过集群的方式来实现水平扩展无法正对某业务按需伸缩。分布式架构系统由独立部署的节点、组件组成分布在不同的服务器上通过网络通信完成整个业务。主要是部署形态是分布在各个服务器上的解决单机扛不住容易挂的问题。可以理解为一个公司业务变大了租了多个办公地点员工之间通过发邮件、打电话协同办公至于怎么分工分布式本身没说死。拆分方式有2种垂直拆分按功能拆成多个系统比如用户系统、商品系统、订单系统各自独立部署。水平拆分同一个功能部署多个副本或者数据库分库分表比如订单系统部署 5 个实例一起扛流量。关键点分布式不等于一定要按功能拆。一个单体应用部署 3 个副本 负载均衡也是分布式部署。分布式只强调“多节点、网络通信、协作”不规定服务怎么划分、怎么治理。它是 SOA 和微服务的共同基础。优点每个子系统可采用不同的技术和语言进行开发。每个子系统可按需伸缩。通过垂直拆分将每个子系统变成小型系统功能简单前期开发成本低周期短。缺点系统与系统之间存在数据冗余耦合性较大。如订单系统、物流系统都需要使用用户系统SOA架构在多个系统/分布式的基础上将重复的功能抽取为组件以服务的方式向各个系统提供服务。各系统之间通过webservice、RPC 等方式进行通信。是微服务架构的雏形粗粒度集中治理。举个例子集团下面有几个分公司各自办公。集团发现财务、人事、采购每个分公司都重复搞于是成立“财务中心”“人事中心”“采购中心”各分公司都去这些中心办事。但所有请求都要先经过“集团总服务台”ESB总服务台帮你转接、翻译、排队。流程正规但总服务台容易成为瓶颈。优点将重复的功能抽取为服务提高开发效率提高系统的复用性、可维护性。针对不同服务的特点按需伸缩如订单服务可靠性比较高可以做集群其他服务可以不做集群。采用ESB减少系统的接口耦合缺点系统与服务的界限模糊会导致抽取的服务的颗粒度过大系统与服务之间的耦合度高虽然使用ESB, 但服务的接口协议不固定种类繁多不利用系统维护。微服务微服务也是分布式架构方案基于SOA架构思想对服务层进行细粒度的拆分所拆分的每个服务只完成某个特定的业务功能。如订单服务只实现订单相关的业务用户服务只实现用户管理相关的业务服务的颗粒度很小所以叫做微服务。例如美食街上一排小摊位一个只做包子一个只做饮料一个只做烧烤。每个摊位自己进货、自己记账、自己决定几点开门。摊位之间用微信下单没有总服务台。灵活、迭代快但管理起来很麻烦卫生、消防、纠纷都要各自处理。微服务架构特征如下单一职责微服务拆分粒度更小每一个服务都对应唯一的业务能力做单一职责避免重复业务开发。例如电商网站针对不同用户的积分及会员给用户不同的打折力度可以将模块划分为用户服务、积分服务、会员服务后续需要维护只针对这个模块即可。面向服务微服务对外暴露业务接口。例如上面的用户有多少积分由于是独立的模块需要将积分服务接口暴露出来供用户服务调用。自治团队独立、技术独立、数据独立、部署独立。隔离性强服务调用做好隔离、容错、降级、避免出现级联问题。优点服务拆分颗粒度更小有利于资源重复利用提高开发效率更加精准的指定每个服务的优化方案按需伸缩适用于互联网时代产品迭代周期更短缺点开发的复杂性增加因为一个业务流程需要多个微服务通过网络交互完成微服务过多服务治理成本高不利于系统维护。分布式架构不一定是微服务架构但微服务架构一定是分布式架构。SpringCloud 集成了各种微服务功能组件并基于 SpringBoot 实现了这些组件的自动装配可以开箱即用。下面是 SpringCloud 与 SpringBoot 的版本兼容关系。小结单体架构简单方便高度耦合扩展性差适合小型项目。例如学生管理系统分布式架构松耦合扩展性好但架构复杂难度大。适合大型互联网项目例如京东微服务一种良好的分布式架构方案优点拆分粒度更小、服务更独立、耦合度更低缺点架构非常复杂运维、监控、部署难度提高 SpringCloud是微服务架构的一站式解决方案集成了各种优秀微服务功能组件2. 服务拆分及远程调用服务拆分注意事项不同微服务不要重复开发相同的业务微服务数据独立们不要访问其它微服务的数据库微服务可以将自己的业务作为接口供其它微服务调用微服务远程调用假设有个微服务有订单、用户两个模块根据订单 id 查询订单信息并且返回用户信息。可以在订单模块直接去访问用户的数据库吗显然不行不同的微服务之间不要做相同的业务。只要在订单模块调用用户模块的接口由用户模块访问用户数据库然后把查询结果返回到订单模块不就好了吗。那么如何在 java 代码中发起一个 Http 请求呢用Spring 提供的工具 RestTemplate 可以实现。我们知道 Bean 的注入只能放在配置类中而带有 SpringBootApplication 注解的启动类本身也是一个配置类一旦将这个工具类注入进来后我们就可以调用它里面的getForObject() 接口【get 请求】或 postForObject() 接口【post 请求】二、EureKa服务调用关系服务提供者暴露接口供其它微服务调用服务消费者调用其它微服务提供的接口如果服务A调用了服务B而服务B又调用了服务C服务B的角色是什么对于A调用B的业务而言A是服务消费者B是服务提供者;对于B调用C的业务而言B是服务消费者C是服务提供者1. EureKa 原理分析假如上面提到的 user-service 服务提供者部署了多个实例那么 order-service 服务调用者就不能把请求接口写死否则另外存在的提供者就没有了意义。小朋友你是否有很多问号问题一order-service在发起远程调用的时候如何得知user-service实例的ip地址和端口问题二假如有多个user-service实例地址order-service调用时该怎么选择问题三消费者 order-service 如何得知某个 服务提供者 user-service 实例是否已宕机Eureka 架构中分为两类角色分别时 EurekaServer(服务端)和 EurekaClient(客户端) 两类。服务端记录服务信息监测服务提供者是否存活。客户端包含服务提供则和服务消费者因为它们的身份会随着业务需求的变化而变化。原理解析为了解决最开始提出的问题这里就需要用 SpringCloud 的注册中心Eureka-server来解决。不管是服务消费者还是服务提供者在将来都有可能会变化身份eureka 将服务消费者和服务提供者都视为客户端这些服务在启动时会将自己的信息提供给 eureka 注册中心这叫服务注册。由注册中心挑选服务提供者供消费者使用利用负载均衡算法挑选。那怎么确保注册中心挑选的服务提供者没有宕机呢服务提供者会间隔一定时间30s向注册中心证明它还活着如果哪一天服务提供者不证明了那注册中心就从其它提供者里面挑选候补反正哥们最不缺备胎了。2. EureKa 使用想要使用 eureka, 首先需要搭建 EurekaServer 服务 然后将服务提供者(user-serice)和服务消费者(order-service)都注册到 Eureka 中最后在服务消费者(order-service)完成服务拉取通过负载均衡挑选一个服务实现远程调用。2.1 搭建 EureKa 服务1. 创建一个模块 eureka-server2. pom 中引入依赖dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-netflix-eureka-server/artifactId /dependency3. 编写启动类EnableEurekaServer SpringBootApplication public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); } }4. 编写 application.yml 配置文件server: port: 10086 spring: application: name: eureka-server eureka: client: service-url: defaultZone: http://127.0.0.1:10086/eureka5. 启动测试ctrl shift F10, 点击端口可以跳转到 Eureka 的管理网页ctrl shift F10下面这个是比较重要的记录了注册到 eureka 的实例每一个服务就是一个实例2.2 EureKa 服务注册想要注册 user-service, 由两个步骤1. 引入 eureka 客户端依赖dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-netflix-eureka-client/artifactId /dependency2. 在 user-service 模块的 application.yml 文件中注入 eureka 实例地址及服务名称eureka: client: service-url: # eureka 的地址信息 defaultZone: http://127.0.0.1:10086/eureka spring: application: name: userservice注意先启动 Eureka 服务端服务再启动客户端服务 。我们也可以将 order-servie 多次启动模拟多实例部署但为了避免端口冲突需要修改端口设置。设置完之后可以看到多了一个服务启动之后可以发现已经注册到 eureka 中了2.3 EureKa 服务发现因为服务拉取是基于服务列表的然后对服务列表做负载均衡。1. 修改 OrderService 代码修改访问的url 路径用服务命代替ip和端口String url http://userservice/user/ order.getUserId();2. 在 order-service 项目的启动类 OrderApplication 中的 RestTemplate 添加负载均衡注解.LoadBalanced3. 重启后输入地址 localhost:8080/order/101 和 localhost:8080/order/102 均查询出来了结果回到 idea 查看控制台发现 userApplication 的两个实例都分别有条查询记录说明实现了负载均衡。3 小结三、 Ribbon 负载均衡 扩展1. 负载均衡原理我们添加了LoadBalanced注解后就实现了负载均衡这是什么原理呢这功劳归属于 Ribbon, 当我们发送请求后Ribbon 后向 eureka 拉取服务提供者然后 Ribbon 就会在拉去的列表中找一个服务供我们使用。我们发出的请求是 http://userservice/user/1怎么变成了http://localhost:8081的呢接下来我们在 OrderApplication 启动类里跟进源码来看实现过程。连续按下两次 shift , 搜索LoadBalancerInterceptor 这个类发现它实现了 ClientHttpRequestInterceptor 接口这个接口有个 intercept() 方法说明在 LoadBalancerInterceptor 一定是会重写 intercept() 方法的也就是说LoadBalancerInterceptor这个类拦截了用户发送的请求然后在 eureka 根据服务名称获取服务列表再利用负载均衡算法得到真实的服务地址信息替换服务服务名称。request.getURI()获取请求的 URL 地址originalUrl.getHost()获取 URL 路径的服务名user-servicethis.loadBalancer.execute()处理服务名称和用户请求继续跟进 execute 方法继续跟进getServer()发现 负载均衡选取其中一个服务是根据 IRule 这个接口来决定的。这样负载均衡的流程就让我们弄明白了。总结SpringCloudRibbon 底层采用LoadBalancerInterceptor 负载均衡拦截器拦截RestTemplate这个请求利用 getLoadBalance()得到服务名称列表后利用 IRule 内置负载均衡规则得到一个服务提供者RibbonLoadBalancerClient将请求地址 http://userservice/user/1 替换成 http://localhost:8081/user/1 并发送真实的请求。2 负载均衡策略2.1 负载均衡策略通过上面负载均衡的原理我们知道 Ribbon 里面有个 IRule 接口来定义负载均衡的规则下面用一个图示展示 IRule 的子接口每个子接口都是一种规则。不同规则的含义如下内置负载均衡规则类规则描述RoundRobinRule它是Ribbon默认的负载均衡规则。AvailabilityFilteringRule对以下两种服务器进行忽略(1在默认情况下这台服务器如果3次连接失败这台服务器就会被设置为“短路”状态。短路状态将持续30秒如果再次连接失败短路的持续时间就会几何级地增加。(2并发数过高的服务器。如果一个服务器的并发连接数过高配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限可以由客户端的..ActiveConnectionsLimit属性进行配置。WeightedResponseTimeRule为每一个服务器赋予一个权重值。服务器响应时间越长这个服务器的权重就越小。这个规则会随机选择服务器这个权重值会影响服务器的选择。ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。BestAvailableRule忽略那些短路的服务器并选择并发数较低的服务器。RandomRule随机选择一个可用的服务器RetryRule重试机制的选择逻辑2.2 自定义负载均衡策略通过自定义 IRule 可以修改负载均衡规则有2种方式实现。1.代码方式在order-service中的OrderApplication类中定义一个新的IRuleBean public IRule randomRule(){ return new RandomRule(); // 定义为 RandomRule 规则 }2. 配置文件方式在order-service的application.yml文件中添加新的配置也可以修改规则userservice: # 服务名称 ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 RandomRule2.3 饥饿加载Ribbon默认是采用懒加载即第一次访问时才会去创建LoadBalanceClient请求时间会很长。而饥饿加载则会在项目启动时创建降低第一次访问的耗时通过下面配置开启饥饿加载ribbon: eager-load: enabled: true #开启饥饿加载 clients: # 指定饥饿加载的服务名称 - userservice # 如果有多个服务要设置换行接着写就行3 小结1. Ribbon 负载均衡规则格则接口是 IRule默认实现是 ZoneAvoidanceRule, 根据 zone 选择服务列表然后轮询2. 负载均衡自定义方式代码方式配置灵活但修改时需要重新打包发布配置方式直观方便无需重新打包发布但无法做到全局配置
返回列表