1. 单体应用
- 什么是单体应用
项目所有资源都在一个应用中,打包成一个war 包,使用一个tomcat运行,运行在一个进程中。
- 单体应用的缺点
- 项目越大,编译越难,部署越难,测试越难
- 技术选型单一
- 数据库选型单一
- 一个模块挂了整个项目就崩了
- 单个tomcat更能处理的并发有限,可以做集群,但是不方便局部(某一个模块)扩展
2. MicroService微服务架构
- 使用微服务架构就可以解决单体项目缺点。
- 什么是MicroService架构
微服务就是把一个大的系统,拆分成多个小的服务,每个服务只专注一个业务,每个服务有各自的进程,微服务之间使用网络通信协议进行数据交互(通常是基于HTTP的RESTful API)
- 微服务的特点
- 数据库选型多样
- 技术选型多样
- 每一个服务只专注一个业务
- 微服务之间通过网络协议来通信
- 微服务作局部拓展方便(不同的业务访问量不同)
- 开发 维护 升级更加方便
- 微服务的缺点
- 成本高
- 技术要求比较高
- 部署比较麻烦
单体应用与微服务的对比图解
- 总结:小项目(低并发)适合使用单体项目,大项目(高并发)适合使用微服务
3. SpringCloud 简介
Spring cloud是一个基于Spring Boot实现的服务治理工具包,用于微服务架构中管理和协调服务的
- SpringCloud 的组成部分
SpringCloud 组合了各家公司开发的成熟的,经得住考验的服务框架
- SpringCloud 五大神兽
- 服务注册发现——Netflix Eureka : 帮我们注册服务的通信地址
- 客服端负载均衡——Netflix Ribbon\Feign : 解决网络通信
- 断路器——Netflix Hystrix :解决微服务故障
- 服务网关——Netflix Zuul :微服务的大门(安保部门)
- 分布式配置——Spring Cloud Config :统一管理微服务的配置
- Spring cloud 与 dubbo 的对比
- Dubbo 是阿里巴巴服务化治理的核心框架是rpc【远程过程调用】框架
- SpringCloud是一系列微服务解决方案
- Dubbo 基于TCP 作数据传输,性能非常高
- Spring cloud 基于HTTP,性能低于Dubbo
4. 搭建SpringCloud 注册中心(Eureka)
- 创建多模块工程
springcloud-parent
springcloud-eureka-server-1000 //注册中心EurekaServer
springcloud-order-server-3000 //订单服务EurekaClient ,消费者
springcloud-user-server-2000 //用户服务EurekaClient ,提供者
- springcloud-parent 的pom依赖配置
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<groupId>cn.itsource.springcloud</groupId>
<artifactId>springcloud-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- springcloud-eureka-server-1000导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- springcloud-eureka-server-1000 的主配置类
/**
* @EnableEurekaServer :开启注册中心
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication1000 {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication1000.class);
}
}
- springcloud-eureka-server-1000配置文件application.yml
server:
port: 1000
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false #禁用注册中心向自己注册
fetchRegistry: false #不让注册中心获取服务的注册列表
serviceUrl:
defaultZone: http://localhost:1000/eureka/
#注册中心的注册地址 ,其他微服务需要向这个地址注册
5. 搭建提供者服务 springcloud-user-server-2000
- 导入依赖
<dependencies>
<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>
</dependencies>
- 创建配置类
//@EnableDiscoveryClient:开启注册中心客户端 EurekaClient
@SpringBootApplication
@EnableDiscoveryClient
public class UserServerApplication2000 {
public static void main(String[] args) {
SpringApplication.run(UserServerApplication2000.class);
}
}
- 配置文件
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1000/eureka/ #注册中心地址
server:
port: 2000
spring:
application:
name: user-server
6.搭建消费者服务 springcloud-order-server-3000
步骤参考搭建服务提供者,搭建完成效果如下
7. 订单服务和用户服务完成通信
1.依赖公共模块
<dependency>
<groupId>cn.itsource.springcloud</groupId>
<artifactId>springcloud-common-user</artifactId>
<version>...</version>
</dependency>
2.创建controller
/**
* 用户提供者服务
*/
@RestController
public class UserProviderController {
/**
* 提供者方法,orderServer消费者来调用
* @param id
* @return
*/
// @RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id")Long id){
System.out.println("UserProviderController.getUserById被调用了......");
return new User(id,"zs:"+id , "123");
}
}
3.order-server消费者服务
1.依赖公共模块
<dependency>
<groupId>cn.itsource.springcloud</groupId>
<artifactId>springcloud-common-user</artifactId>
<version>...</version>
</dependency>
2.定义RestTemplate的bean
/**
* SpringMvc提供的一个基于Rest风格的http调用工具
* @return
*/
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
3.定义消费者的Controller
/**
* 订单消费者服务
*/
@RestController
public class OrderConsumerController {
@Autowired
private RestTemplate restTemplate ;
/**
* 该方法是浏览器来调用
* @param id
* @return
*/
@GetMapping("/order/user/{id}")
public User getUserById(@PathVariable("id") Long id){
System.out.println("OrderConsumerController.getUserById被调用了......");
String url = "http://localhost:2000/user/"+id;
User user = restTemplate.getForObject(url, User.class);
return user;
}
}
8. EurekaServer高可用集群
一.单节点故障
1.什么是EurekaServer单节点故障
如果只有一个EurekaSever,如果EurekaSever挂了那么整个微服务都不可用
2.解决方案
EurekaServer高可用集群
二.EurekaServer集群
1.搭建EurekaServer集群
创建两个本地域名 C:\Windows\System32\drivers\etc\hosts
127.0.0.1 peer1
127.0.0.1 peer2
修改注册中心eureka-server-1000
server:
port: 1000
eureka:
instance:
hostname: peer1
client:
registerWithEureka: false #禁用注册中心向自己注册
fetchRegistry: false #不让注册中心获取服务的注册列表
serviceUrl:
defaultZone: http://peer2:1001/eureka/
#注册中心的注册地址 ,其他微服务需要向这个地址注册
搭建第二个注册中心eureka-server-1001 - 复制
server:
port: 1001
eureka:
instance:
hostname: peer2
client:
registerWithEureka: false #禁用注册中心向自己注册
fetchRegistry: false #不让注册中心获取服务的注册列表
serviceUrl:
defaultZone: http://peer1:1000/eureka/
#注册中心的注册地址 ,其他微服务需要向这个地址注册
3.修改EurekaClient (UserServer ,OrderServer)
eureka:
client:
serviceUrl:
defaultZone: http://peer1:1000/eureka/,http://peer2:1001/eureka/ #注册中心地址
...
8 Ribben 负载均衡
ribbon是负载均衡器,是基于RestTemplate ,它赋予了RestTemplate 负载均衡的能力
一集群和负载均衡原理
二 服务提供者user-server集群
1.创建user-server服务2001 - 赋值
2.修改配置
eureka:
client:
serviceUrl:
defaultZone: http://peer1:1000/eureka/,http://peer2:1001/eureka/ #注册中心地址
instance:
prefer-ip-address: true #使用ip地址注册
instance-id: user-server1 #指定服务的id
server:
port: 2000
spring:
application:
name: user-server
注意:instance-id需要修改 , 而 spring.application.name 不需要修改 , 端口需要修改
3.修改主类名,pom中的名字,parent中的模块增加
三.order-server集成Ribbon
- 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
- 修改RestTemplate的Bean的定义
/**
* SpringMvc提供的一个基于Rest风格的http调用工具
* @LoadBalanced :ribbon的负载均衡标签,赋予RestTemplate有负载均衡的能力
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
@LoadBalanced :ribbon的负载均衡标签,赋予RestTemplate有负债均衡的能力
- 修改Controller调用方式
@GetMapping("/order/user/{id}")
public User getUserById(@PathVariable("id") Long id){
System.out.println("OrderConsumerController.getUserById被调用了......");
//String url = "http://localhost:2000/user/"+id;
String url = "http://user-server/user/"+id;
User user = restTemplate.getForObject(url, User.class);
return user;
}
修改效果: String url = “http://user-server/user/”+id;
ribbon默认使用的轮询策略
9 Feign的负载均衡处理
一. 什么是feign
基于Ribbon封装的客户端负载均衡器
二.Feign的集成 - springcloud-dept-server-4000
- 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 在配置类开启feign
@SpringBootApplication
@EnableFeignClients("cn.itsource.client")
public class DeptServerApplication4000
...
- 编写feign的接口
/**
* @FeignClient(value="user-server") : 针对于用户服务调用的 Fiegn的客户端接口
* value属性就是该接口要调用的目标服务的名字
* Feign是如何实现服务调用的:
* 1.通过@FeignClient(value="user-server")标签上的服务名字能够找到要调用的目标服务
* 2.通过接口中的方法的 @GetMapping的url路径找到目标服务的controller的方法 ,
* 所以要保证Feign客户端接口的方法和目标服务的对应的方法要完全一致。
*
*/
@FeignClient(value="user-server")
public interface UserFeignClient {
@GetMapping("/user/{id}")
User getUserById(@PathVariable("id")Long id);
}
Feign客户端接口的方法和目标服务的对应的方法要完全一致
- 调用方式
@RestController
public class DeptConsumerController {
@Autowired
private UserFeignClient userFeignClient ;
/**
* 该方法是浏览器来调用
* @param id
* @return
*/
@GetMapping("/dept/user/{id}")
public User getUserById(@PathVariable("id") Long id){
User user = userFeignClient.getUserById(id); //使用Feign的接口调用
return user;
}
}
- 总结,Ribben与Feign都可以用来实现负载均衡,一般都是用Feign。可以通过下面方法改变负载均衡的策略
/**
* ribbon默认使用的轮询策略
* 现在修改为随机策略
*/
@Bean
public IRule rule(){
return new RandomRule();
}