搭建springcloud工程
子父工程的形式
架构大致如下:
mircoservice-eureka : 注册中心,提供注册服务
mircoservice-user : 用户服务,提供数据库查询服务
mircoservice-consume : 远程调用服务,提供接口查询数据
父工程 pom文件
<modules>
<module>mircoservice-eureka</module>
<module>mircoservice-user</module>
<module>mircoservice-consume</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.fangh</groupId>
<artifactId>mircoservice</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
<lombok.version>1.18.10</lombok.version>
<mybatis-plus.version>3.2.0</mybatis-plus.version>
<mysql-connector.version>5.1.46</mysql-connector.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
子工程
eureka 注册中心
加入maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
yml 文件配置
server:
port: 9000
eureka:
client:
#注册中心是否将自己注册进去
register-with-eureka: false
#点击进去可以看到是一个Map,key 要从类 EurekaClientConfigBean 看
service-url:
defaultZone: http://127.0.0.1:9000/eureka/
在application 主方法上面加上注解 @EnableEurekaServer
mircoservice-user 项目
pom文件:
<!-- web 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Mysql 连接池-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- mybatis-plus 插件-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--eureka 客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
yml 配置文件
server:
port: 9001
eureka:
client:
#点击进去可以看到是一个Map,key 要从类 EurekaClientConfigBean 看
service-url:
defaultZone: http://127.0.0.1:9000/eureka/
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: root
application:
name: mircoservice-user
application 主方法加上注解 @EnableDiscoveryClient![主方法加上注解 @EnableDiscoveryClient](https://i-blog.csdnimg.cn/blog_migrate/b1f613de062ca361d4245d0aa3bceebb.png)
为什么使用 @EnableDiscoveryClient 而不是 @EnableEurekaClient ?
因为**@EnableEurekaClient只是针对于eureka** 生效,其他注册中心不生效,日后将注册中心改成zookeeper 或者consul 都不会有问题
mircoservice-consume 项目工程
pom文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
yml 文件
server:
port: 9000
eureka:
client:
#注册中心是否将自己注册进去
register-with-eureka: false
#点击进去可以看到是一个Map,key 要从类 EurekaClientConfigBean 看
service-url:
defaultZone: http://127.0.0.1:9000/eureka/
在application 主方法上加上注解 @EnableDiscoveryClient![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b6bfee3432a23ddd1f7f72311121e66e.png)
为什么使用 @EnableDiscoveryClient 而不是 @EnableEurekaClient ?
因为**@EnableEurekaClient只是针对于eureka** 生效,其他注册中心不生效,日后将注册中心改成zookeeper 或者consul 都不会有问题
服务间的调用
昨天已经学习了服务间的调用有两种,各自的介绍也说了。
springcloud 学习第一天----微服务的介绍和了解
第一种实现(前提注入 RestTemplate bean 对象)
String forObject = restTemplate.getForObject("http://127.0.0.1:9001/user/" + id, String.class);
直接通过 RestTemplate 调用,简单实用,但是拓展性不高,如果服务ip或者端口改变都得改变,增加日后维护的难度。
第二种实现(前提注入 RestTemplate DiscoveryClient bean对象)
//获取服务实例,可能存在多个实例,即负载均衡
List<ServiceInstance> clientInstances = discoveryClient.getInstances("mircoservice-user");
//获取其中一个实例(暂时只有一个实例对象)
ServiceInstance serviceInstance = clientInstances.get(0);
String url = "http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/user/" + id;
String forObject = restTemplate.getForObject(url, String.class);
通过 DiscoveryClient 对象获取服务实例对象列表,然后自己可以通过一定的算法【hash、轮询、随机等等】,获取其中一个实例进行远程服务调用。[^hash 算法]:通过将访问ip生成一个固定hash值,然后通过hash值分配一个固定访问服务。
注:暂时只取第一个服务调用
第三种实现(前提要注入 RibbonLoadBalancerClient bean 对象)
注入RibbonLoadBalancerClient
调用代码如下
ServiceInstance choose = ribbonLoadBalancerClient.choose("mircoservice-user");
String forObject = restTemplate.getForObject("http://"+choose.getHost()+":"+choose.getPort()+"/user/" + id, String.class);
第四种实现(在 RestTemplate 注入bean 增加一个 @LoadBalanced)
restTemplate.getForObject("http://mircoservice-user/user/" + id, String.class);
底层实现方式
1.LoadBalancerInterceptor 拦截器实现
这种方式其实底层是通过拦截器做的,通过 LoadBalancerInterceptor 这个类 实现服务直接调用。
通过上面的类可以知道,它是通过 LoadBalancerClient 执行 execute 方法,来获取他真实的ip 地址和端口,但是他是如何实现负载均衡的呢?
2.通过LoadBalancerClient 执行 execute 方法
通过上面那个方法可以看出,是通过 ILoadBalancer 负载均衡器去获取相对应的实例,也就是说这个负载均衡器实际上会根据serviceId 会自动获取一个实例,那个实例又是怎么根据什么算法获取的呢?
3.ILoadBalancer 负载均衡器根据算法获取实例对象
通过上面代码可知,如果负载均衡器为空,会自动获取默认的负载均衡器,那么默认的算法规则是什么呢?
通过上面代码可以知道,他默认算法规则就是 RoundRobinRule 类 ,这个类进去发现其实就是轮询,但是你看下它的源码就会发现一个问题
通过上面的代码可以知道,当负载均衡数量超过十个就会出现问题,因此,当超过十个就要重新使用其他算法来获取服务器实例。
4.配置负载均衡器算法规则
其实很简单:在yml 文件中加入配置文件
serviceId: ribbon:NFLoadBalancerRuleClassName:负载均衡算法器类全路径
mircoservice-user:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
第五种实现(前提是引用 feign 依赖)
具体请看springcloud 学习第四天----feign的学习
总结
eureka 总结
1.其实eureka 内容不多,主要是配置服务器端和客户端,但是配置客户端时记得使用 @EnableDiscoveryClient ,方便日后使用。
2.eureka 集群,通过互相注入的原则,在 defaultZone 中添加其他注册中心地址,用逗号分隔开
client:
#注册中心是否将自己注册进去
register-with-eureka: false
#点击进去可以看到是一个Map,key 要从类 EurekaClientConfigBean 看
service-url:
defaultZone: http://127.0.0.1:9000/eureka/,http://127.0.0.1:9090/eureka/
ribbon 总结
1.ribbon 极大的方便了我们的调用和使用,代码也简化了很多,根据serviceId 就能找到相对应的服务,还能通过相对应的算法选择一个服务进行远程调用
2 其实看ribbon 的源码,极大的享受,设计算法中通过适配器来做的,根据不同的类选择不同的算法规则,以后写代码的时候可以借鉴下。
3目前负载均衡中的适配器的算法只有以下几种