> 文章列表 > SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

微服务技术栈导学

微服务技术是分布式架构(把服务做拆分)的一种

而springcloud仅仅是解决了拆分时的微服务治理的问题,其他更复杂的问题并没有给出解决方案

一个完整的微服务技术要包含的不仅仅是springcloud

微服务技术栈

包括什么
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

认识微服务

(一)服务架构演变

1、单体架构

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

2、分布式架构

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

3、服务治理

在拆分的过程中也会有一些问题
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

4、微服务

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

5、总结

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

(二)微服务技术对比

1、微服务结构

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

2、微服务技术对比

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
SpringCloudAlibaba兼容了前面两种

3、企业需求

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

(三)SpringCloud

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

服务拆分

(一)案例Demo

1、服务拆分注意事项

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

2、导入服务拆分Demo

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
order表user_id虽然和user表进行关联,但是因为是跨database的,因此无法进行关联查询

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
项目中所有的微服务:
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
以下是两个分别的application.yml

server:port: 8080
spring:datasource:url: jdbc:mysql://localhost:3306/cloud_order?useSSL=falseusername: rootpassword: root123456driver-class-name: com.mysql.jdbc.Driver
mybatis:type-aliases-package: cn.itcast.user.pojoconfiguration:map-underscore-to-camel-case: true
logging:level:cn.itcast: debugpattern:dateformat: MM-dd HH:mm:ss:SSS
server:port: 8081
spring:datasource:url: jdbc:mysql://localhost:3306/cloud_user?useSSL=falseusername: rootpassword: root123456driver-class-name: com.mysql.jdbc.Driver
mybatis:type-aliases-package: cn.itcast.user.pojoconfiguration:map-underscore-to-camel-case: true
logging:level:cn.itcast: debugpattern:dateformat: MM-dd HH:mm:ss:SSS

将两个都启动:
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
在浏览器中(下载Chrome插件Json Viewer)
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

(二)服务远程调用

1、根据订单id查询订单功能

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

2、远程调用方式分析

那么问题就转变成了:如何在java代码中(像浏览器一样)发起http请求,这样就能实现远程调用了
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
Spring提供了一个工具——RestTemplate,用来发http请求
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

通过Bean的方式把RestTemplate注册为其中的一个对象,然后将来可以在任何地方注入这个对象来使用

写在哪里呢?Bean的注入只能放在配置类中,而启动类(OrderApplication)(带有@SpringBootApplication)本身也是配置类,所以完全可以在这里写Bean的注入

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}/* 创建RestTemplate并注入Spring容器* @return*/@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

接下来就可以利用它来发http请求了
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

修改OrderService

@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;// 0.注入RestTemplate@Autowiredprivate RestTemplate restTemplate;public Order queryOrderById(Long orderId) {// 1.查询订单Order order = orderMapper.findById(orderId);// 2.利用RestTemplate发送http请求,查询用户// 2.1.url路径String url = "http://localhost:8081/user/" + order.getUserId();// 2.2.发送http请求,实现远程调用(getForObject默认返回json,加上User.class参数g告诉它返回值的类型,自动转化成User对象)User user = restTemplate.getForObject(url, User.class);// 3.封装user到Orderorder.setUser(user);// 4.返回return order;}
}

然后重启Order服务(User服务就不需要重启了)
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

3、总结

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

Eureka注册中心

(一)提供者与消费者

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

(二)eureka原理分析

1、服务调用出现的问题

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

刚才将user-service服务的ip和端口硬编码在代码中的,有一定问题
所以不能用硬编码方式

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

2、Eureka的作用

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

每一个服务启动时都会把自己的信息注册给eureka

如果某个心脏不跳动了,eureka会将这个从列表中删除
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

3、总结

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

(三)搭建eureka服务

1、动手实践

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

2、搭建EurekaServer

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

搭建EurekaServer需要创建一个独立的微服务

starter是springboot中的自动装配,也就是说在这个依赖中已经帮我们把springeureka的所有的配置都做好了,也就是说我们可以零配置直接拿来用了

当然,自动装配是需要有开关的,第二步这个注解就是eurekaserver自动装配的开关

第三步需要编写一些配置信息,端口信息、服务名称、eureka的地址信息

接下来开始写:
1、创建一个新的module
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
引入依赖:

<dependencies><!--eureka服务端--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency>
</dependencies>

注意到我们引入的时候并没有指定版本信息,以前学习springboot时也遇到过这种情况,原因是在我们的父工程中,已经把依赖的版本都管理好了,所以可以进入cloud-demo的父工程的pom文件看,可以看到spring-boot-starter-parent的版本为2.3.9.RELEASE,以及spring-cloud版本和其他,并且有spring-cloud-dependencies依赖库,里面有大量的springcloud的组件及其版本信息,全都定义好了,所以在我们引入springcloud组件时,我们无需指定任何版本信息

