首页> 中国专利> 具有可扩展和可定制的计算引擎的面向网络服务的架构内的服务提供者

具有可扩展和可定制的计算引擎的面向网络服务的架构内的服务提供者

摘要

一种使用提供者服务获取数据并对该数据执行计算的方法。提供者票单服务(PTS)从一个或多个客户端接收票单。每个票单包括计算标识符和有效载荷。计算标识符识别使用有效载荷中的信息待执行的计算。PTS将唯一的票单标识符与每个票单相关联。票单管理器将来自PTS的选定的票单提交给提供者宿主服务(PHS);其通过检查选定的票单中的提供者标识信息来确定哪一提供者将执行由选定的票单识别的计算。PHS启动调用被确定执行由选定的票单的计算标识符识别的计算的提供者的提供者宿主线程(PHT)。该提供者执行计算并将结果返回给PHS,PHS将结果传递回PTS,而PTS将结果返回给发出请求的客户端。

著录项

法律信息

  • 法律状态公告日

    法律状态信息

    法律状态

  • 2016-11-16

    授权

    授权

  • 2013-08-28

    实质审查的生效 IPC(主分类):G06F9/445 申请日:20110928

    实质审查的生效

  • 2013-07-31

    公开

    公开

说明书

发明领域

本发明一般涉及面向服务的架构(SOA),更特别涉及具有可脚本化、 可扩展和可定制的计算引擎的网络服务提供者的面向服务的架构内的提 供者服务。

背景

电力管理软件收集通过电力监控系统的各种监控设备如电表测得的 数据并分析测得的数据,以帮助设施运营商降低与能源相关的成本,通过 使运营商快速响应报警以避免危急情况来避免停止运行,并通过例如识别 用于提高效率的机会来优化设备利用率。此软件通常运行在通过网络上收 集测量的数据的服务器或工作站上。模块形式的功能可以与软件一起提 供,但软件不是特别可扩展、可扩充和可定制的。添加新的模块来对测量 数据执行不同的计算,目前是一项费时和劳动密集的任务,特别是通过第 三方完成时。缺乏对请求的计算的集中管理的处理,导致重复的存储和计 算,及任务的非粘性的(non-cohesive)协调和管理,从而延缓将相关的、 有意义的信息最终报告给设施运营商,并导致处理和存储器资源的使用效 率低下。

发明内容

根据本公开的一个方面,公开了一种使用提供者服务获取数据并对所 述数据执行计算的方法。该方法包括:在提供者票单服务,从一个或多个 客户端接收多个票单(Ticket),每个所述票单包括计算标识符和有效载荷, 所述计算标识符识别使用至少在所述票单的有效载荷中指示的信息待执 行的计算;对于在所述提供者票单服务接收到的每个所述票单,将唯一的 票单标识符与各相应的票单相关联;票单管理器将来自所述提供者票单服 务的选定的票单提交给提供者宿主服务;确定多个提供者中的哪一个或多 个将执行由所述选定的票单的所述计算标识符识别的计算;所述提供者宿 主服务启动至少一个提供者宿主线程,所述至少一个提供者宿主线程调用 或实例化被确定来执行由所述选定的票单的所述计算标识符识别的计算 的一个或多个提供者;在所述提供者票单服务从所述提供者宿主服务接收 由所述被调用的一个或多个提供者执行的计算的结果,及将所述结果返回 给与所述选定的票单相关联的发起请求的客户端。

该方法还可以包括,在执行由所述选定的票单请求的计算之前,确定 由所述选定的票单请求的计算是否已经执行,并且,如果已经执行,获取 先前计算的结果,并将所述先前计算的结果作为待返回的结果返回到与所 述选定的票单相关联的发起请求的客户端。该方法还可以包括:将所述先 前计算的结果存储在所述提供者票单服务的数据存储器中。该方法还可以 包括,在执行由所述选定的票单请求的计算之前,确定是否另一提供者正 在执行由所述选定的票单请求的计算的过程中,且如果是的话,等待所述 另一提供者执行所述计算并提供结果,并将来自所述另一提供者的结果作 为待返回的结果返回给与所述选定的票单相关联的所述发出请求的客户 端。该方法还可以包括:基于至少一个标准,确定是否存储所述结果;及 响应于所述至少一个标准被满足,将所述结果存储在所述提供者票单服务 的数据存储器中。

所述至少一个标准可以包括:(a)由所述选定的票单请求的计算是否 已经被至少一个其它的客户端请求;(b)所述结果被预期请求或已被请求 的频率;(c)用于执行所述计算的数据是否在预定的时间期间之内。所述 标准还可以或可替代地基于由所述选定的票单请求的计算被所述一个或 多个客户端的其他客户端请求的频率。

该方法还可以包括:从提供所述第一票单的所述客户端接收利用与所 述第一票单相关联的所述票单标识符对所述结果的请求;及响应于从发出 请求的客户端接收到所述请求,在所述数据存储器中查询所述结果。所述 方法还可以包括将提供者标识插入到所述选定的票单中,所述提供者标识 识别所述一个或多个提供者中的哪一个将被调用用于执行由所述选定的 票单的所述计算标识符识别的计算。所述方法还可以包括:将与所述选定 的票单相关联的所述票单标识符发送到发送所述选定的票单的所述客户 端。所述方法还可以包括:从所述一个或多个客户端接收对所述选定的票 单的状态的请求;响应于接收到对所述选定的票单的状态的请求,所述提 供者票单服务在票单状态表中查询所述选定的票单的状态;及所述提供者 票单服务将所述选定的票单的状态发送到请求所述选定的票单的状态的 客户端,所述状态包括所述选定的票单的处理是否挂起或正在进行中的指 示,且如果所述选定的票单的状态是正在进行中,所述票单提供者服务还 发送关于多少处理已完成或尚待完成以产生所述结果的指示。所述被调用 的提供者可使用托管在所述提供者宿主服务的本地或所述提供者宿主服 务的外部的输入数据进行待执行的计算,所述提供者宿主服务还至少部分 地基于本地或外部数据。

