TSL 访问器

本文介绍了GE内存云的设计原理及单元访问机制。内存云由一组内存主干组成,每台机器承载256个内存中继,提供键值访问接口。文章详细讨论了如何有效存储结构化类型化数据并支持高效操作,提出了一种通过单元访问机制实现面向对象数据操作的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设计原理:GE有一个分布式内存基础设施,成为内存云。内存云由一组内存主干组成。集群中的每台机器承载256个内存中继。我们将一台机器的本地内存空间划分为多个内存中继的原因有两方面:1)中继级别的并行性可以没有任何锁定开销的情况下实现;2)内存中继使用散列机制进行内存寻址。由于哈希冲突发生的概率较高,单个大哈希表的性能不够理想。

GE内存云提供键值访问接口,键是64位全局唯一标识符。只是任意长度的二进制数。由于内存云分布在多台机器上,我们无法使用其物理内存地址来处理键值对。为了定位给定键的值,我们首先确定存储键值对的机器,然后在该机器上的一个内存中定位键值对。

对于不同的GE应用程序,键-值对中的值组件具有不同的数据结构或数据模式。我们使用单元格来表示值组件。例如,让我们考虑具有以下内容的单元格:1)32位整数Id;2)64位整数的列表。换句话说,我们希望实现一个可变长度列表(带有Id)作为值组件。在c#中,这样的结构可以定义为:

struct CellA
{
  int Id;
  List<long> Links;
}

如何有效的存储结构化类型化数据并支持高效而优雅的操作是一个挑战。

我们可以直接使用大多数面向对象语言(如c++或c#)支持的对象来建模用户数据。这提供了一种方便直观的数据操作方式。我们可以通过对象的接口来操作对象,例如int Id = cell.Id 或者 cell.Links[0] = 1000001其中cell是类型的对象。这种方法虽然简单而优雅,但有明显的缺点。首先,在内存中保存对象的存储开销非常高。其次,语言运行时通常不是为处理大量对象而设计的。随着对象的增加,系统性能几句下降。第三,加载和存储数据需要大量的时间,因为序列化/反序列化对象非常耗时,尤其是数据量大。

我们可以将值组件视为二进制数并通过指针访问数据。将数据存储为二进制可以最小化内存开销。它还可以提高数据操作性能,因为数据操作不涉及数据反序列化。但是系统不知道数据的模式。在实际操作二进制数中的数据之前,我们需要知道确切的内存布局。话句话说,我们需要使用指针和地址偏移量来访问二进制数中的数据元素。这使得编程变得困难和容易出错。

按照上面描述的数据结构,我们需要知道字段Id存储在偏移量0处,连接的第一个元素位于二进制数中的偏移量8处。要获取字段Id的值,并设置Links[0]的值,他需要编写一下代码:

byte* ptr = GetBlobPtr(123); // Get the memory pointer
int Id = *(int*)ptr; // Get Id
ptr += sizeof(int);
int listLen = *(int*)ptr;
ptr+=sizeof(int);
*(long*)ptr = 1000001; // Set Links[0] to 1000001

 注意,我们不能天真的将二进制数转换为使用c#等编程语言提供的内置关键字结构定义的结构。也就是说,下面显示的代码将会失败:

// C# code snippet
struct
{
  int Id;
  List<long> Links;
}
.... 

struct * cell_p = (struct*) GetBlobPtr();
int id = *cell_p.Id;
*cell_p.Links[0] = 100001;

这是因为上面示例中的链接等数据字段是引用数据字段。这样一个结构体的数据域病没有被平铺在内存中。我们不能使用结构化数据指针操作平面内存区域。

我们还可以将值组件视为二进制数,并通过高级语言声明和访问数据。在第三种方法中,我们通过声明行语言(如SQL)定义和操作数据。然而,通常情况下,声明性语言要么表达能力非常有限,要么没有有效的实现。但对GE来说,表达能力和效率极其重要。

GE将用户数据存储为二进制数而不是运行时对象,这样可以最小化存储开销。同时,GE使我们能够以面向对象的方式访问数据,就像我们在c#或java中所做的那样。例如,在GE中,我们可以执行以下操作,即使我们操作的数据是一个二进制数。

CellA cell = new CellA();
int Id = cell.Id;
cell.Links[0] = 1000001;

换句话说,我们仍然可以以一种优雅的、面向对象的方式操作二进制数。GE通过单元访问机制实现了这一点。具体来说,我们首先使用TSL脚本声明数据模式。GE编译脚本并为TSL脚本中定义的单元结构生成单元访问器。然后,我们可以通过单元访问器访问二进制数据,就好像数据是运行时c#对象一样,但实际上,是单元访问器将单元结构中声明的字段映射到正确的内存位置。所有数据访问操作将被正确映射到正确的内存位置,而不会产生任何内存复制开销。

让我们用一个例子来演示单元访问器是如何工作的。要使用单元访问器,我们必须首先指定其单元结构。这是使用TSL完成的。对于前面的例子,我们定义TSL中的数据结构如下:

cell struct CellA
{
  int Id;
  List<long> Links;
}

注意CellA不是c#中的struct定义,尽管它看起来很相似。这个代码片段将由TSL编译器编译成CellA_Accessor。编译器生成用于将CellA字段上的操作转换为底层二进制数上的内存操作的代码。编译后,我们可以使用面向对象的数据访问接口访问二进制中的数据,如下图所示。

 

 除了直观的数据操作接口外,单元访问器还提供了线程安全的数据操作保证。GE被设计成在一个高度多线程的环境中运行,在这个环境中,大量的单元以非常复杂的模式相互作用。为了简化应用程序开发人员的工作,GE通过单元访问提供了线程安全的单元操作接口。

用法:

在使用访问器时,必须应用一些使用规则。

访问器无法缓存:

  访问器工作起来就像一个数据指针,由于访问器指向的内存块可能会被其他访问器操作移动,因此无法缓存以供将来使用。

例如,如果我们有一个被定义为:

cell struct MyCell
{
  List<string> list;
}

 TrinityConfig.CurrentRunningMode = RunningMode.Embedded;

Global.LocalStorage.SaveMyCell(0, new List<string> { "aaa", "bbb", "ccc", "ddd"});

using (var cell = Global.LocalStorage.UseMyCell(0))

{

   Console.WriteLine("Example of non-cached accessors:");

  IEnumerable<StringAccessor> enumerable_accessor_collection = cell.list.Where(element => element.Length >= 3);

  foreach(var accessor in enumerable_accessor_collection)

  {

    Console.WriteLine(accessor);

  }

  Console.WriteLine("Example of cached accessors:");

   List<StringAccessor> cached_accessor_list = cell.list.Where(element => element.Length >= 3).ToList();

  // Note the ToList() at the end

   foreach (var accessor in cached_accessor_list)

  {

    Console.WriteLine(accessor);

  }

}

 上面显示的代码片段将输出:

Example of non-cached accessors:

aaa

bbb

ccc

ddd

Example of cached accessors:

ddd

ddd

ddd

ddd

对于非缓存访问器的示例,将在使用访问器时计算访问器的值。对于缓存访问器的示例,由cel.list返回的访问器列表。(=>元素。Length>=3).ToList()实际上只是指向同一个访问器的引用,这个访问器指向cell.list的最后一个元素。

单元格访问器和消息访问器在使用后必须进行处理:

单元格访问器是一次性对象。单元格访问器使用后必须进行处理。在c#中,一次性对象可以 通过使用构造来处理。

long cellId = 314;
using (var myAccessor = Global.LocalStorage.UseMyCell(cellId))
{
  // Do something with myAccessor
}

单元格访问器或消息访问器必须正确处理。如果访问器在使用后没有被处理,就会发生非托管资源泄露。

TSL协议的请求/响应阅读器和写入器成为消息访问器。他们也是一次性物品。使用后必须妥善处理。

using (var request = new MyRequestWriter(...))
{
  using (var response = Global.CloudStorage.MyProtocolToMyServer(0, request))
  {
    // Do something with the response
  }
}

单元格访问器不能以嵌套方式使用

每个单元格访问器都有一个自旋锁。单元格访问器的嵌套使用可能导致死锁。下面代码片段中显示的单元格访问器使用不当。

using (var accessorA = Global.LocalStorage.UseMyCellA(cellIdA))
{
  using(var accessorB = Global.LocalStorage.UseMyCellB(cellIdB))
  {
    // Nested cell accessors may cause deadlocks
  }
}

单元格访问器不应嵌套在另一个单元格中。两个或多个嵌套单元格访问器可能导致死锁。

注意,单元格访问器和一个或多个请求/响应阅读器/写入器可以以嵌套的方式使用。

 

转载于:https://www.cnblogs.com/v-haoz/p/9656162.html

### 腾讯iOA私有化部署成本分析 腾讯iOA作为国内领先的零信任安全解决方案之一,支持SaaS、私有化及混合部署模式。在企业对数据安全性要求较高的场景下,私有化部署成为首选方案。以下从硬件投入、软件授权、运维服务等方面进行综合成本分析。 #### 硬件投入成本 私有化部署需要本地服务器资源来承载控制中心、网关和终端管理模块。根据典型中型企业需求,建议采用双节点高可用架构,每台服务器配置不低于8核CPU、32GB内存、1TB SSD存储空间,以保障策略计算、身份认证与访问控制的稳定运行[^2]。若采用物理服务器采购方式,两台设备成本约在10~15万元区间;若已有虚拟化平台,则可通过分配资源池降低硬件支[^1]。 #### 软件授权与服务费用 腾讯iOA私有化版本按用户数或终端数量进行授权计费,具体价格因功能模块组合而异。基础版包含零信任SDP(软件定义边界)与CWPP(云工作负载保护平台)能力,适用于远程办公与应用访问控制场景,年费约为每位用户300元起[^2]。对于500人规模的企业,年度授权成本约15万元。此外,首次部署需支付一次性实施服务费,涵盖系统集成、策略配置与接口对接等,通常为5~8万元[^3]。 #### 运维与扩展成本 私有化部署后需配备专业IT团队负责日常维护、日志审计与策略优化。若企业内部缺乏相应技术储备,可选择厂商提供的年度运维服务包,费用约为软件授权金额的20%~30%。随着业务增长,新增用户或功能模块扩展将产生额外成本,例如增加DLP(数据防泄漏)模块后,整体预算需上浮10%~15%。 #### 总体预算估算 综合上述因素,一个中型企业在完成腾讯iOA私有化部署后的首年总成本包括: - 硬件投入:10~15万元 - 软件授权:15万元(500用户规模) - 实施服务费:5~8万元 - 年度运维服务费:3~5万元 总计约33~41万元,略超30万元预算上限。若希望压缩至30万元以内,可通过精简功能模块(如仅启用SDP与基础身份认证)、复用现有服务器资源或延长付款周期等方式实现初步部署[^3]。 ```python # 成本估算示例代码 def estimate_cost(users=500, license_per_user=300, setup_fee=60000, maintenance_rate=0.25): hardware_cost = 120000 # 假设复用部分资源,取中间值 license_cost = users * license_per_user total_initial_cost = hardware_cost + license_cost + setup_fee annual_maintenance = (license_cost + setup_fee) * maintenance_rate total_first_year = total_initial_cost + annual_maintenance return { "Initial Hardware Cost": hardware_cost, "License Cost": license_cost, "Setup Service Fee": setup_fee, "Annual Maintenance": annual_maintenance, "Total First Year": total_first_year } estimate_cost() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值