在微服务之间共享文件

Posted

技术标签:

【中文标题】在微服务之间共享文件【英文标题】:Sharing files between microservices 【发布时间】:2017-05-27 07:39:32 【问题描述】:

我正在尝试将项目从其当前的单体状态转移到微服务架构。该项目位于 Node.js 中,因此我开始研究 Seneca.js,尤其是其 seneca-mesh 模块。将图像操作(裁剪、调整大小等)移动到微服务中似乎是最明智的第一步,因为它现在大大降低了我的应用程序的速度。

当应用程序是单体应用程序时,将某些文件传递到文件操作逻辑中没有问题——只需从本地存储磁盘读取即可。然而,对于微服务,如果我们牢记可扩展性,它就会变得更加困难。当然,我可以构建一个图像处理微服务,在同一台主机上进行扩展,并在它之间共享我需要的目录,这样它们也可以从本地磁盘读取。

如果我想要一个真正可扩展的微服务,它可以在不同具有不同 IP 地址且不共享相同文件系统的机器上运行和扩展?我想也许我可以利用 Node 的流 API 并通过 HTTP 或 TCP 或套接字来回发送这些文件。

据我所知,Seneca.js 无法以正确的方式。当然,我可以通过 Seneca.js 将文件从主应用程序发送到图像处理服务,如下所示:

fs.createReadStream('/files/hello.jpg')
  .on('data', function(data) 
    seneca.act( role: 'file', cmd: 'chunk', data: data , cb);
  )
  .on('end', function(err) 
    seneca.act( role: 'file', cmd: 'end' );
  )
  .on('error', function(err) 
    seneca.act( role: 'test', cmd: 'error' );
  );

并分块接收:

seneca.add( role: 'file', cmd: 'chunk' , writeToFileCb);
seneca.add( role: 'file', cmd: 'end' , endFileWriteCb);

但这种方法看起来很丑陋,而且还需要重新发明。

另一种方法是提供一些 HTTP 服务器并将文件发送为 multipart/form-dataapplication/octet-stream,如下所示:

fs.createReadStream('file.json')
  .pipe(request.post('http://image-manipulator'))

但这意味着重新发明微服务通信的框架。总而言之,我就分布式微服务之间的文件共享以及可能的框架寻求建议。

【问题讨论】:

不错的形容词 - wheel-reinventive。我会记住的。 安东,您对此有何决定?我正在做类似的事情。 @JoshC.,我最终将我的逻辑从直接图像处理转移到图像处理代理,例如github.com/imazen/imageflow。 API 接收文件,执行检查(mime 类型等)并将文件上传到 S3 之类的东西。当图像显示给最终用户时,他们会收到一个类似https://images.example.org/some-image.jpg?width=300&quality=80 的 URL。 Imageflow(在这个域上运行)被设置为从这个 S3 中提取图像(如果没有缓存),处理它,发送给用户并缓存它。 如果您正在处理其他文件(图像除外),我想这种方法也有效。 API 接收文件,将其上传到 S3 并将对它的引用存储在数据库中。然后,如果您需要访问此文件,只需下载它¯\_(ツ)_/¯ 我想这是最简单的方法。 @AntonEgorov 我正朝着类似的方向发展。在微服务之间何时应该和不应该共享数据是很棘手的。共享数据库表可能是一个禁忌,但发布的文件可以吗??? ¯\_(ツ)_/¯ 【参考方案1】:

如果您正在使用微服务架构,您应该考虑使用微服务来管理文件!如果您是微服务环境,请不要流式传输文件。 例如,您可以创建一个 FileManagerService,其 API 公开用于 CRUD 实现,并且仅使用 seneca act/add 来提供重要数据...文件 URL、大小等。

【讨论】:

谢谢,唯一的问题是,如果它真的是一个分布式系统,我可能想要创建额外的FileManagerService 副本以分配负载,那么我需要让所有这些服务同步具有完全相同的数据,因此我必须创建某种代理或将文件上传到FileManagerService 的所有正在运行的实例。作为“奖励”,我将不得不编写逻辑来从现有服务中复制新创建的服务的所有内容:) 微服务​​变得越来越痛苦,而不是解决方案。 如何将文件上传到FileManagerService,即如果文件上传请求命中userManagerService,userManagerServer将如何将请求发送给fileManagerService处理?【参考方案2】:

如果您使用 Seneca,我强烈建议您阅读 The Tao of Microservices,作者是 Seneca 本人的 Richard Rodger。

他以这种方式直接解决您的问题(第 3 章第 15 节):

带宽很重要。

微服务系统的网络特性意味着它们很容易受到带宽限制。即使你从充足的供应开始,你也必须采取稀缺的心态。行为不端的微服务很容易导致内部产生的拒绝服务攻击。 让您的信息小而精巧。不要使用它们发送大量实际数据,而是发送对批量数据存储的引用。 [...]

要在服务之间发送图像,不要发送图像二进制数据,发送指向图像的 URL。

回到您的具体情况,您应该使用允许您存储/检索文件的服务,并在您的 Seneca 服务之间的消息中仅传递文件的 URL。以纯粹的分布式方式构建这样的系统并非易事,因此我宁愿使用 AWS S3 或同等产品。

【讨论】:

所以你是说:在 api 网关上应该是连接和上传到 S3 的一部分,然后应该将带有文件数据的消息发送到服务? 否:- 客户端仅与 API 网关通信。只有 API 网关可以调用服务 - 上传/下载文件元数据(名称、S3 URL 等...但不是数据)的命令/查询使用服务(小消息)。然后,客户端从 API 网关获取元数据——实际数据是“带外”下载的,即不使用服务(对于消息来说太大)。根据您的上下文采取不同的方法: - 如果可以公开 URL,则客户端直接下载 - API 网关下载 S3 文件并将其内容转发给客户端 但是你需要一个文件数据在S3上上传,所以文件数据需要通过seneca消息传输到文件服务才能上传,对吗? Sorry but no :) 文件数据必须由另一个传输网络传输,因为它会阻塞服务网络(需要低延迟才能按预期执行) 没关系。 :) 我需要使用什么网络将数据从 api 传输到服务?有例子吗?

以上是关于在微服务之间共享文件的主要内容,如果未能解决你的问题,请参考以下文章

微服务架构中如何在微服务之间共享java模型

我应该在微服务之间共享我的库吗?

JWT 注销:在微服务架构中的服务之间共享被列入黑名单的无效令牌

Linux 服务器之间如何进行文件目录共享

如何在微服务和API网关架构中对不同的配置文件进行身份验证和授权

如何在微服务架构中使用 docker-compose 最好地处理共享服务以进行本地开发?