Spring cloud之服務治理:Spring cloud Eureka

Spring cloud中的服務治理,大致分爲兩部分:服務註冊,服務發現。

服務治理是微服務架構中最核心最基礎的模塊,主要用來實現各個微服務模塊之間的自動化註冊與發現。在傳統的架構中,隨着服務或者模塊原來越多,需要大量的靜態配置來維護實例清單。這種狀況,無論對於開發還是運維,都是比較頭疼的事。爲了解決微服務架構中服務實例維護問題,產生了大量的服務治理框架和產品,這些框架和產品都是圍繞着服務註冊與服務發現這兩大機制完成對微服務實例的自動化管理

1.基本概念

  服務註冊:服務治理框架中,都會有一個註冊中心,每個模塊或者服務都得向註冊中心註冊自己,登記自己提供的服務,將主機與端口號,版本號,通信協議等附加信息告知註冊中心,註冊中心按服務名分類組織服務清單。通常,同樣的一個服務可能會有多個進程,比如服務A,有兩個進程分別是:192.168.0.100:8000,192.168.0.101:8000。一個服務多個實例最顯而易見的好處是:當一個實例由於種種原因掛了(比如網絡狀況,比如IO異常導致的),那麼註冊中心(Eureka Server)就能快速切換到另一個實例提供服務,這樣保證了整個系統的穩定和可靠。實現服務提供者的高可用。

而要實現這一點,這兩個實例都需要向註冊中心註冊自己,並提供相同的服務名。

服務發現:因爲各個服務都在服務治理框架下運行,服務間的調用不再通過指定具體的實例地址來訪問,比如使用http client這種方式。因爲在服務註冊中,每個服務都提供了一個獨一無二的服務名。因此服務間的調用就是通過服務名實現的。所以,服務調用方在調用服務提供方的接口時,向註冊中心獲取所有服務實例清單,找到服務提供方的服務名,再根據服務名取出服務實例,比如前面提到的192.168.0.100:8000,192.168.0.101:8000。而具體調用哪一個實例,需要以某種策略來進行決定,這就是客戶端負載均衡,這裏只是粗略地講個概念。

2. 服務註冊

Spring cloud的服務註冊使用的組件是 Spring cloud Eureka,包括服務端組件和客戶端組件。

Eureka服務端,也稱之爲服務註冊中心,並且支持高可用配置。Eureka客戶端,需要向Eureka註冊自己並對外提供服務的發現或者消費。客戶端通過註解和參數配置的方式向註冊中心註冊自己,程序在運行時,客戶端週期性向服務端發送心跳來更新它的服務租約,同時從Eureka服務端獲取服務清單並緩存到本地,週期性刷新服務狀態。

搭建服務註冊中心:

pom.xml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.liang.springcloud</groupId>
    <artifactId>spring-cloud-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-cloud-test</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <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>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
            </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Brixton.SR5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

需要提醒的是,spring boot和spring cloud版本需要對應

入口方法:

@EnableEurekaServer
@SpringBootApplication
public class SpringCloudTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudTestApplication.class, args);
    }

}

注意,@EnableEurekaServer註解啓動一個服務註冊中心。

配置文件 application.properties:

server.port=1111
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

eureka.client.register-with-eureka=false: 由於該應用爲註冊中心,所以設置爲false,表示不向自己註冊自己。

eureka.client.fetch-registry=false: 因爲註冊中心職責就是維護服務實例,設爲false,表示不需要去檢索服務。

eureka.client.serviceUrl.defaultZone: 註冊地址,在本例中,其實就是 http://localhost:1111/eureka/

啓動程序,訪問http://localhost:1111/eureka/,可以看到界面如下:

下面是一個另一個sprig boot服務,向註冊中心註冊自己。

註冊服務提供者

pom.xml文件:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.liang</groupId>
    <artifactId>service_produ</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>service_produ</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Brixton.SR5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

入口方法:

/**
 * 服務提供者
 */
@EnableDiscoveryClient
@SpringBootApplication
public class ServiceProduApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceProduApplication.class, args);
    }

}

配置文件application.yml:

spring:
  application:
    name: hello-service
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1111/eureka/

其中,spring.application.name是服務名,必須有。eureka.client.serviceUrl.defaultZone是註冊中心的註冊地址,必須和註冊中心保持一致。必須有。

提供接口的controller:

@RestController
public class HelloController {
    private final Logger logger=Logger.getLogger("liang");
    //該對象可以打印服務相關的內容
    @Autowired
    private DiscoveryClient client;
    @RequestMapping("/hello")
    public String index(){
        ServiceInstance instance=client.getLocalServiceInstance();
        //打印主機名和服務名
        logger.info("helloHost:"+instance.getHost()+",service_id:"+instance.getServiceId());
        return "Hello world";
    }
}

先後啓動服務註冊中心和這裏的hello-service服務,在Eureka的信息面板上可以看到hello-service服務。訪問"/hello"接口,日誌會輸出主機名和服務名。

高可用註冊中心:

在分佈式環境中,需要充分考慮一個節點發生故障對系統造成的影響。所以各個組件儘量以高可用的模式進行部署。註冊中心也一樣,如果系統中只有一個註冊中心的實例,一旦發生故障,那麼整個系統就癱瘓了,這不是我們想看到的。

其實,服務註冊中心既可以是服務提供方,也可以是服務消費方(需要修改註冊中心的配置文件)。Eureka Server的高可用其實就是將自己作爲服務向其他的註冊中心註冊自己,這樣可以實現服務實例清單的同步,達到高可用的效果。在Eureka 客戶端(服務提供方),需要將這些註冊中的註冊地址都寫到配置文件中,這樣一旦某個註冊中心出現問題,另外一個註冊中心就會立即工作,整個系統不會受影響。

下面是一個spring boot服務,使用Ribbon訪問其他服務的接口

3.服務發現與消費

服務消費的組件是Ribbon,Ribbon是一個基於http和tcp的客戶端負載均衡器,它可以在客戶端配置ribbonServiceList服務端列表去輪詢訪問以達到負載均衡的作用。

pom.xml:

    <groupId>com.liang</groupId>
    <artifactId>ribbon-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ribbon-consumer</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <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>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Brixton.SR5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

入口方法:

/**
 * 服務消費者
 */
@EnableDiscoveryClient//該註解讓該應用成爲Eureka客戶端應用
@SpringBootApplication
public class RibbonConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(RibbonConsumerApplication.class, args);
    }
    @Bean
    @LoadBalanced//該註解開啓客戶端負載均衡
    RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

配置文件application.yml:

spring:
  application:
    name: ribbon-consumer
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1111/eureka/
server:
  port: 9000

無論是服務提供者還是消費者,對於Eureka來說,都是客戶端,所以都要有服務名和註冊地址。

controller接口調用hello-service中的接口:

@RestController
public class ConsumerController {
    @Resource
    private RestTemplate restTemplate;
    @RequestMapping(value = "ribbon-consumer",method = RequestMethod.GET)
    public String helloConsumer(){
        //HELLO-SERVICE
        return restTemplate.getForEntity("http://HELLO-SERVICE/hello",String.class).getBody();

    }
}

啓動服務,調用該接口,就會執行hello-service中的“/hello”接口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章