1. 程式人生 > >二十五、SpringBoot與分散式(Zookeeper和Dubbo、Spring Boot和Spring Cloud)

二十五、SpringBoot與分散式(Zookeeper和Dubbo、Spring Boot和Spring Cloud)

一、分散式應用

在分散式系統中,國內常用zookeeper+dubbo組合,而SpringBoot推薦使用全棧的Spring,SpringBoot+SpringCloud。

分散式系統:

  • 單一應用架構

當網站流量很小時,只需一個應用,將所有功能都部署在一起,以減少部署節點和成本。此時,用於簡化增刪改查工作量的資料訪問框架(ORM)是關鍵。

  • 垂直應用架構

當訪問量逐漸增大,單一應用增加機器帶來的加速度越來越小,將應用拆成互不相干的幾個應用,以提升效率。此時,用於加速前端頁面開發的Web框架(MVC)是關鍵。

  • 分散式服務架構

當垂直應用越來越多,應用之間互動不可避免,將核心業務抽取出來,作為獨立的服務,逐漸形成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。此時, 用於提高業務複用及整合的分散式服務框架(RPC)是關鍵。

  • 流動計算架構

當服務越來越多,容量的評估,小服務資源的浪費等問題逐漸顯現,此時需增加一個排程中心基於訪問壓力實時管理叢集容量,提高叢集利用率。此時,用於提高機器利用率的資源排程和治理中心(SOA)是關鍵。

二、Zookeeper和Dubbo

  • ZooKeeper

ZooKeeper 是一個分散式的,開放原始碼的分散式應用程式協調服務。它是 一個為分散式應用提供一致性服務的軟體,提供的功能包括:配置維護、 域名服務、分散式同步、組服務等。

  • Dubbo

Dubbo是Alibaba開源的分散式服務框架,它最大的特點是按照分層的方式來架構,使用這種方式可以使各個層之間解耦合(或者最大限度地鬆耦合)。從服務模型的角度來看,Dubbo採用的是一種非常簡單的模型,要麼是提供方提供服務,要麼是消費方消費服務,所以基於這一點可以抽象出服務提供方(Provider)和服務消費方(Consumer)兩個角色。

1、將服務提供者註冊到註冊中心

  • 1.引入dubbo和zkclient相關依賴
        <!-- 引入dubbo -->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.1.0</version>
        </dependency>
        <!-- 引入zookeeoer的客戶端工具 -->
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
  • 2.配置dubbo的掃描包和註冊中心地址
dubbo.application.name=provider-ticket
dubbo.registry.address=zookeeper://192.168.3.226:2181
dubbo.scan.base-packages=com.atguigu.ticket.service
  • 3.使用@Service 釋出服務
package com.atguigu.ticket.service;

public interface TicketService {
    public String getTicket();
}


package com.atguigu.ticket.service;

import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;

@Component
@Service //將服務釋出出去
public class TicketServiceImpl implements TicketService{
    @Override
    public String getTicket() {
        return "《hahaha》";
    }
}

2、將服務消費者註冊到註冊中心

  • 1.引入dubbo和zkclient相關依賴
        <!-- 引入dubbo -->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.0</version>
        </dependency>
        <!-- 引入zookeeoer的客戶端工具 -->
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
  • 2.配置dubbo的掃描包和註冊中心地址
dubbo.application.name=consumer-user
dubbo.registry.address=zookeeper://192.168.3.227:2182
  • 3.引用服務
package com.atguigu.ticket.service;

public interface TicketService {
    public String getTicket();
}

package com.atguigu.user.service;

import com.alibaba.dubbo.config.annotation.Reference;
import com.atguigu.ticket.service.TicketService;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Reference
    TicketService ticketService;
    public void hello(){
       String ticket = ticketService.getTicket();
       System.out.println("買到票拉"+ticket);
    }
}

3、遇到一個問題沒有解決:'消費方'註解引用'提供方'的介面時報空指標

java.lang.NullPointerException
	at com.atguigu.user.service.UserService.hello(UserService.java:13)
	at com.atguigu.user.ConsumerUserApplicationTests.contextLoads(ConsumerUserApplicationTests.java:18)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

三、Spring Boot和Spring Cloud

1、Spring Cloud

