dubbo多服务本地开发调试

发表于:2020-9-02 09:54

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:叁滴水    来源:CSDN

  前言
  在dubbo多服务开发的时候经常有这种问题,比如有用户服务,订单服务,商品服务,消息服务,日志服务等等吧,反正服务很多的情况下,在新增一个简单的功能,在代码调试时需要启动所有相关的服务。
  比如调试任服务都需要用户服务进行登录,日志服务进行记录日志,消息服务进行短信发送,但是这些服务只是使用就好,并不进行代码的修改。然而这种情况,也在本地启动服务,会造成内存的浪费,笔者开发的时候随随便便一个小功能都需要启动4个服务,16G的内存瞬间就没了,很是难受。
  一、解决思路
  百度了好多资料,有的说进行服务的分组,或者进行直接提供者,也试过,但是比如这次开发用到了a,b,c服务,明天开发另外一个功能需要x,y,z服务,每次都要配置好麻烦。而且一旦手残发到线上,那就是要被骂死了。
  我的实现思路是,每次进行远程调用时,都加一个调用标识——起始ip信息,这个起始的ip在每次远程调用时都进行传递,然后修改负载均衡规则,优先选择为起始ip的服务。
  如上,所有的开发者,全部注册到一个注册中心,比如前端vue进行调用时,api做为入口(api对各个服务进行调用)
  1.和前端同学进行联调,前端同学链接开发B的机器进行接口调用
  2.api寻找用户服务,进行登录(携带了开发B的ip)
  3.api寻找订单服务,查询订单(携带开发B的ip),这里有可能会调用到开发A的订单服务,毕竟是同一个注册中心。
  4.订单服务去商品服务,查询订单下的商品,订单服务发现自己不是起始调用者,优先选择起始ip的服务,所以选择调用开发B的商品服务。
  实现这个步骤很简单,只需要两步:
  1.新增一个调用的拦截添加起始ip信息
  2.自定义路由优先选择本地地址。
  二、代码
  1.自定义拦截器
  代码如下(示例):
public class DevFilter implements Filter {
    private static final Log logger = 
    LogFactory.getLog(DevLoadBalance.class);
    /**
     * 每次进行远程条用都经过此方法,加入开始ip的标识
     */
    public Result invoke(Invoker<?> invoker, Invocation invocation) 
    throws RpcException {
        logger.info("dev filter start");
        //判断是否存在开始ip
        Object fromIp = RpcContext.getContext().getAttachment(DevDubboConstants.START_IP);
        if(fromIp==null){
            try {
                //第一次调用时,设置开始ip
                fromIp = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
        logger.info("dev filter set startip is "+fromIp);
        //设置ip信息,这种设置信息,可以在服务提供者进行获取。
        //这种方式是dubbo的隐式传参  有兴趣的参考官方
        // http://dubbo.apache.org/zh-cn/docs/user/demos/attachment.html
 //当然还有url中进行拼接上下文信息,有兴趣的可以任意选择。
        RpcContext.getContext().setAttachment(DevDubboConstants.START_IP,fromIp.toString());
        return invoker.invoke(invocation);
    }
}
  dubbo拦截器代码处理好之后需要在resources\META-INF\dubbo目录下新增一个com.alibaba.dubbo.rpc.Filter文件,内容如下:
  dev=com.dubbo.router.filter.DevFilter
  注意:spi文件名要和Filter的包路径一样,官方写的是org.apache.dubbo.rpc.Filter,实际情况要根据自己的版本进行自行调整。
  2.自定义负载规则
  代码如下(示例):
 private static final Log logger = 
 LogFactory.getLog(DevLoadBalance.class);
    public static final String NAME = "dev";

    public <T> Invoker<T> select(List<Invoker<T>> list, URL url, Invocation invocation) throws RpcException {
        logger.info("loadBalance select start");
        //获取起始ip信息
        Object fromIp = RpcContext.getContext().getAttachment(DevDubboConstants.START_IP);
        if(fromIp==null){
            try {
                //如果没有获取到起始ip,则优先选择自己的ip
                fromIp = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
        logger.info("loadBalance select ip is:"+fromIp);
        //选择起始ip的服务,或者自己的服务进行调用
        for(Invoker<T> invoker:list){
            if(invoker.getUrl().getIp().equals(fromIp.toString())){
                return invoker;
            }
        }
        logger.info("select super loadBalance");
        //如果起始ip没有启动服务,自己也没有启动,则使用默认规则
        return super.select(list,url,invocation);
    }
  在resources\META-INF\dubbo路径下新建com.alibaba.dubbo.rpc.cluster.LoadBalance内容如下:
  dev=com.dubbo.router.loadbalance.DevLoadBalance
  注意LoadBalance的包路径,根据自己版本自行修改哈。
  3.环境配置
  实现逻辑大概就是这样,有自己的想法可以自己优化哈,下载工程,通过maven进行打包,引入。
  yml配置示例:loadbalance选择dev,filter选择dev。
dubbo:
  application:
    name: shop-api #服务明后才能
  registry:
    address: zookeeper://192.168.16.128:2181 #zookeeper服务地址
  provider:
    loadbalance: dev
  consumer:
    filter: dev
  port: 8281  #项目端口
  javaAPI配置示例:
 public static void main(String[] args) {
        // 当前应用配置
        ApplicationConfig application = new ApplicationConfig();
        application.setName("yyy");
        // 连接注册中心配置
        RegistryConfig registry = new RegistryConfig();
        registry.setAddress("zookeeper://127.0.0.1:2181");
        ReferenceConfig<IUserService> reference = new ReferenceConfig<IUserService>(); 
        reference.setApplication(application);
        reference.setRegistry(registry); // 多个注册中心可以用setRegistries()
        reference.setInterface(IUserService.class);
        reference.setVersion("1.0.0");
        reference.setLoadbalance("dev");
        reference.setFilter("dev");
        // 和本地bean一样使用xxxService
        IUserService iUserService = reference.get();
        iUserService.getUserInfo("111");
    }
  总结
  笔者使用的yml配置,两个yml文件,测试环境使用dev文件,生成使用另一个。如果大家在开发的时候使用更好的开发方式,希望大家可以多多指点。

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号