该方法还可以包括:所述被调用的提供者向由所述提供者票单服务托 管的数据存储器或托管在所述提供者宿主服务和所述提供者票单服务外 部的数据服务请求在所述票单的有效载荷中指示的信息;及响应于所述被 调用的提供者请求所述信息,所述被调用的提供者从所述数据存储器或外 部的数据服务接收输入数据,并使用所接收到的输入数据执行由所述选定 的票单请求的计算。该方法还可以包括:使用票单管理器,根据队列将所 述票单存储在票单存储器中;识别每个所述票单的状态并将包括所述选定 的票单的每个所述票单的状态的指示存储在票单状态表中;在每次所述票 单中的选定的票单的状态被识别为挂起时,增加挂起的票单计数;在所述票 单存储器中查询在所述队列的前面的所述票单中的第一个;及根据所述第 一个票单从所述多个提供者中识别要被调用的至少一个提供者来执行由 所述第一个票单的计算标识符指示的计算。

该方法还可以包括响应于在所述提供者票单服务接收到所述选定的 票单,在所述票单状态表中将所述选定的票单的状态从挂起更新为在进行 中。该方法还可以包括:将所述结果存储在所述提供者票单服务的数据存 储器中;及响应于将所述结果存储在所述提供者票单服务的数据存储器 中,在所述票单状态表中将所述选定的票单的状态从在进行中更新为完 成。

所述票单中的至少一些票单中的每个还包括指示相对于其他票单的 调用的优先级顺序的优先级字段,所述第一个票单在对应的优先级字段中 包括与所述其他票单中的至少一些票单相比较高的优先级顺序。该方法还 可以包括,响应于将所述结果返回到与所述选定的票单相关的客户端,从 所述票单存储器中删除所述选定的票单并从所述票单状态表中删除所述 选定的票单的状态。该方法还可以包括:在所述提供者票单服务接收取消 所述票单之一的请求;所述提供者票单服务基于所述被取消的票单中的提 供者标识信息,确定通知哪一提供者;通知被确定为与所述待被取消的票 单相关联的提供者,所述待被取消的票单已经接收到取消请求;及取消所 述待被取消的票单。

该方法可以还包括响应于在所述提供者票单服务接收到所述多个票 单,通过可扩展的标记语言(XML)格式化每个所述票单,或将所述每个 票单格式化为JavaScript对象表示(JSON)格式。所述有效载荷可包括执 行与所述计算标识符相关联的计算所需要的一组输入或参数。所述一组输 入或参数包括指示执行与所述计算标识符相关联的计算所需要的至少一 些数据的源的源标识。

该方法还可以包括:与所述选定的票单相关联的被调用的提供者至少 部分地基于所述选定的票单的有效载荷执行由所述选定的票单的计算标 识符所指示的计算;及响应于执行所述计算,所述被调用的提供者输出与 所述选定的票单相关联的所述计算的结果。该方法还可以包括所述提供者 宿主服务还托管被确定为执行由所述选定的票单的计算标识符识别的计 算的所述一个或多个提供者。该方法还可以包括所述提供者宿主服务通知 所述提供者票单服务有多少提供者宿主线程可用于执行由所述票单请求 的计算。

所述启动至少一个提供者宿主线程包括调用多个提供者并将所述多 个提供者链接在一起,所述被链接的一些提供者执行中间计算并产生中间 结果,以产生作为被返回给与所述选定的票单相关联的发出请求的客户端 的结果的结果。该方法还可包括读取配置文件以确定如何将所述被链接的 提供者链接在一起,所述配置文件至少指示处理每个所述被链接的提供者 的顺序。该方法还可包括将所述中间结果存储在托管在所述提供者票单服 务的本地的数据存储器中。

所述选定的票单可包括源标识、标题标识和日期或日期范围,所述源 标识识别用于执行由所述选定的票单的计算标识符识别的计算的数据源, 所述标题信息识别关于来自所述源标识的数据的标题信息,及所述日期或 日期范围对应于来自所述数据源的标题数据的日期或日期范围。所述选定 的票单还可包括与所述源标识和所述标题标识相关联的依赖性标识,所述 依赖性标识相对于与其它的每个所述票单相关联的依赖性标识具有唯一 的值,以允许具有相同的源标识和相同的标题标识的相同的源-标题组合的 多个实例。所述依赖性标识可识别多个使用时间(TOU)安排中的一个, 每个所述TOU安排与相同的源标识和相同的标题标识相关联,所述计算 基于由所述依赖性标识识别的TOU安排来确定使用时间(TOU)的价格 或能源使用量。所述信息可包括指示由公用资源系统中的一个或多个智能 电子设备测量的公用资源的特性的值或根据所述公用资源的特性计算出 的值。

所述公用资源可以是水、空气、天然气、电力、或蒸汽。例如,所述 公用资源是电力,且所述特性包括电流或电压。根据电流或电压计算出的 值可包括能量。所述提供者票单服务可托管在计算机器上及所述提供者宿 主服务托管在所述计算机器上。所述提供者宿主服务可包括多个提供者宿 主服务,所述提供者票单服务托管在计算机器上且所述多个提供者宿主服 务中的至少一些托管在其他计算机器上,所述其他计算机器可通信地耦合 到托管所述提供者票单服务的所述计算机器。所述方法还可包括将统一资 源标识符(URI)与所述提供者宿主服务相关联。

本公开的上述及其它的方面和实现对于本领域的普通技术人员而言, 在参考参照附图提供的各种实施例和/或方面的详细描述后,将是明显的, 接下来提供附图的简要描述。

附图描述

本发明的上述和其它的优点,在阅读下面的详细描述和参考附图后, 将变得明显。

图1是根据本公开的一个方面的包括提供者票单服务和提供者宿主服 务的提供者服务的功能框图;

图2是提供者票单服务和提供者宿主服务内的各种组件的功能框图;

图3是示出了从客户端接收有效载荷的提供者票单服务的功能框图;

图4是示出了从提供者票单服务请求票单的提供者宿主服务的功能框 图;

图5是示出了将票单传递到提供者宿主服务的提供者票单服务的功能 框图;

图6是示出了对票单进行处理并将结果传递到提供者票单服务的数据 存储器的提供者宿主服务的功能框图;

图7是示出了请求由提供者票单服务所处理的票单的状态的客户端的 功能框图;

图8是由提供者票单服务的票单管理器的状态管理器使用的统一建模 语言(UML)格式的状态机;

图9是示出了提供者票单服务使用回调函数通知客户端票单已经完成 的功能框图;

图10是由图1所示的提供者服务使用的示例性算法的流程图。

详细描述

