Spring Cloud Ribbon

Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于 Netflix Ribbon 实现。 通过 Spring Cloud 的封装, 可以让我们轻松地将面向服务的 REST 模板请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon 虽然只是一个工具类框架,它不像服务注册中心、 配置中心、 API 网关那样需要独立部署, 但是它几乎存在于每一个Spring Cloud 构建的微服务和基础设施中。

服务端负载均衡

负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容。 因为负载均衡是对系统的高可用、 网络压力的缓解和处理能力扩容的重要手段之一。 我们通常所说的负载均衡都指的是服务端负载均衡, 其中分为硬件负载均衡和软件负载均衡。 硬件负载均衡主要通过在服务器节点之间安装专门用于负载均衡的设备,比如 F5 等;而软件负载均衡则是通过在服务器上安装一些具有均衡负载功能或模块的软件来完成请求分发工作, 比如Nginx等。不论采用硬件负载均衡还是软件负载均衡,只要是服务端负载均衡都能以类似下图的架构:

Spring Cloud Ribbon


件负载均衡的设备或是软件负载均衡的软件模块都会维护一个下挂可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候, 该设备按某种算法(比如线性轮询、 按权重负载、 按流量负载等)从维护的可用服务端清单中取出一台服务端的地址, 然后在负载均衡服务器内部进行转发。

客户端负载均衡

客户端负载均衡和服务端负载均衡最大的不同点在千上面所提到的服务清单所存储的位置。 在客户端负载均衡中, 所有客户端节点都维护着自己要访问的服务端清单, 而这些服务端的清单来自于服务注册中心,比如上一章我们介绍的Eureka服务端。同服务端负载均衡的架构类似, 在客户端负载均衡中也需要心跳去维护服务端清单的健康性, 只是这个步骤需要与服务注册中心配合完成。

Spring Cloud Ribbon


RestTemplate

Get请求

@RequestMapping
(
"queryAll"
)
public

List
<
User
>
queryByPage
(
Integer
pageNow
,
Integer
pageSize
)

{

return

...
}
String
url
=
"http://localhost:9999/queryAll"
;
Map
params
=
new

HashMap
();
params
.

put
(
"pageNow"
,
2
);
params
.
put
(
"pageSize"
,
5
);
User
[]
users
=
restTemplate
.
getForObject
(
url
,

User
[].
class
,
params
);

Post请求

@PostMapping
(
"saveUser"
)
public

void
saveUser
(
@RequestBody

User
user

)

throws

InterruptedException

{
}
String
url
=
"http://localhost:9999/saveUser"
;
User
user
=
new

User
(
"1"
,
"zhangsan"
);
user
.
setBirthDay
(
new

Date
());
restTemplate
.
postForEntity
(
url
,
user
,
null
);

Delete请求

@DeleteMapping
(

"deleteUserByIds"
)
public

void
deleteUserByIds
(
String
[]
ids
)

throws

InterruptedException

{
}
String
url
=
"http://localhost:9999/deleteUserByIds?ids={1}"
;
restTemplate
.
delete
(
url
,
"1,2,3,5"
);

搭建Ribbon测试

引入Ribbon支持

<dependencymanagement>

<dependencies>

<dependency>

<groupid>
org.springframework.cloud
/<groupid>

<artifactid>

spring-cloud-dependencies
/<artifactid>

<version>
Finchley.SR1
/<version>

<type>
pom
/<type>

<scope>
import
/<scope>

/<dependency>

/<dependencies>
/<dependencymanagement>
<dependencies>

<dependency>

<groupid>
org.springframework.cloud
/<groupid>

<artifactid>
spring-cloud-starter-netflix-ribbon
/<artifactid>

/<dependency>
/<dependencies>

添加RestTemplateBean配置

@SpringBootApplication
public

class

WebApplication

{

public

static

void
main
(
String
[]
args
)

{

SpringApplication
.
run
(
WebApplication
.
class
,
args
);

}

@Bean

@LoadBalanced

public

RestTemplate
restTemplate
(){

return

new

RestTemplate
();

}
}

配置application.properties

hello
-
service
.

ribbon
.
listOfServers
=
localhost
:
7777
,
localhost
:
8888
,
localhost
:
9999
其中 hello-service作用是命名服务,以后Ribbon的负责均衡会根据配置文件的配置的调用列表轮训调用.

测试ribbon负责均衡

@RunWith
(
SpringRunner
.
class
)
@SpringBootTest
(
classes
=

WebApplication
.
class
)
public

class

RestTemplateApplicationTests

{

@Autowired

private

RestTemplate
restTemplate
;

@Test

public

void
testHelloService
(){

String
url
=
"http://hello-service/test"
;

String
forObject
=
restTemplate
.
getForObject
(
url
,

String
.
class
);

System
.
out
.
println
(
forObject
);

}
}
测试多次尝试负载均衡效果 : )

Ribbon和Eureka集成

启动web实例,作为服务提供端

  • 依赖清单

<parent>

<groupid>
org.springframework.boot
/<groupid>

<artifactid>
spring-boot-dependencies
/<artifactid>

<version>
2.0.5.RELEASE
/<version>
/<parent>

<dependencymanagement>

<dependencies>

<dependency>

<groupid>
org.springframework.cloud
/<groupid>

<artifactid>
spring-cloud-dependencies
/<artifactid>

<version>
Finchley.SR1
/<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.cloud
/<groupid>

<artifactid>
spring-cloud-starter-netflix-eureka-server
/<artifactid>

/<dependency>
/<dependencies>
<build>

<plugins>



<plugin>

<groupid>
org.springframework.boot
/<groupid>

<artifactid>
spring-boot-maven-plugin
/<artifactid>

/<plugin>

/<plugins>
/<build>
  • 代码清单
