https://natsbyexample.com/examples/os/intro/dotnet2

NATS 中的对象存储能力是在 Stream 之上的一种抽象,它将消息的主题视为类似键值对中的键,但是其中的内容可以跨越多个数据块。使得它支持大型数据。并且通常作为可读/可写流进行加载和读取。

比较来说,Key-Value 存储限制保存的数据量为 1M, 而对象存储没有这个限制。

注意:对象存储不是分布式存储系统。所有存储的文件需要适应目标文件系统。
它支持客户端应用程序创建并存储一组文件的存储桶(对应于流)。文件以块的形式存储和传输,允许通过 NATS 基础设施安全地传输任意大小的文件。

1. 创建对象存储管理器

使用 JSContext 来创建对象存储的管理器 NatsObjContext

var opts = new NatsOpts
{
    Url = url,
    LoggerFactory = loggerFactory,
    Name = "NATS-by-Example",
};
await using var nats = new NatsConnection(opts);
var js = new NatsJSContext(nats);
var objMgr = new NatsObjContext(js);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

2. 创建命名的对象存储

借助对象管理器来创建一个命名的对象存储。每个对象存储可以看做一个字典。

var store = await objMgr.CreateObjectStore("configs");
  • 1.

3. 检查对象存储的状态

使用对象存储的 GetStatusAsync() 可以检查它的状态

var status = await store.GetStatusAsync();
logger.LogInformation("The object store has {Size} bytes", status.Info.State.Bytes);
  • 1.
  • 2.

Output

info: NATS-by-Example[0]
      The object store has 0 bytes
  • 1.
  • 2.

4. 存储数据和元数据

使用 PutAsync() 将数据存储到对象存储中。除了数据本身之外,还可以附加描述数据的元数据。

如果重复使用相同的 Key 存储数据,新的数据将会覆盖旧的数据。

每块数据关联一个元数据的描述,可以通过它对数据进行说明。

const int bytes = 10_000_000;
var data = new byte[bytes];

var info = await store.PutAsync(key: "a", data);
logger.LogInformation("Added entry {Name} ({Size} bytes)- '{Description}'", info.Name, info.Size, info.Description);

await store.UpdateMetaAsync("a", new ObjectMetadata { Name = "a", Description = "still large data" });
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

Output

info: NATS-by-Example[0]
      Added entry a (10000000 bytes)- '(null)'
  • 1.
  • 2.

ObjectMetadata 有一个 Headers 的属性,支持字符串形式的键值对说明。

public Dictionary<string, string[]>? Headers { get; set; }
  • 1.

5. 提取存储的数据

使用键值来提取存储的数据。

var data1 = await store.GetBytesAsync("a");
logger.LogInformation("Data has {Size} bytes", data1.Length);
  • 1.
  • 2.

Output

info: NATS-by-Example[0]
      Data has 10000000 bytes
  • 1.
  • 2.

6. 删除对象存储

借助键值可以删除存储的数据。

await store.DeleteAsync("a");
  • 1.

7. 以字节流的方式存储和读取数据

可以使用字节流对象,而不是字节数组来存储和提取数据。

const int bytes = 10_000_000;
var data = new byte[bytes];

// 使用字节流提供数据
info = await store.PutAsync(new ObjectMetadata { Name = "b", Description = "set with a stream" }, new MemoryStream(data));
logger.LogInformation("Added entry {Name} ({Size} bytes)- '{Description}'", info.Name, info.Size, info.Description);

// 使用字节流提取数据,数据被填充到流中
var ms = new MemoryStream();
info = await store.GetAsync("b", ms);
logger.LogInformation("Got entry {Name} ({Size} bytes)- '{Description}'", info.Name, info.Size, info.Description);

await obj.DeleteObjectStore("configs", CancellationToken.None);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

Output

info: NATS-by-Example[0]
      Added entry b (10000000 bytes)- 'set with a stream'
info: NATS-by-Example[0]
      Got entry b (10000000 bytes)- 'set with a stream'
  • 1.
  • 2.
  • 3.
  • 4.

8.管理对象存储

列出存储的数据

var count = 0;
await foreach (var entry in store.ListAsync())
{
    logger.LogInformation("Entry {Name} ({Size} bytes)- '{Description}'", info.Name, info.Size, info.Description);
    count++;
}
logger.LogInformation("The object store contains {Count} entries", count);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

Output

info: NATS-by-Example[0]
      Entry a (10000000 bytes)- '(null)'
info: NATS-by-Example[0]
      The object store contains 1 entries
  • 1.
  • 2.
  • 3.
  • 4.
  1. 监控对象存储中的变更
var watcher = Task.Run(async () =>
{
    await foreach (var m in store.WatchAsync(new NatsObjWatchOpts{IncludeHistory = false}))
    {
        logger.LogInformation(">>>>>>>> Watch: {Bucket} changed '{Name}' {Op}", m.Bucket, m.Name, m.Deleted ? "was deleted" : "was updated");
    }
});
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

Output

info: NATS-by-Example[0]
      >>>>>>>> Watch: configs changed 'a' was updated
  • 1.
  • 2.
  1. 使用 NATS CLI 管理对象存储

NATS CLI 提供了 object 命令管理对象存储

创建对象存储

nats object add myobjbucket
  • 1.

保存文件

nats object put myobjbucket ~/Movies/NATS-logo.mov
  • 1.

列出保存的对象

nats object ls myobjbucket
  • 1.

See:  https://docs.nats.io/nats-concepts/jetstream/obj_store/obj_walkthrough