本公开内容提出一种软件架构,如网络服务提供商的面向服务的架构 (SOA),其具有可脚本化、可扩展和可定制的计算引擎,是可插入到SOA 架构中以扩展提供者服务(PS)100提供的计算和数据的类型。提供者服 务100可被用于对来自公用资源系统的信息进行分析。此信息包括由公用 资源系统中的一个或多个智能电子设备测量的公用资源的特性的指示值 或从该特性计算的值。该公用资源可以是水、空气、煤气、电力、或蒸汽。 在电力的情况下,例如,特征可以是电流或电压。可以从测得的电流和电 压计算能量值。智能电子装置测量并存储被监视的公用资源的各种特性 (例如,电压、电流、波形畸变、功率等),且来自每个智能电子装置的 数据可以被系统内的本地数据采集点收集并上传到一个或多个计算机器, 如服务器,用于存储或分析。

图1是提供者服务100的高层概览的功能框图,其包括提供者票单服 务102和提供者宿主服务104,这两个都被包括在Windows通信接口 (WCF)服务106中。提供者服务100的功能包括以下项的任意组合(没 有特定的顺序):

(a)从一个或多个客户端如Silverlight小工具(gadget)110接受请求, 以执行工作,如计算;

(b)合并要求,从而消除冗余的工作;

(c)管理和报告(在请求时)正在进行的工作的状态;

(d)获得执行计算所需要的数据和元数据;

(e)执行由客户端请求的计算;及

(f)在被请求时,将计算结果传递到进行请求的客户端。

提供者服务可以使用可插入的称为提供者的动态链接库(DLL),如示 于图2的提供者208,在此扩展它可工作的计算和数据的类型。提供者服 务100在这个例子中用作SOA架构的一部分。提供者服务100可以使用 “轮询”模式,其中其服务的用户周期性地调入以获得状态和结果。这种 模式提供了最灵活的环境,因为它适应来自客户端的所有潜在的调用,包 括驻留在防火墙后面的那些调用。

提供者服务100的逻辑设计包括至少三部分(参见图1和2):

1.提供者票单服务102;

2.一个或多个提供者宿主服务104;及

3.插件式提供者208;

提供者票单服务102(PTS)表示提供者服务100的“公共面孔”。一 个或多个外部客户端,如小工具110,与提供者票单服务102通信。提供 者票单服务102的功能包括:接受执行或进行例如计算的工作的请求,合 并请求以消除冗余的工作,管理和报告正在进行的工作的状态,并当被请 求时传递计算结果。

提供者宿主服务104(PHS)负责查看提供者服务100的真实工作-在 输入数据上运行的计算-完成并将结果传递到缓存或数据存储器200(如图 2所示)。通过(在一台物理机器或多台物理机器)上运行多个提供者宿主 服务,可实现可扩展性,提供者宿主服务将结果传递到数据存储器200。

提供者是由提供者宿主服务106实例化(或调用)和管理的插件式动 态链接库(DLL)。提供者收集执行一个或多个计算所需要的输入数据,执 行一个或多个计算,并返回计算结果。如提供者208的提供者包括以下逻 辑,(a)收集执行计算所需的输入数据,(b)执行给定的计算,及(c)提 供关于正在进行的计算的进展的状态信息(在受到要求时)。此状态信息 可以包括完成百分比、成功或失败、及失败的原因,重试次数等。

提供者票单服务102和提供者宿主服务104之间的对应关系可以是一 对一或一对多的。例如,一个提供者票单服务102和一个提供者宿主服务 104可以在如计算机的一台计算机器上被执行。另外,一个提供者票单服 务102可以与一个以上的提供者宿主服务104通信。这些提供者宿主服务 可以被托管和执行在一个或多于一个计算机器上,但每个提供者宿主服务 将其各自的计算结果返回到一个提供者票单服务。换句话说,指代提供者 票单服务102与提供者宿主服务的方式之一是PTS102是主/控制器而 PHS104是其“工人”。

提供者票单服务104的非限制职责包括处理以下项的任意组合(没有 特定的顺序):

1.经由来自诸如小工具110的客户端的WCF调用,接收工作请求 “Payload”(如为XML片段或JSON字符串的形式),请求执行计算,将 该Payload嵌入“票单”202(正确形成的XML文档)中并返回唯一的票 单标识符(GUID字符串)到客户端作为令牌。如本文所用的,WCF是指 Windows通信接口,其是用于建立连接的、面向服务的应用的.NET框架 的应用程序接口。XML指可扩展的标记语言。JSON指JavaScript对象表 示法。GUID是指全局唯一标识符,该术语是由软件开发人员理解的。

2.在票单存储器204中存储XML格式的票单,并创建对象以跟踪它 正在工作的票单的进度(例如,在票单中指定的计算正在被执行)。

3.在票单管理器206中接收和处理票单取消请求,并将关于票单取消 的消息通知任何工作进程(即提供者宿主服务)。

4.在状态管理器210中,在被请求时,报告票单进度/状态。

5.在被请求时,将最终的票单结果数据(即,所请求的计算的结果) 返回到客户端。

6.允许外部实体读取先前已存储的数据。

7.将PHS队列212中排队的票单交给提供者宿主服务。

在一个示例性的实现中,提供者票单服务102被“包裹”在Windows 通信接口(WCF)服务106中,WCF服务106将其自身注册为消息传送 服务客户端。WCF服务106允许支持Silverlight的组件,如Silverlight小 工具110,与支持Silverlight的或不支持Silverlight的WCF服务通信,以 便通过使用标准的WCF服务获得最大的灵活性,并且提供者票单服务102 不需要支持Silverlight。WCF API(应用程序接口)允许客户端访问提供者 票单服务102的所有公共功能。消息传送服务将被提供者服务100用于访 问如验证和配置的其他应用模块。如本文所用的,Silverlight是指可从微软 公司获得的SilverlightTMWeb应用框架。Silverlight是将多媒体、 计算机图形、动画和交互性集成到单一的运行时环境的Web应用框架。

提供者宿主服务104管理和执行可插入的提供者,如提供者208。提供 者宿主服务104可以托管多个提供者宿主线程108,每个线程108执行一 个或多个提供者208。提供者宿主服务104允许运行的线程108的最大数 量是可配置的。提供者宿主服务104也可以被配置为只处理某些类型的计 算和提供者。

提供者208也可以链接。例如,单一的线程可以运行确定的序列中的 多个提供者,每一个提供者的输出作为序列中的下一个提供者的输入,并 且链中的最后一个提供者产生最终结果。提供者可以被配置为接受这样的 链接,且仅可以允许提供者的预先配置的组合。这些组合可以由从驻留在 提供者票单服务102中的配置文件中获得的信息确定。