|-
java

|-
com
.
jiangzz

|-
controller

|-
UserController
.
java

|-

WebIntanceApplication
.
java
|-
resources

|-
application
-
app1
.
properties


|-
application
-
app2
.
properties
  • 启动web实例,并且将服务注册到eureka注册中心


UserController.java

package
com
.
jiangzz
.
controller
;
import
org
.
springframework
.
web
.
bind
.
annotation
.
RequestMapping
;
import
org
.
springframework
.
web
.
bind
.
annotation
.

RestController
;
@RestController
public

class

UserController

{

@RequestMapping
(
"hello"
)

public

String
helloService
(){

return

"哈喽!"
;

}
}

application-app1.properites

server
.
port
=
9091
# 配置服务
spring
.
application
.
name
=
user
-
service
eureka
.

instance
.
instance
-
id
=
user
-
server
-
1
eureka
.
instance
.
prefer
-
ip
-
address
=

true
eureka
.
instance
.
lease
-
renewal
-
interval
-
in
-
seconds
=

2
eureka
.
instance
.
lease
-
expiration
-
duration
-
in

-
seconds
=

6
# 注册Eureka
eureka
.
client
.
fetch
-
registry
=
false
eureka
.
client
.
service
-
url
.
defaultZone
=
http
:
//eureka:1111/eureka,http://eureka:2222/eureka,http://eureka:3333/eureka

application-app2.properites

server
.
port
=
9092
# 配置服务
spring
.
application
.
name
=
user
-
service
eureka
.
instance

.
instance
-
id
=
user
-
server
-
2
eureka
.
instance
.
prefer
-
ip
-
address
=

true
eureka
.
instance
.
lease
-
renewal
-
interval
-
in
-
seconds
=

2
eureka
.
instance
.
lease
-
expiration
-
duration
-
in
-

seconds
=

6
# 注册Eureka
eureka
.
client
.
fetch
-
registry
=
false
eureka
.
client
.
service
-
url
.
defaultZone
=
http
:
//eureka:1111/eureka,http://eureka:2222/eureka,http://eureka:3333/eureka

WebIntanceApplication.java

package
com
.
jiangzz
;
import
org
.
springframework
.
boot
.
SpringApplication
;
import
org
.
springframework
.

boot
.
autoconfigure
.
SpringBootApplication
;
import
org
.
springframework
.
cloud
.
netflix
.
eureka
.
EnableEurekaClient
;
@SpringBootApplication
@EnableEurekaClient
public

class

WebInstanceApplication

{

public

static

void
main
(
String
[]
args
)

{

SpringApplication
.
run
(
WebInstanceApplication
.
class

,
args
);

}
}

启动之后服务查看Eureka服务

Spring Cloud Ribbon


启动Web消费端,集成Ribbon

  • 依赖清单

<parent>

<groupid>
org.springframework.boot
/<groupid>

<artifactid>
spring-boot-dependencies
/<artifactid>

<version>
2.0.5.RELEASE
/<version>
/<parent>

<dependencymanagement>

<dependencies>

<dependency>

<groupid>
org.springframework.cloud
/<groupid>

<artifactid>
spring-cloud-dependencies
/<artifactid>

<version>
Finchley.SR1
/<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.cloud
/<groupid>

<artifactid>
spring-cloud-starter-netflix-eureka-server
/<artifactid>

/<dependency>

<dependency>

<groupid>
org.springframework.cloud
/<groupid>

<artifactid>
spring-cloud-starter-netflix-ribbon
/<artifactid>

/<dependency>
/<dependencies>
<build>

<plugins>



<plugin>

<groupid>
org.springframework.boot
/<groupid>

<artifactid>
spring-boot-maven-plugin
/<artifactid>

/<plugin>

/<plugins>
/<build>
  • 代码清单
|-
java

|-
com
.
jiangzz

|-

WebInstanceApplication
.
java

|-
controller

|-

UserRestController
.
java
|-
resources

|-
application

.
properties

WebInstanceApplication.java

package
com
.
jiangzz
;
import
org
.
springframework
.
boot
.
SpringApplication
;
import
org
.
springframework
.
boot
.
autoconfigure
.
SpringBootApplication
;
import
org
.
springframework
.
cloud
.
client
.
discovery
.
EnableDiscoveryClient
;
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
;
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public

class

WebInstanceApplication


{

public

static

void
main
(
String
[]
args
)

{

SpringApplication
.
run
(
WebInstanceApplication
.
class
,
args
);

}

@Bean

@LoadBalanced

public

RestTemplate
restTemplate
(){

return

new

RestTemplate
();

}
}

UserRestController.java

package
com
.
jiangzz
.
controller
;
import
org
.
springframework
.
beans
.
factory
.
annotation
.
Autowired
;
import
org
.
springframework
.
web
.
bind
.
annotation
.
RequestMapping
;
import
org
.
springframework
.
web
.
bind
.
annotation
.
RestController
;
import

org
.
springframework
.
web
.
client
.
RestTemplate
;
@RestController
public

class

UserRestController

{

@Autowired

private

RestTemplate
restTemplate
;

@RequestMapping
(
"hello"
)

public

String
hello
(){

return
restTemplate
.
getForObject
(
"http://USER-SERVICE/hello"
,
String
.
class
);

}
}

application.properties

# 服务端口
server
.
port
=
9999
# 配置消费者
spring
.
application
.
name
=
user
-
service
-
consumer
eureka
.
instance
.
prefer
-
ip
-
address
=
true
# 注册Eureka
eureka
.
client
.
fetch
-
registry
=
true
eureka
.
client
.

service
-
url
.
defaultZone
=
http
:
//eureka:1111/eureka,http://eureka:22


分享到:


相關文章: