2021-06-25 波卡生态下的 CRU技术分解

外壳存储管理器

sManager(Storage Manager)是一个文件拣选机器人,它从 Crust Network 连续拣选和处理文件。节点运营商可以自定义这个模块来实现他们自己的文件处理策略。基本上,sManager分为以下几个部分:

  1. Picker:从链中收听新文件,将拉取任务添加到Pulling Queue
  2. PullerPulling Queue从IPFS中取任务,从IPFS中拉取文件,文件下载成功后,添加封箱任务Sealing Queue
  3. Sealer : 从 中提取任务Sealing Queue,通过调用 sWorker API 对文件进行密封;
  4. 决策引擎:节点自行定制细节拾取机制;

用法

  1. 克隆回购
git clone https://github.com/crustio/crust-smanager.git
复制
  1. 安装
cd crust-smanager && yarn
复制
  1. 调试
yarn debug $CHAIN_ADDR $IPFS_ADDR $SWORKER_ADDR $NODEID $CHAIN_ACCOUNT
复制
  • $CHAIN_ADDR:Chain的websocket地址,默认为 ws://localhost:9944
  • $IPFS_ADDR:IPFS的API地址,默认为 http://localhost:5001
  • $SWORKER_ADDR:sWorker的API地址,默认为 http://localhost:12222
  • $NODEID: 节点类型,只有2种类型,成员或隔离,默认为 isolation
  • $CHAIN_ACCOUNT:Chain的账号,用于组去重和成员判断,Maxwell的格式为 5HnF6QzzXqTyzoLieVjcE4aw71NxhNK8XAH5634yXmGzz16N
  1. Docker化
./dockerize.sh
复制

流量

整个 sManager 工作流程如下图所示。

管理流程

它分为3个过程。通常,它从链中拾取文件,从 IPFS 中提取文件并使用 sWorker 密封文件。

1.挑选

拣货过程包括:

  1. 从链上订阅新的最终区块
  2. 解析block的信息,通过解析events和extrinsics获取新文件
  3. 获取组信息并判断成员节点是否应该选择文件
  4. 法官档案的cid合法性
  5. 从链中删除过期文件和关闭文件
  6. 清除过时的拉封队列任务

2.拉

拉取过程包含:

  1. 循环拉取队列中的所有拉取任务
  2. 对于每个任务,puller 都会将其发送Decision Engine到判断我们是否捡起它(有关它如何决定拉动的详细信息
  3. 通过调用IPFS的pin API异步拉取,如果成功,将其加入密封队列

3. 密封

封口过程包含:

  1. 循环密封队列中的所有密封任务
  2. 对于每一个任务,sealer 都会将它发送到Decision Engine我们判断我们是否密封它(有关它如何决定密封的详细信息
  3. 通过调用sWorker的seal API异步封箱,如果成功,整个取件结束,等待上报工作。

组件

sManager的代码分为4部分:

  1. Cron job:调度执行拉封过程,拣选过程由链的新块触发;
  2. Queues:当前sManager的队列系统在内存中,管理不同的任务;
  3. APIs:与Chain、IPFS和sWorker集成;
  4. 决策引擎:自定义提货机制;

1. 定时任务

描述

sManager 的入口是 3 个 crob 作业:由链的新区块触发的采摘作业;由定时作业触发的拉动作业和密封作业。源代码可以在这里检查

  const de = new DecisionEngine(
    chainAddr,
    ipfsAddr,
    sworkerAddr,
    nodeId,
    chainAccount,
    ipfsTimeout,
    sworkerTimeout
  );

  // TODO: Get cancellation signal and handle errors?
  de.subscribeNewFiles().catch(e =>
    logger.error(`💥  Caught pending queue error: ${e.toString()}`)
  );
  de.subscribePullings().catch(e =>
    logger.error(`💥  Caught pulling queue error: ${e.toString()}`)
  );
  de.subscribeSealings().catch(e =>
    logger.error(`💥  Caught sealing queue error: ${e.toString()}`)
  );
复制

定制

节点可以通过调整拉封作业的cron作业时间来自定义。请参考节点 cron 语法来更改触发时间。

2. 队列

描述

Queue 是 sManager 使用的基本数据结构,目前 sManager 使用in-memory queue,这意味着当 sManager 重新启动时它会被清除。队列的结构如下所示,源代码可以在这里查看

export interface BT {
  // Block number
  bn: number;
}

export default class TaskQueueextends BT> {
  private _tasks: T[];
  private readonly maxLength: number; // queue length
  private readonly maxDuration: number; // task outdated time
  // ...
}
复制

它显示了基本队列的特征:

  • TaskT(task) 应该有bn(block number) 成员字段
  • maxLength: 队列应该有最大长度
  • maxDuration: 队列应该定期清除过时的任务

sManager 中有 2 个队列:pullingQueuesealingQueuedecision模块中定义。

interface Task extends BT {
  // The ipfs cid value
  cid: string;
  // Object size
  size: number;
}

private pullingQueue: TaskQueue;
private sealingQueue: TaskQueue;
复制

定制

节点可以通过以下方式自定义:

  • 通过导入持久化队列RedisMongoDB或者任何其他数据库/消息中间件来保存任务,然后程序重启时它不会消失
  • 动态maxLengthmaxDuration你的内存或CPU利用率设计

3. API

sManager 与 Crust 的 3 个模块进行通信:Chain、IPFS 和 sWorker,节点可以在决策引擎中添加更多的 api 调用,请参阅完整的 API 调用文档:

3.1 链

当前链的 API 调用如下所示,源代码可以在这里查看

  • subscribeNewHeads: 监听最好的最终块,用于监听块中的新文件
  • isSyncing: 判断链是否还在同步中,使用 subscribeNewHeads
  • header: 获取最新的区块头,被使用 isSyncing
  • getChainAccount: 获取链上账号arg[4]($CHAIN_ACCOUNT),用于判断节点是否为群主
  • sworkIdentity: 获取sWorker身份,用于获取群主信息
  • groupMembers: 获取节点的组成员信息,用于去重文件
  • parseNewFilesAndClosedFilesByBlock:解析FileSuccess事件并place_storage_order获取新文件(新的拉取任务);解析CalculateSuccessIllegalFileClosed获取过期/非法文件(已删除的文件
  • maybeGetFileUsedInfo:[FileInfo, UsedInfo]通过cid获取,用于判断文件的副本是否已满
  • withApiReady: 确定ApiPromise可以使用
  • parseFileInfo: 将place_storage_order外部数据传输到FileInfo

3.2 IPFS

当前 IPFS 的 API 调用如下所示,源代码可以在这里查看

  • pin: ipfs pin [cid]
  • unpin: ipfs pin rm [cid]
  • size: ipfs object stat [cid]
  • exist: ipfs pin ls --type=recursive | grep [cid]
  • free: ipfs repo stat

3.3 sWorker

当前 sWorker 的 API 调用如下所示,源代码可以在这里查看

  • seal: 密封IPFS中存在的文件,此调用为同步调用,请确保1 by 1执行
  • delete: 删除sWorker已经密封的文件,以及IPFS中的原文件
  • free: 剩余磁盘容量

4. 决策引擎

决策引擎决定了 Node 不同的拾取机制,当前默认的决策如下所示,决策引擎的源代码可以在这里查看

4.1 自由空间判断

sManager 在尝试从 IPFS 中拉取文件并尝试使用 sWorker 密封文件时,会判断当前可用空间。

  1. 拉文件前
  private async pickUpPulling(t: Task): Promise<boolean> {
    try {
      // 1. Get and judge file size is match
      // TODO: Ideally, we should compare the REAL file size(from ipfs) and
      // on-chain storage order size, but this is a COST operation which will cause timeout from ipfs,
      // so we choose to use on-chain size in the default strategy

      // Ideally code:
      // const size = await this.ipfsApi.size(t.cid);
      // logger.info(`  ↪ 📂  Got ipfs file size ${t.cid}, size is: ${size}`);
      // if (size !== t.size) {
      //   logger.warn(`  ↪ ⚠️  Size not match: ${size} != ${t.size}`);
      //   // CUSTOMER STRATEGY, can pick or not
      // }
      const size = t.size;

      // 2. Get and judge repo can take it, make sure the free can take double file
      const free = await this.freeSpace();
      // If free < t.size * 2.2, 0.2 for the extra sealed size
      if (free.lte(t.size * 2.2)) {
        logger.warn(`  ↪ ⚠️  Free space not enough ${free} < ${size}*2.2`);
        return false;
      }

      // 3. Judge if it should pull from chain-side
      return await this.shouldPull(t.cid);
    } catch (err) {
      logger.error(`  ↪ 💥  Access ipfs or sWorker error, detail with ${err}`);
      return false;
    }
  }
复制
  1. 封文件前
  private async pickUpSealing(t: Task): Promise<boolean> {
    const free = await this.freeSpace();

    // If free < file size
    if (free.lt(t.size)) {
      logger.warn(`  ↪ ⚠️  Free space not enough ${free} < ${t.size}`);
      return false;
    }

    return true;
  }
复制

4.2 文件副本判断

sManager 将在拉取文件之前获取文件的副本信息。当副本已满(当前为 200,由 定义MaxFileReplicas)时,节点将拒绝拉取此文件。

  /**
   * Judge if replica on chain is full or file on chain is exist
   * @param cid ipfs cid value
   * @returns wether file not exist or replica is full
   * @throws crustApi error
   */
  private async isReplicaFullOrFileNotExist(cid: string): Promise<boolean> {
    const usedInfo: UsedInfo | null = await this.crustApi.maybeGetFileUsedInfo(
      cid
    );

    logger.info(`  ↪ ⛓  Got file info from chain ${JSON.stringify(usedInfo)}`);

    if (usedInfo && _.size(usedInfo.groups) > consts.MaxFileReplicas) {
      logger.warn(
        `  ↪ ⚠️  File replica already full with ${usedInfo.groups.length}`
      );

      return true;
    } else if (!usedInfo) {
      logger.warn(`  ↪ ⚠️  File ${cid} not exist`);
      return true;
    }

    return false;
  }
复制

4.3 组去重

因为同一组内只有1个副本,所以sManager提供了重复数据删除机制,简单的使用modbycid(toNum)group length

  /**
   * Judge if is member can pick the file
   * @param cid File hash
   * @returns Whether is my turn to pickup file
   */
  private async isMyTurn(cid: string): Promise<boolean> {
    // Member but without groupOwner is freaking strange, but anyway pass with true
    if (
      this.nodeId === consts.MEMBER &&
      this.groupOwner &&
      this.members.length > 0
    ) {
      // 1. Get group length
      const len = this.members.length;
      // 2. Get my index
      const myIdx = this.members.indexOf(this.crustApi.getChainAccount());
      // 3. Judge if should pick storage order
      if (myIdx !== -1) {
        const cidNum = lettersToNum(cid);
        logger.info(
          `  ↪  🙋  Group length: ${len}, member index: ${myIdx}, file cid: ${cid}(${cidNum})`
        );
        return cidNum % len === myIdx;
      }
    }

    return true;
  }
复制

节点自定义其决策引擎有一些线索:

  1. 以文件价格排序拉队列,从高到低排序;
  2. 选择错误大小的文件(有序文件大小<实际文件大小),关闭它以获得整个奖励

欢迎更多定制化决策贡献给sManager,当然您也可以开发自己的sManager。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旷工说事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值