springcloud高级

第一章 负载均衡 Ribbon

 
(Spring Cloud 高级)
 

一、 Ribbon 在微服务中的作用

 

1 什么是 Ribbon

 
1.Ribbon 是一个基于 Http 和 TCP 的客服端负载均衡工具,它是基于 Netflix Ribbon 实
现的。
2.它不像 spring cloud 服务注册中心、配置中心、API 网关那样独立部署,但是它几乎
存在于每个 spring cloud 微服务中。包括 feign 提供的声明式服务调用也是基于该 Ribbon
实现的。
3.ribbon 默认提供很多种负载均衡算法,例如 轮询、随机 等等。甚至包含自定义的负
载均衡算法。
 

2 Ribbon 解决了什么问题

 
他解决并提供了微服务的负载均衡的问题。
 

二、 集中式与进程内负载均衡的区别

 

1 负载均衡解决方案的分类

 
目前业界主流的负载均衡方案可分成两类:
 
第一类:集中式负载均衡, 即在 consumer 和 provider 之间使用独立的负载均衡设施(可
以是硬件,如 F5, 也可以是软件,如 nginx), 由该设施负责把 访问请求 通过某种策略转发
至 provider;
 
第二类:进程内负载均衡,将负载均衡逻辑集成到 consumer,consumer 从服务注册中
心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的 provider。
Ribbon 就属于后者,它只是一个类库,集成于 consumer 进程,consumer 通过它来获取
到 provider 的地址。
 
 

2 两种负载均衡方式结构图

三、 Ribbon 的入门案例

 
Ribbon 中对于集群的服务采用的负载均衡的策略默认的是轮询
 

1 Consumer

@Service
public class UserService {
@Autowired
private LoadBalancerClient loadBalancerClient;//ribbon 负
载均衡器
public List<User> getUsers(){
//选择调用的服务的名称
//ServiceInstance 封装了服务的基本信息,如 IP,端口
ServiceInstance si = 
this.loadBalancerClient.choose("eureka-provider");
//拼接访问服务的 URL
StringBuffer sb = new StringBuffer();
//http://localhost:9090/user
sb.append("http://").append(si.getHost()).append(":").appen
d(si.getPort()).append("/user");
System.out.println(sb.toString());
//springMVC RestTemplate
RestTemplate rt = new RestTemplate();
ParameterizedTypeReference<List<User>> type = new
ParameterizedTypeReference<List<User>>() {};
//ResponseEntity:封装了返回值信息
ResponseEntity<List<User>> response = 
rt.exchange(sb.toString(),HttpMethod.GET, null, type);
List<User> list =response.getBody();
return list; } }
View Code

2 Consumer 的配置文件

spring.application.name=eureka-consumer
server.port=9091
#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://user:123456@eur
eka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/

3 Provider 的集群部署

 

3.1将 provider 打包。部署到 linux 环境中

 

3.2创建启动脚本 server.sh

