1.关键字
2.背景
在讨论eureka之前,我们先稍微了解分布式系统的通信及配置问题。
通常情况,项目演化的最开始阶段,服务或者服务器数量并不多,可能只有个位数量。服务之间的通信通过在应用中直接配置对方的ip就可以轻松解决,如下图。
随着业务变的更加复杂,以及用户数量和访问量的增加,同时为了项目的高可用,项目的部署架构开始使用集群模式和负载均衡支撑业务。此时,服务的数量仍然可控,服务器的稳定性也在接受范围,通过DNS或者负载均衡服务配置目标项目的集群ip,如下图:
互联网的发展,极大的增加了用户数量和项目的访问量,服务的稳定性越来越难以控制。原本包含全功能栈的单体应用显得越来越笨重,无法支撑从开发、管理 到 部署、可扩展性等项目生命周期的各个环节。微服务概念大行其道,为这样的问题开出了一剂灵丹妙药。然而自然世界是公平的,打开了一扇门可能会同时关闭一扇窗。微服务过度的分隔项目,会使原来一个项目变成无数个子项目(微服务),项目数量的急增,对服务的配置和管理提出了难题。
- 服务数量剧增,通过负载均衡手工配置ip变得越来越复杂
- 访问量和服务数量的增加,使服务的稳定性受到极大的考验,失败服务必须通过手工操作才能移除
- 访问量波动时,无法快速伸缩服务,新增的节点必须先配置到负载均衡器并重启负载均衡才能生效
上面的问题总结成一点就是: 如何能让服务调用方自动找到服务的提供方,即不需要人工参与,新增的提供方服务节点让调用方快速感知并调用。
3.eureka概述
eureka 是spring cloud解决方案中的服务注册发现组件。
服务代表一组功能(如接口)的集合。一个微服务(大项目按业务分隔开来的、业务独立的小项目)项目就是一个服务。根据上面的分析可知,通常服务之间会相互通信(调用),通过在服务中直接配置对方的ip是一种传统的解决方案。但随着服务数量急增和自动化要求,这种方式越来越难以适应微服务架构。因此就急需寻找一个合理的解决方案。
问题的核心是:
- 服务调用方如何能自动“感知”或“找到”服务提供方。
- 感知的标准:目标服务的ip和端口
如果能把每一个服务都记录到一个黄页(配置列表)中,服务使用方通过这个黄页自己查找就不可以解决了吗?就如同电话本一样,每个人只要把自己的电话和姓名记录到本上,使用时到电话本中查找对应姓名即可。
听起来不错,可是有这里又产生了太多的疑问:姓名是什么?电话又是什么?谁来给每个服务起名字?谁又来登记?电话本又是谁?
问题的核心指明了,服务的ip和端口相当于电话。只要为一个服务创建一个唯一且不会轻易更改的名字。创建一个单独的项目用于登记名字与ip端口的映射关系;微服务自身启动时自动把自己的ip和端口注册(登记)到登记服务器上。服务调用方只需配置一提供方的唯一名字,通过名字从登记服务器查询对应的ip端口列表即可完可发现。
如上图:服务B和C有两个节点,它们的名字分名为:service-B,service-C,当B,C服务启动时,分别把自己的ip和端口注册到注册服务器;服务A如果需要调用B的接口,需要先通过注册服务器,查询名字为service-B的映射,因此获得:192.168.0.1:8080和192.168.0.2:9090两台机器。它可随机选择一台机器,并直接通过ip调用对应的接口。不B服务器性能瓶颈时,可以再加一台servce-B节点,并自动注册到注册服务器,完全不需要手工配置和重启机器,完美解决了服务间的松耦合。
本质:把易变更的IP配置从硬编码转换成对不易变更的唯王名字的硬编码。
eureka正是对上面原理的具体实现,但是它做的更多,更完善,具体如下:
- 同时实现注册发现服务端和客户端
- 高可用
- 身份验证
- 状态健康检查
4.eureka服务器
4.1搭建服务器
创建一个名为demo-springeureka的项目,代码结构如下
maven配置如下:
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.flypigs.spring</groupId>
<artifactId>demo-springeureka</artifactId>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-common-version>1.5.3.RELEASE</spring-common-version>
</properties>
<!--依赖-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
创建 EurekaApp main方法类,java代码如下:
package com.flypigs.spring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
*
*
*/
@SpringBootApplication
@EnableEurekaServer //eureka server
public class EurekaApp
{
public static void main( String[] args )
{
//启动项目
SpringApplication.run(EurekaApp.class,args);
}
}
classpath下创建application.yml配置文件,配置如下:
#应用名称
spring:
application:
name: discover-server
#集群中第一个
---
spring:
profiles: integration1
#端口
server:
port: 8080
#自身配置:关闭客户端身份
eureka:
instance:
preferIpAddress: true
client:
#registerWithEureka: false
#fetchRegistry: false
serviceUrl:
defaultZone: http://user:user123@localhost:8181/eureka/
healthcheck:
enabled: true
# 安全认证的配置
security:
basic:
enabled: true
user:
name: user # 用户名
password: user123 # 用户密码
#集群中第二个
---
spring:
profiles: integration2
server:
port: 8181
#自身配置:关闭客户端身份
eureka:
instance:
preferIpAddress: true
client:
#registerWithEureka: false
#fetchRegistry: false
#做为客户端,集群中的其它服务器节点
serviceUrl:
defaultZone: http://user:user123@localhost:8080/eureka/
#启用健康检查(心跳),否则,注册服务器中一直处于可用状态
healthcheck:
enabled: true
# 安全认证的配置
security:
basic:
enabled: true
user:
name: user # 用户名
password: user123 # 用户密码
如果不想创建集群,可以 registerWithEureka为false,
fetchRegistry为false; 如果要创建集群,则注释这两个配置,并设置eureka.client.serviceUrl.defaultUrl对应其它节点的地址。如果不想启用
security,则注释掉相关配置,同时去除
http://user:user123@localhost:8080/eureka/中的user:user123@,则否必须配置对应的用户名密码才可以使用注册服务器。
验证
浏览器中打开:http://localhost:8080/,输入:security.user.name 和 security.user.password指定的值登录操作
打开如下:注册服务器的两个节点相互注册到对方服务器上
4.2特性
待续...
5.eureka客户端
注册服务器实现了服务的注册登记管理,如果服务自己实现注册以及定时发送自身的健康状态是一件较为麻烦的事情。eureka已经帮我提供了一个客户端,它实现了服务启动后自动注册、心跳等操作。下面我们搭建一个简单的客房端服务
创建一个项目名为demo-springclient2,代码结构如下:
maven配置如下:
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.flypigs.spring</groupId>
<artifactId>demo-springclient2</artifactId>
<packaging>jar</packaging>
<name>demo-springclient2</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-common-version>1.5.3.RELEASE</spring-common-version>
</properties>
<!--依赖-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--spring cloud eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!--actuator 用于打开默信的endpoints:如:Status Page and Health Indicator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
创建main 方法类如下:
package com.flypigs.spring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
*
*
*/
@SpringBootApplication
@EnableEurekaClient//eureka client
public class Client2App
{
public static void main( String[] args )
{
//启动项目
SpringApplication.run(Client2App.class,args);
}
}
classpath下创建配置文件:application.yml
#应用名称
spring:
application:
name: client2
profiles:
active: integration
#端口
server:
port: 9191
#管理接口配置
management:
context-path: /admin
port: ${server.port}
#自身配置:
eureka:
instance:
preferIpAddress: true
statusPageUrlPath: ${management.context-path}/info
healthCheckUrlPath: ${management.context-path}/health
instance-id: ${spring.cloud.client.ipAddress}:${server.port}
homePageUrl: https://${spring.cloud.client.ipAddress}:${server.port}
metadata-map:
cluster: default
client:
serviceUrl:
defaultZone: http://user:user123:localhost:8080/eureka/,http://user:user123:localhost:8181/eureka/
启动后,在服务注册发现ui页面,会发现又多出一个服务。
6.接下来
本节简单了解了eureka的基本原理,简单搭建一演示项目,但与真正用于生产还有些差距,后续我们会了创建真正的服务调用方和提供方,了解注册发现及服务之间的调用过程。