提供者宿主服务104的职责包括以下项的任意组合(没有特定的顺序):

·通知提供者票单服务102,它有可用于执行票单的X个线程(其中 X是一个整数值);

·从提供者票单服务102接收票单(PTS102呼入提供者宿主服务104, 以将票单交给PHS104),并将它们放置在PTS102的本地队列212中;

·启动或调用托管提供者208的提供者宿主线程108,并将票单传递到 每个被调用的线程108;

·在它们的存在期中监测和管理线程108;

·终止已超过其被分配的运行时间的线程108;

·将进度报告从提供者208传回提供者票单服务102。当提供者208 被链接时,PHS104基于被链接的提供者208的数目调整完成的百分比报 告。例如,如果四个链接的提供者的第一个提供者报告100%完成,则整 体进度是仅完成25%。

每个提供者宿主线程108的职责包括以下项的任意组合(没有特定的 顺序):

·实例化一个或多个提供者208;

·将来自由提供者208执行的计算的结果数据转发到数据存储器200; 及

·将提供者208的进度和状态报告给提供者票单服务102。

在示例性配置中,提供者208可以驻留在插件式动态链接库(DLL) 中,其将由提供者宿主服务104使用。一个动态链接库可包括多个提供者, 允许第三方通过创建执行新的计算的新的提供者来扩展提供者服务100的 功能,产生汇总数据的新的类型,使用新的层次结构类型来工作等等。提 供者的开发人员可以对他们的提供者编写代码(使用提供的软件开发工具 包或SDK),以处理以下任务的任意组合(没有特定的顺序):

·检查票单并确定需要获得什么输入数据来进行其计算,如通用数据 模型(在SOA上下文中)主题;

·在适用时,从数据存储器200和/或从数据服务总线600(图6)或 DSB请求必要的输入数据;

·对输入数据执行计算;及

·将结果以及任何适用的中间数据存储在数据存储器200中。

本文所披露的架构支持创建提供者,如提供者208,其允许脚本化计算, 从而去除创建提供者插件的需要,因为通过创建新的脚本,可以实现几乎 任何计算。但是,针对具体的计算创建定制的提供者可以提供使用可脚本 化的提供者不可能实现的优化的机会。

通过详细描述客户端工作请求的示例性过程,从发出请求的那一刻起 到结果数据被发送,现在将描述提供者服务100的操作。客户端或小工具 项目110应该首先被配置为调用提供者服务100上的方法或提供者。假设 提供者服务100被正确地安装和配置在如服务器的计算机器上,在以下非 限制性的例子中,小工具或其他客户端被配置为调用提供者服务100:

1.在小工具或客户端110的项目中,引用被添加到(在这个例子)称 为ProviderMethods.dll112的动态链接库。该DLL112包括发布高层方法 小工具110将调用以请求计算的接口。

2.“using”声明被添加到小工具/客户端的代码,如“using  Company.Modules.Calculation.Provider.”

3.找到要执行或实施的所希望的计算的名称。

4.在小工具/客户端代码中添加对所定位的计算的调用,诸如,例如, “Provider.GetEnergyRolledUp,”这是一个对名为GetEnergyRoUedUp的提 供者的调用,它返回对输入数据的积累的(rolled-up)能量计算,所述输 入数据指示计算在期望的时间期间的能量消耗所需要的值。

5.对于使用Visual的小工具开发人员,Intellisense 功能将揭示提供给计算提供者的适当的方法参数。

在这个例子中,在ProviderMethods.dll文件112中的方法是为了方便小 工具的开发者而存在的高级别的、易于援引的调用。在替代的实现中,一 些或全部的提供者在ProviderMethods.dll文件112中不具有高级别的调用。 在这种情况下,开发者可以发布包括调用所需的计算的高级别的方法的单 独的DLL112。这个单独的DLL112将需要在小工具项目110中被引用。 另一个例子涉及小工具/客户端开发人员查找针对需要被传递到特定的提 供者的数据的实际的计算标识符和XML格式,并作出到提供者服务的直 接的WCF调用。这绕过了如ProviderMethods.dll112的DLL中的高级别 的方法调用,但最终产生相同的结果。

本节描述了从提交工作请求(图3)的客户端110进行请求到客户端 110获取结果(图6)的路径的一个例子。路径的示例性列表如下:

1.客户端110提交票单有效载荷到提供者票单服务102(PTS)(图3), 并从PTS102收到一个唯一的令牌。处理器206使用状态管理器210检查 对于已接收到的票单,是否存在校验和(票单标识符)。如果必要的话, 处理器206也可以产生票单,并添加新的校验和或更新现有的校验和(票 单标识符)和可选地更新状态,并将此信息传递给状态管理器210。处理 器206也可以将一新票单加入队列中或更新URI的端点。

2.PTS102将接收到的有效载荷嵌入票单202中,其被放在可由PTS 102访问的票单存储器204中(图3)。

3.提供者宿主服务(PHS)104通知PTS102,它已准备好接受一个或 多个票单202(图4)。处理器206将用于PHS104的URI的端点插入PHS 队列212。

4.PTS102提交票单到PHS104(图5)。票单管理器206从PHS队列 212获得用于PHS104的排队的URI,并从票单存储器204获得排队的票 单,将票单提交给PHS202,将票单从票单存储器204中出列并更新状态 管理器210中的票单的状态。

5.PHS104的线程管理器216启动运行适当的提供者208的线程108 (图5)。

6.由提供者208处理与票单202相关的计算,以执行请求的计算。

7.提供者208将计算结果写入数据存储器200(图6)。

8.客户端110通过传递其从PTS102收到的对应于票单的令牌来检查 进展情况(图7)。票单管理器206将对应于票单的校验和(票单标识符) 传递到状态管理器210,它返回票单的状态(例如,挂起、进行中、等待、 已完成),且票单管理器206将返回的状态报告给客户端110。

9.客户端诸如从数据存储器200获取结果。在图9中,示出了通过回 调函数通知客户端110票单的完成情况的框图。当由票单队列902指示票 单已完成,且结果被返回到提供者票单服务102,PTS102经由WCF服务 106内部的内部接口904将结果发送到消息服务通信包装器910内的消息 客户端906,其使用回调函数将结果传递回客户端110。

使用相同编号的段落,每个上述块的更详细的描述如下。

1。客户端110提交票单有效载荷,并且提供者票单服务102接收有效 载荷(参见图3)。在这个例子中,“票单有效载荷”描述了需要执行的计 算,并且可以是,例如,XML片段或JSON字符串。有效载荷几乎可以采 用任何形式,只要其被打算用于的提供者插件知道如何解释其信息。在这 个例子中,“票单”是包装一个或多个票单有效载荷的结构良好的XML文 档,并提供关于请求的额外的“看家”信息,如请求的日期和时间。

客户端110不负责提交票单有效载荷或票单,虽然如果需要的话,它 们可以直接通过WCF调用来提交票单有效载荷。相反,客户端对 ProviderMethods.dll112中的接口方法进行高层的调用,且这些方法112从 提供的参数产生票单有效载荷。示例性有效载荷可以是这样的:

在上述有效载荷的示例中,客户端110提供关于设备(即,针对请求 的计算所需的数据源),标题(例如,关于来自所识别的源的数据的诸如 电流、电压、能量、功率等标题信息),及被请求执行的计算的日期或日 期范围的信息。应当指出,这对于执行所请求的计算并不是充分的信息。 在这个例子中,所需的计算甚至没有在上面的XML片段中指示。相反, 高层方法实现可以将额外的参数以及有效载荷传递到提供者票单服务 102。具体而言,方法112可以提供标识所需要的特定计算的GUID、可以 被回调结果状态的URI(以供将来使用),和指示请求的优先级(也供将来 使用)的整数。如本文所用的,在互联网的上下文中,URI是指统一资源 定位符。GUID是指全局唯一标识符,如软件应用的背景下所理解的。在 下面的表1中提供了被编码在标题标识符(topicId)中的标题信息的实例。

每一个有效载荷可以有“id”属性,其是唯一地标识该特定的有效载荷 的结构的GUID。有效载荷结构的任何变化可导致该有效载荷被分配一个 新的GUID。提供者208可以被写成期望有效载荷标识的特定组合,并且 通过识别有效载荷标识的旧组合,提供者208可以支持向后兼容较旧的有 效载荷标识。

除了源和标题标识信息,票单可以进一步包括与源标识与标题标识相 关的依赖性标识。依赖性标识具有相对于与其它的每个票单相关联的依赖 性标识的唯一的值,以允许具有相同的源标识和相同的标题标识的相同的 源-标题组合的多个实例。例如,依赖性标识可识别一些使用时间(TOU) 的安排中的一个,每个TOU安排与相同的源标识和相同的标题标识相关 联。可替换地,依赖性标识可以与不同的成本表相关联。例如,TOU安排 可以具有能量消耗的三个不同期间:高峰期、肩峰期、和非高峰期。根据 能量数据的来源,TOU安排可以是不同的。例如,对于一种数据源,高峰 期可发生在上午8时至上午10时之间,但在一年中的不同时间,对于相 同的数据源,高峰期可发生在上午9时至晚上12时之间。如果没有依赖 性标识,PHS104将无法根据特定的TOU安排针对计算能量消耗的目的区 分数据。此外,不同的成本安排在不同的使用期间适用。例如,在高峰期 的成本安排通常高于在非高峰期间的。依赖性标识允许相同的源标题数据 用于根据不同的成本安排或根据不同的TOU安排计算能量消耗。在本质 上,依赖性标识是允许相同的源标题标识符的多个实例在不同的计算中使 用而被存储和索引的第三标识符。

在这个例子中,ProviderMethods.dll包装器方法在提供者票单服务102 上将有效载荷信息传递给称为SubmitRequest的标准方法。SubmitRequest 的方法签名的一个例子是:string SubmitRequest(int calculationId,string  payload,URI endpoint,int priority)。

为了防止需要添加相关方法到ProviderMethods.dll112,从而重新编译 和分发DLL,提供者开发人员可以分配动态链接库(或者甚至提供者DLL 本身),其输出包括其高层方法的接口。

2.提供者票单服务102将有效载荷嵌入票单中,且票单连同嵌入的有 效负载被放置在票单存储器204,如图3所示。一旦PTS102接收到该有 效载荷和其他信息,其将它“包装”在例如下面这样的票单202中:

另外,标准化的信息已被添加到上面的示例性票单202中。具体来说, 以下字段的任意组合可以出现在票单202中:

ticketId字段是包括运行在票单202的有效载荷部分的MD5(消息摘 要算法5)校验和的票单标识符。该票单标识符是用来唯一标识在提供者 服务100中的该特定的工作请求的标识符。注意传递相同的有效载荷的另 一个SubmitRequest调用将导致产生相同的ticketId值。以这种方式,重复 /冗余的工作请求可以被识别。事实上,当提供者票单服务102首先产生用 于新传递的有效载荷的票单202时,它会使用提供者票单服务102的状态 管理器210组件(跟踪每个工作项目的目前状态的组件)检查以查看是否 相同的工作请求(即具有相同ticketId的请求)已经在提供者票单服务102 的票单存储器204组件中。如果是这样的话,代替创建新的结构来跟踪新 的工作请求,在状态管理器210中现有的结构被更新以反映已提出的新的 请求与之重复这一事实,且以前存储的票单(在票单存储器204中)被使 用新的请求者的URI端点更新。如果在系统中不存在相同的请求,在状态 管理器210中创建新的结构以跟踪工作,并且新的票单被存储在PTS102 的票单存储器204组件中。

calculationId字段是对应于用于唯一地标识所请求的计算的GUID的 计算标识符。在示例性实现中,计算标识符直接对应于单一的提供者208。 在其他涉及将多个提供者链接在一起的实现中,计算标识符可对应于提供 者的有序列表。驻留在托管PTS102的机器上的基于XML的配置文件提 供指示列表中的每个提供者将被调用的一系列顺序的这些映射。

priority字段允许调用者(如客户端,诸如客户端110)表明他们的计 算请求具有比其他调用高/低的优先级。

creationDateTimeUtc字段是指票单(不是有效载荷)被创建的UTC(协 调世界时)格式的日期和时间。此信息可用于使请求失效(即指示其已超 时)。

rawDataAvailable字段指示是否与请求一起提供了(执行请求的计算所 需要的)原始数据。有些客户端可能希望提供从外部来源获得的数据,而 不是依赖于应用模块(如数据源驱动器)的其他部分提供数据。在这种情 况下,WCF方法被调用来允许用户与票单一起传递他们自己的数据,且此 标志将在票单中被设置。通常情况下,票单包括标识被用于执行所请求的 计算的原始数据的源的源标识符,及被分配该计算任务的提供者从所标识 的源获取原始数据。

endpoint字段指所有票单请求者的端点或URI,允许票单跟踪这些请 求者。如果有效载荷到达提供者票单服务102(PTS),及具有相同的ticketId 的有效载荷已在进行中,则调用者的URI被添加到该列表中。对于新的 ticketId,创建新的票单,且端点部分包括单一的URI。

providerOrderedListOfIds字段指定提供者以及它们的标识符和包含它 们的动态链接库的名称的有序列表。顺序指示(在链式提供者的情况下) 提供者将被运行来执行所需的计算的顺序或序列。需要注意的是,因为一 个DLL可以包含多个提供者,一个DLL名称可以由多于一个的提供者标 识符引用。从calculationId字段到该信息的映射可以从基于XML的配置文 件得到,该基于XML的配置文件位于托管提供者票单服务102的计算机 器上。因为这种映射已经在PTS102被解析,在提供者宿主服务(PHS) 104中不需要发生映射或查找。PHS104只需访问提供者DLL,这样PHS 可以加载和运行DLL。

3.如图4所示,提供者宿主服务104(PHS)诸如通过请求一个或多 个票单,通知提供者票单服务102(PTS),它已准备好接受票单。在这个 例子中,“懒推(lazy push)”模型用于将票单从PTS102发送到PHS104, 并如下工作。线程管理器216是一种关于运行在它自己的线程108中的PHS 类的方法。这是PHS104的主线程108。线程管理器216负责使PTS102 被通知它已准备好X(其中X是整数值)个工作请求。

提供者宿主服务(PHS)类包括例如,通过检查容纳映射到计算标识 符的线程标识符的数据结构,返回可用于执行工作的提供者宿主线程108 的数量的方法。PHS类可以执行简单或复杂的逻辑,以确定它还可以承担 多少线程。

PHS104调用PTS102上的方法,在这个例子中称为RequestTicket, 且PTS102将PHS的URI放在列表或队列212中。PHS的URI可以在此 队列212中存在不止一次,因为PHS104可能愿意在同一时间在不同的线 程上在一个以上的计算上工作。PTS102维护PHS104能够处理的计算的 列表。如果对于发出票单请求的PHS104而言,在此列表中没有条目,则 PTS102调用在PHS104上的方法以要求该列表。随着工作变得可用,PTS 102试图发送票单到在其队列中的PHS URI。各个PHS(如果有不止一个 的话)可以接受或拒绝票单202,且可返回表明其拒绝的原因的状态结果。 PTS102可以决定是否发送票单202到队列212中的另一个PHS,是否使 该票单失效等。PHS104可能会拒绝票单,因为它太忙(即所有被允许的 线程处于活动状态),或由于一些其他的原因。

4.PTS102将票单202提交到PHS104,如图5所示。WCF线程在提 供者宿主服务类上运行SubmitTicket方法。SubmitTicket方法解析票单202 以确定提供者DLL的名称,以及这些DLL是否存在并可以被正确加载。 票单应被发送到支持请求的计算的提供者宿主服务,但PHS104可以选择 性地验证必要的提供者存在于托管PHS104的计算机器上,作为完整性检 查。在这个例子中,PHS104具有存在的DLL的内存列表,且PHS104可 以使用DLL名称作为键值查找DLL的创造者。SubmitTicket方法使用此 信息来确定是返回成功还是失败到发起请求的PTS102。返回值不是简单 的布尔值,而是指示PHS104是否太忙或者具有一些错误状况的更具描述 性的返回值。

关于SubmitTicket的逻辑可以如下进行操作。如果PHS104太忙,返 回忙。如果PHS104不是太忙,对于每个提供者,询问DLL是否支持提 供者和提供者的有效载荷标识。如果是的话,返回接受,否则返回是提供 者标识还是有效载荷标识被拒绝的指示。

SubmitTicket方法创建但不启动提供者宿主线程(PHT)108(线程管 理器216稍后将做这些),并将对被启动的线程的引用存储在数据结构214 中。该数据结构214存储线程标识符、计算标识符、校验和、和线程过期 或“存在时间”(TTL)和PHT108的类实例。它也将返回PHT108何时 完成的代码。线程管理器216使用TTL来确定是否计算花费的时间太长。

5.提供者宿主服务(PHS)104启动运行合适的提供者208的线程。 当WCF线程运行PHS类的ISubmitTicket::Submit方法时,PHS104接收到 票单202。在此方法中,新的提供者宿主线程(PHT)108针对该请求被实 例化或调用,但不能运行。关于该请求的票单202、线程实例以及其他信 息将被放置在PHS类的结构中供日后引用。

PHS104包括线程管理器216,其是运行在线程上的PHS类的方法并 监视线程108且如果它们超出超时限制终止它们。线程管理器216防止被 锁定的线程占用资源及从不退出。线程管理器216还启动在以前的步骤中 被实例化的任何PHT。

提供者宿主线程(PHT)108具有成员,且在启动时进行某些分配, 如下所述。PHT108从线程管理器216接收接口,使用该接口来访问数据 存储器200(即IDataAccess)。如果提供者是链接的话,它还获得提供者 数量,并将其存储在成员属性中。PHT108也具有对实例化的提供者208 引用的成员,即使在提供者链接的例子中,其指向当前的实例化的提供者 208。PHT108具有托管票单202的成员,以及为事件或其它信号启用的 (signal-able)对象,其由线程管理器216用来发信号通知PHT108它已 经耗尽时间。如果线程管理器216没有从PHT108得到响应,它会调用 TerminateThread来终止该线程。在发信号通知PHT108它已经耗尽时间并 将终止后,线程管理器216将块放在PHT108线程标识符上,并等待合理 时间让它终止。如果它在等待期后没有终止,线程管理器216调用 TerminateThread来终止该线程。

在PHT108在其存在期内且没有报告完成,线程管理器216对该线程 什么都不做。如果退出状态已被更改为某种完成,线程管理器216报告完 成或失败并进行到线程标识上的块(0)直到线程结束。如果线程108在合理 的时间内没有结束,它无论如何需要TerminateThread。如果线程成功自行 终止,线程管理器可以请求更多的票单。

