Learn SpringCloud Eureka take you from 0-1

First, what is a service registry

A service registry is a core component of service implementation and management of registration, similar to the role of a directory service, mainly used to store service information such as service provider url string routing information. A service registry is one of the most basic facilities SOA architecture.

1. The role of the service registry

1. Registration Service

Found 2 services

2. Common registry

1 Dubo registries Zookeeper

2 SpringCloud of Eureka

3. Service registry to solve any problems

1. Service Management

2. dependency management services

4. What is the Eureka registry

Eureka is developed Netflix service discovery component itself is based on a Rest service, SpringCloud be integrated in its children in order to achieve SpringCloud service registration and discovery, while also providing load balancing and registration

Three roles 4.1 Eureka registry
  • Eureka Server

    Services provided by the Register, Get, Renew interface such as registration and discovery.

  • Application Service(Service Provider)

    Service provider

    The self-service to Eureka Server instance registered in

  • Application Client(Service Consumer)

    Caller to the service

    Get the list of services through Eureka Server, consumer services

Two, Eureka entry case

1. Create a project

1.1 Add dependence
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.13.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.luyi</groupId>
	<artifactId>springcloud-eureka-server</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springcloud-eureka-server</name>
	<description>Demo project for Spring Boot</description>

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

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.SR5</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.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka-server</artifactId>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>
复制代码
1.2 modify the startup class
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}
复制代码
1.3 modify the global configuration file
spring.application.name=eureka-server
#修改服务器端口
server.port=8761

#是否将自己注册到eureka-server中,默认为true
eureka.client.registerWithEureka=false

#是否从Eureka-server中获取服务信息,默认为true
eureka.client.fetchRegistry=false
复制代码
Eureka-Server 1.4 access through a browser service management platform

Third, set up Eureka clusters

1. Create a project

1.1 Creating project

springcloud-eureka-server-ha

1.2 modify the configuration file

In the construction of Eureka cluster, you need to add multiple profiles, and the use of multi-environment configuration SpringBoot, the number of nodes in the cluster need to add a number of configuration files

1.3 Configuration node in the cluster configuration file

Eureka1

spring.application.name=eureka-server
#修改服务器端口
server.port=8761

#设置Eureka实例名称,以配置文件的变量为主
eureka.instance.hostname=eureka1

#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://eureka2:8761/eureka/
复制代码

EUREKA2

spring.application.name=eureka-server
#修改服务器端口
server.port=8761

#设置Eureka实例名称,以配置文件的变量为主
eureka.instance.hostname=eureka2

#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://eureka1:8761/eureka/
复制代码
1.4 Add logback log configuration file
<?xml version="1.0" encoding="UTF-8" ?>
 <configuration>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->  
    <property name="LOG_HOME" value="${catalina.base}/logs/" />  
    <!-- 控制台输出 -->   
    <appender name="Stdout" class="ch.qos.logback.core.ConsoleAppender">
       <!-- 日志输出编码 -->  
        <layout class="ch.qos.logback.classic.PatternLayout">   
             <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
            </pattern>   
        </layout>   
    </appender>   
    <!-- 按照每天生成日志文件 -->   
    <appender name="RollingFile"  class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/server.%d{yyyy-MM-dd}.log</FileNamePattern>   
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>   
        <layout class="ch.qos.logback.classic.PatternLayout">  
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
            </pattern>   
       </layout> 
        <!--日志文件最大的大小-->
       <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
         <MaxFileSize>10MB</MaxFileSize>
       </triggeringPolicy>
    </appender>     

    <!-- 日志输出级别 -->
    <root level="DEBUG">   
        <appender-ref ref="Stdout" />   
        <appender-ref ref="RollingFile" />   
    </root> 



<!--日志异步到数据库 -->  
<!--     <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
        日志异步到数据库 
        <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
           连接池 
           <dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
              <driverClass>com.mysql.jdbc.Driver</driverClass>
              <url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
              <user>root</user>
              <password>root</password>
            </dataSource>
        </connectionSource>
  </appender> -->

</configuration>
复制代码
1.5 Eureka cluster deployment

Deployment environment: jdk1.8

  1. The project package

  2. The jar package uploaded to the / usr / local / eureka folder

1.6 startup script writing
#!/bin/bash
 
cd `dirname $0`
 
CUR_SHELL_DIR=`pwd`
CUR_SHELL_NAME=`basename ${BASH_SOURCE}`
 
JAR_NAME="项目名称"
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=配置文件变量名称"
#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
复制代码

Add Permissions

chmod -R 755 server.sh

1.7 modify the hosts file linux

vi /etc/hosts