Spring Cloud是一個分散式的整體解決方案。Spring Cloud 為開發者提供了在分散式系統(配 置管理,服務發現,熔斷,路由,微代理,控制匯流排,一次性token,全域性瑣,leader選舉,分 布式session,叢集狀態)中快速構建的工具,使用Spring Cloud的開發者可以快速的啟動服務或構建應用、同時能夠快速和雲平臺資源進行對接。

SpringCloud分散式開發五大常用元件

  • 服務發現——Netflix Eureka
  • 客服端負載均衡——Netflix Ribbon
  • 斷路器——Netflix Hystrix
  • 服務閘道器——Netflix Zuul
  • 分散式配置——Spring Cloud Config

2、微服務

3、Spring Cloud 入門

  • 1.建立註冊中心

/** * 1、引入eureka * 2、配置Eureka資訊 * 3、@EnableEurekaServer  //啟用註冊中心的功能 * */

pom.xml

                <!-- 引入eureka -->
                <dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		</dependency>

application.yml

# 配置Eureka資訊
server:
  port: 8761
eureka:
  instance:
    hostname: eureka-server # eureka例項的主機名
  client:
    register-with-eureka: false #不把自己註冊到eureka上
    fetch-registry: false #不從eureka上來獲取服務到註冊資訊
    service-url:
      defaultZone: http://localhost:8761/eureka/

EurekaServerApplication

//啟用註冊中心的功能
@EnableEurekaServer  
@SpringBootApplication
public class EurekaServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(EurekaServerApplication.class, args);
	}
}
  • 2.建立provider

/** * 1、引入eureka-client * 2、配置Eureka資訊 * 3、寫service和control並執行,將服務註冊進註冊中心 * */

pom.xml

                <!-- 引入eureka-client -->                
                <dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
                <!-- 引入web -->               
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

application.yml

server:
  port: 8002
spring:
  application:
    name: provider-ticket
eureka:
  instance:
    prefer-ip-address: true #註冊服務的時候使用服務的ip地址
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

Service

@Service
public class TicketService {
    public String getTicket(){
        System.out.println("8002");
        return "<鬥牛>";
    }
}

Controller

@RestController
public class TicketController {
    @Autowired
    TicketService ticketService;
    @GetMapping("/ticket")
    public  String getTicket(){
        return ticketService.getTicket();
    }
}

執行測試結果

  • 3.建立consumer

/** * 1、引入eureka-client * 2、配置Eureka資訊 * 3、@EnableDiscoveryClient //開啟發現服務功能 * 4、使用RestTemplate 傳送http請求的 * 5、@LoadBalanced //使用負載均衡機制 * */

pom.xml

                <!-- 引入eureka-client -->                
                <dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
                <!-- 引入web -->               
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

application.yml

server:
  port: 8200
spring:
  application:
    name: consumer-user
eureka:
  instance:
    prefer-ip-address: true #註冊服務的時候使用服務的ip地址
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

ConsumerUserApplication

@EnableDiscoveryClient //開啟發現服務功能
@SpringBootApplication
public class ConsumerUserApplication {
	public static void main(String[] args) {
		SpringApplication.run(ConsumerUserApplication.class, args);
	}

	//傳送http請求的
	@LoadBalanced //使用負載均衡機制
	@Bean
	public RestTemplate restTemplate(){
		return new RestTemplate();
	}
}

Controller

@RestController
public class UserController {
    @Autowired
    RestTemplate restTemplate;
    @GetMapping("/buy")
    public String buyTicket(String name){
        String s = restTemplate.getForObject("http://PROVIDER-TICKET/ticket", String.class);
        return "購買力"+name+s;
    }
}

執行測試結果

  • 4.provider多例項測試

1.將不同埠號的provider-ticket打包放在service資料夾中

2.在兩個終端視窗啟動兩個服務

Amy:~ Amy$ cd /Users/Amy/Downloads/service 
Amy:service Amy$ java -jar provider-ticket-0.0.1-8001SNAPSHOT.jar

Amy:~ Amy$ cd /Users/Amy/Downloads/service 
Amy:service Amy$ java -jar provider-ticket-0.0.1-8002SNAPSHOT.jar

3.啟動ConsumerUserApplication

4.執行ConsumerUser的buy方法(多次執行),啟用了負載均衡機制