ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Dubbo 对象序列化、超时、重试、多版本控制

2022-06-11 19:03:09  阅读:228  来源: 互联网

标签:Dubbo 版本控制 jobs 接口 User import 序列化 com


之前已经快速搭建了 Dubbo 入门 Demo,本篇博客将继续在此 Demo 的基础上,介绍一下 Dubbo 在实际项目开发中必然会用到的一些简单实用的技术点,只需要编写很少的代码或者进行一些注解配置即可实现,大大提高了开发效率。在本篇博客的最后,会提供源代码的下载,需要注意的是:在运行本 Demo 代码时,必须先启动 Zookeeper 作为注册中心。


一、对象序列化

我们在编写服务接口时,如果接口参数或者接口返回值,需要使用实体类对象的话,那么实体类必须要实现 Serializable 接口,否则在运行过程中会报错。既然实体类是在接口定义中使用,因此 Dubbo 服务端和客户端都必须使用,所以本 Demo 就将实体类也放到了 dubbo_interface 这个公共模块中,如下图所示:

image

在 dubbo_interface 公共模块中,增加了 com.jobs.domain 包,增加实体类 User

package com.jobs.domain;

import java.io.Serializable;

//实体类承载数据,要想在 Dubbo 客户端和服务端之间传输,
//必须实现 Serializable 接口
public class User implements Serializable {

    private String name;
    private Integer age;

