Home>Article>Java> Detailed explanation of SpringCloud’s microservice deployment

Detailed explanation of SpringCloud’s microservice deployment

不言
不言 forward
2018-10-27 11:56:24 5879browse

This article brings you a detailed explanation of Spring Cloud's microservice deployment. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

One of the characteristics of microservices is that they have many small granularities (single functions, such as user management, SMS sending management, email sending management, file management, etc.) and can be deployed, expanded, and run independently A small application can be called an API, which is a service provider. APIs can call each other, but most of them are called by apps. For example, the student management system is user-oriented and is a collection of many functions. It needs to call many APIs to complete business functions, so this student management system It can be called an app.

The role of eureka

Traditional single application development is to integrate all the api and app codes together and run them in the same process. Corresponding to java web, in layman's terms, they are all packaged. Deployed in a war and run in a tomcat. Each API and app of a microservice has its own process, that is, it has its own tomcat. If a certain API hangs up, it will not affect the operation of other APIs and apps.

Detailed explanation of SpringCloud’s microservice deployment

The api is exposed in the restfull style, so when the app (api) calls the api, it takes the form of http://ip:port Communicate. So here comes the question, if there are many apps that call a certain API, if the IP or port of the API changes, and if the API IP and port information in the app is written in the configuration file, do we need to notify each app? , saying that the address and port of this API have changed, and the app needs to be modified, recompiled and deployed (this is just an example. In actual situations, some companies may write configuration files or databases to configure constants). This is too troublesome. If the address and port of the api change, it would be great if the app can learn the change in time. Another drawback is that it cannot be visually observed whether the API is down.

So, if you add a service management center between the app and the api, the api is like the service management center registration information. The app gets the api information from the service management center. The api has a unique identifier. When the api changes Notify the service management center, which notifies the relevant app or app to regularly obtain the latest API information from the service management center. At the same time, the service management center has high stability and reliability.

eureka is for such a service management center. The following is a picture I drew based on my own understanding.

Detailed explanation of SpringCloud’s microservice deployment

The following is the official architecture diagram

Detailed explanation of SpringCloud’s microservice deployment

1.Application Service is equivalent to service provider/api

2.Application Client is equivalent to service consumer/app

3.Make Remote Call is actually to realize the use of services/such as httpClient, restTemplate

4.us-east-1 Eureka cluster service

5.us-east-1c, us-east-1d, us-east-1e are specific eureka

Eureka:

  1. is a pure servlet application, which needs to be built into a war package and deployed

  2. used The Jersey framework implements its own RESTful HTTP interface

  3. The synchronization between peers and the registration of services are all implemented through the HTTP protocol

  4. Timing tasks (send Heartbeat, scheduled cleaning of expired services, node synchronization, etc.) are implemented through the Timer that comes with the JDK

  5. The memory cache is implemented using Google's guava package

Eureka cluster construction

Similar functions to eureka include zookeeper, etcd, etc. Spring boot has integrated eureka, so we can set up the environment and deploy and run it like spring boot.

I learned using eclipse under window10.

Preparation.

Modify the hosts file and add (location: C:WindowsSystem32driversetc) at the end

127.0.0.1 01.eureka.server 127.0.0.1 02.eureka.server 127.0.0.1 03.eureka.server

Create an ordinary maven project eureka-server under eclipse.

pom.xml

 4.0.0 com.fei.springcloud springcloud-eureka-server 0.0.1-SNAPSHOT eureka服务端    alimaven http://maven.aliyun.com/nexus/content/repositories/central/  true   true       alimaven http://maven.aliyun.com/nexus/content/repositories/central/  true   true      UTF-8 UTF-8  UTF-8 1.8 1.8 1.8   org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE     org.springframework.cloud spring-cloud-starter-eureka-server      org.springframework.cloud spring-cloud-dependencies Dalston.RELEASE pom import       org.springframework.boot spring-boot-maven-plugin    

Start class Application.java

package com.fei.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

Note the annotation: @EnableEurekaServer, indicating that this is the server service

Configuration file application.properties

logging.config=classpath:logback.xml logging.path=d:/logs ##tomcat set### # eureka的默认端口是8761 server.port=8081 server.session-timeout=60 ########### spring.application.name=eureka-server-01 ####下面2个一定要false,因为这程序是要作为服务端 但是jar中存在eureka-client.jar,所以要false,否则启动会报错的 #是否注册到eureka eureka.client.register-with-eureka=false #是否获取注册信息 eureka.client.fetch-registry=false #为了便于测试,取消eureka的保护模式,如果启动的话, 比如api提供者关闭了,但是eureka仍然保留信息 eureka.server.enable-self-preservation=false #服务名称 eureka.instance.hostname=01.server.eureka #eureka的服务地址,/eureka是固定的 eureka.client.serviceUrl.defaultZone=http://02. server.eureka:8082/eureka/,http://03.server.eureka:8083/eureka/

Note: For the configuration of eureka.client.serviceUrl.defaultZone, if it is 01, fill in the addresses and ports of 02 and 03; if it is 02, fill in the addresses and ports of 01 and 03, that is to say Let the three eureka services 01, 02, and 03 synchronize data with each other. If it is 01->02->03->01, then when the api provider registration information reaches 01, 01 will synchronize the data to 02. But 02 will not be synchronized to 03, and 01 will not be synchronized to 03, which means that 03 is missing data. Look at the source code. The registration information of the service will not be disseminated twice. See PeerAwareInstanceRegistryImpl.java

Detailed explanation of SpringCloud’s microservice deployment

启动01 eureka,然后修改application.properties,变为02 eureka的配置

logging.config=classpath:logback.xml logging.path=d:/logs ##tomcat set### # eureka的默认端口是8761 server.port=8082 server.session-timeout=60 ########### spring.application.name=eureka-server-02 ####下面2个一定要false,因为这程序是要作为服务端, 但是jar中存在eureka-client.jar,所以要false,否则启动会报错的 #是否注册到eureka eureka.client.register-with-eureka=false #是否获取注册信息 eureka.client.fetch-registry=false #为了便于测试,取消eureka的保护模式,如果启动的话, 比如api提供者关闭了,但是eureka仍然保留信息 eureka.server.enable-self-preservation=false #服务名称 eureka.instance.hostname=02.server.eureka #eureka的服务地址,/eureka是固定的 eureka.client.serviceUrl.defaultZone=http://01.server. eureka:8081/eureka/,http://03.server.eureka:8083/eureka/

然后执行启动类,03也是一样的操作。

浏览器访问http://01.server.eureka:8081/(或者http://02.server.eureka:8082/,或者http://03.server.eureka:8083/)看到

Detailed explanation of SpringCloud’s microservice deployment

api提供者

创建个普通的maven项目eureka-api,该api是个用户服务提供者。采取spring boot开发模式

Detailed explanation of SpringCloud’s microservice deployment

pom.xml

 4.0.0 com.fei.springcloud springcloud-eureka-server 0.0.1-SNAPSHOT eureka服务端    alimaven http://maven.aliyun.com/nexus/content/repositories/central/  true   true      alimaven http://maven.aliyun.com/nexus/content/repositories/central/  true   true     UTF-8 UTF-8  UTF-8 1.8 1.8 1.8   org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE     org.springframework.cloud spring-cloud-starter-eureka      org.springframework.cloud spring-cloud-dependencies Dalston.RELEASE pom import       org.springframework.boot spring-boot-maven-plugin    

它和eureka 服务端,有个依赖是不一样的。

application.properties

logging.config=classpath:logback.xml logging.path=d:/logs ##tomcat set### # eureka的默认端口是8761 server.port=9081 server.session-timeout=60 ########### spring.application.name=api-user-server #像eureka服务注册信息时,使用ip地址,默认使用hostname eureka.instance.preferIpAddress=true #服务的instance-id默认默认值是${spring.cloud.client.hostname :${spring.aplication.name} :${spring.application.instance_id:${server.port}} , #也就是机器主机名:应用名称:应用端口 eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port} #eureka的服务地址 eureka.client.serviceUrl.defaultZone=http://01.server.eureka:8081/eureka/

Application.java

package com.fei.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @EnableEurekaClient @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

@EnableEurekaClient,不管是消费者还是提供者,对应eureka server来说都是客户端client

写个普通的controller,UserProvider.java.提供个根据id获取用户信息的接口

