上传文件Dubbo报错: Data length too large: xxxxx, max payload: 8388608

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: 上传文件Dubbo报错: Data length too large: xxxxx, max payload: 8388608

一、场景:

服务端是微服务,服务A有个上传图片的功能,需求是限制大小为10M,用户通过客户端把图片上传到服务AA再调用服务B把文件上传至阿里oss。

功能实际上很简单,实现的代码如下:

服务A的Controller层逻辑

@PostMapping("/upload")
public Result<String> upload(@RequestParam MultipartFile file) {
    Long userId = SecurityContextHolder.getUserId();
    return Result.success(feedbackService.uploadAttachment(userId, file));
}

服务A的Service层逻辑

@DubboReference(version = "1.0.0")
private RemoteFileService fileService;
@Override
public String uploadAttachment(Long userId, MultipartFile file) {    
    // 文件大小限制为10M
    if (file.getSize() > 10 * 1024 * 1024) {
        throw new ClientErrorException("文件大小超过10M限制");
    }
    // 文件上传OSS
    return fileService.storage(file.getBytes(), file.getOriginalFilename(), userId);   
}

服务B的业务逻辑,文件保存到阿里云OSS

@DubboService(version = "1.0.0")
public class DubboFileService implements RemoteFileService {
  @Override
  public String storage(byte[] bytes, String fileName, Long userId) {
      String fileId = String.format("file/%d-%d%s", userId, System.currentTimeMillis(), fileName.substring(fileName.lastIndexOf('.')));
      //上传到oss
      if (!ossService.upload(fileId, bytes)) {
          throw new ServerErrorException("上传失败");
      }
      //文件信息
      FileInfo info = new FileInfo();
      info.setUserId(userId);
      info.setMd5(Md5Utils.getMD5(bytes));
      info.setSize(bytes.length);
      info.setName(fileName);
    //完整路径
      String filePath = String.format("%s/%s", ExternalUrl.CDN_HOST, fileId);
      info.setDownload(filePath);
      //保存到数据库
      fileMapper.addOne(info);
  
      return filePath;
  }
}

两个服务调用是采用的dubbo协议,配置如下:

公共配置:

dubbo:  
  application:
    name: ${spring.application.name}
  protocol:
    # dubbo 协议
    name: dubbo
    # dubbo 协议端口( -1 表示自增端口,从 20880 开始)
    port: -1
    threads: 2000
  registry:
    address: nacos://${spring.cloud.nacos.discovery.server-addr}/?namespace=dubbo
    check: false
  #生产者
  provider:
    timeout: 25000
  #消费者
  consumer:
    timeout: 25000
    check: false

服务A配置

# dubbo
dubbo:
  scan:
    # dubbo 服务扫描基准包
    base-packages: com.xxx.feedback.dubbo
  cloud:
    subscribed-services: feedback

服务B配置

# dubbo
dubbo:
  scan:
    # dubbo 服务扫描基准包
    base-packages: com.xxx.file.dubbo
  cloud:
    subscribed-services: file

二、测试过程

测试上传9.83M文件,报500错误,显示后台异常,查看日志,异常日志如下

[ERROR] 2023-12-13 10:42:31.918 o.a.d.r.transport.AbstractCodec         [52]: Data length too large: 12111020, max payload: 8388608, channel: NettyChannel [channel=[id: 0x25031a14, L:/192.168.0.2:53556 - R:/192.168.0.2:20881]]
org.apache.dubbo.remoting.transport.ExceedPayloadLimitException: Data length too large: 10307502, max payload: 8388608, channel: NettyChannel [channel=[id: 0x25031a14, L:/192.168.0.2:53556 - R:/192.168.0.2:20881]]
        at org.apache.dubbo.remoting.transport.AbstractCodec.checkPayload(AbstractCodec.java:50)
        at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encodeRequest(ExchangeCodec.java:270)
        at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encode(ExchangeCodec.java:71)
        at org.apache.dubbo.rpc.protocol.dubbo.DubboCountCodec.encode(DubboCountCodec.java:40)
        at org.apache.dubbo.remoting.transport.netty4.NettyCodecAdapter$InternalEncoder.encode(NettyCodecAdapter.java:69)
