Spring Cloud Ribbon 是一個基於 HTTP 和 TCP 的客戶端負載均衡工具,它基於 Netflix Ribbon 實現。 通過 Spring Cloud 的封裝, 可以讓我們輕鬆地將面向服務的 REST 模板請求自動轉換成客戶端負載均衡的服務調用。Spring Cloud Ribbon 雖然只是一個工具類框架,它不像服務註冊中心、 配置中心、 API 網關那樣需要獨立部署, 但是它幾乎存在於每一個Spring Cloud 構建的微服務和基礎設施中。
服務端負載均衡
負載均衡在系統架構中是一個非常重要,並且是不得不去實施的內容。 因為負載均衡是對系統的高可用、 網絡壓力的緩解和處理能力擴容的重要手段之一。 我們通常所說的負載均衡都指的是服務端負載均衡, 其中分為硬件負載均衡和軟件負載均衡。 硬件負載均衡主要通過在服務器節點之間安裝專門用於負載均衡的設備,比如 F5 等;而軟件負載均衡則是通過在服務器上安裝一些具有均衡負載功能或模塊的軟件來完成請求分發工作, 比如Nginx等。不論採用硬件負載均衡還是軟件負載均衡,只要是服務端負載均衡都能以類似下圖的架構:
件負載均衡的設備或是軟件負載均衡的軟件模塊都會維護一個下掛可用的服務端清單,通過心跳檢測來剔除故障的服務端節點以保證清單中都是可以正常訪問的服務端節點。當客戶端發送請求到負載均衡設備的時候, 該設備按某種算法(比如線性輪詢、 按權重負載、 按流量負載等)從維護的可用服務端清單中取出一臺服務端的地址, 然後在負載均衡服務器內部進行轉發。
客戶端負載均衡
客戶端負載均衡和服務端負載均衡最大的不同點在千上面所提到的服務清單所存儲的位置。 在客戶端負載均衡中, 所有客戶端節點都維護著自己要訪問的服務端清單, 而這些服務端的清單來自於服務註冊中心,比如上一章我們介紹的Eureka服務端。同服務端負載均衡的架構類似, 在客戶端負載均衡中也需要心跳去維護服務端清單的健康性, 只是這個步驟需要與服務註冊中心配合完成。
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其中 hello-service作用是命名服務,以後Ribbon的負責均衡會根據配置文件的配置的調用列表輪訓調用.
-
service
.
ribbon
.
listOfServers
=
localhost
:
7777
,
localhost
:
8888
,
localhost
:
9999
測試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服務
啟動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
閱讀更多 Java開發交流 的文章