构建微服务项目步骤
SpringCloud,基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件。
Spring cloud有哪些常用组件,作用是什么?
@Autowired
//返回类型:(url,实体map,返回类型Class responseType)
private RestTemplate restTemplate;//提供多种便捷访问http服务的方法,简单的restful服务模板
package com.liang.springcloud.controller;
import com.liang.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@Controller
@ResponseBody
public class DeptConsumerController {
//理解:消费者,不应该有service层
//RestTemplate很多方法给我们直接调用,注册到spring中
@Autowired
//返回类型:(url,实体map,返回类型Class responseType)
private RestTemplate restTemplate;//提供多种便捷访问http服务的方法,简单的restful服务模板
private static final String REST_URL_PREFIX = "http://localhost:8001";
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept, Boolean.class);
}
//http://localhost:8001/dept/list要从这个地址拿到数据
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX+"dept/list", List.class);
}
}
@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer //服务端的启动类,可以接受别人注册进来
public class EurekaService_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaService_7001.class,args);
}
}
@EnableEurekaClient//cs架构,自动在服务启动后自动注册到eureka中
Eureka: 怎么读?
Netflix 在设计Eureka时,遵循的就是AP原则
Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper;
心跳监测机制,五秒不回复证明挂掉,就会把服务节点移掉
自我保护机制(宁可保留全部服务,也不盲目注销任何健康的服务)
注意yml文件,编写要空一格
搭建eureka集群,对应配置文件加上绑定互联
server:
port: 7003
# eureka配置
eureka:
instance:
hostname: eureka7003.com #Eureka服务端的实例名称
client:
register-with-eureka: false # 表示是否向eureka注册中心注册自己
fetch-registry: false # fetch-registry 如果为false,则表示自己为注册中心
service-url: # 监控页面
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/
server:
port: 8001
#mybatis的配置
mybatis:
type-aliases-package: com.liang.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
#spring的配置
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
username: root
password: root
# Eureka的配置,服务注册到哪里
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springcloud-provider-dept8001-liangwh #修改的是eureka status默认的描述信息
#info配置
info:
app.name: liangwh-springcloud
company.name: liangwh123321.com
cap原则,一个分布式系统不可能同时满足三个
作为服务注册中心,Eureka比Zookeeper好在哪里?
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具(轮询和随机)
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将NetFlix的中间层服务连接在一起。Ribbon的客户端组件提供一系列完整的配置项如: 连接超时、重试等等。简单的说,就是在配置文件中列出LoadBalancer (简称LB: 负载均衡)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等等) 去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法
负载均衡,把用户的请求平摊到多个服务上,达到高可用
ribbon能干嘛?
。LB,即负载均衡 (Load Balance) ,在微服务或分布式集群中经常用的一种应用。
。负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA(高可用)
。常见的负载均衡软件有 Nginx,Lvs 等等
·dubbo、 SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义
。负载均衡简单分类:
集中式LB0
即在服务的消费方和提供方之间使用独立的LB设施,如Nginx(反向代理),由该设施负责把访问请求通过某种策略转发至服务的提供方!
进程式LB,将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器
Ribbon就属于进程内LB它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!
表明引用的类没有注入到bean中需要在该类加上注解 @Bean
@Configuration
public class ConfigBean {
//配置负载均衡实现RestTemplate
@Bean
@LoadBalanced//ribbon
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
//ribbon 和 eureka整合以后,客户端可以直接调用,不用关心ip 和 端口号
//消费者主启动类
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能去加载我们自定义的ribbon类
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = liangRule.class)
public class DeptConsumer_88 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_88.class, args);
}
}
package com.liang.myrule;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class LiangRandomRule extends AbstractLoadBalancerRule {
//每个服务,访问6次,换下一个服务(3个)
//total=0,默认=0,如果=6,指向下一个服务节点
//index= 0,默认=0,如果total = 5,index+1
private int total = 0; //被调用的次数
private int currentIndex = 0; //当前谁提供的服务
@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();//获得可访问服务器
List<Server> allList = lb.getAllServers();//获取全部服务
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
// int index = this.chooseRandomInt(serverCount);//生成区间随机数
// server = (Server)upList.get(index);//从活着的服务中,随机获取一个
// -自定义算法开始==============================
if (total<5){
server = upList.get(currentIndex);
total++;
}else {
total = 0;
currentIndex ++;
if (currentIndex>=upList.size()){
currentIndex = 0;
}
server = upList.get(currentIndex);//从活着的服务中,获得指定的服务来操作
}
// -自定义算法结束==============================
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
@Configuration
public class liangRule {
@Bean
public IRule myRule(){
return new LiangRandomRule();//默认是轮询,现在我们自定义访问自己定义的算法
}
}
简介
在service加上注解
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
@Component//注入到容器
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id")Long id);
@GetMapping("/dept/list")
public List<Dept> queryAll();
@PostMapping("/dept/add")
public boolean addDept(Dept dept);
}
@RestController
public class DeptConsumerController {
//理解:消费者,不应该有service层
//RestTemplate很多方法给我们直接调用,注册到spring中
@Autowired
//返回类型:(url,实体map,返回类型Class responseType)
private RestTemplate restTemplate;//提供多种便捷访问http服务的方法,简单的restful服务模板
//ribbon(负载均衡) 我们这里的地址应该是一个变量,通过服务访问
// private static final String REST_URL_PREFIX = "http://localhost:8001";
// private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
@Autowired
private DeptClientService deptClientService;
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return this.deptClientService.addDept(dept);
}
//http://localhost:8001/dept/list要从这个地址拿到数据
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return deptClientService.queryById(id);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return this.deptClientService.queryAll();
}
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.liang.springcloud"})
public class FeignDeptConsumer_88 {
public static void main(String[] args) {
SpringApplication.run(FeignDeptConsumer_88.class, args);
}
}
简介
Hvstrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障以提高分布式系统的弹性。
"断路器"本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个服务预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故喷在分布式系统中的蔓延,乃至雪崩
Hystrix能干嘛
。服务降级
。服务熔断
。服务限流
。接近实时的监控
服务熔断是什么?
熔断机制是对应雪崩效应的一种微服务链路保护机制
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回 错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在Springloud框架里熔断机制通过Hystrix实现。Hvstrix会监控微服务间调用的状况,当失败的调用到一定闻值,5秒内20次调用失败就会启动熔断机制。
熔断机制的注解是 @HystrixCommand。
在主启动类加上注解@EnableCircuitBreaker//添加对熔断的支持
链式编程注解(在对应实体类加上即可)
@Accessors(chain = true)//链式写法
@Data
@NoArgsConstructor
@Accessors(chain = true)//链式写法
public class Dept implements Serializable {
private Long deptno;//主键
private String dname;
private String db_source;//一个服务对应一个数据库,数据库存的字段
public Dept(String dname) {
this.dname = dname;
}
}
//备选方法
@GetMapping("/dept/get/{id}")
public Dept hystrixGet(@PathVariable("id") Long id){
return new Dept()
.setDeptno(id)
.setDname("id=>"+id+"没有对应信息,null==@hystrix")
.setDb_source("no this database in mysql");
}
@GetMapping("/dept/get/{id}")
@HystrixCommand(fallbackMethod = "hystrixGet")//只要失败就调用其他方法
public Dept get(@PathVariable("id") Long id){
Dept dept = deptService.queryById(id);
if (dept == null){
throw new RuntimeException("id=>"+id+"不存在这个id");
}
return dept;
}
//备选方法
public Dept hystrixGet(@PathVariable("id") Long id){
return new Dept()
.setDeptno(id)
.setDname("id=>"+id+"没有对应信息,null==@hystrix")
.setDb_source("no this database in mysql");
}
#开启降级 feign.hystrix
feign:
hystrix:
enabled: true
@Component//注入到容器
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFactory.class)
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id")Long id);
@GetMapping("/dept/list")
public List<Dept> queryAll();
@PostMapping("/dept/add")
public boolean addDept(Dept dept);
}
//降级~
@Component
public class DeptClientServiceFactory implements FallbackFactory {
@Override
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
@Override
public Dept queryById(Long id) {
return new Dept().setDeptno(id)
.setDname("id=>"+id+"没有对应的信息,客户端提供了降级的信息,这个服务现在已经被关闭")
.setDb_source("no数据");
}
}
总结
什么是服务熔断?什么是服务降级?区别是什么?
相同点:
不同点:
熔断是下游服务故障触发的,降级是为了降低系统负载
服务熔断
服务降级
@EnableHystrixDashboard //开启
直接访问
概述
什么是Zuul?
路由
过滤
主启动类加上注解@EnableZuulProxy //zuul启动
访问地址:http://www.liangstudy.com:9527/springcloud-provider-dept/dept/get/1
zuul:
routes:
mydept.serviceId: springcloud-provider-dept # 配置自定义路径
mydept.path: /mydept/**
ignored-services: "*" # 忽略全部
#ignored-services: springcloud-provider-dept #不能再使用这个路径访问
prefix: /liang #设置访问公共的前缀
http://www.liangstudy.com:9527/mydept/dept/get/1
http://www.liangstudy.com:9527/liang/mydept/dept/get/1
概述
分布式系统面临的–配置文件的问题
微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务,由于每个服务都需要必要的配置信息才能运行,所以一套集中式的,动态的配置管理设施是必不可少的。SpringCloud提供了ConfigServer来解决这个问题,我们每一个微服务自己带着一个application.yml,那上百的的配置文件要修改起来,岂不是要发疯!
Spring loud Config 为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置。
springc config 分为服务端和客户端两部分
Springcloud config分布式配置中心能干嘛
。集中管理配置文件
。不同环境,不同配置,动态化的配置更新,分环境部署,比如 /dev /test/ /prod /beta /release
。运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息。
。当配置发生变动时,服务不需要重启,即可感知到配置的变化,并应用新的配置0
。将配置信息以REST接口的形式暴露
Git add .添加到本地仓库
Git status 查看当前文件的提交状态
Git commit -m ‘描述信息’ 提交到本地暂存区
Git push上传到远程服务器
修改git的配置
$ git config --global user.email "[email protected]"
$ git config --list
$ git config --global user.name "liangweihao"
主启动类加上注解@EnableConfigServer
访问路径:http://localhost:3344/application-dev.yml
客户端拿服务端的代码