淘宝的架构演变(重点最少看10次以上)
淘宝架构演变
springCloud与springboot区别:springCloud基于springboot
微服务架构
1、微服务”一词源于 Martin Fowler的名为 Microservices 的博文,
可以在他的官方博客上找到http://martinfowler.com/articles/microservices.html
2、微服务是系统架构上的一种设计风格,它的主旨是将一个原本独立的系统拆分成多个小型服务,
这些小型服务都在各自独立的进程中运行,服务之间一般通过 HTTP 的 RESTfuL API 进行通信协作。
3、被拆分成的每一个小型服务都围绕着系统中的某一项或些耦合度较高的业务功能进行构建,
并且每个服务都维护着白身的数据存储、业务开发自动化测试案例以及独立部署机制。
4、由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写。
Spring Cloud
- Spring Cloud 是一系列框架的有序集合。
- Spring Cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来。
- 通过 Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
- 它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、 断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
- Spring Cloud项目官方网址:https://spring.io/projects/spring-cloud
Spring Cloud 与 Dubbo 对比
- Spring Cloud 与 Dubbo 都是实现微服务有效的工具。
- Dubbo 只是实现了服务治理,而 Spring Cloud 子项目分别覆盖了微服务架构下的众多部件。
- Dubbo 使用 RPC 通讯协议,Spring Cloud 使用 RESTful 完成通信,Dubbo 效率略高于 Spring Cloud。
小结
- 微服务就是将项目的各个模块拆分为可独立运行、部署、测试的架构设计风格。
- Spring 公司将其他公司中微服务架构常用的组件整合起来,并使用 SpringBoot 简化其开发、配置。称为 Spring Cloud
- Spring Cloud 与 Dubbo都是实现微服务有效的工具。Dubbo 性能更好,而 Spring Cloud 功能更全面。
Eureka
概念:
- Eureka 是 Netflix 公司开源的一个服务注册与发现的组件 。
- Eureka 和其他 Netflix 公司的服务组件(例如负载均衡、熔断器、网关等) 一起,被 Spring Cloud 社区整合为
- Spring-Cloud-Netflix 模块。
- Eureka 包含两个组件:Eureka Server (注册中心) 和 Eureka Client (服务提供者、服务消费者)。
开发步骤:
-
搭建 Provider 和 Consumer 服务。
-
使用 RestTemplate 完成远程调用。
1、Spring提供的一种简单便捷的模板类,用于在 java 代码里访问 restful 服务。 2、其功能与 HttpClient 类似,但是 RestTemplate 实现更优雅,使用更方便。
-
搭建 Eureka Server 服务。
(1)创建 eureka-server 模块 (2)引入 SpringCloud 和 euraka-server 相关依赖 (3)完成 Eureka Server 相关配置 (4)启动该模块
-
改造 Provider 和 Consumer 称为 Eureka Client。
(1)引 eureka-client 相关依赖 (2)完成 eureka client 相关配置 (3)启动 测试
-
Consumer 服务 通过从 Eureka Server 中抓取 Provider 地址 完成 远程调用
Eureka – 相关配置及特性
Eureka包含四个部分的配置
- instance:当前Eureka Instance实例信息配置
- client:Eureka Client客户端特性配置
- server:Eureka Server注册中心特性配置
- dashboard:Eureka Server注册中心仪表盘配置
Eureka – 相关配置及特性 - instance
eureka:
instance:
hostname: localhost # 主机名
prefer-ip-address: # 是否将自己的ip注册到eureka中,默认false 注册 主机名
ip-address: # 设置当前实例ip
instance-id: # 修改instance-id显示
lease-renewal-interval-in-seconds: 30 # 每一次eureka client 向 eureka server发送心跳的时间间隔
lease-expiration-duration-in-seconds: 90 # 如果90秒内eureka server没有收到eureka client的心跳包,则剔除该服务
Eureka – 相关配置及特性 - server
eureka:
server:
#是否开启自我保护机制,默认true
enable-self-preservation:
#清理间隔(单位毫秒,默认是60*1000)
eviction-interval-timer-in-ms:
Eureka – 相关配置及特性 - client
eureka:
client:
service-url:
# eureka服务端地址,将来客户端使用该地址和eureka进行通信
defaultZone:
register-with-eureka: # 是否将自己的路径 注册到eureka上(默认是true)。
fetch-registry: #是否需要从eureka中抓取数据(默认是true)。
Eureka – 相关配置及特性 - dashboard
eureka:
dashboard:
enabled: true # 是否启用eureka web控制台
path: / # 设置eureka web控制台默认访问路径
消费者创建
- 在微服务分布式中,业务都会被拆分成一个独立的服务,并且在多个服务器上部署相同的服务。服务与服务的通讯是基于http restful的。SpringCloud我们会使用到两种消费工具,Ribbon+Feign。
- Ribbon实现了服务的负载均衡
- Feign默认集成了Ribbon。
- 所以一般情况下我们使用Feign作为消费端。
服务消费者创建(Ribbon)
Ribbon 概述
-
Ribbon是 Netflix 提供的一个基于HTTP和TCP的客户端负载均衡工具。
-
Ribbon主要有两个功能:
1、简化远程调用 2、负载均衡
使用步骤:(获取服务方使用)
1、导入坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
2、配置文件
server:
port: 9201
spring:
application:
name: eureka-customer-ribbon
eureka:
client:
service-url:
defaultZone: http://localhost:9001/eureka
3、创建消费端代码
- 新建我们的启动类RibbonApp
- 在工程的启动类中,通过@EnableDiscoveryClient向服务中心注册;并且向程序的ioc注入一个bean:restTemplate;
- 并通过@LoadBalanced注解表明这个restRemplate开启负载均衡的功能。
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonApp {
public static void main(String[] args) {
SpringApplication.run(RibbonApp.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
returnnew RestTemplate();
}
}
新建一个HelloController
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@RequestMapping(value = "/hello")
public String hello(@RequestParam String name) {
return helloService.helloService(name);
}
}
新建一个HelloService层,引入我们的template
@Service
public class HelloService {
@Autowired
private RestTemplate template;
public String helloService(String name) {
return template.getForObject("http://eureka-provider/hello?name=" + name, String.class);
}
}
到这里我们就可以直接访问我们的消费端。
http://localhost:9201/hello?name=张三,可以发现Ribbon帮我们实现了负载均衡
Ribbon 负责均衡策略:
随机 :RandomRule
轮询 :RoundRobinRule
最小并发:BestAvailableRule
过滤:AvailabilityFilteringRule
响应时间:WeightedResponseTimeRule
轮询重试:RetryRule
性能可用性:ZoneAvoidanceRule
Ribbon架构图
- 一个服务注册中心,eureka server,端口为9001
- EurekaProvider工程跑了两个实例,端口分别为9101,9102分别向服务注册中心注册
- EurekaRibbon端口为9201,向服务注册中心注册
- 当EurekaRibbon通过restTemplate调用eureka-prodiver的hello接口时,因为用ribbon进行了负载均衡,会轮流的调用eureka-prodiver:9101和9102两个端口的hello接口;
服务消费者(Feign)
使用Ribbon还是比较繁琐,我们有更简单的方式去实现服务调用,就是我们的Feign调用工具。
创建我们的EurekaFeign项目
- 创建EurekaFeign项目,同样也是采用SpringBoot形式的Maven工程,基于Feign消费+restful风格
使用步骤:
1、引入pom文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、配置文件
编写我们的配置文件application.yml,配置端口9202,并且将服务注册到Eureka
server:
port: 9202
spring:
application:
name: eureka-customer-feign
eureka:
client:
service-url:
defaultZone: http://localhost:9001/eureka
feign:
hystrix:
enabled: true
3、创建消费端代码
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
publicclass FeignApp {
publicstaticvoid main(String[] args) {
SpringApplication.run(FeignApp.class, args);
}
}
新建一个HelloService服务接口,然后添加@FeignClient注解,表明我们调用的哪个服务,在接口中编写我们在服务提供者中相应的接口。
@FeignClient(value = "eureka-provider")
public interface HelloService {
@RequestMapping("/hello")
String hello(@RequestParam(value = "name") String name);
}
创建一个请求HelloController
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@RequestMapping("/hello")
public String hello(String name) {
return helloService.hello(name);
}
}
然后启动我们的启动类,就可以通过http://localhost:9202/hello?name=张三访问到我们的服务
断路器
雪崩效应
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
断路器就是故障转移(将当前出现故障的请求重新返回特定消息)
Ribbon使用断路器
改造Eureka-ribbon 工程的代码,首先在pom.xml文件中加入spring-cloud-starter-netflix-hystri的依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
然后在我们的启动类上加上开启Hystrix的注解@EnableHystrix
然后改造我们的Service层
@Service
public class HelloService {
@Autowired
private RestTemplate template;
@HystrixCommand(fallbackMethod = "helloError")
public String helloService(String name) {
return template.getForObject("http://eureka-provider/hello?name=" + name, String.class);
}
public String helloError(String name) {
return "Hello," + name + ",服务器发生异常!!!";
}
}
这样我们就实现了在Ribbon下使用断路器。
我们只需要先正常启动EurekaServer,然后启动生产者,并且启动我们的Ribbon消费者服务,通过http://localhost:9202/hello?name=张三 访问我们的服务
浏览器打印:Hello 张三,From Port:9101
当我们关闭生产者打印:Hello,张三,服务器发生异常!!!
这里就证明我们在Ribbon下使用断路器成功。
Feign使用断路器
Feign是自带断路器的,但是有些版本没有自动打开,我们这里需要在配置文件
1、中配置开启断路器。配置如下
feign:
hystrix:
enabled:true
2、然后对我们的RurekaFeign的接口类进行改造,直接在注解上加上我们的fallback指定回调的类就行了。代码如下
@FeignClient(value = "eureka-prodiver", fallback = HelloServiceImpl.class)
public interface HelloService {
@RequestMapping("/hello")
public String hello(@RequestParam(value = "name") String name);
}
3、然后写一个我们的接口的实现类HelloServiceImpl实现我们的hello方法,并且注入到容器中。
@Component
public class HelloServiceImpl implements HelloService {
@Override
public String hello(String name) {
return "Hello " + name + ",服务器发生异常!!!";
}
}
然后同样和Ribbon那样操作,先让生产者正常启动访问,然后关闭生产者访问。
结果和Ribbon结果想过,则证明断路器起作用了。
ZUUL路由网关
介绍zuul
在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。
一般情况下,用户访问首先通过负载均衡,然后到达我们的路由配置,最后才访问到我们的具体服务。
zuul的作用是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/order转发到到order服务。
搭建zuul环境
创建一个EurekaZuul的Maven项目
1、引入pom依赖(zuul依赖)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
2、创建我们的配置文件(将通过/api-a/hello的请求用Ribbon消费,通过/api-b/hello的请求通过feign访问,这个就是zuul路由网关)
server:
port: 9401
spring:
application:
name: eureka-zuul
eureka:
client:
service-url:
defualtZone: http://localhosts:8761/eureka
registry-fetch-interval-seconds: 5
instance:
lease-renewal-interval-in-seconds: 5
lease-expiration-duration-in-seconds: 15
prefer-ip-address: true
instance-id: ${spring.application.name}-${server.port}
zuul:
retryable: true
testFilter:
pre:
disable: true
routes:
eureka-provider: /c/**
a:
path: /a/**
serviceId: eureka-customer-ribbon
b:
path: /b/**
serviceId: eureka-customer-feign
d:
path: /d/**
url: forward:/hello
baidu:
path: /baidu/**
url: http://baidu.com
3、创建我们的启动类,注意需要添加开启zuul网关
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
publicclass EuulApp {
publicstaticvoid main(String[] args) {
SpringApplication.run(EuulApp.class, args);
}
}
4、启动访问