    public User() {
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

在 TestService 接口中定义一个方法使用 User 实体类:

package com.jobs.service;

import com.jobs.domain.User;

public interface TestService {

    User GetUserDetail(int id);
}

在 Dubbo 服务端实现该接口:

package com.jobs.service.impl;

import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Service;

//需要注意:这里的 @Service 注解是 Dubbo 提供的
//不要使用 Spring 提供的 @Service 注解
@Service
public class TestServiceImpl implements TestService {

    @Override
    public User GetUserDetail(int id) {
        User user;
        if (id == 1) {
            user = new User("任肥肥", 38);
        } else {
            user = new User("候胖胖", 40);
        }
        return user;
    }
}

在 Dubbo 客户端进行调用和测试:

package com.jobs.controller;

import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/test")
public class TestController {

    //这里生成远程接口代理,从而可以调用远程服务接口
    @Reference
    private TestService testService;

    //测试实现了 Serializable 接口的实体类承载数据进行传输
    //采用 restful 风格,把传递的参数写在路径上
    @GetMapping("/getuser/{id}")
    public User GetCal(@PathVariable("id") int uid) {
        User user = testService.GetUserDetail(uid);
        return user;
    }
}

二、地址缓存

当 Dubbo 客户端调用过一次 Dubbo 服务端的接口之后,服务端接口的地址就被缓存到 Dubbo 客户端了,所以 Dubbo 客户端并不是每次调用服务端接口,都得向 Zookeeper 注册中心获取接口服务地址。

当接口服务地址发生变化时,Zookeeper 注册中心会通知 Dubbo 客户端,此时 Dubbo 客户端会重新到注册中心获取最新的接口地址,然后缓存到 Dubbo 客户端中。因此如果 Zookeeper 注册中心宕机挂掉了,不会影响 Dubbo 客户端调用之前已经调用过的接口服务,但是新的接口服务就无法调用了。


三、超时和重试

我们既可以在 Dubbo 客户端的 @Reference 注解上配置超时和重试,也可以在 Dubbo 服务端的 @Service 注解上配置超时和重试。但是比较推荐的做法是在 Dubbo 服务端进行配置超时和重试,因为服务的开发者知道具体接口的执行耗费时间。需要注意的是:如果同时在客户端和服务端都配置了超时和重试的话,客户端上的配置会覆盖服务端的配置。

如果不进行配置的话,超时的时间默认为 1000 毫秒,重试的次数默认为 2 次,下面列出服务端的配置:

package com.jobs.service.impl;

import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Service;

//需要注意:这里的 @Service 注解是 Dubbo 提供的
//不要使用 Spring 提供的 @Service 注解

//一般情况下,超时和重试,配置在 Dubbo 服务端,
//如果在 Dubbo 客户端配置超时和重试的话,会覆盖服务端的配置
//以下表明超时时间为 2 秒,先尝试请求 1 次,如果超时则再重试 1 次,一共最多请求 2 次
//如果不配置的话,默认超时是 1 秒钟,默认重试次数是 2 次
@Service(timeout = 2000, retries = 1)
public class TestServiceImpl implements TestService {

    @Override
    public User GetUserDetail(int id) {
        User user;
        if (id == 1) {
            user = new User("任肥肥", 38);
        } else {
            user = new User("候胖胖", 40);
        }
        return user;
    }
}

需要注意的是:根据业务重要性的实际情况,建议在服务端中,把读服务和写服务,进行分离。因为对于读取数据的服务,在超时后进行重试,一般情况下对业务不会有影响。但是对于写数据的接口服务来说,如果超时后进行重试,可能会影响业务,因此一般对于写服务,配置重试的次数为 0。当然要解决重复写数据对业务影响的问题,也是解决方案的,以上建议仅供参考。


四、多版本控制

对于 Java 来说,同一个接口的实现类,可以有多个。因此对于 Dubbo 服务端来说,同一个服务的实现类可以有多个,可以给不同的实现类通过 @Service 注解配置版本号,版本号是字符串,可以随意配置。在 Dubbo 客户端只需要在 @Reference 注解上配置要调用接口服务的版本,即可调用具体版本的服务接口。如下图所示,我们新建了一个 TestServiceImpl2 类实现 TestService 接口,作为一个新版本的服务。

image

下面列出两个版本服务的代码:

package com.jobs.service.impl;

import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Service;

//需要注意:这里的 @Service 注解是 Dubbo 提供的
//不要使用 Spring 提供的 @Service 注解
@Service(timeout = 2000, retries = 1, version = "1.0")
public class TestServiceImpl implements TestService {

    @Override
    public User GetUserDetail(int id) {
        User user;
        if (id == 1) {
            user = new User("任肥肥", 38);
        } else {
            user = new User("候胖胖", 40);
        }
        return user;
    }
}
package com.jobs.service.impl;

import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Service;

//这里编写了另外一个版本的服务,多个版本的服务可以同时存在
@Service(timeout = 2000, retries = 1, version = "2.0")
public class TestServiceImpl2 implements TestService {

    @Override
    public User GetUserDetail(int id) {
        User user;
        if (id == 1) {
            user = new User("李墩墩", 38);
        } else {
            user = new User("乔豆豆", 40);
        }
        return user;
    }
}

在 Dubbo 客户端通过 @Reference 注解上配置要调用接口服务的版本:

package com.jobs.controller;

import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/test")
public class TestController {

    //这里生成远程接口代理,从而可以调用远程服务接口
    //通过 version 配置,可以指定调用哪个版本的接口服务
    @Reference(version = "2.0")
    private TestService testService;

    //测试实现了 Serializable 接口的实体类承载数据进行传输
    //采用 restful 风格,把传递的参数写在路径上
    @GetMapping("/getuser/{id}")
    public User GetCal(@PathVariable("id") int uid) {
        User user = testService.GetUserDetail(uid);
        return user;
    }
}

多版本控制的情况,比较适合灰度发布。接口在大规模更新之前,大部分用户仍然使用原来的接口服务,先让一部分用户使用新接口服务,如果用了一段时间没有问题的话,就可以让所有的用户都使用新接口服务,从而完成灰度发布。


本篇博客源代码下载地址:https://files.cnblogs.com/files/blogs/699532/DubboDemo2.zip

标签:Dubbo,版本控制,jobs,接口,User,import,序列化,com
来源: https://www.cnblogs.com/studyjobs/p/16366520.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有