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


分享到:


相關文章: