负载均衡
Ribbon
简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中列出load Balancer后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。
Ribbon是一个客户端负载均衡器,它可以按照一定规则来完成一种多台服务器负载均衡调用,这些规则还支持自定义
接着昨天的项目接着搞
product-consumer-ribbon-9002 module
pom.xml
<dependencies>
<!--springboot支持-->
<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>
</dependency>
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.yyf</groupId>
<artifactId>product-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--客户端负载均衡实现 ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 9002
spring:
application:
name: PRODUCT-CONSUMER-RIBBON
eureka:
client:
service-url:
#defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿
#集群配置,每一个注册中心都要配置
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
instance:
prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
Java代码
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
//服务消费者获取服务列表后,要通过特定负载均衡策略,选择其中一种来完成调用。在ribbon负载均衡策略分为以下两种
// 1 内置 轮询(默认) 可用性过滤 权重 随机
// 2 自定义 IRule
// 修改负载均衡策略-只需要把负载均衡策略纳入spring管理
@Bean
public IRule myRule(){
return new RandomRule(); //随机
}
}
@RestController
@RequestMapping("/product9")
public class ProductController {
public static final String URL_PREFIX = "http://PRODUCT-SERVICE/product8/"; //通过服务名从注册中心获取服务列表,通过负载均衡调用
@Autowired
private RestTemplate restTemplate;
@GetMapping("/product/{id}")
public Product getProduct(@PathVariable("id")Long id){
//调用远程服务 http请求
String url = URL_PREFIX+id;
return restTemplate.getForObject(url,Product.class );
}
}
Feign
Feign是以接口方式进行调用,而不是通过RestTemplate来调用,feign底层还是ribbon,它进行了封装,让我们调用起来更加happy.
与上面的module相似
依赖包
<!--feign的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
application.yml
server:
port: 9003
spring:
application:
name: PRODUCT-CONSUMER-FEIGN
eureka:
client:
service-url:
#defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿
#集群配置,每一个注册中心都要配置
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
instance:
prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
入口类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients//如果你的client就在该类的子子孙孙包,否则可以指定报名
//加了它以后,就会扫描加了@FeignClient这个注解的接口,并且为这些接口产生代理对象
//并且把这些代理对象纳入spring管理,我们要使用时直接获取就可以完成远程调用
public class ProductConsumerFeign9003Application {
public static void main(String[] args) {
SpringApplication.run(ProductConsumerFeign9003Application.class, args);
}
}
feign客户端
@FeignClient(value = "PRODUCT-SERVICE")
@RequestMapping("/product8")
public interface ProductClient {
@GetMapping("/{id}")
Product getProductById(@PathVariable(name = "id")Long id);
}
Hystrix断路器
对依赖做隔离,Hystrix就是处理依赖隔离的框架,同时也是可以帮我们做依赖服务的治理和监控.。
当我们使用了Hystrix时,Hystrix将所有的外部调用都封装成一个HystrixCommand或者 HystrixObservableCommand对象,这些外部调用将会在一个独立的线程中运行。我们可以将出现 问题的服务通过熔断、降级等手段隔离开来,这样不影响整个系统的主业务
资源隔离(限流):包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
熔断:当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。
降级机制:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。
缓存:提供了请求缓存、请求合并实现。
Hystrix实现(服务提供者实现)
需要新建服务提供者 eureka-service-hystrix-8003
pom
<dependencies>
<!--springboot支持-->
<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>
</dependency>
<!--eureka客户端支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.yyf</groupId>
<artifactId>product-common</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!--断路器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 8003
spring:
application:
name: PRODUCT-SERVICE
eureka:
client:
service-url:
#defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿
#集群配置,每一个注册中心都要配置
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
instance:
prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
入口类
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix 开启Hystrix
public class ProductServicehystrix8003Application {
public static void main(String[] args) {
SpringApplication.run(ProductServicehystrix8003Application.class, args);
}
}
服务类代码
@RestController
@RequestMapping("/product8")
public class ProductController {
@GetMapping("/{id}")
@HystrixCommand(fallbackMethod = "failGet")
public Product getProductById(@PathVariable(name="id")Long id){
if (id.intValue()==2){
throw new RuntimeException("报错了!");
}
return new Product(id,"name-8002");
}
public Product failGet(Long id){
return new Product(id,"错误");
}
}
Feign实现
新建module product-consumer-hystrix-9004
pom
<dependencies>
<!--springboot支持-->
<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>
</dependency>
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.yyf</groupId>
<artifactId>product-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--客户端负载均衡实现 ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!--feign的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 9004
spring:
application:
name: PRODUCT-CONSUMER-HYSTRIX
eureka:
client:
service-url:
#defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿
#集群配置,每一个注册中心都要配置
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
instance:
prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
feign:
hystrix:
enabled: true #开启熔断支持
client:
config:
remote-service: #服务名,填写default为所有服务
connectTimeout: 3000
readTimeout: 3000
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
入口类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients//如果你的client就在该类的子子孙孙包,否则可以指定报名
//加了它以后,就会扫描加了@FeignClient这个注解的接口,并且为这些接口产生代理对象
//并且把这些代理对象纳入spring管理,我们要使用时直接获取就可以完成远程调用
public class ProductConsumerHystrix9004Application {
public static void main(String[] args) {
SpringApplication.run(ProductConsumerHystrix9004Application.class, args);
}
}
托底工厂类
@Component
public class ProductClientHystrixFallbackFactory implements FallbackFactory<ProductClient> {
@Override
public ProductClient create(Throwable throwable) {
return new ProductClient() {
@Override
public Product getProductById(Long id) {
return new Product(id,"出错了");
}
};
}
}
客户端
@FeignClient(value = "PRODUCT-SERVICE",fallbackFactory = ProductClientHystrixFallbackFactory.class)
@RequestMapping("/product8")
public interface ProductClient {
@GetMapping("/{id}")
Product getProductById(@PathVariable(name = "id")Long id);
}
把服务提供者关闭就可以测试得到效果. 或者断点超时,或者睡眠超时测试
Zuul路由网关
Zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用。
Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门,也要注册入Eureka.
创建module 创建zuul_gateway_4399
pom
<dependencies>
<!--springboot支持-->
<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>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 4399
spring:
application:
name: ZUUL-GATEWAY
eureka:
client:
service-url:
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
instance:
instance-id: gateway-4399.com
prefer-ip-address: false
zuul:
routes: #路由们 什么地址转发给那个服务
product.serviceId: product-service #服务名的小写
product.path: /product8/** #以/product开头的地址统统转发给 product-servcie服务处理
# xx.serviceId: product-servcie
# xx.path: /product
ignored-services: "*" #所有服务都不允许以服务名来访问
prefix: "/services/" #为所有服务的访问都加上统一的前缀
retryable: true
ribbon:
ConnectTimeout: 250 # 连接超时时间(ms)
ReadTimeout: 2000 # 通信超时时间(ms)
OkToRetryOnAllOperations: true # 是否对所有操作重试
MaxAutoRetriesNextServer: 2 # 同一服务不同实例的重试次数
MaxAutoRetries: 1 # 同一实例的重试次数
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMillisecond: 3000 # 熔断超时时长:3000ms
入口类
@SpringBootApplication
@EnableZuulProxy
public class ZuulGetWay4399Application {
public static void main(String[] args) {
SpringApplication.run(ZuulGetWay4399Application.class, args);
}
}
这个时候我们就能通过
直接访问地址:http://localhost:8001/product8/1
路由访问地址:http://localhost:4399/services/product8/1
SpringCloud Config分布式配置中心
微服务架构中,每个项目都有一个yml配置,管理起来麻烦,因为没有统一的地方管理,改了一点儿配置都需要改jar包。要使用spring cloud config来统一管理。
新建module
congif-server-1299
pom
<dependencies>
<!--springboot支持-->
<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>
</dependency>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--配置中心支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 1299
eureka:
client:
service-url:
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka # 集群
instance:
prefer-ip-address: true
spring:
application:
name: config-server-1299
cloud:
config:
server:
git:
uri: github的地址
username: github的账号
password:github的密码
下面是在github上存的配置,主要是方便测试
spring:
profiles:
active:
- dev
---
spring:
profiles: dev #开发环境
application:
name: MISCROSERVICE-USER-DEV
---
spring:
profiles: test #测试环境
application:
name: MISCROSERVICE-USER-TEST
入口类
@SpringBootApplication
@EnableEurekaClient //加入注册中心
@EnableConfigServer //启用配置服务端
public class ConfigServerApplication_1299 {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication_1299.class);
}
}
就可以测试了
http://localhost:1299/application-user/test
http://localhost:1299/application-user/test
新建module config_client_3355 springboot
pom
<dependencies>
<!--springboot支持-->
<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>
</dependency>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--configclient端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
bootstrap.yml
spring:
cloud:
config:
name: application-user #github上面名称
profile: dev #环境
label: master #分支
uri: http://127.0.0.1:1299 #配置服务器
eureka:
client:
service-url:
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka # 集群
instance:
prefer-ip-address: true #显示客户端真实ip
application.yml
spring:
application:
name: tset
入口类
@SpringBootApplication
@EnableEurekaClient
public class ConfigClient3355Application {
public static void main(String[] args) {
SpringApplication.run(ConfigClient3355Application.class, args);
}
}
如果读取到就会有application.name,这个名字会显示在Eureka里面,通过Eureka上面名字判断是否读取到了