spring cloud 实践(一) enreka

Enreka Server搭建

项目搭建

SPRING INITIALIZR快速构建项目,转到带全部选项,在Cloud Discovery勾选Eureka Server并创建下载项目。看到起pom文件如下:(这里我用的maven,也可以生成gradle)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>lyyljs.cloud</groupId>
<artifactId>eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka</name>
<description>Demo project for Spring Boot</description>

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

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</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>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>

然后再Application.java文件里使用注解声明是Enreka Server

1
2
3
4
5
6
7
8
9
@EnableEurekaServer		//通过该注解激活为Eureka服务器
@SpringBootApplication
public class EurekaApplication {

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

}

接着编写配置文件,这里使用application.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spring:
application:
name: spring-cloud-eureka

server:
port: 8000

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

其中有几个重要的参数

  • eureka.client.register-with-eureka :表示是否将自己注册到Eureka Server,默认为true。单点可关闭,集群必须开启。
  • eureka.client.fetch-registry :表示是否从Eureka Server获取注册信息,默认为true。单点可关闭,集群必须开启。
  • eureka.client.serviceUrl.defaultZone :设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
  • eureka.server.enable-self-preservation :设置为false代表关闭注册中心的保护机制,默认为true。

接着就可以启动server了。

现在还是单点,这肯定是不行的,这种关键服务如果down掉会有毁灭性的后果。所以需要配置集群。我们修改配置文件。

  • application.yml
1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: spring-cloud-eureka
# profiles:
# active: peer
# peer是单注册中心配置文件,peer1,2,3为集群1,2,3配置文件

server:
register:
port1: 8000
port2: 8001
port3: 8002
  • application-peer.yml
1
2
3
4
5
6
7
8
9
10
11
12
# 单点配置,仅用于自己测试用
server:
port: ${server.register.port1}

eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.register.port1}/eureka/
  • application-peer1.yml
1
2
3
4
5
6
7
8
9
10
# 集群1号机
server:
port: ${server.register.port1}

eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.register.port2}/eureka/,http://${eureka.instance.hostname}:${server.register.port3}/eureka/
  • application-peer2.yml
1
2
3
4
5
6
7
8
9
10
# 集群2号机
server:
port: ${server.register.port2}

eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.register.port1}/eureka/,http://${eureka.instance.hostname}:${server.register.port3}/eureka/
  • application-peer3.yml
1
2
3
4
5
6
7
8
9
10
# 集群3号机
server:
port: ${server.register.port3}

eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.register.port1}/eureka/,http://${eureka.instance.hostname}:${server.register.port2}/eureka/

添加完成后,通过修改application.yml里spring.profiles.active打包运行,或直接打包后在java命令后添加参数java -jar eureka-0.0.1-SNAPSHOT.jar –spring.profiles.active=peer1运行。

我这里有三台机器,启动前两个时因为找不到第三个会报错,在全部启动起来后便不会报错。

在同一台机器上运行多个注册中心时容易出现EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.错误。这是因为Eureka server和client心跳频率低于了阈值。在没有实例的时候出现属于正常现象。

eureka.server.renewalPercentThreshold参数定义了renews(上一分钟内收到的心跳次数)和renews threshold(server期望在每分钟中收到的心跳次数)的比值,默认值为0.85。当server在15分钟内,比值低于percent,即少了15%的微服务心跳,server会进入自我保护状态,此时server不会删除注册信息。
本机测试的时候可以将此值调低,stackoverflow给出的本机测试推荐值为0.49(多注册中心),0(单注册中心)。

enreka配置

Spring Cloud Enreka配置分为3个部分:Server,Client和Instance。
这里Spring Cloud Enreka版本为2.1.0-Release,对应Enreka版本为1.9.8。
下面说明以yml文件格式保存,对应值皆为默认值。因从java源代码查找并复制过来(不符合配置文件规范)所以需要修改才可使用。

Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
eureka:
server:
# 来自EurekaServerConfigBean,spring-cloud-netflix-enreka-server-2.1.0.RELEASE
# MINUTES = 60 * 1000
aWSAccessId: null #AWS Access Id 亚马逊云使用 绑定Elastic IP
aWSSecretKey: null #AWS Secret Key 亚马逊云使用 绑定Elastic IP
eIPBindRebindRetries: 3 #绑定Elastic IP 重试次数
eIPBindingRetryIntervalMs: 5 * MINUTES # eIP绑定重试间隔 eIP已绑定时 也作刷新间隔
eIPBindingRetryIntervalMsWhenUnbound: 1 * MINUTES # eIP未被绑定时绑定重试间隔
route53BindRebindRetries: 3 # 绑定Route53域名重试次数
route53BindingRetryIntervalMs: 5 * MINUTES # 绑定Route53域名重试间隔
route53DomainTTL: 30 # Route53域名TTL
bindingStrategy: AwsBindingStrategy.EIP # 绑定策略EIP, ROUTE53, ENI
useAwsAsgApi: true # 是否使用 AWS API查询ASG statuses
aSGQueryTimeoutMs: 300 # 向AWS请求ASG信息超时时间
aSGUpdateIntervalMs: 5 * MINUTES # ASG信息更新间隔
aSGCacheExpiryTimeoutMs: 10 * MINUTES # ASG信息过期时间
primeAwsReplicaConnections: true # 检查是否应启动与副本的连接,在AWS,防火墙有时需要为新节点建立网络连接
listAutoScalingGroupsRoleName: ListAutoScalingGroups # 角色名称,用于描述从第三方AWS账户得到的自动缩放组

enableSelfPreservation: true # 是否开启自我保护,开启后会检查renewals参数是否
# 低于renewalPercentThreshold阈值,低于时启动自我保护模式,
# 此时会关闭过期删除(注册信息)以避免因client与server之间网络不畅通导致的误删
renewalPercentThreshold: 0.85 # 一个周期(renewalThresholdUpdateIntervalMs)实际收到心跳包与期望收到心跳包最小比值,
# 低于该阈值开启自我保护
renewalThresholdUpdateIntervalMs: 15 * MINUTES # 一个间隔周期,用于心跳检测
expectedClientRenewalIntervalSeconds: 30 # 期望客户端发送心跳间隔时间,应与客户端发送间隔时间相同,否则自我保护机制失效

peerEurekaNodesUpdateIntervalMs: 10 * MINUTES # 集群里eureka节点的变化信息更新的时间间隔
numberOfReplicationRetries: 5 # 向peer节点发送同步请求重试次数
peerEurekaStatusRefreshTimeIntervalMs: 30 * 1000 # 获取peer节点状态更新信息 时间间隔
waitTimeInMsWhenSyncEmpty: 5 * MINUTES # Eureka服务器启动时无法从对等节点获取实例时的等待时间
peerNodeConnectTimeoutMs: 200 # 向peer节点发送同步请求超时时间
peerNodeReadTimeoutMs: 200 # 从peer节点同步获取信息超时时间
peerNodeTotalConnections: 1000 # peer节点复制时HTTP连接最大数
peerNodeTotalConnectionsPerHost: 500 # 单个peer节点复制时HTTP连接最大数
peerNodeConnectionIdleTimeoutSeconds: 30 # HTTP连接允许的最大闲置时间

disableDelta: false # 增量信息是否服务与客户端
retentionTimeInMSInDeltaQueue: 3 * MINUTES # 缓存增量信息时间,保证客户端在丢失信息时能重新获得这些信息
deltaRetentionTimerIntervalInMs: 30 * 1000 # 清理任务休眠间隔,用于清理过期的增量信息(delta information)

evictionIntervalTimerInMs: 60 * 1000 # task唤醒和执行时间间隔,用于过期实例

responseCacheAutoExpirationInSeconds: 180 # registry payload被change events失效后在cache中保存时间
responseCacheUpdateIntervalMs: 30 * 1000 # 缓存的客户端payload需要更新的时间间隔
useReadOnlyResponseCache: true # 注册信息响应缓存,使用了二级缓存结构,带有过期策略的读写缓存以及没有过期的只读缓存(com.netflix.eureka.registry.ResponseCache)

maxIdleThreadInMinutesAgeForStatusReplication: 10 # 状态复制线程最大闲置时间(Minutes)
minThreadsForStatusReplication: 1 # 状态复制线程最小线程数
maxThreadsForStatusReplication: 1 # 状态复制线程最大线程数
maxElementsInStatusReplicationPool: 1000 # 状态复制线程池阻塞队列存放数量

syncWhenTimestampDiffers: true # 当时间戳出现差异时是否同步实例

registrySyncRetries: 0 # 在启动时从peer节点获取注册信息重试次数
registrySyncRetryWaitMs: 30 * 1000 # 重试同步间隔时间

maxElementsInPeerReplicationPool: 10000 # 复制事件线程池阻塞队列限制
maxIdleThreadAgeInMinutesForPeerReplication: 15 # replication线程最大闲置时间
minThreadsForPeerReplication: 5 # replication线程池最小线程数
maxThreadsForPeerReplication: 20 # replication线程池最大线程数
maxTimeForReplication: 30000 # 丢弃replication events前尝试复制的最大时间

disableDeltaForRemoteRegions: false # 增量信息是否服务与远程客户端
remoteRegionConnectTimeoutMs: 1000 # 连接远程peer节点超时时间
remoteRegionReadTimeoutMs: 1000 # 从远程peer节点读取信息超时时间
remoteRegionTotalConnections: 1000 # 远程peer节点复制时HTTP连接最大数
remoteRegionTotalConnectionsPerHost: 500 # 单个远程peer节点复制时HTTP连接最大数
remoteRegionConnectionIdleTimeoutSeconds: 30 # HTTP连接允许的最大闲置时间
gZipContentFromRemoteRegion: true # 远程连接是否开启gZip压缩
remoteRegionUrlsWithName: empty Map # HashMap region name-remote region discovery url
remoteRegionUrls: null # url,该选项已被remoteRegionUrlsWithName取代
remoteRegionAppWhitelist: null # Map<String, Set<String>> regionName-A set of application names 应用白名单
remoteRegionRegistryFetchInterval: 30 # 从远端拉取注册信息时间间隔
remoteRegionFetchThreadPoolSize: 20 # 远端拉取注册信息线程池大小
remoteRegionTrustStore: "" # 空字符串 远端抓取信息证书文件
remoteRegionTrustStorePassword: changeit # 远端抓取信息证书文件密码
disableTransparentFallbackToOtherRegion: false # 如果本地区域中没有该应用程序的实例,则将禁用回退到远程区域中的应用程序(如果有配置)的旧行为。true 禁用旧行为

batchReplication: false # 是否开启对群集节点之间的复制进行批处理,以提高网络效率
rateLimiterEnabled: false # 是否开启速率限制器
rateLimiterThrottleStandardClients: false # 是否对标准客户端限速
rateLimiterPrivilegedClients: Collections.emptySet() # 空set 除开标准enreka客户端之外的受信客户端
rateLimiterBurstSize: 10 # 令牌桶算法(token bucket algorithm)的属性,速率限制的burst size
rateLimiterRegistryFetchAverageRate: 500 # 令牌桶算法的属性,平均执行注册请求速率
rateLimiterFullFetchAverageRate: 100 # 令牌桶算法的属性,平均执行请求速率
logIdentityHeaders: true # enreka服务器是否追踪clientAuthHeaders

enableReplicatedRequestCompression: false # 在请求中压缩复制数据
jsonCodecName: null # 指定json编/解码器类名,没有则使用默认解码器
xmlCodecName: null # 制定xml编/解码器类名,没有则使用默认解码器

minAvailableInstancesForPeerReplication: -1 # 未知含义,在EurekaServerConfigBean有,在EurekaServerConfig无,
# 在spring-cloud-enraka中只有EurekaServerConfigBean和一个测试类有设定该值,但并未使用
# 从字面意义看,是peer复制最少可用实例
initialCapacityOfResponseCache: 1000 # responseCache初始缓存大小

myUrl: null # 定义自身url,用于Eureka URLs不匹配IP地址或hostname时(如将enreka实例放在负载均衡器下)
# 需要使用完整地址,如http://eureka-node1.mydomain.com:8010/eureka/v2/
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
eureka:
client:
# 来自EurekaClientConfigBean,spring-cloud-netflix-enreka-client-2.1.0.RELEASE
# DEFAULT_PREFIX: /eureka
# DEFAULT_URL: "http://localhost:8761" + DEFAULT_PREFIX + "/"
# DEFAULT_ZONE: defaultZone
# MINUTES: 60

enabled: true # 是否开启enreka client
registryFetchIntervalSeconds: 30 # 从enreka服务器抓取注册信息频率
instanceInfoReplicationIntervalSeconds: 30 # 复制实例变化信息到eureka服务器频率
initialInstanceInfoReplicationIntervalSeconds: 40 # 初始复制实例信息到eureka服务器时长
eurekaServiceUrlPollIntervalSeconds: 5 * MINUTES # 询问Eureka Server信息变化的时间间隔

proxyPort: null # 获取eureka服务的代理端口
proxyHost: null # 获取eureka服务的代理主机
proxyUserName: null # 获取eureka服务的代理用户名
proxyPassword: null # 获取eureka服务的代理密码

eurekaServerReadTimeoutSeconds: 8 # 建立读取enreka server超时时间
eurekaServerConnectTimeoutSeconds: 5 # 建立到enreka server连接超时
backupRegistryImpl: null # 实现了BackupRegistry接口的类名称,用于第一次从enreka服务器获取注册信息失败时降级操作
eurekaServerTotalConnections: 200 # 到所有enreka server的总连接数
eurekaServerTotalConnectionsPerHost: 50 # 到单个enreka host的总连接数

useDnsForFetchingServiceUrls: false # eureka客户端是否应该使用DNS机制来获取eureka服务器的地址列表
eurekaServerURLContext: null # URL context:用于构建服务url,来连接enreka server
# 当enreka服务器ip列表来自于DNS需要使用此项
eurekaServerPort: null # eureka服务器的端口,当enreka服务器ip列表来自于DNS需要使用此项
eurekaServerDNSName: null # DNS名称,用来获取enreka服务器ip列表

region: us-east-1 # AWS datacenters 区域

eurekaConnectionIdleTimeoutSeconds: 30 # 与enreka服务器的http连接闲置超时时间
registryRefreshSingleVipAddress: null # 客户端只对一个单一的VIP注册表的信息感兴趣
heartbeatExecutorThreadPoolSize: 2 # 心跳线程池初始大小
heartbeatExecutorExponentialBackOffBound: 10 # 心跳指数回退属性,是重试延迟的最大倍数值

cacheRefreshExecutorThreadPoolSize: 2 # 缓存刷新线程池大小
cacheRefreshExecutorExponentialBackOffBound: 10 # 缓存刷新回退属性,是重试延迟的最大倍数值

serviceUrl: # zone: 服务的url/urls(以,号分隔) url需要时全路径,如http://ec2-256-156-243-129.compute-1.amazonaws.com:7001/eureka/
DEFAULT_ZONE: DEFAULT_URL # client下端注释值

gZipContent: true # 连接是否开启gZip压缩

registerWithEureka: true # 是否注册该实例到enreka服务器
preferSameZoneEureka: true # 实例是否使用同一zone里的eureka服务器

logDeltaDiff: false # 是否记录eureka服务器和客户端之间在注册表的信息方面的差异
# enreka客户端每次从服务器仅取服务器增加的信息以减少网络开销;收到增量信息后,
# enreka客户端会向服务器验证是否有差异(丢失)。如果这个过程失败则会尝试获取全部信息。
# 当获取全部信息时,是否记录服务器信息与本地信息的差异
disableDelta: false # 见上,是否关闭增量更新
fetchRemoteRegionsRegistry: null # 逗号隔开的区域列表,用来获取服务注册信息
availabilityZones: new HashMap<>() # 逗号隔开的实例所在的地区下可用性的区域列表(AWS datacenter下使用)
filterOnlyUpInstances: true # 仅获取实例状态为UP的应用
fetchRegistry: true # 是否从enreka server获取注册信息