package com.fei.springcloud.provider; import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserProvider { @GetMapping(value="/find/{id}") public String find(@PathVariable("id") String id,HttpServletRequest request){ //实际项目中,这里可以使用JSONObject,返回json字符串 //为了便于测试消费者app的负载均衡,返回服务端端口 String s = "张三"+" 服务端端口:"+request.getLocalPort(); return s; } }

执行Application.java,将application.properties的端口修改为9082,再次执行

浏览器访问http://01.server.eureka:8081/

Detailed explanation of SpringCloud’s microservice deployment

Application就是文件中定义的spring.application.name=api-user-server,它会自动转为大写

如果想免费学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java进阶群:478030634,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

app消费者

在Spring Cloud Netflix中,使用Ribbon实现客户端负载均衡,使用Feign实现声明式HTTP客户端调用——即写得像本地函数调用一样.

Detailed explanation of SpringCloud’s microservice deployment

ribbo负载均衡的app消费者

创建个普通的maven项目eureka-app-ribbo.

pom.xml

 4.0.0 com.fei.springcloud springcloud-eureka-app-ribbo 0.0.1-SNAPSHOT eureka消费者ribbo    alimaven http://maven.aliyun.com/nexus/content/repositories/central/  true   true       alimaven http://maven.aliyun.com/nexus/content/repositories/central/  true   true      UTF-8 UTF-8  UTF-8 1.8 1.8 1.8   org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE      org.springframework.cloud spring-cloud-starter-ribbon    org.springframework.cloud spring-cloud-starter-eureka    org.springframework.boot spring-boot-starter-web      org.springframework.cloud spring-cloud-dependencies Dalston.RELEASE pom import       org.springframework.boot spring-boot-maven-plugin    

application.properties

logging.config=classpath:logback.xml logging.path=d:/logs ##tomcat set### # eureka的默认端口是8761 server.port=7081 server.session-timeout=60 ########### spring.application.name=app-user #像eureka服务注册信息时,使用ip地址,默认使用hostname eureka.instance.preferIpAddress=true #服务的instance-id默认默认值是${spring.cloud.client.hostname}${spring.application.name} :${spring.application.instance_id:${server.port}} , #也就是机器主机名:应用名称:应用端口 eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port} #eureka的服务地址 eureka.client.serviceUrl.defaultZone=http://01.server.eureka: 8081/eureka/,http://02.server.eureka:8082/eureka/, http://03.server.eureka:8083/eureka/

UserController.java

logging.config=classpath:logback.xml logging.path=d:/logs ##tomcat set### # eureka的默认端口是8761 server.port=7081 server.session-timeout=60 ########### spring.application.name=app-user #像eureka服务注册信息时,使用ip地址,默认使用hostname eureka.instance.preferIpAddress=true #服务的instance-id默认默认值是${spring.cloud.client.hostname} :${spring.application.name}:${spring.application.instance_id:${server.port}} , #也就是机器主机名:应用名称:应用端口 eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port} #eureka的服务地址 eureka.client.serviceUrl.defaultZone=http://01.server.eureka:8081/eureka/ ,http://02.server.eureka:8082/eureka/,http://03.server.eureka:8083/eureka/

使用restTemplate需要自己拼接url

启动类Application.java

package com.fei.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @EnableEurekaClient @SpringBootApplication public class Application { @Bean //定义REST客户端,RestTemplate实例 @LoadBalanced //开启负债均衡的能力 RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

eureka服务

Detailed explanation of SpringCloud’s microservice deployment

浏览器访问http://127.0.0.1:7081/user/find

看到信息“张三 服务端端口:9081”,刷新浏览器看到“张三 服务端端口:9082”,说明的确是有负载均衡。

但是访问外网的时候,http://127.0.0.1:7081/user/test,也就是域名不在eureka注册过的,就不行了。

Detailed explanation of SpringCloud’s microservice deployment

以后再研究下如何解决。

feign的app消费者

feign可以写个接口,加上相关的注解,调用的时候,会自动拼接url,调用者就像调用本地接口一样的操作。

Feign也用到ribbon,当你使用@ FeignClient,ribbon自动被应用。

像ribbo创建个项目,或者直接在ribbo项目修改都OK。

pom.xml 把ribbo的依赖修改为feign

 4.0.0 com.fei.springcloud springcloud-eureka-app-feign 0.0.1-SNAPSHOT eureka消费者feign    alimaven http://maven.aliyun.com/nexus/content /repositories/central/  true   true       alimaven http://maven.aliyun.com/nexus/content/repositories/central/  true   true      UTF-8 UTF-8  UTF-8 1.8 1.8 1.8   org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE      org.springframework.cloud spring-cloud-starter-feign    org.springframework.cloud spring-cloud-starter-eureka    org.springframework.boot spring-boot-starter-web      org.springframework.cloud spring-cloud-dependencies Dalston.RELEASE pom import       org.springframework.boot spring-boot-maven-plugin    

application.properties和上面一样

logging.config=classpath:logback.xml logging.path=d:/logs ##tomcat set### # eureka的默认端口是8761 server.port=7081 server.session-timeout=60 ########### spring.application.name=app-user #像eureka服务注册信息时,使用ip地址,默认使用hostname eureka.instance.preferIpAddress=true #服务的instance-id默认默认值是${spring.cloud.client.hostname} :${spring.application.name}:${spring.application.instance_id:${server.port}} , #也就是机器主机名:应用名称:应用端口 eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port} #eureka的服务地址 eureka.client.serviceUrl.defaultZone=http://01.server.eureka 8081/eureka/,http://02.server.eureka:8082/eureka/, http://03.server.eureka:8083/eureka/

增加个UserService.java接口类

package com.fei.springcloud.service; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient("API-USER-SERVER") public interface UserService { @GetMapping(value="/user/find/{id}") String find(@PathVariable("id") String id); } UserController.java package com.fei.springcloud.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.fei.springcloud.service.UserService; @Controller @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping(value = "/find") @ResponseBody public String find() { //url中对应api提供者的名称,全大写 String s = userService.find("123"); return s; } }

浏览器访问http://127.0.0.1:7081/user/find,得到信息“张三 服务端端口:9081”,刷新,得到“张三 服务端端口:9082”,Feign也用到ribbon,当你使用@ FeignClient,ribbon自动被应用。所以也会负载均衡

ribbo负载均衡策略选择

Detailed explanation of SpringCloud’s microservice deployment

AvailabilityFilteringRule:过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) | 使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态

RandomRule:随机选择一个server

BestAvailabl:选择一个最小的并发请求的server,逐个考察Server,如果Server被tripped了,则忽略

RoundRobinRule:roundRobin方式轮询选择, 轮询index,选择index对应位置的server

WeightedResponseTimeRule:根据响应时间分配一个weight(权重),响应时间越长,weight越小,被选中的可能性越低

RetryRule:对选定的负载均衡策略机上重试机制,在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server

ZoneAvoidanceRule:复合判断server所在区域的性能和server的可用性选择server

ResponseTimeWeightedRule:作用同WeightedResponseTimeRule,二者作用是一样的,ResponseTimeWeightedRule后来改名为WeightedResponseTimeRule

在app消费者的application.properties配置文件中加入

#ribbo负载均衡策略配置,默认是依次轮询 API-USER-SERVER.ribbon.NFLoadBalancerRuleClassName=com. netflix.loadbalancer.RandomRule

其中API-USER-SERVER是api服务提供者的服务名称,也就是说,可以给每个不同的api服务提供者配置不同的复制均衡策略,验证就不贴图了

负载均衡策略在消费端配置的缺点

在上面的例子中,ribbon的负载均衡是在消费端完成的。流程是这样的:提供者服务A集群,启动2个进程A1,A2,都注册到eureka,app消费端根据api服务者名称获取到A1,A2的具体连接地址,ribbon就对A1,A2进行负载均衡。

缺点:

1) 如果所有的app消费端的配置策略不好,导致绝大部分的请求都到A1,那A1的压力就大了。也就是说负载策略不是有api提供者所控制的了(这里就不说A1,A2所在的服务器哪个性能更好了,因为如果app/api都是在Docker中运行,k8s负责资源调配的话,可以认为每个服务的进程所在的docker配置是一样的,比如A服务对应的A1,A2系统环境是一致的,B服务对应的B1,B2,B3系统环境是一致的,只是所对应的宿主机服务器估计不一样而已)。

2)如果api提供者需要开放给第三方公司的时候,总不能把A1,A2告诉第三方吧,说我们这A服务集群了,有A1,A2,你随意吧。

我们实际项目中的做法,都是每个提供者服务都有自己的nginx管理自己的集群,然后把nginx的域名提供给app消费者即可。之所以每个服务提供者都有自己的nginx,是因为docker被k8s管控的时候,ip都是变化的,需要更新到nginx中。如果A,B都共用一个nginx,那A重构建部署的时候,A1,A2的ip变化了,需要更新到nginx中去,那如果导致nginx出现问题了,岂不是影响到B的使用了,所以A,B都有自己的nginx。那spring cloud没有解决方案了吗?有。spring cloud集成了zuul,zuul服务网关,不但提供了和nginx一样的反向代理功能,还提供了负载均衡、监控、过滤等功能。

The above is the detailed content of Detailed explanation of SpringCloud’s microservice deployment. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete