从头开始学Redisson--------分布式远程服务(Remote Service)

x33g5p2x  于2021-12-28 转载在 其他  
字(3.9k)|赞(0)|评价(0)|浏览(469)

一、Redisson使用远程服务

       当前有两台服务器连接的是同一个Redisson中间件,这两台服务器叫它们A节点与B节点吧。A节点可以发布一些API接口,也实现了它们,并向Redisson服务中心注册。B节点向Redisson注册中心订阅这些API接口,因此它可以向Redisson服务器发送这些请求,这些请求最终会被注册中心转发到A节点。这样,B节点就能够通过Redisson注册中心与A节点通信,从而实现远程服务调用功能。

       分布式远程服务(Remote Service)提供了两种类型的RRemoteService实例:

**         服务端(远端)实例** - 用来执行远程方法(工作者实例即worker instance). 例如

RRemoteService remoteService = redisson.getRemoteService();
SomeServiceImpl someServiceImpl = new SomeServiceImpl();

// 在调用远程方法以前,应该首先注册远程服务
// 只注册了一个服务端工作者实例,只能同时执行一个并发调用
remoteService.register(SomeServiceInterface.class, someServiceImpl);

// 注册了12个服务端工作者实例,可以同时执行12个并发调用
remoteService.register(SomeServiceInterface.class, someServiceImpl, 12);

**        客户端(本地)实例** - 用来请求远程方法. 例如:

RRemoteService remoteService = redisson.getRemoteService();
SomeServiceInterface service = remoteService.get(SomeServiceInterface.class);

String result = service.doSomeStuff(1L, "secondParam", new AnyParam());

二、服务端(生产端)实战

        (1)首先服务器端会定义一个接口IMailService,并实现它IMailServiceImpl。这里注意的是,IMailService与MailDto都是在API模块里面的,方便打包并发布。MailDto需要实现序列化接口,因为需要存放在Redis中并

public interface IMailService {

    MailDto queryMail(Long id);
}

@Service
public class IMailServiceImpl implements IMailService {

    @Autowired
    private MailMapper mailMapper;

    @Override
    public MailDto queryMail(Long id) {
        Mail mail = mailMapper.selectByPrimaryKey(id);
        MailDto dto = new MailDto();
        if (mail != null) {
            BeanUtils.copyProperties(mail, dto);
        }
        return dto;
    }
}

      (2)向Redisson注册中心发布API。CommandLineRunner接口的功能是在SpringBoot项目启动的时候执行相关的功能。

@Component
public class RemoteServiceInit implements CommandLineRunner {
    private static final Logger LOGGER = 
                           LoggerFactory.getLogger(RemoteServiceInit.class);

    @Autowired
    private RedissonClient redisson;

    @Autowired
    private IMailService iMailService;

    @Override
    public void run(String... strings) throws Exception {
        LOGGER.info("初始化Redisson远程调度");
        RRemoteService remoteService = redisson.getRemoteService();
        //初始化5个并发实例
        remoteService.register(IMailService.class, iMailService, 5);
    }
}

 三、客户端(消费端)实战

      生产端的IMailService与MailDto最好定义在API模块,方便打包发布。打包成jar以后,导入到消费端项目B中。消费端项目B需要与生产端连接相同的Redisson服务器。

@Service
public class RemoteMailService {

    @Autowired
    private RedissonClient redisson;

    public MailDto queryMail(Long id) {
        //获取Redisson远程服务
        RRemoteService remoteService = redisson.getRemoteService();
        //应答回执超时1秒钟,远程执行超时30秒钟
        RemoteInvocationOptions options = RemoteInvocationOptions.defaults();
        //拿到生产端的接口
        IMailService iMailService = remoteService.get(IMailService.class,options);
        //调用
        return iMailService.queryMail(id);
    }
}


Redisson远程服务

 四、响应模式附录

      涉及到网络传输,所以可能有传输失败的情况。更多的应答模式如下。

      noResult()是指远程调用的方法,不需要有返回值。noAck()表示消费端不需要要服务端响应。

// 应答回执超时1秒钟,远程执行超时30秒钟
RemoteInvocationOptions options = RemoteInvocationOptions.defaults();

// 无需应答回执,远程执行超时30秒钟
RemoteInvocationOptions options = RemoteInvocationOptions.defaults().noAck();

// 应答回执超时1秒钟,不等待执行结果
RemoteInvocationOptions options = RemoteInvocationOptions.defaults().noResult();

// 应答回执超时1分钟,不等待执行结果
RemoteInvocationOptions options = RemoteInvocationOptions.defaults().
                                        expectAckWithin(1, TimeUnit.MINUTES).noResult();

// 发送即不管(Fire-and-Forget)模式,无需应答回执,不等待结果
RemoteInvocationOptions options = RemoteInvocationOptions.defaults().noAck().noResult();

RRemoteService remoteService = redisson.getRemoteService();
YourService service = remoteService.get(YourService.class, options);

       下面的这段代码是我自己实测的。

       expectResultWithin(15,TimeUnit.SECONDS)表示,如果生产端服务器能够接通的话,在15秒之内需要返回数据,否则报异常No response after 15000ms for request。 

       expectAckWithin(10,TimeUnit.SECONDS)表示,生产端服务器需要在10秒内有响应,否则报异常No ACK response after 10000ms for request。

public MailDto queryMail(Long id) {

        RRemoteService remoteService = redisson.getRemoteService();
        //应答回执超过5秒钟,不等待执行结果
        RemoteInvocationOptions options = RemoteInvocationOptions.defaults().
                expectResultWithin(15, TimeUnit.SECONDS).expectAckWithin(10,TimeUnit.SECONDS);
        Long start = System.currentTimeMillis();
        IMailService iMailService = remoteService.get(IMailService.class,options);
        MailDto result = null;
        try {
             result =  iMailService.queryMail(id);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        Long end = System.currentTimeMillis();
        System.out.println(end - start);
        return result;
    }

相关文章