dollarReplacement: _- # 在与enreka服务器通信(反)序列化替换$
escapeCharReplacement: __ # 同上,替换_符号
allowRedirects: false # 允许server重定向client的请求

onDemandUpdateStatusChange: true # 本地状态更新是否触发频率受限的on-demand更新到enreka server
encoderName: null # 临时配置选项配置使用编码器,当最新的编码器稳定后移除
decoderName: null # 同上
clientDataAccept: EurekaAccept.full.name() # full, compact 客户端数据接收使用的EurekaAccept名称

shouldUnregisterOnShutdown: true # 客户端关闭时向enreka server注销

shouldEnforceRegistrationAtInit: false # 客户端初始化期间是否强制注册
order: 0 # CompositeDiscoveryClient用来排序可用客户端
Instance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
eureka:
instance:
# 来自EurekaInstanceConfigBean,spring-cloud-netflix-enreka-client-2.1.0.RELEASE
# UNKNOWN: unknown

# spring boot actuator
actuatorPrefix: /actuator # actuator endpoints默认前缀
statusPageUrlPath: actuatorPrefix + "/info" # 状态信息页面相对路径
statusPageUrl: null # 状态信息页面绝对路径
homePageUrlPath: / # 主页相对路径
homePageUrl: null # 主页绝对路径
healthCheckUrlPath: actuatorPrefix + "/health" # 健康检查相对路径
healthCheckUrl: null # 健康检查绝对路径
secureHealthCheckUrl: null # 安全端口健康检查绝对路径

appname: unknown # 应用注册名 如未设定appname,则查询spring.application.name,如皆未设定,则为unknown
appGroupName: null # 应用组名称
instanceEnabledOnit: false # 实例注册到eureka服务器时,是否马上开始通讯
nonSecurePort: 80 # 非加密接受通讯端口
securePort: 443 # 加密接受通讯端口
nonSecurePortEnabled: true # 是否使用非加密接受通讯端口
securePortEnabled: false # 是否使用加密接受通讯端口
leaseRenewalIntervalInSeconds: 30 # enreka客户端发送心跳间隔
leaseExpirationDurationInSeconds: 90 # 心跳过期时间,enreka服务端在接收心跳后,如在此时间内未收到下一跳,则删除该实例
virtualHostName: unknown # 虚拟主机名 未设定该值则为spring.application.name,如皆未设定,则为unknown
instanceId: null # 实例id,实例注册到eureka服务端的唯一的实例ID,未设定则从metadataMap查询
secureVirtualHostName: unknown # 安全虚拟主机名 如未设定,则查询spring.application.name,如皆未设定,则为unknown
aSGName: null # AWS autoscaling group name
metadataMap: new HashMap # enreka元数据,元数据被发送到eureka服务器,其他实例可以使用
dataCenterInfo: MyOwn # DataCenterInfo.Name.MyOwn Netflix, Amazon, MyOwn 该实例被部署的数据中心
ipAddress: null # 实例的ip地址,无配置会使用默认发现的第一个非回环地址 相关类 org.springframework.cloud.commons.util.InetUtils
namespace: eureka # 用于查找属性的命名空间,Spring Cloud中会被忽略
hostname: null # 配置的主机名,无配置会从OS中获取。 InetUtils
preferIpAddress: false # IP优先于(取代)从OS中获取的主机名。 InetUtils
initialStatus: UP # InstanceStatus.UP/DOWN/STARTING/OUT_OF_SERVICE/UNKNOWN
# 注册到enreka server时实例状态
# UP:可以通讯 DOWN:下线,禁止通讯,health check失败时
# STARTING: 正在进行初始化,禁止通讯 OUT_OF_SERVICE: 主动离线
# UNKNOWN: 未知
参考链接