分布式的框架设计由于 Dubbo 与 Spring Cloud 的缘故,现在非常的流行,事实上,很多情况下这中框架设计是被滥用的。例如有一次面试一个开发者,侃侃而谈说了自己做的项目如何使用 Spring Cloud 的框架,各个组件如何协作,如何分布部署在10部阿里云的虚拟机上。结果问了一下系统的并发访问量是多少呢?他说是2000(你没看错,我也没输错,就是这么多个0),我当时不说,心里MMP,2000并发搞这么大的阵仗?
当然,当软件开始使用分布式架构时,注册和发现的机制是非常有用的,最近在做一个点播服务,转码服务端通过 python 来调用 ffmpeg 进行,对外提供 restful 接口,而本来系统也有一些 Restful 的服务,而后续的功能也能预计会增加一些。现在好几个组件都使用 Springboot 编写,所有的调用都是通过 hardcode 配置文件而实现的。想着就使用 Spring Cloud 管理起来,用的是 Spring Cloud 建议的注册服务器 eureka。
Spring 自己的那套搭建起来倒是很简单,服务器相互注册,Springboot 应用也只需改几个配置文件就能连接起来。但是毕竟项目中还有 Python 提供的 Restful 服务,最好这些也能注册到 Spring Cloud 中,但网上找到的 python eureka 的资料不多,所以最终还是打算自己编写算了。捣鼓了几天把注册退出服务写完了,由于代码现在还未来得及优化,太丑就不贴出来了,以下是注册与发现的流程和 restful 参数,懂了之后,各路高手写起来也是很快的。
首先,确保你的 Spring Cloud Eureka Server 运行起来。
以下是相关 restful 交互流程
1,向 Spring Cloud Eureka Server 发送注册信息,注册成为服务(当然,也可以通过配置不注册自己的服务作为服务,仅作为为服务的使用者)
注册的地址为:http://spring-cloud-server:8761/eureka/apps/[你的应用服务名]/[你的节点ID]
节点id,spring 默认为(无中括号): [ip:服务名小写:端口],实现时可做参考
本例子中为:http://192.168.3.163:8761/eureka/apps/YOUR-SERVICE/192.168.3.111:your-service:8000
发送的 content-type为 application/json
发送时使用的 http method 为:POST
发送的内容为:(发送时请去掉多余的换行,制表和空格符号,直接写入request body中)
{
'instance': {
'instanceId': '192.168.3.111:your-service:8000',
'hostName': '192.168.3.111',
'app': 'YOUR-SERVICE',
'ipAddr': '192.168.3.111',
'status': 'UP',
'overriddenstatus': 'UNKNOWN',
'port': {
'$': 8000,
'@enabled': 'true'
},
'securePort': {
'$': 443,
'@enabled': 'false'
},
'countryId': 1,
'dataCenterInfo': {
'@class': 'com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo',
'name': 'MyOwn'
},
'leaseInfo': {
'renewalIntervalInSecs': 30,
'durationInSecs': 90,
'registrationTimestamp': 0,
'lastRenewalTimestamp': 0,
'evictionTimestamp': 0,
'serviceUpTimestamp': 0
},
'metadata': {
'management.port': '8000'
},
'homePageUrl': 'http://192.168.3.111:8000/',
'statusPageUrl': 'http://192.168.3.111:8000/info',
'healthCheckUrl': 'http://192.168.3.111:8000/health',
'vipAddress': 'http://192.168.3.111/',
'secureVipAddress': 'http://192.168.3.111/',
'isCoordinatingDiscoveryServer': 'false',
'lastUpdatedTimestamp': '1536310204574',
'lastDirtyTimestamp': '1536310204574'
}
}
请注意保存你的 lastDirtyTimestamp,之后心跳的时候你需要使用到该字段。
2,使用以下接口获取(发现)相关的注册信息:
网址为:http://spring-cloud-server:8761/eureka/apps
本例子中为:http://192.168.3.163:8761/eureka/apps
使用的http method 为:GET
返回的信息是一个XML文档,格式如下:
1
UP_3_
YOUR-SERVICE
192.168.3.111:your-service:8000
192.168.3.111
MSTOR-VIDEO-TRANSCODE-CENTRE
192.168.3.111
UP
UNKNOWN
8000
443
1
MyOwn
30
90
1536310204574
1536310204574
0
1536310204574
8000
http://192.168.3.111:8000/
http://192.168.3.111:8000/info
http://192.168.3.111:8000/health
http://192.168.3.111
http://192.168.3.111
false
1536310204574
1536310204574
ADDED
EUREKA
192.168.3.116:eureka:8762
192.168.3.116
EUREKA
192.168.3.116
UP
UNKNOWN
8762
443
1
MyOwn
30
90
1536303101988
1536310773961
0
1536303101988
8762
http://192.168.3.116:8762/
http://192.168.3.116:8762/actuator/info
http://192.168.3.116:8762/actuator/health
eureka
eureka
false
1536303101988
1536302098452
ADDED
192.168.3.116:eureka:8761
192.168.3.116
EUREKA
192.168.3.116
UP
UNKNOWN
8761
443
1
MyOwn
30
90
1536303103823
1536310785455
0
1536303103047
8761
http://192.168.3.116:8761/
http://192.168.3.116:8761/actuator/info
http://192.168.3.116:8761/actuator/health
eureka
eureka
true
1536303103837
1536303101851
ADDED
返回的基本就是现在(包括你注册的组件)已经注册的组件的列表,以XML格式存储,请将这些信息转换成你所用语言的相关实体并且记录。并且对为提供通过组件名称来获取 Status 为 UP 的组件的相关能力。
3,发送心跳,按照我们注册时填写的时间,我们将每30秒中左右向服务器发送心跳信息。
发送地址为:http://spring-cloud-server:8761/eureka/apps/[你的服务名]/[你的节点ID]?status=UP&lastDirtyTimestamp=[注册时记录的lastDirtyTimestamp]
本例中的地址为:http://192.168.3.163:8761/eureka/apps/YOUR-SERVICE/192.168.3.111:your-service:8000?status=UP&lastDirtyTimestamp=1536310204574
发送的 http method 为:PUT
4,同时,我们定期更新我们的服务缓存,为了降低传输压力,我们使用 delta 来获取
地址为:http://spring-cloud-server:8761/eureka/apps/delta
本例中为:http://192.168.3.163:8761/eureka/apps/delta
使用的http method 为:GET
如果所有的服务地址都没有发生变化,返回是非常简单的信息,如下:
92
UP_3_
其中 version_delta 是版本信息,apps_hashcode 的 UP_3_ 表示现在还有3部机器存活,但请不要以此来进行计算。如果版本有变化,delta会返回变更的节点,信息大致如下:
94
UP_2_
YOUR-SERVICE
192.168.3.111:your-service:8000
192.168.3.111
YOUR-SERVICE
192.168.3.111
DOWN
UNKNOWN
8000
443
1
MyOwn
30
90
1536312407562
1536312407562
1536312407566
1536310699505
8090
http://192.168.3.111:8000/
http://192.168.3.111:8000/info
http://192.168.3.111:8000/health
mstor-video-transcode-centre
mstor-video-transcode-centre
false
1536312407566
1536312408251
DELETED
请根据delta信息来对你不本地缓存的服务进行整理。或者也可以通过上述的获取整个库的服务对你数据的缓存进行刷新。这个注册服务信息的刷新也是每隔30秒进行一次。
5,节点的退出。
在节点的退出的时候,先发送DOWN信息,该请求和节点注册完全一致,只是 JSON 中的 status 由 UP 改成 DOWN,这里不再赘述。
之后,调用删除的 URL:http://spring-cloud-server:8761/eureka/apps/[你的服务名]/[你的服务实例id]
本例中为 http://192.168.3.163:8761/eureka/apps/YOUR-SERVICE/192.168.3.111:your-service:8000
使用的 HTTP 方法为 DELETE
6,info以及 health 接口
一般的模式下,应该由组件主动向服务器汇报自己的状态的,但 Spring Cloud 有另一种方式来由服务器发起请求获取组件的内容,在这种情况下,要求组件提供两个接口,默认情况下分别是 /info 以及是 /health,这也可以在注册实例时指定。默认情况下,Springboot 应用 /info 接口返回一个空的 JSON 对象, /health 返回
{"description": "Composite Discovery Client", "status": "UP"}
按照以上步骤,你的其他应用(例如 python)就可以纳入到 Spring Cloud 的体系当中了。