#!/bin/bash
cd `dirname $0`
CUR_SHELL_DIR=`pwd`
CUR_SHELL_NAME=`basename ${BASH_SOURCE}`
JAR_NAME="springcloud-eureka-provider-0.0.1-SNAPSHOT.jar"
JAR_PATH=$CUR_SHELL_DIR/$JAR_NAME
#JAVA_MEM_OPTS=" -server -Xms1024m -Xmx1024m -XX:PermSize=128m"
JAVA_MEM_OPTS=""
#SPRING_PROFILES_ACTIV="-Dspring.profiles.active=eureka2"
SPRING_PROFILES_ACTIV=""
LOG_DIR=$CUR_SHELL_DIR/logs
LOG_PATH=$LOG_DIR/${JAR_NAME%..log
echo_help()
{
 echo -e "syntax: sh $CUR_SHELL_NAME start|stop"
}
if [ -z $1 ];then
 echo_help
 exit 1
fi
if [ ! -d "$LOG_DIR" ];then
 mkdir "$LOG_DIR"
fi
if [ ! -f "$LOG_PATH" ];then
 touch "$LOG_DIR"
fi
if [ "$1" == "start" ];then
 # check server
 PIDS=`ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk '{print $2}'`
 if [ -n "$PIDS" ]; then
 echo -e "ERROR: The $JAR_NAME already started and the PID is ${PIDS}."
 exit 1
 fi
 echo "Starting the $JAR_NAME..."
 # start
 nohup java $JAVA_MEM_OPTS -jar $SPRING_PROFILES_ACTIV $JAR_PATH >> 
$LOG_PATH 2>&1 &
 COUNT=0
 while [ $COUNT -lt 1 ]; do
 sleep 1
 COUNT=`ps --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk 
'{print $2}' | wc -l`
 if [ $COUNT -gt 0 ]; then
 break
 fi
 done
 PIDS=`ps --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print 
$2}'`
 echo "${JAR_NAME} Started and the PID is ${PIDS}."
 echo "You can check the log file in ${LOG_PATH} for details."
elif [ "$1" == "stop" ];then
 PIDS=`ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk '{print $2}'`
 if [ -z "$PIDS" ]; then
 echo "ERROR:The $JAR_NAME does not started!"
 exit 1
 fi
 echo -e "Stopping the $JAR_NAME..."
 for PID in $PIDS; do
 kill $PID > /dev/null 2>&1
 done
 COUNT=0
 while [ $COUNT -lt 1 ]; do
 sleep 1
 COUNT=1
 for PID in $PIDS ; do
 PID_EXIST=`ps --no-heading -p $PID`
 if [ -n "$PID_EXIST" ]; then
 COUNT=0
 break
 fi
 done
 done
 echo -e "${JAR_NAME} Stopped and the PID is ${PIDS}."
else
 echo_help
 exit 1
fi
View Code

4 启动 Consumer 

四、 Ribbon 的常见负载均衡策略

 

五、 Ribbon 指定其他负载均衡策略

 

1 修改代码更换负载均衡策略

 

1.1创建项目

1.2在启动类中添加创建负载均衡策略对象的方法

@EnableEurekaClient
@SpringBootApplication
public class ConsumerApplication {
7 区域敏感性策略 ZoneAvoidanceRule:
1.以一个区域为单位考察可
用性,对于不可用的区域整个丢 弃,从剩下区域中选可用的
provider
2.如果这个 ip 区域内有一个或多
个实例不可达或响应变慢,都会降
低该 ip 区域内其他 ip 被选中的权 重。
@Bean
public RandomRule createRule(){
return new RandomRule();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, 
args);
} }

2 修改配置文件更换负载均衡策略

#设置负载均衡策略 eureka-provider 为调用的服务的名称
eureka-provider.ribbon.NFLoadBalancerRuleClassName=com.netf
lix.loadbalancer.RandomRule

六、 Ribbon 的点对点直连 

2 去掉 Eureka 的坐标添加 Ribbon 坐标

<!-- ribbon 坐标 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>

3 修改配置文件去掉与 Eureka 相关的配置,添加新配置项

spring.application.name=eureka-consumer-LB
server.port=9091
#禁用 eureka
ribbon.eureka.enabled=false
#指定具体的服务实例清单
eureka-provider.ribbon.listOfServers=192.168.70.137:9090

4 修改启动类去掉报错代码

@SpringBootApplication
public class ConsumerApplication {
/*@Bean
public RandomRule createRule(){
return new RandomRule();
}*/
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, 
args);
} }

第二章 声明式服务调用 Feign

 
(Spring Cloud 高级)
 

一、 什么是 Feign

 
Feign 是一种声明式、模板化的 HTTP 客户端(仅在 consumer 中使用)。
 

二、 什么是声明式,有什么作用,解决什么问题?

 
声明式调用就像调用本地方法一样调用远程方法;无感知远程 http 请求。
 
1,Spring Cloud 的声明式调用, 可以做到使用 HTTP 请求远程服务时能就像调用本地
方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。
 
2,它像 Dubbo 一样,consumer 直接调用接口方法调用 provider,而不需要通过常规的
Http Client 构造请求再解析返回数据。
 
3,它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细
节,更无需关注分布式环境开发。
 

三、 编写 Feign 的入门案例

1 需求

 
实现 Ego 电商平台中的商品基本操作
 

2 项目设计

3 创建项目

 

3.1创建 Product-Service

 

3.1.1创建项目

3.1.2修改 pom 文件添加依赖

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.bjsxt</groupId>
 <artifactId>springcloud-ego-product-service</artifactId> <version>0.0.1-SNAPSHOT</version>
 
 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.13.RELEASE</version> <relativePath /> <!-- lookup parent from repository -->
</parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEn
coding> <project.reporting.outputEncoding>UTF-8</project.reporting.
outputEncoding> <java.version>1.8</java.version>
</properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR5</version> <type>pom</type> <scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope>
</dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId>
</dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
</project>
View Code

3.1.3创建 Service 接口

/**
* Product 服务接口
* @author Administrator
*
*/
@RequestMapping("/product")
public interface ProductService {
//查询所有商品
@RequestMapping(value="/findAll",method=RequestMethod.GE
T)
public List<Product> findAll();
}
View Code

3.1.4创建 POJO 类 

public class Product {
private Integer id;
private String name;
public Integer getId() {
return id; }
public void setId(Integer id) {
this.id = id; }
public String getName() {
return name; }
public void setName(String name) {
this.name = name; }
public Product(Integer id, String name) {
super();
this.id = id;
this.name = name; }
public Product() {
super();
// TODO Auto-generated constructor stub
} }
View Code

3.2创建 Product-Provider

 

3.2.1创建项目

3.2.2修改 pom 文件添加依赖

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.bjsxt</groupId> <artifactId>springcloud-ego-product-provider</artifactId
> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.13.RELEASE</version> <relativePath /> <!-- lookup parent from repository -->
</parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEn
coding> <project.reporting.outputEncoding>UTF-8</project.reporting.
outputEncoding> <java.version>1.8</java.version>
</properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR5</version> <type>pom</type> <scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope>
</dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId>
</dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- 添加 product-service 坐标 -->
<dependency>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-ego-product-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies> <build> <plugins>
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
View Code

3.2.3添加全局配置文件

spring.application.name=ego-product-provider
server.port=9001
#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://user:123456@eur
eka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/

3.2.4编写 Controller

/**
* Product-Provider 服务
* @author Administrator
*
*/
@RestController
public class ProductController implements ProductService {
@Override
public List<Product> findAll() {
List<Product> list = new ArrayList<>();
list.add(new Product(1, "电视"));
list.add(new Product(2, "电脑"));
list.add(new Product(3, "冰箱"));
list.add(new Product(4, "手电筒"));
return list; } }

3.2.5编写 SpringBoot 的启动类

@EnableEurekaClient
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, 
args);
} }
View Code

3.3创建 Product-consumer

3.3.1创建项目

3.3.2修改 pom 文件添加依赖

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.bjsxt</groupId> <artifactId>springcloud-ego-product-consumer</artifactId
> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.13.RELEASE</version> <relativePath /> <!-- lookup parent from repository -->
</parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEn
coding> <project.reporting.outputEncoding>UTF-8</project.reporting.
outputEncoding> <java.version>1.8</java.version>
</properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR5</version> <type>pom</type> <scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope>
</dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId>
</dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- 添加 Feign 坐标 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!-- 添加 product-service 坐标 -->
<dependency>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-ego-product-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
View Code

3.3.3添加全局配置文件

spring.application.name=ego-product-consumer
server.port=9002
#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://user:123456@eur
eka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/

3.3.4编写 Controller 

/**
* Product Consumer 服务
* @author Administrator
*
*/
@RestController
public class ProductController {
@Autowired
ProductConsumerService consumerservice;
/**
* Consumer 中的查询所有商品的方法
* @return
*/
@RequestMapping(value="/list",method=RequestMethod.GET)
public List<Product> getAll(){
return this.consumerservice.findAll();
} }
View Code

3.3.5编写 Service 接口

@FeignClient(name="ego-product-provider")
public interface ProductConsumerService extends
ProductService{
}

3.3.6编写 SpringBoot 启动类

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

四、 Feign 的请求参数处理

1 单个参数处理
 
1.1修改 Product-Service
 
 
/**
* Product 服务接口
* @author Administrator
*
*/
@RequestMapping("/product")
public interface ProductService {
//查询所有商品
@RequestMapping(value="/findAll",method=RequestMethod.GE
T)
public List<Product> findAll();
//根据商品 ID 查询商品
@RequestMapping(value="/getProductById",method=RequestMe
thod.GET)
public Product getProductById(@RequestParam("id") Integer 
id);
}
View Code
1.2修改 Product-Provider
/**
* Product-Provider 服务
* @author Administrator
*
*/
@RestController
public class ProductController implements ProductService {
@Override
public List<Product> findAll() {
List<Product> list = new ArrayList<>();
list.add(new Product(1, "电视"));
list.add(new Product(2, "电脑"));
list.add(new Product(3, "冰箱"));
list.add(new Product(4, "手电筒"));
return list; }
@Override
public Product getProductById(Integer id) {
return new Product(id, "SpringCloud");
} }
View Code
1.3修改 Product-Consumer 
/**
* Product Consumer 服务
* @author Administrator
*
*/
@RestController
public class ProductController {
@Autowired
ProductConsumerService consumerservice;
/**
* Consumer 中的查询所有商品的方法
* @return
*/
@RequestMapping(value="/list",method=RequestMethod.GET)
public List<Product> getAll(){
return this.consumerservice.findAll();
}
/**
* Consumer 中根据商品 id 查询商品
*/
@RequestMapping(value="/get",method=RequestMethod.GET)
public Product getProduct(@RequestParam("id") Integer id){
return this.consumerservice.getProductById(id);
} }
View Code
2 多个参数处理
 
2.1方式一 GET 提交方式
 
