SpringCloud
1. 概念
1.1 微服务的技术栈1.2 Spring Cloud是什么1.3 Spring Cloud技术栈1.4 为什么使用Spring Cloud1.5 服务治理1.6 负载均衡1.7 容错保护1.8 服务网关 2. 创建注册中心Eureka
2.1 添加依赖2.2 写配置文件2.3 启动2.4 结果演示2.5 小笔记 3. 创建会员服务
3.1 添加依赖3.2 配置文件3.3 创建MemberController与MemberService3.4 启动3.5 演示结果3.6 小笔记 4. 创建订单服务
4.1 添加依赖4.2 配置文件4.3 创建OrderController和OrderService4.4 启动4.5 演示结果4.6 小笔记 5. 网关配置
5.1 添加依赖5.2 配置文件5.3 创建过滤器5.4 启动5.5 结果演示5.6 小笔记 6. 解决雪崩效应
6.1 添加依赖6.2 配置文件6.3 使用Feign 重写service层和控制层,以及添加fallback6.4 启动6.5 演示6.6 小笔记
SpringCloud 1. 概念 1.1 微服务的技术栈负载均衡,网关路由:高可用、集群部署,校验、请求转发、服务集成。服务治理:服务注册、发现。容错:避免雪崩。监控跟踪:监控资源利用、服务响应、容器资源利用情况。消息总线:消息队列、异步通信。配置管理:统一配置管理。 1.2 Spring Cloud是什么
Spring Cloud为开发人员构建微服务架构提供了完整的解决方案,SpringCloud是若干个框架的集合,它包括spring-cloud-config、spring-cloud-bus等近20个子项目,它提供了服务治理、服务网关、智能路由、负载均衡、断路器、监控跟踪、分布式消息队列、配置管理等领域的解决方案。
1.3 Spring Cloud技术栈 微服务的兴起出现了很多优秀的公司和技术:
服务治理:Dubbo(阿里巴巴)、Dubbox(当当)、Eureka(Netflix)等 。配置管理:Disconf(百度)、QConf(360)、Diamood(淘宝)等 。服务跟踪:Hydra(京东)、Zipkin(Twitter)、Sleuth(Spring Cloud)等 。 1.4 为什么使用Spring Cloud
微服务架构的优点表明它可以提高我们的生产力,但是分布式系统本身的技术成本问题给互联网那些创业型公司不少的挑战,阿里、百度等巨头所提供的微服务技术只是解决其中某个问题,而整合封装这些优秀的技术恐怕是Spring最擅长的领域了,Spring Cloud也正因为此而诞生。
使用Spring Cloud来构建微服务架构可以省去你整合各家技术的成本,Spring Cloud为我们构建微服务架构提供了一站式的解决方案,就好比当初Spring诞生是为解决EJB企业应用开发的众多问题而提供的一站式轻量级企业应用开发解决方案一样,随着使用Spring Cloud公司数量的增加,相信微服务将被Spring Cloud一统江湖。
- 什么是服务治理:
- 微服务架构的缺点中最主要的就是由于微服务数量众多导致维护成本巨大,服务治理为解决此问题而产生的。服务治理的作用是让维护人员从人工维护中解放出来,由服务自维护,微服务作为服务提供方主动向服务治理中心注册,服务的消费方通过服务治理中心查询需要的服务并进行调用。
1.6 负载均衡
负载均衡是微服务架构中必须使用的技术,通过负载均衡来实现系统的高可用、集群扩容等功能。负载均衡可通过硬件设备及软件来实现,硬件比如:F5、Array等 ,软件比如:LVS、Nginx等 。
用户请求先到达负载均衡器(也相当于一个服务),负载均衡器根据负载均衡算法将请求转发到微服务。负载均衡算法有:轮训、随机、加权轮训、加权随机、地址哈希等方法,负载均衡器维护一份服务列表,根据负载均衡算法将请求转发到相应的微服务上,所以负载均衡可以为微服务集群分担请求,降低系统的压力。
1.7 容错保护
容错保护是指微服务在执行过程中出现错误并从错误中恢复的能力。微服务容错性不好很容易导致雪崩效应,
微服务的雪崩效应表现在服务与服务之间调用,当其中一个服务无法提供服务可能导致其它服务也死掉,比如:单点登录服务调用用户信息服务查询用户信息,由于用户信息服务无法提供服务导致单点登录服务一直等待,从而导致用户登录、用户退出功能无法使用,像这样由一个服务所引起的一连串的多个服务无法提供服务即是微服务的雪崩效应。
Spring Cloud Hystrix
Spring Cloud Hystrix 是基于Netflix的开源框架Hystrix的整合,它实现了断路器、线程隔离、信号隔离等容错功能。
服务网关是在微服务前边设置一道屏障,请求先到服务网关,网关会对请求进行过虑、校验、路由等处理。有了服务网关可以提高微服务的安全性,校验不通过的请求将被拒绝访问。
前边介绍的Ribbon客户端负载均衡技术可以不用经过网关,因为通常使用Ribbon完成微服务与微服务之间的内部调用,而对那些对外提供服务的微服务,比如:用户登录、提交订单等,则必须经过网关来保证微服务的安全。
Spring Cloud Zuul
Spring Cloud Zuul是整合Netflix公司的Zuul开源项目实现的微服务网关,它实现了请求路由、负载均衡、校验过虑等 功能。
2. 创建注册中心Eureka
2.1 添加依赖
pom.xml
2.2 写配置文件4.0.0 org.example springcloud-test-eureka 1.0-SNAPSHOT spring-boot-starter-parent org.springframework.boot 1.5.2.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-dependencies Dalston.RC1 pom import org.springframework.boot spring-boot-maven-plugin spring-milestones Spring Milestones https://repo.spring.io/milestone false
application.yml
server:
port: 8888
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${eureka.port}/eureka/
2.3 启动
创建EurekaApp.java
package com.zsl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
2.4 结果演示
2.5 小笔记
通过注册中心来实现各个服务的管理,方便服务的管理。 3. 创建会员服务 3.1 添加依赖
pom.xml
3.2 配置文件4.0.0 org.example springcloud-test-member 1.0-SNAPSHOT spring-boot-starter-parent org.springframework.boot 1.5.2.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-ribbon org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-dependencies Dalston.RC1 pom import org.springframework.boot spring-boot-maven-plugin spring-milestones Spring Milestones https://repo.spring.io/milestone false
application.yml
eureka:
client:
service-url:
defaultZone: http://localhost:9999/eureka/
server:
port: 9763
spring:
application:
name: member
3.3 创建MemberController与MemberService
MemberController
package com.zsl.controller;
import com.zsl.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
public class MemberController {
@Value("${server.port}")
private String port;
@Autowired
private MemberService memberService;
@RequestMapping("/getUsers")
public List getMemberList(){
return memberService.getMemberList();
}
@RequestMapping("/info")
public String getInfo(){
return "this is member service!";
}
}
MemberService
package com.zsl.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class MemberService {
public List getMemberList(){
List users = new ArrayList();
users.add("小包子");
users.add("大头");
return users;
}
}
3.4 启动
MemberApp
package com.zsl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class MemberApp {
public static void main(String[] args) {
SpringApplication.run(MemberApp.class,args);
}
}
3.5 演示结果
在注册中心的结果显示。注册中心发现了member服务
访问 会员服务的/getUsers
3.6 小笔记每一个服务都是Eureka客户端,与Eureka服务端连接,进而可以实现Eureka服务端上的服务相互连通 4. 创建订单服务 4.1 添加依赖
pom.xml
4.2 配置文件4.0.0 org.example springcloud-test-order 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-starter-eureka org.springframework.cloud spring-cloud-starter-ribbon org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-ribbon org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-dependencies Dalston.RC1 pom import org.springframework.boot spring-boot-maven-plugin spring-milestones Spring Milestones https://repo.spring.io/milestone false
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9999/eureka/
server:
port: 9764
spring:
application:
name: order
4.3 创建OrderController和OrderService
OrderController
package com.zsl.controller;
import com.zsl.service.OderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class OrderController {
@Autowired
private OderService oderService;
@RequestMapping("/getOrderUsers")
private List getOrderAll(){
System.out.println("订单服务开始调用会员服务");
return oderService.getOderByUsers();
}
@RequestMapping("/info")
public String getInfo(){
return "this is order service!";
}
}
OrderService
package com.zsl.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@SuppressWarnings("unchecked")
@Service
public class OderService {
@Autowired
RestTemplate restTemplate;
public List getOderByUsers(){
return restTemplate.getForObject("http://member:9762/getUsers",List.class);
}
}
4.4 启动
OrderApp
package com.zsl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableEurekaClient
@SpringBootApplication
public class OrderApp {
public static void main(String[] args) {
SpringApplication.run(OrderApp.class,args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
4.5 演示结果
Eureka注册中心
访问服务
4.6 小笔记一个服务调用另外一个服务可以通过另一个服务的服务名进行访问。 5. 网关配置 5.1 添加依赖
pom.xml
5.2 配置文件4.0.0 org.example springcloud-test-zuul 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-starter-eureka org.springframework.cloud spring-cloud-starter-zuul org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-dependencies Dalston.RC1 pom import org.springframework.boot spring-boot-maven-plugin spring-milestones Spring Milestones https://repo.spring.io/milestone false
application.yml
eureka:
client:
service-url:
defaultZone: http://localhost:9999/eureka/
server:
port: 9966
spring:
application:
name: network
zuul:
host:
connect-timeout-millis: 60000
socket-timeout-millis: 60000
routes:
api-a:
path: /api-member/**
service-id: member
api-b:
# 自定义路径
path: /api-order/**
# 服务id
service-id: rder
5.3 创建过滤器
package com.zsl.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class TokenFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(TokenFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx =RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("token");
if (accessToken != null) {
return null;
}
log.warn("token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
} catch (Exception e) {
}
return null;
}
}
5.4 启动
package com.zsl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class ZuulApp {
public static void main(String[] args) {
SpringApplication.run(ZuulApp.class,args);
}
}
5.5 结果演示
通过访问这个 api-xxx 路径来访问 5.6 小笔记
网关通过设置路由,来确定每个路径去向哪个服务器,从而实现对每个服务的把控。 6. 解决雪崩效应 6.1 添加依赖
pom.xml
6.2 配置文件4.0.0 org.example springcloud-test-feign-order 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-starter-eureka org.springframework.cloud spring-cloud-starter-ribbon org.springframework.cloud spring-cloud-starter-hystrix org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-feign org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-dependencies Dalston.RC1 pom import org.springframework.boot spring-boot-maven-plugin spring-milestones Spring Milestones https://repo.spring.io/milestone false
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9999/eureka/
server:
port: 9765
tomcat:
max-threads: 50
spring:
application:
name: service-order-feign
feign:
hystrix:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 4000
6.3 使用Feign 重写service层和控制层,以及添加fallback
feign是 是Netflix开发的声明式,模板化的HTTP客户端 ,能更加优雅的调用rest api同restTemplate
Hystrix 叫做断路器/熔断器。微服务系统中,整个系统出错的概率非常高,因为在微服务系统中,涉及到的模块太多了,每一个模块出错,都有可能导致整个服务出现故障,当所有模块都稳定运行时,整个服务才算是稳定运行。
controller
package com.zsl.controller;
import com.zsl.service.MemberFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class OderFeignController {
@Autowired
private MemberFeign memberFeign;
@RequestMapping("/getOderByUserList")
public List getOderByUserList(){
System.out.println("掉用service-member服务");
return memberFeign.getOderByUserList();
}
@RequestMapping("/getInfo")
public String getInfo(){
return "info";
}
}
service
package com.zsl.service;
import com.zsl.fallback.FallBack;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
import java.util.Map;
@FeignClient(value = "service-member",fallback = FallBack.class)
public interface MemberFeign {
@RequestMapping("/getMember")
public List getOderByUserList();
}
fallback
package com.zsl.fallback;
import com.zsl.service.MemberFeign;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class FallBack implements MemberFeign {
@Override
public List getOderByUserList() {
List map = new ArrayList<>();
map.add("no order list");
System.out.println("服务器发生异常..............");
return map;
}
}
6.4 启动
package zsl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
public class FeignApp {
public static void main(String[] args) {
SpringApplication.run(FeignApp.class,args);
}
}
6.5 演示
改造会员服务的service代码,每次请求睡眠三秒,创建雪崩效应场景。
使用压力测试
同时发送51次请求
最终展示结果是:访问/getInfo连接不影响,而有的 访问/getOderByUserList的请求会被段掉,调用fallback
.测试的时候,刷新浏览器,最终返回本地服务。
测试的请求,有的也被返回本地服务
6.6 小笔记
使用Feign,以接口的形式调用rest api
使用hytrix 解决服务器的雪崩效应。
四个机制:
隔离(线程池隔离和信号量隔离):限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
降级:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。
熔断:当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。