192.168.234.130 eureka1
192.168.234.131 eureka2
复制代码
1.8 Start eureka registry
./server.sh start	#启动
./server.sh stop	#停止
复制代码

Fourth, the registration center in Eureka to build a highly available service Provider

1. Create a project

springcloud-eureka-provider

1.1 Add dependence
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.13.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.luyi</groupId>
	<artifactId>springcloud-eureka-provider</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springcloud-eureka-provider</name>
	<description>Demo project for Spring Boot</description>

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

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.SR5</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.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>
复制代码
1.2 modify the startup class
//表示Eureka的客户端
@EnableEurekaClient
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}
复制代码
1.3 modify the provider's profile
spring.application.name=eureka-provider
server.port=9090

#设置服务注册中心地址,向所有注册中心做注册
eureka.client.serviceUrl.defaultZone=http://eureka1:8761/eureka/,http://eureka2:8761/eureka/
复制代码
1.4 modify the Windows host file

C:\Windows\System32\drivers\etc

192 168 234 130 192 168 234 131 eureka1 EUREKA2

1.5 writing service interface
@RestController
public class UserController {

    @RequestMapping("/user")
    public List<User> getUsers(){
        List<User> users = new ArrayList<>();
        users.add(new User(1, "zhangsan", 20));
        users.add(new User(2, "lisi", 22));
        users.add(new User(3, "wangwu", 30));
        return users;
    }
}
复制代码
1.6 Creating entity
/**
 * Author: LuYi
 * Date: 2019/11/6 12:30
 * Description: 描述
 */
public class User {

    private Integer userid;
    private String username;
    private Integer userage;

    public User() {
    }

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

    public Integer getUserid() {
        return userid;
    }

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

    public String getUsername() {
        return username;
    }

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

    public Integer getUserage() {
        return userage;
    }

    public void setUserage(Integer userage) {
        this.userage = userage;
    }
}
复制代码

Fifth, the availability of Eureka registration center set up Consumer Services

Consumers and producers of services are required to register at the registration center Eureka

1. Create a project

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

#设置服务注册中心地址,向所有注册中心做注册
eureka.client.serviceUrl.defaultZone=http://eureka1:8761/eureka/,http://eureka2:8761/eureka/
复制代码
1.2 complete service calls in Service
@Service
public class UserService {

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

    public List<User> getUsers(){

        //选择调用的服务的名称
            //ServiceInstance:封装了服务的基本信息,如:ip、端口号
        ServiceInstance si = loadBalancerClient.choose("eureka-provider");
        //拼接访问服务的url
        StringBuffer sb = new StringBuffer();

        //http://localhost:9090/user
        sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");

        //SpringMVC RestTemplate
        RestTemplate restTemplate = new RestTemplate();
        ParameterizedTypeReference<List<User>> type = new ParameterizedTypeReference<List<User>>() {
        };

        //ResponseEntity:封装了返回值信息
        ResponseEntity<List<User>> entity = restTemplate.exchange(sb.toString(), HttpMethod.GET, null, type);
        return entity.getBody();
    }
}
复制代码
1.3 Creating Controller
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/consumer")
    public List<User> getUsers(){
        return userService.getUsers();
    }
}
复制代码

Six, Eureka registry architecture principles

1.Eureka Chart

  • Register (registration services): their own IP and port number registered to Eureka
  • Renew (service contract): send a heartbeat packet sent once every 30s, he was still alive to tell Eureka
  • Cancel (Services offline): When the provider will send a message to close Eureka, to remove yourself from the list of services. Consumer prevent calls to non-existent service
  • Get registry (Registry access to services): Get a list of other services
  • Replicate (data cluster synchronization): synchronous data replication and Eureka cluster
  • Make Remote Call (remote call): complete remote service invocation

Seven, based on distributed CAP theorem, the two main registry analysis framework: the difference between Eureka and Zookeeper

1. What is the principle of CAP

CAP principle, also known as CAP theorem means that in a distributed system, Consistency (consistency), Availability (availability), Partition tolerance (partitions fault tolerance), the three can not have both, can only pick two.

CAP proposed by Eric Brewer in 2000 PODC meeting. The conjecture is proved in two years later, we are familiar with called CAP theorem

Eureka and the difference 2.Zookeeper

Eight, Eureka elegance stop taking

1. Under what circumstances, Eureka will open self-protection

1.1 Self-protection conditions

In general, micro Eureka service after registration, every 30s will send a heartbeat packet, and it will delete the 90s did not send a heartbeat packet services on a regular basis.

1.2 There are two situations in which the heart does not receive micro Eureka Server service
  • Micro service its own reasons

  • The reason micro-services network between Eureka and the

    If it is because micro-service failure will not lead to not receive heartbeat packets appear in large quantities, will only lead to part failure, and can lead to large-scale network failures can not receive heartbeat packets.

    Taking into account this distinction, Eureka sets a threshold value, if large-scale income in a short time no heartbeat packet, it will be judged as a network failure, so it does not remove the Eureka heartbeat expired service

  • Threshold is how much

    Over 15 minutes is determined whether less than 85%

    Eureka Server During operation, the heart will determine whether the failure ratio of 85% in 15 minutes

    This algorithm is called a self-protection mode Eureka Server.

2. Why self-protection

  • Because while retaining ** "good data" and "bad data" to delete all data ** better than better, if it is because of self-protection into the network failure, when the fault has been repaired, it will automatically exit the self-protection mode
  • Micro-service load balancing strategy will automatically eliminate micro-services node death

3. How to turn off self-protection

Modify Eureka Server configuration file

#关闭自我保护:true为开启,false为关闭
eureka.server.enable-self-preservation=false
#清理间隔(单位:毫秒,默认是60*1000)
eureka.server.eviction-interval-timer-in-ms=60000
复制代码

4. How elegant stop taking

4.1 does not need to protect themselves in the closed configuration in Eureka Server
4.2 needs to be added in the service pack actuator.jar
4.3 modify the configuration file
#启动shutdown
endpoints.shutdown.enabled=true
#禁用密码验证
endpoints.shutdown.sensitive=false
复制代码
4.4 sends a URL request to shut down services
public class HttpClientUtil {

	public static String doGet(String url, Map<String, String> param) {

		// 创建Httpclient对象
		CloseableHttpClient httpclient = HttpClients.createDefault();

		String resultString = "";
		CloseableHttpResponse response = null;
		try {
			// 创建uri
			URIBuilder builder = new URIBuilder(url);
			if (param != null) {
				for (String key : param.keySet()) {
					builder.addParameter(key, param.get(key));
				}
			}
			URI uri = builder.build();

			// 创建http GET请求
			HttpGet httpGet = new HttpGet(uri);

			// 执行请求
			response = httpclient.execute(httpGet);
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (response != null) {
					response.close();
				}
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return resultString;
	}

	public static String doGet(String url) {
		return doGet(url, null);
	}

	public static String doPost(String url, Map<String, String> param) {
		// 创建Httpclient对象
		CloseableHttpClient httpClient = HttpClients.createDefault();
		CloseableHttpResponse response = null;
		String resultString = "";
		try {
			// 创建Http Post请求
			HttpPost httpPost = new HttpPost(url);
			// 创建参数列表
			if (param != null) {
				List<NameValuePair> paramList = new ArrayList<>();
				for (String key : param.keySet()) {
					paramList.add(new BasicNameValuePair(key, param.get(key)));
				}
				// 模拟表单
				UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"utf-8");
				httpPost.setEntity(entity);
			}
			// 执行http请求
			response = httpClient.execute(httpPost);
			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				response.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return resultString;
	}

	public static String doPost(String url) {
		return doPost(url, null);
	}
	
	public static String doPostJson(String url, String json) {
		// 创建Httpclient对象
		CloseableHttpClient httpClient = HttpClients.createDefault();
		CloseableHttpResponse response = null;
		String resultString = "";
		try {
			// 创建Http Post请求
			HttpPost httpPost = new HttpPost(url);
			// 创建请求内容
			StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
			httpPost.setEntity(entity);
			// 执行http请求
			response = httpClient.execute(httpPost);
			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				response.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return resultString;
	}
	
	public static void main(String[] args) {
		String url ="http://127.0.0.1:9090/shutdown";
		//该url必须要使用doPost方式来发送
		HttpClientUtil.doPost(url);
	}
}
复制代码

Nine, how to strengthen the security certification Eureka registry

1. Add the security package EurekaServer

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
复制代码

2. Modify the Eureka Server configuration file

#开启 http basic 的安全认证
security.basic.enabled=true
security.user.name=user
security.user.password=123456
复制代码

3. Modify url to access the cluster nodes

eureka.client.serviceUrl.defaultZone=http://user:123456@eureka2:8761/eureka/
复制代码

4. Modify the configuration file, modify the registry to access user name and password

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

#设置服务注册中心地址,向所有注册中心做注册
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/

#启动shutdown
endpoints.shutdown.enabled=true
#禁用密码验证
endpoints.shutdown.sensitive=false
复制代码

Guess you like

Origin juejin.im/post/5dc80a8d6fb9a04ac07ce52f