2.1.1修改 Product-Service
/**
* Product 服务接口
* @author Administrator
*
*/
@RequestMapping("/product")
public interface ProductService {
//查询所有商品
@RequestMapping(value="/findAll",method=RequestMethod.GE
T)
public List<Product> findAll();
//根据商品 ID 查询商品
@RequestMapping(value="/getProductById",method=RequestMe
thod.GET)
public Product getProductById(@RequestParam("id") Integer 
id);
//添加商品传递多个参数 方式一 :GET 方式
@RequestMapping(value="/add",method=RequestMethod.GET)
public Product addProduct(@RequestParam("id") Integer 
id,@RequestParam("name") String name);
}
View Code
 
 
2.1.2修改 Product-Provider
/**
* Product-Provider 服务
* @author Administrator
*
*/
@RestController
public class ProductController implements ProductService {
@Override
public List<Product> findAll() {
List<Product> list = new ArrayList<>();
list.add(new Product(1, "电视"));
list.add(new Product(2, "电脑"));
list.add(new Product(3, "冰箱"));
list.add(new Product(4, "手电筒"));
return list; }
@Override
public Product getProductById(Integer id) {
return new Product(id, "SpringCloud");
}
@Override
public Product addProduct(Integer id, String name) {
return new Product(id, name);
}
View Code
2.1.3修改 Product-Consumer
/**
* Product Consumer 服务
* @author Administrator
*
*/
@RestController
public class ProductController {
@Autowired
ProductConsumerService consumerservice;
/**
* Consumer 中的查询所有商品的方法
* @return
*/
@RequestMapping(value="/list",method=RequestMethod.GET)
public List<Product> getAll(){
return this.consumerservice.findAll();
}
/**
* Consumer 中根据商品 id 查询商品
*/
@RequestMapping(value="/get",method=RequestMethod.GET)
public Product getProduct(@RequestParam("id") Integer id){
return this.consumerservice.getProductById(id);
}
/**
* 商品添加 传递多个参数。方式一:GET
*/
@RequestMapping(value="/add",method=RequestMethod.GET)
public Product addProduct(Product product){
return
this.consumerservice.addProduct(product.getId(), 
product.getName());
} }
View Code

2.2方式二 POST 提交方式

 
2.2.1修改 Product-Service
/**
* Product 服务接口
* @author Administrator
*
*/
@RequestMapping("/product")
public interface ProductService {
//查询所有商品
@RequestMapping(value="/findAll",method=RequestMethod.GE
T)
public List<Product> findAll();
//根据商品 ID 查询商品
@RequestMapping(value="/getProductById",method=RequestMe
thod.GET)
public Product getProductById(@RequestParam("id") Integer 
id);
//添加商品传递多个参数 方式一 :GET 方式
@RequestMapping(value="/add",method=RequestMethod.GET)
public Product addProduct(@RequestParam("id") Integer 
id,@RequestParam("name") String name);
//添加商品传递多个参数 方式二 :POST 方式
@RequestMapping(value="/add",method=RequestMethod.POST)
public Product addProduct2(@RequestBody Product product);
}
View Code
2.2.2修改 Product-Provider
/**
* Product-Provider 服务
* @author Administrator
*
*/
@RestController
public class ProductController implements ProductService {
@Override
public List<Product> findAll() {
List<Product> list = new ArrayList<>();
list.add(new Product(1, "电视"));
list.add(new Product(2, "电脑"));
list.add(new Product(3, "冰箱"));
list.add(new Product(4, "手电筒"));
return list; }
@Override
public Product getProductById(Integer id) {
return new Product(id, "SpringCloud"); }
@Override
public Product addProduct(Integer id, String name) {
return new Product(id, name);
}
@Override
public Product addProduct2(@RequestBody Product product) {
return product;
} }
View Code
2.2.3修改 Product-Consumer 
/**
* Product Consumer 服务
* @author Administrator
*
*/
@RestController
public class ProductController {
@Autowired
ProductConsumerService consumerservice;
/**
* Consumer 中的查询所有商品的方法
* @return
*/
@RequestMapping(value="/list",method=RequestMethod.GET)
public List<Product> getAll(){
return this.consumerservice.findAll();
}
/**
* Consumer 中根据商品 id 查询商品
*/
@RequestMapping(value="/get",method=RequestMethod.GET)
public Product getProduct(@RequestParam("id") Integer id){
return this.consumerservice.getProductById(id);
}
/**
* 商品添加 传递多个参数。方式一:GET
*/
@RequestMapping(value="/add",method=RequestMethod.GET)
public Product addProduct(Product product){
return
this.consumerservice.addProduct(product.getId(), 
product.getName());
}
/**
* 商品添加 传递多个参数。方式二:POST
*/
@RequestMapping(value="/add2",method=RequestMethod.GET)
public Product addProduct2(Product product){
return this.consumerservice.addProduct2(product);
} }
View Code

五、 Feign 的性能优化

 

1 通过 Gzip 压缩算法,提升网络通信速度

 

1.1gzip 介绍

 
gzip 介绍:gzip 是一种数据格式,采用用 deflate 算法压缩 data;gzip 是一种流行的文件
压缩算法,应用十分广泛,尤其是在 Linux 平台。
gzip 能力:当 Gzip 压缩到一个纯文本文件时,效果是非常明显的,大约可以减少 70%以上的文件大小。
gzip 作用:网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可
以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏
览体验外,另一个潜在的好处是 Gzip 与搜索引擎的抓取工具有着更好的关系。例如 Google
就可以通过直接读取 gzip 文件来比普通手工抓取 更快地检索网页。
 

1.2HTTP 协议中关于压缩传输的规定

 
第一:客户端向服务器请求中带有:Accept-Encoding:gzip, deflate 字段,向服务器表示,
客户端支持的压缩格式(gzip 或者 deflate),如果不发送该消息头,服务器是不会压缩的。
第二:服务端在收到请求之后,如果发现请求头中含有 Accept-Encoding 字段,并且支
持该类型的压缩,就对响应报文压缩之后返回给客户端,并且携带 Content-Encoding:gzip 消
息头,表示响应报文是根据该格式压缩过的。
第三:客户端接收到请求之后,先判断是否有 Content-Encoding 消息头,如果有,按该
格式解压报文。否则按正常报文处理。
 

2 编写支持 Gzip 压缩案例

2.2修改配置文件

 

2.2.1只配置 Consumer 通过 Feign 到 Provider 的请求与相应

的 Gzip 压缩

#-----------------------------feign gzip
#配置请求 GZIP 压缩
feign.compression.request.enabled=true
#配置响应 GZIP 压缩
feign.compression.response.enabled=true
#配置压缩支持的 MIME TYPE
feign.compression.request.mime-types=text/xml,application/x
ml,application/json
#配置压缩数据大小的最小阀值,默认 2048
feign.compression.request.min-request-size=512

2.2.2对客户端浏览器的请求以及 Consumer 对 provider 的请

求与响应做 Gzip 压缩

#-----------------------------spring boot gzip
#是否启用压缩
server.compression.enabled=true
server.compression.mime-types=application/json,application/
xml,text/html,text/xml,text/plain

3 采用 Http 连接池,提升 Feign 的并发吞吐量

 
为什么 http 连接池能提升性能?
 

3.1http 的背景原理

 
a. 两台服务器建立 http 连接的过程是很复杂的一个过程,涉及到多个数据包的交换,并
且也很耗时间。
b. Http 连接需要的 3 次握手 4 次分手开销很大,这一开销对于大量的比较小的 http 消
息来说更大。
 

3.2优化解决方案

 
a. 如果我们直接采用 http 连接池,节约了大量的 3 次握手 4 次分手;这样能大大提升吞
吐率。
b. feign 的 http 客户端支持 3 种框架;HttpURLConnection、httpclient、okhttp;默认是
HttpURLConnection。
c. 传统的 HttpURLConnection 是 JDK 自带的,并不支持连接池,如果要实现连接池的
机制,还需要自己来管理连接对象。对于网络请求这种底层相对复杂的操作,如果有可用的
其他方案,也没有必要自己去管理连接对象。
d. HttpClient 相比传统 JDK 自带的 HttpURLConnection,它封装了访问 http 的请求头,
参数,内容体,响应等等;它不仅使客户端发送 HTTP 请求变得容易,而且也方便了开发人
员测试接口(基于 Http 协议的),即提高了开发的效率,也方便提高代码的健壮性;另外
高并发大量的请求网络的时候,还是用“连接池”提升吞吐量
 

4 将 Feign 的 Http 客户端工具修改为 HttpClient

 

4.1创建项目

4.2修改 pom 文件添加 HttpClient 的坐标
 
<!-- 使用Apache HttpClient替换Feign原生httpURLConnection --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId>
</dependency> <dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-httpclient</artifactId> <version>8.17.0</version>
</dependency>

4.3修改配置文件开启 HttpClient 的使用

 
#启用 httpclient
feign.httpclient.enabled=true
注意:如果使用 HttpClient 作为 Feign 的客户端工具。那么在定义接口上的注解是需要
注意,如果传递的是一个自定义的对象(对象会使用 json 格式来专递)。需要制定类型。
 

4.4Product-Service

/**
* Product 服务接口* @author Administrator
*
*/
@RequestMapping("/product")
public interface ProductService {
//查询所有商品
@RequestMapping(value="/findAll",method=RequestMethod.GE
T)
public List<Product> findAll();
//根据商品 ID 查询商品
@RequestMapping(value="/getProductById",method=RequestMe
thod.GET)
public Product getProductById(@RequestParam("id") Integer
id);
//添加商品传递多个参数 方式一 :GET 方式
@RequestMapping(value="/add",method=RequestMethod.GET)
public Product addProduct(@RequestParam("id") Integer
id,@RequestParam("name") String name);
//----------------------Httpclient----------------------
------------------------
//添加商品传递多个参数 方式二 :POST 方式
@RequestMapping(value="/add2",method=RequestMethod.POST,
consumes=MediaType.APPLICATION_JSON_VALUE)
public Product addProduct2(@RequestBody Product product);
//使用 HttpClient 工具 添加商品传递多个参数 :基于 GET 方式
@RequestMapping(value="/add3",method=RequestMethod.GET,c
onsumes=MediaType.APPLICATION_JSON_VALUE)
public Product addProduct3(Product product);
}
View Code
 
 

六、 查看微服务日志中记录每个接口 URL,状态码和耗时信息

 

1 创建项目

2 添加 logback.xml 文件

3 Logback 的输出日志级别需要时 debug 级别 

<!-- 日志输出级别 -->
 <root level="DEBUG"> 
 <appender-ref ref="Stdout" /> 
 <appender-ref ref="RollingFile" /> 
 </root>

4 在启动类中添加一个方法

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {
// NONE:不记录任何信息,默认值
// BASIC:记录请求方法、请求 URL、状态码和用时
// HEADERS:在 BASIC 基础上再记录一些常用信息
// FULL:记录请求和相应的所有信息
@Bean
public Logger.Level getLog(){
return Logger.Level.FULL; }
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, 
args);
} }

七、 配置 Feign 负载均衡请求超时时间

 
Feign 的负载均衡底层用的就是 Ribbon
1 修改配置文件,设置超时时间
 
1.1全局配置
#全局配置
# 请求连接的超时时间 默认的时间为 1 秒
ribbon.ConnectTimeout=5000
# 请求处理的超时时间
ribbon.ReadTimeout=5000
1.2根据服务名称进行局部超时配置
#局部配置
# 对所有操作请求都进行重试
ego-product-provider.ribbon.OkToRetryOnAllOperations=true
# 对当前实例的重试次数
ego-product-provider.ribbon.MaxAutoRetries=2
# 切换实例的重试次数
ego-product-providert.ribbon.MaxAutoRetriesNextServer=0
# 请求连接的超时时间
ego-product-provider.ribbon.ConnectTimeout=3000
# 请求处理的超时时间
ego-product-provider.ribbon.ReadTimeout=3000

猜你喜欢

转载自www.cnblogs.com/wq-9/p/12124815.html