... ...

查了资料,dubbo默认的传输大小是8388608B(8M)。修改配置,公共配置增加了dubbo.protocol.dubbo.payload一项。

# dubbo配置,其他略
dubbo:
  protocol:
    # dubbo 协议
    name: dubbo
    # dubbo 协议端口( -1 表示自增端口,从 20880 开始)
    port: -1
    threads: 2000
      dubbo:
      # 传输大数据容量 10MB
        payload: 10485760

继续测试,问题依旧,配置完全没有生效。继续查资料,又看到另外一种配置方式

# dubbo
dubbo:
  application:
    name: ${spring.application.name}
  protocol:
    # dubbo 协议
    name: dubbo
    # dubbo 协议端口( -1 表示自增端口,从 20880 开始)
    port: -1
    threads: 2000
    # 传输大数据容量 10M
    payload: 10485760
  registry:
    address: nacos://${spring.cloud.nacos.discovery.server-addr}/?namespace=dubbo
    check: false
  #生产者
  provider:
    payload: 10485760
    timeout: 25000
  #消费者
  consumer:
    parameters:
      payload: 10485760
    timeout: 25000
    check: false

测试成功,说明配置已经生效了。更新到生产环境,再次测试,上传界面一直无响应,等了许久显示超时。日志打印的错误如下:

[ERROR] 2023-12-13 11:23:44.471 c.i.c.s.h.GlobalExceptionHandler        [96]: 请求地址'/upload'发生未知异常.
org.apache.dubbo.rpc.RpcException: Failed to invoke the method storage in the service com.xxx.file.api.RemoteFileService. Tried 3 times of the providers [192.168.0.2:20881] (1/1) from the registry 192.168.0.234:8848 on the consumer 192.168.0.2 using the dubbo version 2.7.15. Last error is: Invoke remote method timeout. method: storage, provider: dubbo://192.168.0.2:20881/com.xxx.file.api.RemoteFileService?anyhost=true&application=feedback&category=providers&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&init=false&interface=com.xxx.file.api.RemoteFileService&metadata-type=remote&methods=download,storage,allFiles&path=com.xxx.file.api.RemoteFileService&payload=11557050&pid=24099&protocol=dubbo&qos.enable=false&register.ip=192.168.0.2&release=2.7.15&remote.application=file&revision=1.0.0&service.name=ServiceBean:/com.xxx.file.api.RemoteFileService:1.0.0&side=consumer&sticky=false&timeout=25000&timestamp=1699945248523&version=1.0.0, cause: org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. start time: 2023-12-13 11:23:19.423, end time: 2023-12-13 11:23:44.443, client elapsed: 86 ms, server elapsed: 24934 ms, timeout: 25000 ms, request: Request [id=591, version=2.0.2, twoway=true, event=false, broken=false, data=null], channel: /192.168.0.2:40518 -> /192.168.0.2:20881
        at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:110)
        at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:265)
        at org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor.intercept(ClusterInterceptor.java:47)
        at org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster$InterceptorInvokerNode.invoke(AbstractCluster.java:92)
        at org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:98)
        at org.apache.dubbo.registry.client.migration.MigrationInvoker.invoke(MigrationInvoker.java:170)
        at org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareClusterInvoker.doInvoke(ZoneAwareClusterInvoker.java:100)
        at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:265)
        at org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor.intercept(ClusterInterceptor.java:47)
        at org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster$InterceptorInvokerNode.invoke(AbstractCluster.java:92)
        at org.apache.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:96)
        at org.apache.dubbo.common.bytecode.proxy2.storage(proxy2.java)
        at com.xx.feedback.service.impl.FeedbackServiceImpl.uploadAttachment(FeedbackServiceImpl.java:387)
        at com.xxx.feedback.service.impl.FeedbackServiceImpl$$FastClassBySpringCGLIB$$f1a53452.invoke(<generated>)
... ...

尝试修改超时配置,把timeout时长改长1分钟。

