• 在项目中同时使用SpringCloud和Dubbo,注册中心选用Eureka?


    一、前置知识

    1、在Spring Boot中使用Dubbo?

    在pom.xml文件中添加Dubbo相关依赖:服务提供者和服务消费者都需要

    <dependency>
        <groupId>org.apache.dubbogroupId>
        <artifactId>dubbo-spring-boot-starterartifactId>
        <version>2.7.8version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1)配置服务提供者

    1、在配置文件中配置Dubbo的相关信息:

    # Dubbo应用名称
    dubbo.application.name=forlan-provider
    # Dubbo注册中心地址
    dubbo.registry.address=zookeeper://localhost:2181
    # Dubbo服务协议
    dubbo.protocol.name=dubbo
    dubbo.protocol.port=20880
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、在服务提供者的启动类上添加@EnableDubbo注解:

    @SpringBootApplication
    @EnableDubbo
    public class ForlanProviderApplication {
        public static void main(String[] args) {
            SpringApplication.run(ProviderApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3、编写服务提供者的接口和实现类:
    添加@Service,指定interfaceClass属性来指定要暴露的接口

    public interface HelloService {
        String sayHello(String name);
    }
    
    @Service(interfaceClass = HelloService.class)
    public class HelloServiceImpl implements HelloService {
        @Override
        public String sayHello(String name) {
            return "Hello, " + name + "!";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2)配置服务消费者

    1、在配置文件中配置Dubbo的相关信息:

    # Dubbo应用名称
    dubbo.application.name=forlan-consumer
    # Dubbo注册中心地址
    dubbo.registry.address=zookeeper://localhost:2181
    # Dubbo服务协议
    dubbo.protocol.name=dubbo
    dubbo.protocol.port=20880
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、在服务消费者的启动类上添加@EnableDubbo注解:
    添加@Reference注解,声明对Dubbo服务的引用

    @SpringBootApplication
    @EnableDubbo
    public class ConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3、编写服务消费者的代码:

    @RestController
    public class HelloController {
        @Reference
        private HelloService helloService;
    
        @GetMapping("/hello")
        public String sayHello(@RequestParam String name) {
            return helloService.sayHello(name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、在Spring Boot中使用Eureka?

    1)Eureka服务器

    在pom.xml文件中添加Eureka服务端依赖

    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    添加配置:

    # 什么都不配,Eureka服务的默认端口号是8761
    
    • 1

    配置Eureka服务器:在Spring Boot应用程序的主类上添加@EnableEurekaServer注解,以将应用程序标记为Eureka服务器。

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaServerApplication {
        public static void main(String[] args) {
            SpringApplication.run(EurekaServerApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2)Eureka客户端

    在pom.xml文件中添加Eureka客户端依赖:

    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    添加配置:

    spring.application.name=forlan
    eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
    
    • 1
    • 2

    配置Eureka客户端:在Spring Boot应用程序的主类上添加@EnableDiscoveryClient注解,以将应用程序标记为Eureka客户端。

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class ForlanApplication {
        public static void main(String[] args) {
            SpringApplication.run(ForlanApplication .class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    完成上述配置后,Spring Boot应用程序将作为Eureka客户端注册到Eureka服务器,并且可以通过Eureka服务器进行服务发现和负载均衡。

    二、项目代码分析

    Eureka相关依赖:

    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
    dependency>
    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Dubbo相关依赖:

    <dependency>
        <groupId>org.apache.dubbogroupId>
        <artifactId>dubbo-spring-boot-starterartifactId>
        <version>2.7.1version>
    dependency>
    <dependency>
        <groupId>org.apache.dubbogroupId>
        <artifactId>dubbo-dependencies-bomartifactId>
        <version>2.7.1version>
        <type>pomtype>
        <scope>importscope>
    dependency>
    <dependency>
        <groupId>org.apache.dubbogroupId>
        <artifactId>dubboartifactId>
        <version>2.7.1version>
        <exclusions>
            <exclusion>
                <groupId>org.springframeworkgroupId>
                <artifactId>springartifactId>
            exclusion>
            <exclusion>
                <groupId>javax.servletgroupId>
                <artifactId>servlet-apiartifactId>
            exclusion>
            <exclusion>
                <groupId>log4jgroupId>
                <artifactId>log4jartifactId>
            exclusion>
        exclusions>
    dependency>
    
    • 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

    1、Eureka服务器

    1)启动类

    加上@EnableEurekaServer,将Spring Boot应用程序配置为Eureka Server,使其能够接收其他服务实例的注册请求,并维护服务实例的状态信息。

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaServerApplication {
        public static void main(String[] args) {
            SpringApplication.run(EurekaServerApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2)配置类

    # 客户端是否注册到eureka,默认true,这里为false
    eureka.client.register-with-eureka=false
    # 是否从Eureka服务器获取注册信息,如果单节点,不需要同步其他节点数据,用false
    eureka.client.fetch-registry=false
    # true:实例以IP的形式注册;false:实例以主机名的形式注册
    eureka.instance.preferIpAddress=true
    # 客户端注册到的Eureka服务器地址
    eureka.client.serviceUrl.defaultZone=http://localhost:8300/eureka/
    #Eureka服务器中用于清理过期实例的驱逐间隔时间,默认5000ms
    eureka.server.evictionIntervalTimerInMs=5000
    #  Eureka服务器更新响应缓存的时间间隔,服务器本地会缓存一份,确保响应性能,但又需要确保是最新的,需要定期拉取
    eureka.server.responseCacheUpdateIntervalMs=5000 
    # Eureka服务器是否使用只读响应缓存,false表示可以对缓存修改,一般建议false
    eureka.server.use-read-only-response-cache=false
    # Eureka服务器是否启用自我保护机制,默认true
    eureka.server.enable-self-preservation=false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2、Dubbo服务提供者

    1)启动类

    加上@EnableDubbo,将Spring Boot应用程序配置为Dubbo服务提供者或消费者

    @SpringBootApplication
    @EnableDubbo
    public class ForlanProviderApplication {
        public static void main(String[] args) {
            SpringApplication.run(ForlanProviderApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2)配置类

    # Dubbo应用名
    dubbo.application.name=forlan-provider
    # 设置应用日志记录器,如Log4j、Logback和Java自带的JUL(Java Util Logging),来记录Dubbo框架的日志信息
    dubbo.application.logger=slf4j
    # 扫描注册com.forlan包下的所有服务接口
    dubbo.scan.base-packages=com.msedu.study
    # Dubbo协议名称
    dubbo.protocol.name=dubbo
    # Dubbo协议端口号
    dubbo.protocol.port=20883
    # Dubbo协议使用的线程池类型为fixed(固定大小线程池)
    dubbo.protocol.threadpool=fixed
    # Dubbo协议使用的线程数量为1000,表示同时处理的请求数量
    dubbo.protocol.threads=1000
    # Dubbo协议使用的线队列长度为2000,当线程数达到最大值时,新请求会被放入任务队列中等待处理
    dubbo.protocol.queues=2000
    # 服务提供者的标签,可以设置不同环境为不同标签
    dubbo.provider.tag=v2.8
    # apiVersionFilter 版本过滤器,保证tag延续
    dubbo.provider.filter=apiVersionFilter,providerFilter
    # Dubbo使用的注册中心为zookeeper,地址为zk-cs:2181
    dubbo.registry.address=zookeeper://zk-cs:2181
    # 指定额外的注册中心键和值
    dubbo.registry.extra-keys=default.dubbo.tag
    # 使用简化的注册中心实现来减少注册中心的复杂性和性能开销
    dubbo.registry.simplified=true
    # Dubbo不在启动时检查注册中心的可用性
    dubbo.registry.check=false
    # 在Dubbo中,注册中心可以按照不同的分组来进行管理和区分,这里指定注册中心的分组为 `formal` 
    dubbo.registry.group=formal
    
    # 省略其它无关配置...
    
    • 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
    标签过滤器

    添加过滤器传递dubbo.tag,用于标识和区分不同的服务

    import org.apache.dubbo.rpc.Filter;
    import org.apache.dubbo.rpc.Invocation;
    import org.apache.dubbo.rpc.Invoker;
    import org.apache.dubbo.rpc.Result;
    import org.apache.dubbo.rpc.RpcContext;
    import org.apache.dubbo.rpc.RpcException;
    import org.apache.dubbo.common.Constants;
    
    public class ApiVersionFilter implements Filter {
    	@Override
    	public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    		String version = invocation.getAttachment("dubbo.tag");
    		if (StringUtil.isNotEmpty(version)) {
    			RpcContext.getContext().setAttachment("dubbo.tag", version);
    		}
    		Result result = invoker.invoke(invocation);
    		return result;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    提供者过滤器

    在每个rpc被调用前执行特定逻辑,清空本地线程变量

    import org.apache.dubbo.common.Constants;
    import org.apache.dubbo.common.extension.Activate;
    import org.apache.dubbo.rpc.Filter;
    import org.apache.dubbo.rpc.Invocation;
    import org.apache.dubbo.rpc.Invoker;
    import org.apache.dubbo.rpc.Result;
    import org.apache.dubbo.rpc.RpcException;
    
    @Activate(group = "provider",value = "providerFilter")
    public class ProviderFilter implements Filter{
    	@Override
    	public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    		// 清空本地线程变量
        	ThreadLocalUtil.clearThreadVarible();
        	Result result = invoker.invoke(invocation);
            return result;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3、Dubbo服务消费方/Eureka客户端

    1)启动类

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableDubbo
    public class ForlanRestApplication {
        public static void main(String[] args) {
            SpringApplication.run(ForlanRestApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    @EnableDiscoveryClient的作用:服务注册到服务注册中心,并且能够发现其他注册的微服务实例
    @EnableDubbo的作用:启用Dubbo服务,标识该类作为Dubbo服务的提供者或消费者

    2)配置类

    Eureka相关
    #eureka地址
    eureka.client.serviceUrl.defaultZone=http://localhost:8300/eureka/
    # 服务示例的版本号
    eureka.instance.metadata-map.version=v2.8
    # true:实例以IP的形式注册;false:实例以主机名的形式注册
    eureka.instance.preferIpAddress=true
    # Eureka客户端发送心跳保持租约的时间间隔,默认30s,这里设置为3s,即每3秒发送一次续约
    eureka.instance.leaseRenewalIntervalInSeconds=3
    # Eureka客户端租约到期时间,默认90s,这里设置为10s,即服务器10s内没收到心跳,则认为该实例不可用
    eureka.instance.leaseExpirationDurationInSeconds=10
    # true:客户端会从服务注册中心获取并缓存服务注册表的信息;false:仅使用本地缓存的信息,客户端默认为true
    eureka.client.fetchRegistry=true
    # 客户端获取服务注册表的间隔时间,即刷新本地缓存时间间隔,默认30s
    eureka.client.registryFetchIntervalSeconds=5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    一般的话,eureka.instance.leaseExpirationDurationInSeconds设置为eureka.instance.leaseRenewalIntervalInSeconds的两倍或更多,以确保在网络故障或其他问题时仍能保持可用

    Dubbo相关
    # Dubbo应用名
    dubbo.application.name=forlan-consumer
    # 设置应用日志记录器,如Log4j、Logback和Java自带的JUL(Java Util Logging),来记录Dubbo框架的日志信息
    dubbo.application.logger=slf4j
    # 扫描注册com.forlan包下的所有服务接口
    dubbo.scan.base-packages=com.forlan
    # Dubbo协议名称
    dubbo.protocol.name=dubbo
    # Dubbo协议端口号
    dubbo.protocol.port=20880
    # 消费者在启动时是否检查服务提供者的可用性,false表示在调用服务时才检查
    dubbo.consumer.check=false
    # 消费者调用服务的超时时间,这里设置为50秒
    dubbo.consumer.timeout=50000
    # 消费者在服务调用失败时的重试次数,默认值为0,表示不进行重试
    dubbo.consumer.retries=0
    # 消费者使用的过滤器链
    dubbo.consumer.filter=consumerFilter,-consumercontext,tagRouterFilter
    # Dubbo使用的注册中心为zookeeper,地址为zk-cs:2181
    dubbo.registry.address=zookeeper://zk-cs:2181
    # 指定额外的注册中心键和值
    dubbo.registry.extra-keys=default.dubbo.tag
    # 使用简化的注册中心实现来减少注册中心的复杂性和性能开销
    dubbo.registry.simplified=true
    # Dubbo不在启动时检查注册中心的可用性
    dubbo.registry.check=false
    # 在Dubbo中,注册中心可以按照不同的分组来进行管理和区分,这里指定注册中心的分组为 `formal` 
    dubbo.registry.group=formal
    # 省略其它无关配置...
    
    • 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
    ConsumerFilter

    获取公共参数(accessToken、requestUUID),从本地线程取,设置到dubbo接口上下文中

    import com.msedu.common.utils.ThreadUtil;
    import org.apache.dubbo.common.Constants;
    import org.apache.dubbo.common.extension.Activate;
    import org.apache.dubbo.rpc.*;
    
    @Activate(group = "consumer",value = "consumerFilter")
    public class ConsumerFilter implements Filter{
    
    	@Override
    	public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    	    
            Result result = null;
            
            try {
            	// 调用dubbo接口前存入上下文参数
            	String accessToken = (String) ThreadUtil.get("accessToken");
            	String requestUUID = (String) ThreadUtil.get("requestUUID");
          		RpcContext.getContext().setAttachment("accessToken", accessToken);
            	RpcContext.getContext().setAttachment("requestUUID", requestUUID);
    
            	result = invoker.invoke(invocation);
            }catch(Exception e) {
            	throw e;
            }
            return result;
    	}
    
    }
    
    • 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
    TagRouterFilter

    项目中配置了-consumercontext,表示移除默认的ConsumerContextFilter,用TagRouterFilter替换,之所以要替换,是因为dubbo自带的过滤器会在调用完成之后清理掉Attachments,由于我们需要在Attachments中保留dubbo.tag,否则无法找到对应的服务,这就是TagRouterFilter的作用,其实就是保留了tag路由,RpcContext.getContext().setAttachment(“dubbo.tag”, invocation.getAttachment(“dubbo.tag”))

    @Activate(group = "consumer", order = -10000)
    public class TagRouterFilter implements Filter {
    
    	@Override
    	public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    		RpcContext.getContext().setInvoker(invoker).setInvocation(invocation)
    				.setLocalAddress(NetUtils.getLocalHost(), 0)
    				.setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort());
    		if (invocation instanceof RpcInvocation) {
    			((RpcInvocation) invocation).setInvoker(invoker);
    		}
    		try {
    			RpcContext.removeServerContext();
    			return invoker.invoke(invocation);
    		} finally {
    			RpcContext.getContext().clearAttachments();
    		}
    	}
    
    	@Override
    	public Result onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
    		RpcContext.getServerContext().setAttachments(result.getAttachments());
    		//保留tag路由
    		RpcContext.getContext().setAttachment("dubbo.tag", invocation.getAttachment("dubbo.tag"));
    		return result;
    	}
    
    }
    
    • 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

    在Dubbo中,AbstractRouter是一个抽象类,用于实现路由策略。它的作用是根据一定的规则,决定将请求路由到哪个服务提供者。具体的路由策略可以通过继承AbstractRouter类并实现其中的方法来自定义。Dubbo提供了多种内置的路由策略,如基于标签、基于权重等。通过配置AbstractRouter的实现类,可以灵活地控制服务的路由行为。

    三、总结

    在项目中,SpringCloud和Dubbo要配置使用的话,需要两个注册中心。

    • Eureka

    网关和Tomcat(Web应用程序)都注册到Eureka,主要是为了方便网关进行路由,网关可以从Eureka获取服务的注册信息,包括服务的主机和端口等信息。这样,网关就可以根据需要将请求路由到相应的服务实例上,实现请求的转发和负载均衡。同时,通过Eureka的服务发现机制,网关可以动态地获取服务实例的变化,以便及时更新路由规则。这种方式可以提高系统的灵活性和可扩展性,使网关能够自动适应服务实例的变化。

    • Zookeeper

    Server(提供服务或资源给客户端)注册到Zookeeper,一方作为Dubbo服务提供者,一方作为Dubbo服务消费者,通过Dubbo进行调用。

    总的来说,网关注册到Eureka,Web应用程序同时注册到Eureka和Zookeeper,一方面是可以通过网关路由转发到Web应用程序,另一方面是作为Dubbo消费者;Server注册到Zookeeper作为服务提供者,也可以作为消费者,通过Dubbo调用其它服务。

    思考题

    1、Dubbo可以使用的注册中心?

    默认使用的是Zookeeper作为注册中心,还可以使用Nacos、Consul等作为注册中心,但不能使用Eureka!

    2、Dubbo为什么不能注册到Eureka?

    Dubbo和Eureka是两个不同的服务注册与发现框架,它们之间的集成并不直接支持。

    Dubbo是一个基于Java的分布式服务框架,它使用自己的注册中心来管理服务的注册和发现。Dubbo的注册中心可以是Zookeeper、Etcd、Consul等。Dubbo的设计目标是为了提供高性能和低延迟的RPC通信,因此它使用了一些特定的协议和机制来实现这些目标。

    Eureka是Netflix开源的服务注册与发现框架,它是基于RESTful风格的,主要用于构建云原生应用和微服务架构。Eureka提供了服务注册、发现和负载均衡等功能,并且与Spring Cloud等微服务框架集成紧密。

    由于Dubbo和Eureka的设计和实现方式不同,它们之间的集成并不直接支持。如果你想在使用Dubbo的同时使用Eureka作为服务注册与发现框架,你可以考虑使用Spring Cloud Alibaba项目中的Nacos作为注册中心,Nacos同时支持Dubbo和Spring Cloud的服务注册与发现。这样可以实现Dubbo与Eureka的集成。

    3、服务A只注册到Eureka,Dubbo服务提供者B只注册到Zookeeper,此时,服务A可以调用到B?

    不可以,因为Eureka和ZooKeeper是两个不同的注册中心,它们之间的服务注册与发现是相互独立的。服务A只能通过Eureka注册中心获取到其他通过Eureka注册的服务的地址信息,而无法获取到通过ZooKeeper注册的服务B的地址信息。

    如果服务A需要通过Dubbo调用服务B,需要服务A将自己注册到Zookeeper,才能拉取到服务注册列表,进行Dubbo调用。

    4、Web应用程序所在服务同时注册到了Eureka和Zookeeper中,两个独立注册中心,需要同步机制来保证一致性?

    Eureka的心跳间隔默认为30秒,项目中设置为3s;而Zookeeper的心跳间隔为两倍的tickTime,默认情况下tickTime为2000毫秒(2秒),所以心跳间隔为4秒。两者的心跳间隔不一致,会导致服务状态出现短暂的不一致,可以调整心跳间隔保持一致,也可以需要使用同步处理机制。
    具体方案有:

    1. 通过监听器机制:在服务注册时,可以注册监听器用于监听Eureka和Zookeeper中的服务变化。当服务状态发生变化时,监听器可以接收到通知,并更新另一个注册中心中的服务状态。
    2. 通过定时任务:定时任务可以周期性地检查Eureka和Zookeeper中的服务状态,如果发现状态不一致,则进行相应的同步操作。
    3. 通过事件驱动:当服务状态变化时,Eureka和Zookeeper可以发布事件通知其他服务节点,其他节点通过接收事件来进行状态同步。
    4. 双向注册中心同步:在服务注册或状态变更时,同时将变更信息同步到两个注册中心中,保证双方的服务状态一致性。

    5、项目中为什么同时使用了两个不同的注册中心?

    一开始项目是分布式系统,使用的是Dubbo+Zookeeper,后面改造成了微服务,引入了SpringCloud,它默认使用的是Eureka,高可用,集成比较好,虽然选择Zookeeper也可以,但在旧版本,貌似Zookeeper不支持集成SpringCloud,所以最终同时存在两个注册中心。

    6、Web应用程序所在服务为什么要同时注册到了Eureka和Zookeeper?

    • 注册到Eureka,是为了方便路由转发
    • 注册到Zookeeper,是为了通过Dubbo调用服务
  • 相关阅读:
    MyBatis基础之概念简介
    Stream流操作
    gdb命令学习笔记
    顺序表的C语言实现(静态/动态)
    kubernetes-调度
    TMK1TTA OSN1800全新板卡10路任意速率业务支路处理板
    【星海出品】ansible入门(四)playbook kolla开源例子
    【深度学习】Yolov8 区域计数
    适合学生党的蓝牙耳机有哪些?学生党蓝牙耳机推荐
    `maven.test.skip` 和 `skipTests` 的区别
  • 原文地址:https://blog.csdn.net/qq_36433289/article/details/133989401