如果线程108超过它的TTL,线程管理器216首先试图通知线程108; 如果失败,线程管理器216强行终止该线程。无论哪种方式,线程管理器 216报告线程失败。

在PHT108中,“本地数据存储”是IDataAccess接口(API的一部分), 其允许与由提供者票单服务102的数据存储器使用的相同的数据库通信, 如图6所示。

PHT108在运行所有的提供者后,但在发信号通知完成之前,将数据 如下写入到数据存储器200(即,提供者票单服务102的数据存储器200): PHT108拥有将提供者标识映射到TransportDataObject或对象的数组或字 典。在PHT108运行所有的提供者后,它为最后的提供者的结果数据翻出 (pull out)TransportDataObject并将其传递到IDataAccess上的 WriteTicketResults,因此将表示计算结果的结果数据写入数据存储器200。

票单202可以包括指示是否原始数据可从数据存储器200获取的字 段。如果是这样的话,提供者208可以通过调用IDataAccess方法从数据 存储器200读取这些数据,并将其传递到票单标识符中。

PHT108具有三个读/写功能:ReadInputData,其中读取由提供者208 进行的计算的输入数据,WriteIntermediateData,其中PHT108为另一个链 接的提供者输出中间结果,WriteResultData,其中,当PHT108是最后链 接的提供者或需要执行所请求的计算的唯一的提供者时,PHT108输出计 算结果。PHT108在提供第三方数据的情况下,及针对链中的不同的提供 者,确定涉及的逻辑。

6.图6图示了由提供者208处理票单202的一个实现。提供者宿主线 程108根据票单202中含有的提供者标识通过检查包含提供者208的DLL 来调用提供者208。提供者208可从至少两个位置获得数据:

·由提供者票单服务102托管的数据存储器200。提供者208可以在 数据存储器200中搜索以前计算的结果或中间数据以缩短由提供者208执 行其计算所需的时间。

·数据服务总线600(DSB)。提供者208可以查询DSB600用于从外 部数据源驱动器(DSD)获取原始数据。

也可以利用上述的组合。例如,显示过去一小时的信息的小工具110 每15分钟刷新一次。提供者208可以从数据存储器200获取前45分钟的 结果,因此只需要从DSB600获取15分钟的原始数据。

在运行时,提供者208在实现在提供者宿主线程类中的接口上调用 UpdateTicketStatus,并访问显示链中的提供者数量的PHT类成员。这允许 PHT代码(其知道来自特定的提供者的完成百分比仅是总体的一部分)计 算总的完成百分比并将完成状态传递给PTS102。

提供者208也可检查票单202是否已被取消,从而提供者208可以尽 早终止计算并释放资源用于其他票单。提供者的编码器可以执行这些更新 和检查,并将适用的中间日期写入到PTS102的数据存储器200。

7.图6图示了移植,其中结果由提供者208写入到数据存储器200。 当完成所请求的计算时,使用提供者的IDataAccess接口,每个提供者试 图将其结果数据写入数据存储器200。提供者宿主服务104(PHS)在票单 状态表中将票单的状态设置为“完成”,票单的进度为100%,并通知提供 者票单服务(PTS)102,提供者208已完成由票单202所请求的计算。

8.图7图示了客户端110如何检查票单的进度。客户端110使用从PTS 102传递回的标记调查提供者服务100,以确定票单202是否完成。如果 客户端110知道提供者208更新其进度状态,客户端110可以定期查询该 进度。这可以被用来通过客户端110显示进度条,或确定等到下一个查询 的时间量。

9.当客户端110确定有为其准备的结果,它再次使用其令牌请求该结 果数据。提供者服务100将该请求传递到票单管理器206。票单管理器206 在数据存储器200中查询相应的结果并返回它。

此时票单202被视为已完成其生命周期。它被从票单存储器204删除 且它的状态信息被从票单状态表中擦除。

提供者服务的通信包装器106可以包括允许回调通知的接口。此外, 当多个提供者被链接在一起来执行一系列计算,票单管理器206使用票单 确定哪些提供者的结果被传回。除了提交票单、检查进度和获取结果外, 客户端110也可以取消票单。当提供者服务100接收到取消请求,票单管 理器206将票单取消状态标记为“真”。由于以下几个原因,票单管理器 206不应该立即删除票单。首先,提供者可能已经在处理该票单。其次, 票单可能仍然处于挂起,但它的ID可能在队列的中部,或者它正忙于被 移交给PHS104。

如果提供者208正在处理票单202,其应定期检查,看票单是否被标 记为取消。在发现此事后,提供者208应立即且完善地终止,执行任何必 要的清理。如果提供者不检查取消,那么它只是运行直至完成。所有受影 响的是,在对过期的票单工作时,线程被占用。在提供者已终止后,PHS104 像往常一样将票单状态设置为“已完成”。

如果在上述的块3中,在票单管理器206从票单存储器204获取票单 时,票单仍是挂起,则票单管理器206删除任何已标记为取消的票单。

票单管理器206将不时清理准备删除的任何已被取消的票单。换句话 说,它会删除任何被取消标志为“真”且状态为“完成”的票单。

名称为状态管理器210的组件驻留在提供者票单服务102中,且包括 一个状态机(或其他方式的管理状态逻辑)和两个字典。状态管理器210 中的第一个字典将票单校验和(即票单标识符,ticketId)映射到状态对象, 其包括关于特定的工作项的所有状态信息。第二字典将客户端令牌(即, requesterId或客户端请求者标识)映射到票单校验和(ticketId)。这允许使 用ticketId或requesterId索引到状态对象。由状态管理器210使用的用于 状态机的示例性逻辑示于图8中。

状态管理器210接收关于票单状态的新的请求。在这个例子中,票单 可以有六个状态:挂起、在进行中、取消挂起、失败、取消在进行中、或 已完成。最初,票单的状态是挂起。当接收到工作请求时,票单的状态被 改变到在进行中,且当计算结果已经完成时,票单的状态从在进行中改变 到完成,且票单管理器206将票单从票单存储器204移除。如果接收到要 求取消票单的请求而票单状态是挂起,则票单的状态被改为取消挂起。取 消票单的请求可以被反转,将票单的状态恢复到挂起。如果票单被取消, 票单管理器206从票单存储器204中去除票单。虽然票单的状态是在进行 中,如果出现错误,例如完成计算的超时限制达到,票单的状态被改变到 “失败”。一旦处于失败状态,票单管理器206可以重新提交票单以重新 计算,在这种情况下,票单的状态被变回挂起并被放置在挂起队列中。另 外,票单管理器206可以从票单存储器204去除失败票单,并通知客户端 110去除及可选择性地通知失败原因。当计算正在被执行且票单的状态是 在进行中时,可以发出取消票单的请求,则将票单的状态改变到正在进行 -取消。例如,另一个提供者可能刚刚完成同样的计算,则可以取消票单, 以避免重复的工作。其他提供者的结果可以被返回到客户端,并且票单的 状态可以改变为完成,然后被去除。取消请求是可以反转的,将票单恢复 到在进行中状态。如果票单被取消,票单管理器206从票单存储器204去 除被取消的票单。

