SpringCloud+SpringBoot搭建服务注册与调用平台

技术需求点:

使用SpringBoot和SpringCloud Eureka搭建一个高可用的服务注册、管理与调用中心,搭建服务调用者和消费者演示如何注册、管理和调用服务,顺带介绍下Spring Eureka的原理。
其中:
1.Eureka Server搭建使用集群结构,2个节点分布于2台机器上;

一.SpringCloud Eureka集群架构

使用Eureka搭建服务注册中心需要区分服务端和客户端,服务端用来注册和管理业务服务,任何业务服务都需要通过服务端注册之后才能提供服务或消费服务,因此,Eureka服务端提供了一种注册和管理业务服务的服务(听起来有点绕)。客户端分为两个角色,业务服务提供者和业务服务消费者,作用根据其字面意思即可理解。因此,这个架构中有三个角色:Eureka Server(注册与管理服务服务端)、Application Servicer(业务服务提供者)、Application Consumer(业务服务消费者)。

举个例子,如下图所示:Application Servicer提供了一个用户查询信息的服务,Application Consumer要远程调用Application Service的查询服务去查询用户信息,在使用之前,这两个服务都必须在Eureka Server中注册登记才行,否则谁知道有哪些服务可用呢?注册登记之后,Eureka Server就可以对所有服务(无论是提供者还是消费者)进行管理,包括服务注册、续约、下线、提供服务列表等,而且为了保证挂了一个节点之后,Eureka Server的高可用,需要把Eureka Server做成集群形式。为了达到这样的目的,本次搭建就可以做成下面架构图的样子了。

image.png

解释一下:
Register(服务注册):把自己的 IP 和端口注册给 Eureka。
Renew(服务续约):发送心跳包,每 30 秒发送一次。告诉 Eureka 自己还活着。
Cancel(服务下线):当 provider 关闭时会向 Eureka 发送消息,把自己从服务列表中删除。防 止 consumer 调用到不存在的服务。
Get Registry(获取服务注册列表):获取其他服务列表。
Replicate(集群中数据同步):Eureka 集群中的数据复制与同步。
Make Remote Call(远程调用):完成服务的远程调用。

  • 准备工作

本次构建的节点规划包括:两个Eureka Server集群节点,一个业务提供者Application Servicer和一个业务消费者Application Consumer,注意起的项目名字,下面使用项目名称来介绍各个角色,整体节点规划如下表所示:

主机名 Ip:Port 角色
springcloud-eureka-server1 192.168.33.100:8761 Eureka Server(注册服务服务端)
springcloud-eureka-server2 192.168.33.101:8761 Eureka Server(注册服务服务端)
springcloud-eureka-provider Localhost(127.0.0.1):9090 Application Servicer(业务服务提供者)
springcloud-eureka-consumer Localhost(127.0.0.1):9091 Application consumer(业务服务消费者)

二.搭建高可用Eureka注册中心(Eureka Server集群)

1.项目结构


image.png

2.pom文件



    4.0.0

    com.third
    springcloud_eureka
    2.0-SNAPSHOT

    
        org.springframework.boot
        spring-boot-starter-parent
        1.5.3.RELEASE
    

    
        UTF-8
        UTF-8
        1.8
    

    
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                Dalston.SR5
                pom
                import
            
        
    


    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            org.springframework.cloud
            spring-cloud-starter-config
        

        
        
            org.springframework.cloud
            spring-cloud-starter-eureka-server
        

        
        
            ch.qos.logback
            logback-classic
            1.2.3
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


3.启动类EurekaApplication

Server端使用@EnableEurekaServer注解

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class,args);
    }
}

4.在配置文件中配置集群节点
这里要说明下,server端最后打的jar包是通用的,分别传到两台机器上之后,使用不同的配置文件启动,所以这里有两个配置文件。在搭建Eureka集群时,添加多个配置文件,并使用SpringBoot的多环境配置方式,集群中需要多少节点就添加多少配置文件。
另外,需要在linux两台机器上配置host:
vi /etc/hosts
192.168.33.100 eureka1
192.168.33.101 eureka2

4.1 application-eureka1.properties

spring.application.name=eureka-server
server.port=8761

#eureka实例名称
eureka.instance.hostname=eureka1
#设置服务注册中心地址,指向另一个注册中心,用于数据传输和通信
eureka.client.serviceUrl.defaultZone=http://eureka2:8761/eureka/

