一,续
在上一篇文章中简单介绍了下consul和集群环境搭建,点我查看上一篇文章。
本篇中将介绍怎么将服务注册至consul集群中,并形成一个公共jar包,在springmvc或者springboot应用启动时将服务注册至consul集群中,应用退出时将服务从consul集群中移除。
二,实现思路
1.consul集群如何利用
这里将利用consul的健康检查的特性来保证我们服务消费方发现的服务是健康可用的。
服务提供方一般是我们的应用程序,比如会员服务,订单服务之类的,服务消费方一般是我们的网关。
比如会员服务有三台机器,将三台机器的ip和port分别注册至consul集群中,当会员服务的某台机器挂掉之后,consul集群中的健康检查就会将该服务标记为严重,网关向consul集群中获取健康的服务列表时,该机器提供的服务将不能被发现,
网关转发请求时自然就不会把请求转发到挂掉的那台机器了。
另外利用服务注册时提供的tag,我们可以利用tag做版本管理,发现服务时可以根据tag来查询。
还有一点就是,我们可以利用该思路来做灰度发布,如果网关做的比较完善的话,我只要保证每个服务有一台机器正常提供服务,整个系统就能一直正常运行,能做到随时增加和减少某个服务的机器。
坑:当你向集群中的某个节点注册服务时,该节点不会向其他节点扩散该服务信息,该节点挂掉后,该服务将不能被发现。我的解决办法比较暴力,将该服务信息向集群中的所有节点注册,服务发现时再将重复的服务信息,即ip+端口+版本一致的话,即认为是重复的服务,只保留一条该服务信息。
2.技术方面
技术方面主要是分别实现spring的InitializingBean,DisposableBean两个接口来达到应用程序启动时执行注册,应用程序退出时销毁服务。
三,实现spring应用程序注册至consul集群公共jar包
1.代码包结构,有以下几个类
- com.sdk.consul.consts.ConsulConsts.java
因为我们的配置文件properties每个环境只有一份,而且同一服务会在多台服务器上部署,每台服务器的ip和端口不一样,所以为了发布的时候不修改properties文件,故一般会在jvm启动参数中配置当前服务的ip和端口,这个文件定义的就是这两个启动参数的名字。 - com.sdk.consul.exception.ConsulServiceException.java
异常类,不多说了。 - com.sdk.consul.utils.Md5Utils.java
对应用服务ip+端口加密生成serviceid,保证服务器ip和端口不变,生成的servcieid也不变 - com.sdk.consul.utils.ServerUtils.java
通过java代码获取当前服务器ip和web服务器(如tomcat)的运行端口,多网卡下会有问题,因此这是获取应用服务ip和端口的最后一个选项。 - com.sdk.consul.utils.StringUtils.java
处理字符串的类,不多帅。 - com.sdk.consul.ConsulConfig.java
服务注册入口,spring mvc将此类在xml中定义成bean即可,类似下面这样:
<bean class="com.sdk.consul.ConsulConfig"></bean>
springboot在启动入口类中@Import(ConsulConfig.class) - com.sdk.consul.ConsulProperty.java
properties配置文件配置信息类 - com.sdk.consul.RegisterService.java
服务操作类,提供注册和销毁服务等方法。
2.jar包依赖
- pom依赖以下jar包
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>com.ecwid.consul</groupId>
<artifactId>consul-api</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.9.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
3.类具体代码
- com.sdk.consul.consts.ConsulConsts.java
package com.sdk.consul.consts;
public class ConsulConsts {
/** JVM启动参数名称-服务暴露地址 */
public static final String CONSUL_SERVICE_URL = "CONSUL_SERVICE_URL";
/**VM启动参数名称-服务暴露端口*/
public static final String CONSUL_SERVICE_PORT = "CONSUL_SERVICE_PORT";
}
- com.sdk.consul.exception.ConsulServiceException.java
package com.sdk.consul.exception;
/**
* Consul服务注册异常类
*/
public class ConsulServiceException extends RuntimeException{
public ConsulServiceException() {
super();
}
public ConsulServiceException(final String message) {
super(message);
}
public ConsulServiceException(final String message, final Throwable cause) {
super(message, cause);
}
}
- com.sdk.consul.utils.Md5Utils.java
package com.sdk.consul.util;
import com.sdk.consul.exception.ConsulServiceException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Md5Utils {
/**
* MD5加密
* @param source 加密前字符串
* @return
* @throws ConsulServiceException
* @throws NoSuchAlgorithmException
*/
public static String encrypt(String source) throws ConsulServiceException,NoSuchAlgorithmException {
if(StringUtils.isEmpty(source)){
throw new ConsulServiceException("Please input a not blank value to encrypt md5.");
}
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] md5Bytes = md5.digest(source.getBytes());
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int