# dubbo配置
dubbo:
  application:
    name: ${spring.application.name}
  protocol:
    # dubbo 协议
    name: dubbo
    # dubbo 协议端口( -1 表示自增端口,从 20880 开始)
    port: -1
    threads: 2000
    # 传输大数据容量 10M
    payload: 10485760
  registry:
    address: nacos://${spring.cloud.nacos.discovery.server-addr}/?namespace=dubbo
    timeout: 25000
    check: false
  #生产者
  provider:
    payload: 10485760
    timeout: 65000
  #消费者
  consumer:
    parameters:
      payload: 10485760
    timeout: 60000
    check: false

再次测试依旧报错,难道说超时配置也不生效?没办法了,只能修改代码了。

服务A(服务消费者)增加timeout参数,但这个时间比消费者略大一点

@DubboReference(version = "1.0.0", timeout = 60 * 1000)

服务B(服务生产者)增加timeout参数,但这个时间比消费者略大一点

@DubboService(version = "1.0.0", timeout = 65 * 1000)

重启生效。

三、总结

相同的代码在不同的环境可能执行效果不一样,一定要认真检查和测试,保证功能没有任何问题才能正式使用。

另外,payload最好设置大一点,我们正常的业务可能是文件+表单一起提交的,大小可能超过10M,防止这种情况就把payload设置大一点。

还有人说可以使用dubbo的hessian协议来解决大文件传输,这个我还没研究,后面有时间再看看。

相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
相关文章
|
9月前
|
Dubbo 应用服务中间件 Nacos
Dubbo “Data length too large“ 问题
解决Dubbo “Data length too large“ 问题
110 0
|
Dubbo 大数据 应用服务中间件
【解决方法】Dubbo报错Data length too large
Data长度超过设置参数的最大值
|
9月前
|
Dubbo 应用服务中间件 Apache
集成Nacos1.2.1和Dubbo2.7.6 消费者报错No provider available for the service xxx
集成Nacos1.2.1和Dubbo2.7.6 消费者报错No provider available for the service xxx
95 0
|
Dubbo 应用服务中间件 数据库
Dubbo分布式架构中 消费者报错Failed to configure a DataSource: ‘url‘ attribute is not specified and no embedded
Dubbo分布式架构中 消费者报错Failed to configure a DataSource: ‘url‘ attribute is not specified and no embedded
162 0
Dubbo分布式架构中 消费者报错Failed to configure a DataSource: ‘url‘ attribute is not specified and no embedded
|
Dubbo 应用服务中间件
Dubbo 报错 Data length too large
Dubbo 报错 Data length too large
550 0
|
Java Apache
Dubbo-admin+Zookeeper 的环境搭建实操与 Could-not-extract-archive 报错踩坑
``` $ brew install zookeeper ==&gt; Downloading https://homebrew.bintray.com/bottles/zookeeper-3.4.13.mojave.bottle.tar.gz ... ``` 先来看dubbo-admin的安装;我们先找到它在apache下的官方GitHub,官方也有相关介绍,中英文版都有(毕竟原本
|
Java Apache
Dubbo-admin+Zookeeper 的环境搭建实操与 Could-not-extract-archive 报错踩坑
``` $ brew install zookeeper ==> Downloading https://homebrew.bintray.com/bottles/zookeeper-3.4.13.mojave.bottle.tar.gz ... ``` 先来看dubbo-admin的安装;我们先找到它在apache下的官方GitHub,官方也有相关介绍,中英文版都有(毕竟原本
Dubbo-admin+Zookeeper 的环境搭建实操与 Could-not-extract-archive 报错踩坑
``` $ brew install zookeeper ==&gt; Downloading https://homebrew.bintray.com/bottles/zookeeper-3.4.13.mojave.bottle.tar.gz ... ``` 先来看dubbo-admin的安装;我们先找到它在apache下的官方GitHub,官方也有相关介绍,中英文版都有(毕竟原本
|
6天前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
6天前
|
Dubbo Java 应用服务中间件
阿里巴巴资深架构师深度解析微服务架构设计之SpringCloud+Dubbo
软件架构是一个包含各种组织的系统组织,这些组件包括Web服务器,应用服务器,数据库,存储,通讯层),它们彼此或和环境存在关系。系统架构的目标是解决利益相关者的关注点。