4.2 application-eureka2.properties

spring.application.name=eureka-server
server.port=8761

#eureka实例名称
eureka.instance.hostname=eureka2
#设置服务注册中心地址,指向另一个注册中心,用于数据传输和通信
eureka.client.serviceUrl.defaultZone=http://eureka1:8761/eureka/

5.Eureka集群部署
部署环境:jdk1.8,正确配置环境变量,且关闭linux的防火墙(systemctl stop firewalld.service或service iptables stop)

maven打jar包,之后上传到【192.168.33.100、192.168.33.101】两台机器上,目录可以自己指定,我的目录是/data/program/eureka。

6.启动脚本
注意:windows编辑的文本到linux上可能换行符之类的符号发生变化,自行百度格式化下。
启动脚本要修稿2个地方

  • JAR_NAME="springcloud_eureka-2.0-SNAPSHOT.jar",值(springcloud_eureka-2.0-SNAPSHOT.jar)要填写你自己maven打的jar包名;
  • SPRING_PROFILES_ACTIV="-Dspring.profiles.active=eureka1",值(eureka1)要填写你的变量文件的变量部分,我的配置文件名字(application-eureka1.properties)
#!/bin/bash

cd `dirname $0`

CUR_SHELL_DIR=`pwd`
CUR_SHELL_NAME=`basename ${BASH_SOURCE}`

JAR_NAME="springcloud_eureka-2.0-SNAPSHOT.jar"
JAR_PATH=$CUR_SHELL_DIR/$JAR_NAME

#JAVA_MEM_OPTS=" -server -Xms1024m -Xmx1024m -XX:PermSize=128m"
JAVA_MEM_OPTS=""

SPRING_PROFILES_ACTIV="-Dspring.profiles.active=eureka1"
#SPRING_PROFILES_ACTIV=""
LOG_DIR=$CUR_SHELL_DIR/logs
LOG_PATH=$LOG_DIR/${JAR_NAME%..log

echo_help()
{
    echo -e "syntax: sh $CUR_SHELL_NAME start|stop"
}

if [ -z $1 ];then
    echo_help
    exit 1
fi

if [ ! -d "$LOG_DIR" ];then
    mkdir "$LOG_DIR"
fi

if [ ! -f "$LOG_PATH" ];then
    touch "$LOG_DIR"
fi

if [ "$1" == "start" ];then

    # check server
    PIDS=`ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk '{print $2}'`
    if [ -n "$PIDS" ]; then
        echo -e "ERROR: The $JAR_NAME already started and the PID is ${PIDS}."
        exit 1
    fi

    echo "Starting the $JAR_NAME..."

    # start
    nohup java $JAVA_MEM_OPTS -jar $SPRING_PROFILES_ACTIV $JAR_PATH >> $LOG_PATH 2>&1 &

    COUNT=0
    while [ $COUNT -lt 1 ]; do
        sleep 1
        COUNT=`ps  --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print $2}' | wc -l`
        if [ $COUNT -gt 0 ]; then
            break
        fi
    done
    PIDS=`ps  --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print $2}'`
    echo "${JAR_NAME} Started and the PID is ${PIDS}."
    echo "You can check the log file in ${LOG_PATH} for details."

elif [ "$1" == "stop" ];then

    PIDS=`ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk '{print $2}'`
    if [ -z "$PIDS" ]; then
        echo "ERROR:The $JAR_NAME does not started!"
        exit 1
    fi

    echo -e "Stopping the $JAR_NAME..."


    for PID in $PIDS; do
        kill $PID > /dev/null 2>&1
    done

    COUNT=0
    while [ $COUNT -lt 1 ]; do
        sleep 1
        COUNT=1
        for PID in $PIDS ; do
            PID_EXIST=`ps --no-heading -p $PID`
            if [ -n "$PID_EXIST" ]; then
                COUNT=0
                break
            fi
        done
    done

    echo -e "${JAR_NAME} Stopped and the PID is ${PIDS}."
else
    echo_help
    exit 1
fi

7.启动eureka注册中心
./server.shstart 启动
./server.shstop 停止
项目中用logback添加了日志,配置文件logback.xml,打印在/data/program/eureka/catalina.base_IS_UNDEFINED/logs目录下。

通过浏览器访问注册中心的管理页面【192.168.33.100:8761、192.168.33.101:8761】,如果看到以下界面,证明Eureka Server集群搭建成功(Instance currently...处,此时应该只有第三个Eureka Server的服务注册上来,我这个截图是截的最后的)。


image.png

三.在高可用的Eureka注册中心构建provider服务

1.项目结构


image.png

2.pom文件
与server的pom基本一致,不一样的地方是client的artifactId用的是spring-cloud-starter-eureka



    4.0.0

    com.third
    springcloud-eureka-provider
    3.0-SNAPSHOT
    jar

    
        org.springframework.boot
        spring-boot-starter-parent
        1.5.3.RELEASE
    

    
        UTF-8
        UTF-8
        1.8
    

    
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                Dalston.SR5
                pom
                import
            
        
    


    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            org.springframework.cloud
            spring-cloud-starter-config
        

        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
        

        
            ch.qos.logback
            logback-classic
            1.2.3
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


3.启动类
client端用的是@EnableEurekaClient注解

@EnableEurekaClient
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class,args);
    }
}

4.provider的配置文件
该服务名字是eureka-provider,该服务提供者把自己的服务注册给Eureka Server注册中心,因为是集群,所以注册给2个节点

spring.application.name=eureka-provider
server.port=9090

#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://192.168.33.100:8761/eureka/,http://192.168.33.101:8761/eureka/

5.编写服务接口
5.1 创建接口

@RestController
public class UserController {

    @RequestMapping("/user")
    public List getUsers(){
        List list=new ArrayList<>();
        list.add(new User(1,"zhagnsan",20));
        list.add(new User(2,"lisi",21));
        list.add(new User(3,"wangwu",22));
        return list;
    }
}

5.2 创建实体

public class User {

    private int userid;
    private String username;
    private int userage;

    public int getUserid() {
        return userid;
    }

    public void setUserid(int userid) {
        this.userid = userid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getUserage() {
        return userage;
    }

    public void setUserage(int userage) {
        this.userage = userage;
    }

    public User(int userid, String username, int userage) {
        this.userid = userid;
        this.username = username;
        this.userage = userage;
    }

    public User() {
        super();
    }
}

启动工程后,可以看到eureka-provider服务提供者已经注册到注册中心,调用UserConller的接口也可以调通。

四.在高可用的Eureka注册中心构建consumer服务

1.项目结构


image.png

2.pom文件与provider的服务除了项目名不同其它完全一致

3.Consumer的配置文件
同样,消费者也需要注册到注册中心

spring.application.name=eureka-consumer
server.port=9091

#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://192.168.33.100:8761/eureka/,http://192.168.33.101:8761/eureka/

4.创建service,在service中完成服务的调用
在consumer中写了个service,在service中通过http请求的形式调用了provider提供的服务。
注意:ServiceInstance .getHost()方法获取host时,有时会获取到你计算机的名字,而不是localhost,我没有深究,拼接的host那里直接写的127.0.0.1,感兴趣的朋友可以研究下。

@Service
public class UserService {

    @Autowired
    private LoadBalancerClient loadBalancerClient;//ribbon负载均衡

    public List getUsers(){
        //选择调用的服务的名称,ServiceInstance 封装了服务的基本信息,如IP,端口等
        ServiceInstance si=this.loadBalancerClient.choose("eureka-provider");
        //拼接访问服务的URL:http://localhost:9090/user
        StringBuffer sb = new StringBuffer();
        sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");

        //springMVC restTemplate
        RestTemplate rt=new RestTemplate();

        ParameterizedTypeReference> type =new ParameterizedTypeReference>() {};

        //ResponseEntity:封装了返回值信息
        ResponseEntity> response=rt.exchange(sb.toString(), HttpMethod.GET,null,type);
        List list=response.getBody();
        return list;
    }
}

5.controller

@RestController
public class ConsumerController {

    @Autowired
    private UserService userService;

    @RequestMapping("/consumer")
    public List getUsers(){
        return userService.getUsers();
    }
}

User与provider中的一样,这个服务中也需要copy一份,运行起来,可以看到consumer也被注册到了Eureka
Server注册中心中,调用接口【127.0.0.1:9091/consumer】,发现返回了provider中"/user"接口的处理结果,说明整个项目搭建成功!


result.png

后记

由于能力有限,若有错误或者不当之处,还请大家批评指正,一起学习交流!

你可能感兴趣的:(SpringCloud+SpringBoot搭建服务注册与调用平台)