2、编写main函数并添加注解
新建cn.itcast.eureka.EurekaApplication类

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {public static void main(String[] args) {SpringApplication.run(EurekaApplication.class, args);}
}

3、编写一个配置文件
resources下新建application.yml

server:port: 10086 # 服务端口
spring:application:name: eurekaserver # eureka的服务名称
eureka:client:service-url: # eureka的地址信息defaultZone: http://127.0.0.1:10086/eureka

注意由于eureka自己也是一个微服务,会将自己也注册到eureka上(这是为了将来eureka集群去用的),所以它也需要一个名字,而且还需要再配一个eureka的地址eureka.client.service-url

也就是说“这里是为了做服务注册才配置这些信息”

然后点击EurekaApplication左边的三角形启动,就可以在下面的服务中看到多出来了EurekaApplication
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
点击这个蓝色的端口号,会自动跳转到浏览器

点击10086,就跳转到了eureka的管理界面
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

status中的up表示正常状态,down表示挂掉了,up后面的是ip

(四)服务注册

1、注册user-service

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
可以看到,除了依赖不一样(刚才时eureka的服务端,现在是eureka的客户端),这个配置和刚才在eureka中做的配置文件长得非常像。为什么?因为eureka启动时会把自己注册到eureka,所以它也需要配服务名称和地址。所以服务名称和地址的配置实际上是服务注册的配置,只要配了它,就可以做注册

<!--eureka客户端依赖-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

然后配置yml文件

server:port: 8081
spring:datasource:url: jdbc:mysql://localhost:3306/cloud_user?useSSL=falseusername: rootpassword: root123456driver-class-name: com.mysql.jdbc.Driverapplication:name: userservice # user服务的服务名称
mybatis:type-aliases-package: cn.itcast.user.pojoconfiguration:map-underscore-to-camel-case: true
logging:level:cn.itcast: debugpattern:dateformat: MM-dd HH:mm:ss:SSS
eureka:client:service-url: # eureka的地址信息defaultZone: http://127.0.0.1:10086/eureka

然后重启UserApplication

接下来把Order服务也注册到Eureka,同上,然后重启
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
这里每个服务都只有一个实例,我们可以每个服务启动多个实例

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
(在这里配置端口,是为了覆盖yml文件的端口的)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
然后把它也启动,
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

(五)服务发现

我们希望orderservice可以基于服务名称拉取到userservice的两个实例信息,然后实现负载均衡
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
用服务名称代替ip、端口:在eureka中可以看到userservice这个服务名代指的就是这两个端口

要在多个实例中负载均衡,要给之前用到的RestTemplate这个Bean加一个注解@LoadBalanced

都弄完之后,我们把两个UserApplication的都清空,因为我们想知道OrderApplication究竟使用的是哪一个UserApplication,因为在OrderService中url中只是userservice,没有加任何ip地址

(六)总结

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

Ribbon负载均衡

(一)负载均衡原理

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
直接在浏览器中访问userservice/user/1是无法访问的

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

(二)负载均衡策略

IRule接口决定了负载均衡的策略
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
ZoneAvoidanceRule是默认

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
注意第一种代码方式是全局的,也就是说我一旦配了上面这种方案,在orderservice中不管你是调用哪一个微服务,都是randomrule;而第二种配置文件方式会先指定服务名称,再指定负载均衡的规则,只针对某个服务而言。

(三)饥饿加载

重启OrderApplication,
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
达到了非常恐怖的311毫秒,然后再刷新一次,
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)
时长就只有19毫秒了

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

创建LoadBalanceClient的过程中还要做服务的拉取,因此时间长

(这个配置是在orderservice的application.yml文件)

server:port: 8080
spring:datasource:url: jdbc:mysql://localhost:3306/cloud_order?useSSL=falseusername: rootpassword: root123456driver-class-name: com.mysql.jdbc.Driverapplication:name: orderservice # order服务的服务名称
mybatis:type-aliases-package: cn.itcast.user.pojoconfiguration:map-underscore-to-camel-case: true
logging:level:cn.itcast: debugpattern:dateformat: MM-dd HH:mm:ss:SSS
eureka:client:service-url: # eureka的地址信息defaultZone: http://127.0.0.1:10086/eureka
userservice:ribbon:NFLoadBalanceRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
ribbon:eager-load: enabled: true # 开启饥饿加载clients: # 指定饥饿加载的服务名称- userservice- xxservice

这个ribbon与上面userservice下的ribbon不冲突

(四)总结

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)