Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cnpmcore 存储支持 s3 吗 #353

Closed
yuantongkang opened this issue Nov 11, 2022 · 17 comments
Closed

cnpmcore 存储支持 s3 吗 #353

yuantongkang opened this issue Nov 11, 2022 · 17 comments
Assignees
Labels
good first issue Good for newcomers help wanted Extra attention is needed

Comments

@yuantongkang
Copy link

No description provided.

@github-actions
Copy link

我们已经看到你的反馈,如果是功能缺陷,可以提供一下重现该问题的方式;如果是新功能需求,我们会尽快加入讨论。同时我们非常期待你可以加入我们的贡献者行列,让项目可以长期可持续发展。

@fengmk2
Copy link
Member

fengmk2 commented Nov 12, 2022

目前不支持,默认实现了阿里云 oss 和社区贡献的腾讯云存储
S3 你可以参考 https://github.com/cnpm/cnpmcore/blob/main/app/infra/NFSClientAdapter.ts 实现。

@fengmk2 fengmk2 added good first issue Good for newcomers help wanted Extra attention is needed labels Jan 18, 2023
@hezhengxu2018
Copy link
Collaborator

s3-cnpm这个项目还可以用吗?

@fengmk2
Copy link
Member

fengmk2 commented Jan 29, 2023

得将里面的 generator function 改成 async function https://github.com/QubitProducts/s3-cnpm/blob/master/s3-cnpm.js

@hezhengxu2018
Copy link
Collaborator

发布了两个依赖s3v2-cnpmcores3-cnpmcore区别是前者用的是aws-sdk的2.x,在生产下需要设置环境变量:

AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE=1

后者用的是最新的@aws-sdk/client-s3,nodejs的最低要求是18。

两个依赖的配置是在原sdk原有配置的基础上添加了bucket的配置项,具体请参考各自的官方文档。

两者都处于基本可用的状态,但是s3没有appendBytes的方法,目前是通过读取原有buffer添加新内容后再次上传的,性能不太好。如果是七牛的S3接口短时间内多次append会有问题,第2次读取的内容有概率是第0次的内容。七牛那边给的反馈是涉及到了分布式存储的高可用快响应的数据服务缓存,数据处理有ms级延时。内网部署的对象存储没有这个问题。如果有上述情况七牛的建议是需要在下次读取前等待1000ms,需要自己改造一下,但是性能就更差了。

@hezhengxu2018
Copy link
Collaborator

两个插件都添加了新的配置项disableURL,因为七牛的S3接口不支持匿名访问,使用pre-signed URL又会使url函数返回的是一个Promise。启用后url将直接是一个undefined,使用createDownloadStream返回存储对象。这样应该就可以直接在七牛上使用,不用再单独包装一个adaper了。

@baxtergu
Copy link

baxtergu commented May 6, 2023

我试了下用 s3-cnpmcore 这个包来做 cnpmcore NFSClient,测试在私有部署的 s3 协议兼容对象存储服务上生成了100gb的数据,暂未发现太大问题。

@fengmk2
Copy link
Member

fengmk2 commented May 6, 2023

我试了下用 s3-cnpmcore 这个包来做 cnpmcore NFSClient,测试在私有部署的 s3 协议兼容对象存储服务上生成了100gb的数据,暂未发现太大问题。

厉害,我整理到官方推荐的 nfsclient 里面去。

@baxtergu
Copy link

baxtergu commented May 6, 2023

我试了下用 s3-cnpmcore 这个包来做 cnpmcore NFSClient,测试在私有部署的 s3 协议兼容对象存储服务上生成了100gb的数据,暂未发现太大问题。

厉害,我整理到官方推荐的 nfsclient 里面去。

s3client unpkg 单个文件请求有点问题,我debug一下

@baxtergu
Copy link

baxtergu commented May 6, 2023

看了下,s3 的 adapter 貌似读取文件没什么问题,但是单个文件请求始终返回的都是空对象,怀疑是不是流处理的问题?

问题接口 GET /:fullname/:versionOrTag/files/:path