下面的示例性代码对应于用于提交工作请求、监测工作状态和获取结 果的接口。

提供者服务100可以作为一个单独的组件。在单独的部署中,提供者 服务100从本地配置文件或存储器获得配置信息。如果被作为应用模块系 统的一部分来部署,它可以直接从配置服务获得它的配置信息。

提供者服务100可以被定制,原因在于提供者服务100可以加载称为 提供者的插件式动态链接库,该提供者能够定制和扩展可用计算的类型。

在本文所提供的例子中,虽然使用平台、框架和接口的任何已知的组 合可以实现提供者服务100的组件,但提供者票单服务102被Windows通 信接口(WCF)服务106包装。WCF API允许客户端访问提供者票单服务 102的所有公开功能。用于编码提供者服务100的组件的软件框架可以是 使用企业库缓存应用块的.NET框架。

图10是用于执行本文所描述的提供者宿主100的功能的算法1000的 一个示例性流程图。该算法1000用于使用提供者服务100获取数据并对 该数据执行计算,且算法1000的功能可以由提供者票单服务102或提供 者宿主服务104或两者执行。该算法在提供者票单服务102从一个或多个 客户端110接收票单(1002)。每个票单包括如上所述的计算标识符和有效 载荷。计算标识符使用在票单的有效载荷中指示的信息和任选的其它信息 来标识待由提供者208执行的计算。请注意,从客户端110传递到提供者 票单服务102的票单的形式不一定是XML格式的数据结构。传递的信息 可包括计算标识符和有效载荷,且这些一起被称为票单。提供者票单服务 102在从客户端110接收计算标识符和有效载荷后,格式化票单并且可以 将附加信息嵌入票单中。因此,虽然“票单”一词用来指最初从客户端接 收到的信息,应当理解在其被提供者票单服务102处理并传递到提供者宿 主服务104时,通过去除或将附加数据插入票单中,票单可以被格式化和 改变。

算法1000将唯一的票单标识符(例如,如上所述的MD5校验和)与 每个票单相关联(1004)。提供者票单服务102的票单管理器206将选定 的票单从PTS102提交给PHS104(1006)。PTS102检查票单中的计算标 识符,以确定哪些提供者待执行由所选定的票单的计算标识符标识的计算 (1008)。

该算法1000确定由计算标识符指示的所请求的计算是否已经被执行, 并预先存储在数据存储器200中(1010)。如果是这样的话,PTS102从数 据存储器200获取先前计算的结果,并将先前计算的结果返回到发出请求 的客户端110(1014)。如果不是这样的话,PTS102确定另一个提供者是 否在执行由所选定的票单所请求的计算的过程中(1012)。如果是这样的 话,PTS102等待另一提供者执行该计算,且当另一提供者已返回计算结 果时,PTS102将该结果提供给与所选定的票单相关联的发起请求的客户 端(1016)。请注意,块1010和1012可以以任何顺序执行。

如果请求的计算尚未被执行,且当前没有被处理,则PHS104启动提 供者宿主线程108,其调用或者实例化(1018)执行由选定的票单的计算 标识符标识的计算的提供者(1020)。PTS102从PHS104接收由被调用的 提供者108执行的计算的结果(1020),并将结果返回到与所选定的票单 相关联的发出请求的客户端(1022)。

应当指出的是,本文示出和讨论的任何算法,包括算法1000,具有执 行特定的功能且可彼此交互的各种模块。但应当理解,为了便于说明,这 些模块仅仅根据它们的功能被划分,且表示计算机硬件和/或存储在非临时 性的计算机可读介质上用于由适当的计算硬件执行的可执行的软件代码。 不同的模块和单元的各种功能可以以任何方式合并或分开为如上所述的 硬件和/或存储在计算机可读介质上的软件而作为模块,且可以单独使用或 组合使用。

此外,本文所公开的任何算法包括可由下列项执行的机器可读指令: (a)微处理器,(b)微控制器,和/或(c)任何其他合适的处理装置。将 容易理解的是,提供者票单服务102和提供者宿主服务104可以实现在任 何一个或多个合适的处理装置上。本文所公开的任何算法,诸如算法1000, 可体现在存储在非临时性的、有形介质上的软件中,所述非临时性的有形 介质诸如,例如,闪速存储器、CD-ROM、软盘、硬盘驱动器、数字多功 能盘(DVD)、或其它存储设备,但是本领域的普通技术人员将容易理解, 整个算法和/或其部分可以替代地由除了控制器以外的设备执行和/或以众 所周知的方式体现在固件或专用硬件中(例如,它可以由专用集成电路 (ASIC)、可编程逻辑器件(PLD)、现场可编程逻辑器件(FPLD)、离散 逻辑等实现)。尽管参照本文描绘的流程图或功能框图对特定的算法进行 了说明,但本领域的普通技术人员将容易理解,可替换地使用许多其他方 法实现示例性机器可读指令的方法。例如,块的执行顺序可以改变,和/ 或一些描述的块可被改变、消除、或组合。

下表列出了可被编码到各个标题组的标题标识(topicId)的标题信息 的例子:

表1

虽然已经示出和描述了本公开的特定实现和应用,应当理解,本发明 不局限于本文所公开的精确结构和组成,且在不脱离由所附权利要求限定 的本发明的精神和范围的情况下,各种修改、改变、和变化从前面的描述 中是明显的。

去获取专利,查看全文>

相似文献

  • 专利
  • 中文文献
  • 外文文献
获取专利

客服邮箱:kefu@zhangqiaokeyan.com

京公网安备:11010802029741号 ICP备案号:京ICP备15016152号-6 六维联合信息科技 (北京) 有限公司©版权所有
  • 客服微信

  • 服务号