@HTTPMethod({
// GET /:fullname/:versionOrTag/files/:path
// GET /:fullname/:versionOrTag/files/:path?meta
path: `/:fullname(${FULLNAME_REG_STRING})/:versionOrTag/files/:path(.+)`,
method: HTTPMethodEnum.GET,
})
async raw(@Context() ctx: EggContext,
@HTTPParam() fullname: string,
@HTTPParam() versionOrTag: string,
@HTTPParam() path: string,
@HTTPQuery() meta: string) {
this.#requireUnpkgEnable();
ctx.vary(this.config.cnpmcore.cdnVaryHeader);
const [ scope, name ] = getScopeAndName(fullname);
path = `/${path}`;
const packageVersion = await this.#getPackageVersion(ctx, fullname, scope, name, versionOrTag);
if (path.endsWith('/')) {
const directory = path.substring(0, path.length - 1);
const files = await this.#listFilesByDirectory(packageVersion, directory);
if (!files) {
throw new NotFoundError(`${fullname}@${versionOrTag}/files${directory} not found`);
}
ctx.set('cache-control', META_CACHE_CONTROL);
return files;
}
const file = await this.packageVersionFileService.showPackageVersionFile(packageVersion, path);
if (!file) {
throw new NotFoundError(`File ${fullname}@${versionOrTag}${path} not found`);
}
const hasMeta = typeof meta === 'string';
if (hasMeta) {
ctx.set('cache-control', META_CACHE_CONTROL);
return formatFileItem(file);
}
ctx.set('cache-control', FILE_CACHE_CONTROL);
ctx.type = file.contentType;
if (file.contentType === 'text/html' || file.contentType === 'text/xml') {
ctx.attachment(file.path);
}
return await this.distRepository.getDistStream(file.dist);

会进入到 s3cnpmcore 的这里
https://github.com/hezhengxu2018/s3-cnpmcore/blob/7528145a3728c4f02af9758d703b8b34afdb4430/src/index.ts#L103

我试了在 s3cnpmcore 里将读取流转成 string,是可以获取到文件内容的,但是在 controller 里 return 以后,获取的 response body 为 {}。

元数据获取没问题 GET /:fullname/:versionOrTag/files/:path?meta

@baxtergu
Copy link

baxtergu commented May 6, 2023

s3client关联配置

    config.nfs.client = new S3Client({
      forcePathStyle: true,
      disableURL: true,
    });

另外我发现在上面配置下,DownloadPackageVersionTar 这个 controller 里的包下载也会有同样的问题,返回的 response body 为空对象,header 什么的都是OK的。是不是 s3 client 转换出的 stream 对象 egg 里面处理出了问题?

我用的 nodejs 18.16.0,我试试降级下16有没有问题。

@hezhengxu2018
Copy link
Collaborator

@aws-sdk/client-s3这个sdk对流的操作需要node18的支持。16需要用s3v2-cnpmcore,用的是老的aws的sdk。

@baxtergu
Copy link

baxtergu commented May 6, 2023

@aws-sdk/client-s3这个sdk对流的操作需要node18的支持。16需要用s3v2-cnpmcore,用的是老的aws的sdk。

我用的node18+@aws-sdk/client-s3 可读流没法被 egg 框架正常转换,是不是egg的问题?我看 @aws-sdk/client-s3 里 getObject.Body.transformToWebStream() 方式生成的可读流,貌似 egg 转换不了?

我在尝试用 v2 的客户端,但是可能要改些源码

@hezhengxu2018
Copy link
Collaborator

我晚点试一下这个新功能看看,两边的单测是一样的不应该会有这种问题😵‍💫

@baxtergu
Copy link

baxtergu commented May 6, 2023

我晚点试一下这个新功能看看,两边的单测是一样的不应该会有这种问题😵‍💫

定位到原因了,需要在

https://github.com/hezhengxu2018/s3-cnpmcore/blob/7528145a3728c4f02af9758d703b8b34afdb4430/src/index.ts#L103

加上下面的流转换代码

import { Readable } from "node:stream";
import type { ReadableStream as ReadableStreamWeb } from "node:stream/web";

async createDownloadStream(key: string) {
...
 const webStream = (
      await this.s3.getObject({ Bucket: this.config.bucket, Key: _key })
    ).Body?.transformToWebStream();

  if (!webStream) {
    return undefined;
  }
    
  return Readable.fromWeb(webStream as ReadableStreamWeb);
}

用 cnpmcore 包形式的那个项目里的 @types/node 要用高版本的,不然没有 node:stream/web 的正确类型定义,不然就是 ignore 掉类型错误,或者手动指定一个能兼容的类型。

s3.getObject().Body.transformToWebStream() 用的是 stream.Readable.toWeb API,可能转换出来的流对象和标准 Readable 流类型不太一样。得手动转换为一个标准的 ReadableStream 再返回才能被 egg 框架自动处理成 response body 。(eggjs 似乎不能将 toWeb 生成的流处理成 response body。 @fengmk2

@hezhengxu2018
Copy link
Collaborator

s3-cnpmcore发布了1.1.2版本,s3v2的应该没有这个问题。还没在实际项目里试验这个功能,有问题的话再撤销发布这个版本

@fengmk2
Copy link
Member

fengmk2 commented May 7, 2023

@fengmk2 fengmk2 closed this as completed May 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

4 participants