六种优化方法 NCache 性能

录制的网络研讨会
通过 Kal Ali 和 Sam Awan

NCache 是用于 .NET 的流行的开源内存中分布式缓存。 它通过缓存应用程序数据和减少昂贵的数据库访问来帮助您扩展 .NET 应用程序。 NCache 通过允许您向缓存层集群添加更多缓存服务器来线性扩展。

了解如何优化 NCache 通过正确配置它以及使用其性能提升功能来提高性能。

此网络研讨会涵盖:

  • 简介 NCache 及其架构
  • 常用方式 NCache 用来
  • NCache 性能提升功能
  • NCache 性能提升配置选项

概述

今天,我们将举办一个网络研讨会,内容是关于改进的六个技巧 NCache 表现。 本次网络研讨会的模式将是只听。 您将有能力提出您想要的任何类型的问题。 右侧窗格中有一个问答选项卡。 您将能够输入您的问题,我们中的一个人将能够为您回答这些问题。 在网络研讨会期间,如果您有任何问题或疑虑,并且无法听到我们的声音,请 - 您可以再次使用聊天窗口。 Kal 将谈论演示文稿的所有技术部分。 如果有什么与技术或销售无关的东西,你们可以直接向我提问。 话虽如此,我将把它交给 Kal,他将开始演示。

好的。 谢谢山姆。 您能否确认您可以看到我的屏幕,因为我刚刚开始分享它? 是的,我可以完美地看到您的屏幕。 好吧,完美。 大家好,Sam 刚刚向我介绍了我,我的名字是 Kal,今天网络研讨会的主题是,六种优化方法 NCache 性能。

因此,在今天的网络研讨会中,我们将介绍一些关于 NCache 以及您可以在应用程序中使用哪些功能来优化性能。 所以, NCache 已经是一个性能解决方案。 它可以快速提高应用程序的性能,因为它减少了访问数据库的次数。 但是,通过这些功能,您实际上可以进一步改进,这六个技巧将实际基于用例。 我将与它们中的每一个一起展示一个用例,并基于适用于您的特定场景的那个,您绝对可以使用它并看看它是如何为您工作的。 所以,我们将介绍一些实际的动手操作,你知道,不同应用程序的演示,据此我们将了解在不同情况下如何 NCache 工作原理以及这些功能如何真正帮助我们。 所以,我现在将继续进行演示。

可扩展性问题

所以,首先,让我们实际谈谈在大多数部署场景中都会出现的可伸缩性问题。 所以,通常你有一个网络农场,它位于一个 负载均衡器 这种层,这种场景通常是非常可扩展的。 因为,正如您看到应用程序的负载越来越大,您基本上可以将更多服务器添加到该层,这实际上会增加您的环境容量,就它可以承受的总负载而言。例如,它可以在一秒钟内接受的总请求数。

实际问题,实际瓶颈在于这些应用程序必须与后端数据源取得联系。 也许是为了获取一些参考数据,也许是为了获取存储在那里的其他类型的数据。 所以,基本上这就是瓶颈所在。 通常后端数据源是数据库。 众所周知,数据库非常适合存储,但问题在于它们通常很慢,因为它们在磁盘上。 它们在高事务负载下往往会阻塞,并且它们的可扩展性不是很好。

解决方案

因此,在这种情况下,公司/组织倾向于走向 NoSQL database,但这不是目前的最佳方法。 因为,这需要整个架构更改,不仅在您的应用程序中,而且在您的实际数据中,以使它们彼此兼容。 因此,在这种情况下,最佳方法是内存中分布式缓存,例如 NCache,它更快,更具可扩展性,因为一切都放在内存中。 因此,如果我们将其与数据库进行比较,在这种情况下,它就存在于磁盘上。 所以,现在我们已经在内存中呈现了一切。 它更具可扩展性,因为分布式缓存在逻辑上是一个单一的单元,但在您下面有多个独立的服务器托管这个集群缓存。

这是一个非常可扩展的拓扑。 您可以在此处添加任意数量的服务器。 如您所知,它所做的是,它基本上不仅汇集了所有这些服务器的内存资源,而且汇集了所有这些资源的计算能力。 因此,当您添加更多数量的服务器时,就可以存储的总数据而言,它会增加您的缓存容量。 以及它可以采取的总操作或总负载。

因此,当您看到 Web 场中出现更多负载时,您实际上也可以增加缓存集群上的服务器数量,这实际上会使该层也具有可扩展性。 因此,现在您的缓存层与来自网络场的请求相匹配。 因此,现在它实际上有助于删除数据库中存在的不可扩展性部分。 最好的部分是,它不是数据库的替代品。 您可以与它一起使用它。 所以,它的作用是,缓存集群基本上位于您的应用程序和数据库之间。 您仍然可以直接拨打电话。 但是,它的作用是,你可以使 NCache 您唯一的数据源并使用它,我们具有此缓存提供的数据访问层功能,您实际上可以通过它,缓存实际上可以将数据写入后端数据源以及从后端获取数据数据源。

因此,使用它,您的缓存与后端数据源保持同步。 因此,您可以从更快的来源获得最新数据,因为它存在于内存中,而且它也是一个更具可扩展性的来源。 因此,在这种情况下,这是一个非常好的权衡。

NCache 部署

那么,让我们谈谈 NCache 此图中的部署。 因此,如果您可以看到,这些基本上是您托管应用程序的应用程序服务器或 Web 服务器。 他们通常坐在负载均衡器后面。 以前,他们直接调用后端数据源,例如数据库,但现在您在此处拥有缓存层。 这是我们推荐的部署,您有一个专用的缓存层来托管您的集群缓存。

NCache 部署

所以,你的应用程序在做什么,他们在做什么 NCache 数据的唯一来源。 他们所有获取数据甚至某种处理的请求都直接在缓存上完成,如果缓存没有使用这些数据访问层提供程序,它实际上可以从数据源中获取。 因此,这就是它在您的环境中所做的事情。 这些服务器,正如我之前提到的,它们被推荐为专用服务器,并且它们是非常便宜的服务器。 唯一的前提条件 NCache 在这种情况下只是 .NET framework. 在这些托管集群缓存的服务器上,您安装了缓存服务器,它具有托管集群缓存的能力,在客户端上,在这些客户端盒上,即您的应用程序服务器上,您拥有 remote client 安装,它可以托管本地缓存,它实际上可以帮助连接到远程集群缓存。

所以,这就是部署的样子。 所有这些都是线性可扩展的。 随着我们添加更多数量的服务器,增加缓存的总容量。

的三种常见用途 NCache

先说一下常用的三种用法 NCache. 我很快就完成了所有这些事情,因为我想了解这六种方法并详细了解它们,所以,如果有任何问题,我肯定可以回答这些问题。 那么,让我们来谈谈三种常见的用法 NCache.

  1. 应用程序数据缓存

    第一个是应用程序数据缓存。 所以,在这张幻灯片上,我们讨论了 NCache. 因此,第一个是应用程序数据缓存。 在这种情况下,基本上,你所做的是,你引入 NCache 您的应用程序中的 API 并使用该 API,您可以添加项目并从缓存中获取项目,您可以在缓存上执行不同的操作,它们需要的方式。 所以呢 NCache 它是否具有主机功能,基本上,您可以在其中缓存任何内容 NCache. 它可以是图像,可以是一些自定义对象、域对象、集合,基本上是任何东西。 因此,任何 .NET 允许的内容都可以缓存在 NCache 并通过介绍使用您的应用程序 NCache API,非常简单易用,非常好用,可以实际对缓存进行不同的操作,实际添加和获取项目。

  2. ASP.NET、ASP.NET Core 高速缓存

    下一个用例是关于 ASP.NET、ASP.NET Core 缓存。 所以,第一个就是,你可以使用 NCache 作为会话状态提供者。 可以是单站点或多站点。 接下来是你可以拥有 NCache 存储您的视图状态。 这是 MVC 之前的东西。 在那之后,视图状态的概念就不再存在了。 之后,对于 ASP.NET,我们有了输出缓存提供程序。 NCache 可以充当那个然后为 ASP.NET Core 应用程序它可以是核心响应缓存。 所以,你可以做到这一点 NCache. NCache 也可以作为 SignalR Backplane. 因此,刚刚在第 2 点中介绍的所有这些选项实际上都不是代码更改选项。 您不需要进行任何类型的代码更改。 您基本上可以更新您的应用程序配置文件并使用您实际拥有的配置文件 NCache 存储您想要存储的任何东西。 它可能是会话,可能是视图状态,可能是您的输出,甚至是核心响应缓存。 所以,使用它你可以拥有 NCache 存储那些东西。 所以,基本上在这种情况下,再次没有代码更改选项,非常好用。 需要几个步骤。 我们有完整的文档。 我们也有示例,按照这些步骤和文档,甚至是示例,您可以在 15 分钟内完成设置。 您可以设置所有内容。 我们实际上可以对其进行测试,看看它对您有用。

  3. 通过事件共享发布/订阅和运行时数据

    下一个是 发布/订阅通过事件共享运行时数据. 因此,基本上在这种情况下,假设您有无服务器应用程序,并且您希望确保它们之间存在某种同步,它们希望传递某些消息、某些数据。 NCache 可以用作媒介。 你可以有发布者,你可以有订阅者,他们可以发布一些消息。 注册到这些的订阅者,比方说,客户实际上可以获取那些从那些从 NCache 在这种情况下。

    因此,一个典型的例子是群聊应用程序。 也许你有群组的成员,都连接到同一个缓存,他们实际上是在一个群聊中。 其中一个成员发布了一些消息,该组的所有其他成员都会收到该数据已添加的通知。 因此,这只是一个基本示例,然后我们甚至还驱动了通知和持续查询。

所以,这些是 NCache 实际上为您提供了我们大多数客户基本上使用的东西。

NCache 建筑

让我们真正谈谈 NCache 现在的建筑。 让我们解释一下它是如何工作的? 所以,基本上 NCache 是一个 100% 的点对点架构。 没有单点故障,也没有主从或多数规则或任何类似的概念 NCache. 可以即时添加和删除服务器。 缓存不需要停止,它会继续正常工作。 即使在其中一台服务器宕机的情况下,基本上在不可预见的情况下,集群也不会整个集群都不会宕机。 它在服务器之间启动恢复逻辑以 redis致敬该数据或从其中一个备份中获取数据,并且在客户端,客户端实际上将其连接故障转移到集群中存在的其余服务器。

动态缓存集群

所以,使用这个数据实际上并没有丢失,客户端的连接实际上是,它们故障转移到其他服务器。 因此,即使其中一台服务器出现故障,他们也会继续发出请求。 因此,只要您有一台服务器启动并运行,您的请求就会得到处理。

因此,所有这些更改,所有这些配置更改服务器都被添加,在不可预见的情况下即时删除,所有这些实际上都在整个集群中传播。 因此,所有这些配置实际上都是动态的。 集群中的任何更新以及配置方面的更新都会映射到集群中存在的所有服务器,并且客户端也会自动知道它。

NCache 系统要求

缓存服务器

让我们谈谈它 NCache 系统要求。 所以,一般来说,比如说,如果你谈论核心,越多越好。 但是,一般来说,我们建议使用 8 个以上的内核。 主要的三件事 NCache 使用的是 CPU、网络资源和内存。 CPU 基本上用于处理传入的请求,或者如果有任何服务器端代码已配置为执行此类操作,这就是使用 CPU 的原因。 其次,RAM 仅用于存储,在数据存储后可能会涉及一些开销,并且网络资源用于维护通信。 例如,从服务器到服务器的通信,然后从客户端到服务器的通信。 因此,您拥有这两个选项,然后推荐的 Windows 服务器是 2012、2016。 NCache is .NET framework,否则,它在所有 Windows 环境中都受支持。

Remote Clients

就...而言 remote clients,唯一的先决条件是拥有 .NET 4.0 或更高版本,并且您的客户端实际上会受到支持。 你可以有 NCache 在那些服务器上。

设置环境

所以,既然我们已经讨论了不同的事情,基本的,你知道的,关于 NCache,让我们谈谈我们如何设置环境。 因此,每当我们有客户评估我们的产品时,我们告诉他们什么,我们都会给他们五个步骤来与之合作 NCache. 第一个是下载一个新的副本 NCache Enterprise 从网站上,第二个是安装 NCache 在你的环境中。 我有 NCache 已经安装在我的两台机器上。 它们实际上是远程盒子 demo1 和 demo2。 而且,一旦我安装在这些盒子上 NCache,我得到一个管理工具 NCache 被称为 NCache 经理. 使用这个工具,我实际上可以创建缓存、配置它们并执行不同的操作,甚至 监控 涉及本案。

通过创建缓存 NCache 经理

所以,让我们继续打开 NCache 经理在这里。 我只需要搜索 NCache 它会自动出现。 所以,一旦你打开它,这就是你得到的视图。 所以,现在我们需要做的是,我们需要创建一个新的集群缓存。 要创建它,请右键单击“Clustered Caches”,单击“Create New Clustered Cache”。

NCache 经理

所以,在这里我需要做的是我需要给它一个名字。 我将继续给它起一个名字“democache”。 所有缓存都需要命名。 只是要保持这一点。 我要点击下一步。

演示缓存

这些是由提供的四种拓扑 NCache 我将选择“分区副本”,因为它是我们所有客户中最推荐和最受欢迎的一个。 它非常可扩展,非常可靠。

分区副本

这是分区副本情况下活动分区和备份分区之间的复制策略。 我将把它保持为异步,因为它更快。

复制策略

这是我指定将托管此集群缓存的这些服务器的地方。 所以,这里我要指定demo1和demo2。 这是我拥有的两个框,107 和 108,然后单击下一步。

指定服务器

这是集群进行通信的集群端口。 它是自动拾取的。

TCP 参数

这是在每个盒子上配置的大小。 因此,总大小将是 2 Gig,一个在 server1 上,一个在 server2 上。

内存大小

这些是一些高级选项。 也许如果您的缓存已满,缓存可以自动从缓存中删除项目。 如果它是敏感数据,您实际上可以关闭驱逐,这样,这些项目不会被自己删除,然后您还可以选择在机器启动后立即自动启动缓存。 所以,我只是要点击完成,这实际上会创建我的缓存。

高级选项

所以,这就是创建缓存是多么容易。 我现在已经配置了缓存。 如果我只是左键单击缓存名称,它会在此处打开所有这些不同的选项卡,如果需要,我可以通过这些选项卡进一步进行一些更改或配置。

卖家专用后台

所以,接下来我要做的是,我要将我的个人盒子添加为 remote client. 为此,只需右键单击缓存名称,然后单击添加节点。

添加节点

而且,这里我只是要给出我个人盒子的IP,即102,现在它被添加了。

盒子IP

因此,一旦添加,我只需右键单击缓存名称并单击开始。 所以,现在缓存正在 107 和 108 盒子上启动。 一旦它启动并运行,我将打开统计数据,我还将向您展示一个监控工具 NCache 被称为 NCache 监视器,它在检查缓存中发生的基本不同的事情方面进行了非常深入的细节。 因此,缓存现在已启动并运行。 要打开统计信息,只需右键单击缓存名称并单击统计信息。

公开统计

所以,这就是它将为这两个框 107 和 108 提取所有这些统计数据。

统计报表

所以,现在让我们真正打开 的监控工具 NCache. 要打开它,请右键单击缓存名称,然后单击监控集群。

打开监控集群

NCache 监视器现在将打开,这将为我们提供两个预配置的仪表板,即服务器仪表板和报表视图仪表板。 因此,使用它,您可以很好地了解缓存中发生的事情。 如果我们在这里看到,例如,这是当前正在消耗的缓存大小,然后是每秒请求数图。 因此,它为您提供了缓存中当前正在发生的许多不同的详细信息,您可以使用这些详细信息来实际调试某些场景或在遇到任何类型的问题时查明真相。

服务器仪表板

所以,我将很快回到 NCache 经理,在这里您实际上也可以创建自己的自定义仪表板。 如果您有任何想要查看的内容而不是此处预先配置的内容,您实际上也可以这样做。 您在缓存服务器类别下和缓存客户端类别下都有控件。 您也可以创建自己的自定义仪表板,以仅查看您真正感兴趣的内容。所以,让我们回到 NCache 经理。 一切都显示为零,因为我们没有针对此缓存运行任何应用程序。

模拟压力并监控缓存统计信息

所以,实际上,让我们通过运行一个应用程序来快速测试它。 所以,我在这里打开了 PowerShell。 让我们真正清除它。 让我们真正打开一个新的。 好的,所以,我打开了一个 PowerShell。 所以,我要做的是,我将运行压力工具应用程序,将一些虚拟负载添加到我的集群缓存中,以模拟一些活动。 因此,使用该活动,我们还将通过 NCache 经理,以及通过 NCache 监视器,看看这对我们有什么作用。

所以运行那个压力测试工具。 我需要再输入一次。 让我们先杀死进程。 同时,如果您有任何问题,请随时在问题和答案选项卡中发布。 Kal,我认为我们目前没有任何问题。 好吧,完美。 某些原因它没有选择。 我回来了是的。 对不起,我只是想说,伙计们,这次会议正在录制中。 因此,无论出于何种原因,如果您无法参加完整的会议,或者您错过了最初的部分,您都可以查看此录音。 我相信我们将在本周晚些时候或下周初发布它。 因此,您将能够继续并再次完成整个会话。

所以,我现在正在做的是我实际上直接进入了那个目录,在那里打开命令提示符并运行压力测试工具。 好的,所以,让我们看看,是的,它被拾取了,我将继续为它命名压力测试工具.exe,然后是演示缓存。 所以,现在它要做的是,它将一些虚拟数据添加到缓存中。 如果我们回到这里,我们现在应该会看到这两个盒子上出现了一些活动。 它在那里。 因此,我们看到在这两个框 107 和 108 上出现了一些活动。

活动

在我们选择的拓扑中 分区副本,每个客户端都连接到集群中存在的所有服务器节点,这就是它连接到两个服务器的原因。 如果我们来到 NCache 监视器,我们可以看到有一个连接到 108 的客户端和一个连接到 107 的客户端。如果您查看 NCache 每秒请求图,我们可以看到有一些活动正在进行。

NCache 监控活动

所以,这个测试只是为了验证一切是否正确,缓存配置是否正确,一切工作正常并且已经过测试。 所以,我要停止压力测试工具应用程序。 现在,让我们回到 NCache 经理。 让我们继续并清除此缓存,因此,对于我们的进一步测试,缓存中不存在任何项目。 所以,一切都显示在 0。让我们回到演示文稿。 所以,我们的环境现在已经设置好了,一切都准备好了。 我们现在可以做的是,我们可以继续幻灯片。

NCache 技巧——性能优化

因此,让我们一一讨论我们将使用的六种优化性能的方法。 只是重申 NCache,集群缓存已经是一种性能特性,您知道,性能可以提高您在应用程序中的性能,减少您的数据库访问,然后您可以从内存中分布式缓存的更快来源中找到数据。 但是,这些功能实际上会根据您的特定用例帮助您进一步提高性能。

  • 客户端缓存

    所以,我们要讨论的第一个是 客户端缓存. 它的作用是,它基本上减少了您访问实际集群缓存的次数。

  • 批量调用

    然后我们将讨论批量调用,它减少了对缓存的访问,这样您只执行一个操作,并且只使用一个调用,多个操作作为回报将在服务器端进行处理。

  • 压缩

    那你也有 压片. 也许如果您的对象大小更大,您可以使用它来减小正在添加或获取的对象的整体大小。 通常,我们建议将对象分解成更小的尺寸,但在不可能的情况下,您可以使用压缩功能。

  • 异步更新

    我们也有异步更新。 因此,使用这些,您的应用程序基本上不会等待执行操作。 也许您可以为此创建一个单独的任务,然后在此基础上您可以负担得起数据自行添加,如果您想要返回任何类型的更新,也许数据是否已添加或是否添加是一个问题,您可以针对该问题注册回调。

  • 紧凑序列化

    下一个是 紧凑序列化. 因此,例如,如果您有自定义对象、域对象,它们没有被标记为可序列化并且在分布式缓存中,因为它完全不在进程中,所有对象都需要被序列化。 因此,如果您在这种情况下无法承受环境中的代码更改,但您还需要使您的自定义对象或域对象可序列化,您可以使用紧凑的序列化功能 NCache 将它们全部标记为可序列化,然后使用您实际上可以继续使用 NCache 在你的环境中。 这是一个无代码更改选项。 只是你可以从 GUI 中计算出来的东西,你已经设置好了。

  • 双网卡

    最后我们有了 双网卡 特征。 因此,如果您想基本上分离从客户端到服务器通信和服务器到服务器通信的流量,分离网络资源,您实际上可以这样做 NCache. 这仅在您拥有、您知道、您的网络资源实际上被传入的过多流量阻塞的情况下。只有在这些情况下,我们才会建议这样做。 但是,如果您当时没有看到这些资源被用尽,您实际上可以为这两种通信保留相同的网络接口卡。

演示

因此,让我们实际执行我们的第一个测试,其中我们将向缓存中添加项目并从缓存中获取项目,我们将使用它作为我们拥有的基本 API 的基线。 同样,它已经过优化,但我们将使用它作为基准,并在其之上执行不同的功能,看看它们如何为我们工作。

所以,第一个,让我们回到这个示例。 因此,这是一个示例,我实际上也可以提供此代码。 这就是我们将用来向您展示我们将要涵盖的基线的内容。 因此,我们在测试 1 中。在测试 1 中,我们基本上将 5,000 个项目添加到大小为 100 KB 的缓存中,然后我们将从缓存中获取这些项目。 这个测试只会让我们知道整个代码所花费的时间,这个获取部分将会花费。 在这个获取部分,循环实际上运行了 5000 次,因为需要获取 5000 个项目,在后面的幻灯片中,我们将介绍不同的特性如何在这种情况下实际提供帮助。

...
try
    {
        cache = NCache.InitializeCache(args[0]);
        cache.Clear();

        Console.WriteLine("TEST 1\n");
        Console.WriteLine("Press anything to add " + objectsCount + " items (100kb Object)");
        Console.ReadKey();
        Console.WriteLine("Adding items now");

        for (int i = 0; i < objectsCount; i++)
            {
                cache.Insert(key + i, obj1);
            }

        Console.WriteLine(objectsCount + " items added. Press any key to retrieve them.");
        Console.ReadKey();
        Console.WriteLine("\nRetrieving " + objectsCount + " items now");
        datetime1 = DateTime.Now;
        ...

所以,让我们实际运行它。 让我们首先验证一切设置是否正确。 是的,democache 测试 1,我将运行它。 所以,这又是第一个测试,只是为了获得数字看起来如何的基线。 我要按 Enter 键。 它将开始将项目添加到缓存中。 如果我们回到 NCache 经理,就在这里,我们看到有一些活动正在进行。 因此,它将项目添加到缓存中。 由于副本拓扑分区中有两台服务器,因此数据正在添加到这两台服务器上,正在添加到服务器 1 上(即 107)和服务器 2 上。因此,数据将被分割。 缓存中的所有项目总数将达到 5,000 个。

因此,在这种情况下,让我们实际等待它完成,一旦完成,我们实际上可以记下该数字并将其用于我们将要测试的后续功能的比较。 几乎完成了,我们已经添加了大约 4,000 多个项目。

添加的项目

请记住,它是一个 100 KB 的对象,对于测试来说这是一个相当大的大小,但这只是为了向您展示不同事物的外观。 我觉得都是加的,是的,都是加的。 柜台实际上已经停止了。 如果我们单击 Enter,它会花费,如果我们单击 Enter,它将开始从缓存中检索这些项目,如果您回到这里,它将显示时间。 因此,我们可以看到每秒获取的次数实际上在上升,并且这两个服务器的每秒请求数也在上升。 因此,这实际上向您展示了开始从缓存中获取这些项目的一些活动。 一旦完成从缓存中获取所有 5000 个项目,它将在屏幕上显示计时器,并使用该计时器将其设置为我们即将进行的测试的基线。

客户端缓存(靠近缓存)

所以,让我们真正谈谈下一个。 下一个,我们将要使用的第一个实际功能是客户端缓存。 那么,让我解释一下什么是客户端缓存? 客户端缓存基本上是本地缓存,存在于客户端和这些客户端上,它的作用是减少您访问集群缓存的次数。 客户端缓存是集群缓存数据的子集。 它将与自己的集群缓存数据保持本地副本。 它与集群缓存保持同步。

客户端缓存

因此,在客户端缓存上执行的任何更新都会传播到集群缓存,反之亦然。 因此,它会随着集群缓存保持更新,如果您的应用程序试图从缓存中获取一些项目,它会提供,如果它确实在此处本地存在这些项目,它只是共享该数据或这些项目那里然后从本地来源。

让我们真正跳回到这一点。 好的,完成此操作大约需要 45 秒。 因此,一旦我们使用客户端缓存,我们实际上可以看到它在该场景中的影响。 我要点击 Enter。 我们要记住这一点,这个数字是 45 秒。

是时候做手术了

所以,我们已经在讨论客户端缓存了。 所以,正如我之前提到的,基本上你有两个选择。 您可以将客户端缓存作为 InProc 或 OutProc 运行,这是您可以想象的。 在 OutProc 的情况下,将运行一个单独的进程,该进程将保持不变,它将与集群缓存保持同步。

当您有一个网络花园场景时,通常建议使用 OutProc 流程,其中您有多个应用程序或应用程序的多个实例在同一个盒子上运行。 因此,他们将有一个共同的资源来处理,即客户端缓存,一个正在运行的单独进程。 第二个选项是 InProc 缓存,如果您有 Web 农场场景(通常在同一个盒子上运行一个或两个应用程序),建议您使用该缓存。

在一种情况下,发生的情况是客户端缓存驻留在应用程序进程中。 因此,在这种情况下,由于它是同一过程的一部分,因此实际上消除了许多开销。 在这种情况下,序列化开销,进程间通信开销,所有这些实际上都被移除了,它们大大提高了性能。

在 OutProc 的情况下,您正在缓存的是应用程序从本地源获取该数据,这些数据与同一个框存在。 因此,实际上减少了一次网络旅行。 因此,这大大提高了性能,我们现在实际上可以看到这一点。

所以,在这个我们要做的是,我们将创建一个客户端缓存,首先作为 OutProc,然后作为 InProc,我们将看到数字的样子。 在当前场景中,如果您记得正常获取需要 45 秒。

Kal,我在这里有一个问题,问题是我们正在谈论的所有功能都是同一产品的一部分吗? 所以,我猜他们在谈论版本。

是的,其中一些仅在企业中可用,但我可以分享 版本比较 文档实际上涵盖了所有这些细节的每一个细节。 所以,也许这实际上会让你得到你正在寻找的确切细节。

而且,我会借此机会问其他人现在有什么问题吗? 不,我们没有任何问题,所以,请继续讨论。

Out-Proc 客户端缓存

所以,我将继续清除缓存的内容。 他们现在完成了。 所以,现在我要继续创建一个客户端缓存。 所以,在 NCache 经理,你的客户端缓存就写在这里。 只需右键单击此处,然后单击创建新的客户端缓存。 所以,在这里,我将保持名称不变。 它设置为客户端缓存。 保持一切默认。 接下来,它现在设置为 OutProc,但我们稍后会将其更改为 InProc。 单击下一步。 它设置为一个 Gig 的大小。 我会保持它。 实际上,我可以将其更改为我想要的任何一个,以及在我们创建集群缓存时也存在的一些进一步的高级设置。 所以,现在客户端缓存其实是在我的个人盒子上配置的,也就是102。

创建客户端缓存

验证这一点的一种快速方法是在我安装后运行列表缓存工具,该工具出现在我的个人框中 NCache 并使用该工具实际上让我知道哪个 NCaches 正在我的个人盒子上运行。 所以,如果我来到这里,让我们实际运行列表缓存。 好的,它正在显示我个人盒子上存在的缓存,即 102。我认为在后面,它仍然出于某种原因尝试启用它。 是的,它似乎在那里启用。 所以,如果你来到这里我们可以看到客户端缓存。 所以,客户端缓存是一个本地缓存,它正在运行。 所以,它现在正在我的个人盒子上运行,我们现在可以实际使用它了。

列出运行缓存

所以,在我真正开始之前,那么,什么 NCache 确实是,它发布了这些计数器,这些计数器现在甚至显示在屏幕上。 因此,可以通过 Windows 性能监视器查看它们。 我要做的是,我将打开 Windows 性能监视器并打开我将要使用的客户端缓存的计数器。

所以,我要,从我的个人盒子里,我要在这里搜索一个性能监控的 PerfMon,使用它我要做的是,我要打开 NCache 类别并查找我作为客户端缓存的特定缓存并为这些缓存打开计数器。 所以,它现在打开了,我要打开一个全新的性能监视器,寻找类别 NCache. 它在那里,在这里我有客户端缓存。 我将单击添加,然后单击确定。 我要将视图更改为报告视图。 所以,现在,这些是计数器。 现在显示的所有内容都是 0,因为它没有被使用。 这是一个正在运行的单独进程,因为我们已将其设置为 OutProc。

让我们看看这些数字现在的样子,来自我的个人盒子。 我将运行应用程序,相同的代码,我不会做任何类型的代码更改。 客户端缓存功能无需代码更改,正如我之前提到的,您只需启用或禁用它,无论您喜欢哪个,它都会自动被拾取。 因此,如果我单击开始按钮,相同的代码,相同的所有内容,甚至相同的测试,一旦我单击“Enter”,它将开始添加这些项目。 好的,所以,一旦我点击进入,它就开始添加这些项目。 如果你回到 NCache 管理器,我们看到在集群缓存上正在添加项目。 如果你打开 NCache 监视器,就是这个,是的,这个,我们看到这里也有一些活动,这就是我最初解释的内容。 当您配置了客户端缓存时,它会使用,当您将项目添加到缓存中时,客户端缓存也会获得一份副本,而集群缓存也会获得一份副本。

性能监视器

如果您有 80% 到 20% 的读写比率,甚至 70% 到 30% 的读写比率,通常建议使用此用例。 这通常建议在您有大量读取的情况下,可能是您环境中的静态数据中的一些参考数据,并且当您启用客户端缓存时,您会看到很大的性能改进。

因此,请记住,第一个仅使用 get API 循环运行的测试,我们有 45 秒的时间从缓存中获取这些项目。 但是,现在使用这个客户端缓存,它会在本地源中找到所有数据,在一个单独的进程中运行在同一个盒子上,我们将看看它是如何为我们工作的。 所以,如果我们在这里向下滚动,我们可以看到这是客户端缓存的计数。 这个计数必须达到 5,000,因为它是单一来源。 因此,所有 5,000 个项目都将出现在集群中,并且它们将分布在所有服务器节点中。 所以,我们只是在等待这些项目增加到 5,000,然后我们将运行测试的第二部分,即从集群缓存中获取这些项目。

所以,要注意的另一件事是,一旦我们从缓存中获取项目,调用将不会进入集群缓存,它们都会被当前本地的客户端缓存拦截,这就是我要展示的内容你来自这些柜台,就在这里。 因此,这些计数器显示的是客户端缓存计数器,但如果您这样做,这些计数器显示的是集群缓存的服务器端计数器。 让我们点击 enter here,它将开始从缓存中检索这些项目。 因此,再次向您展示这里没有移动卡。 所以,这里没有电话。 如果你打开这个,我们可以看到这个活动在这里进行。 正在进行某些提取。 因此,客户端缓存现在被大量使用,这就是在读取多于写入的情况下拥有客户端缓存的全部意义所在。 因此,几秒钟后,我们应该在此处看到显示客户端缓存场景中大小为 5,000 KB 的 100 个项目需要多长时间的结果。 因此,在这里您可以看到,在您的环境中启用了 OutProc 客户端缓存的情况下,它已经从 45 秒下降到 33 秒。

时间减少

所以,你可以看到这是一个很大的进步。 您可以看到超过 10 秒的时间,就应用程序而言,这是一个很长的时间。 因此,它向我们展示了在这种情况下的巨大改进。

进程内客户端缓存

所以,我现在要继续创建一个 In-Proc 客户端缓存,并使用该 InProc 客户端缓存,我们将看看它对我们的执行情况,而实际测试需要 45 秒,而实际测试需要 33 秒客户端缓存 OutProc 测试。 所以,首先我要继续删除这个缓存。 现在它被删除了。 我将创建一个新的缓存。 同样,我将在其旁边键入 InProc,然后单击下一步,并将隔离级别保持为 InProc,保持所有默认值,然后单击完成。 所以,现在这是在我的个人盒子上创建的,我将运行完全相同的测试。 其实,我们先清除缓存中的数据。

所以,现在相同的测试,相同的论点,我刚刚开始。 所以,现在它将再次执行完全相同的测试。 5000 个项目放入大小为 100 KB 的缓存中,然后它将使用客户端 InProc 客户端缓存获取这些项目。 这个概念仍然完全相同。 一旦您的应用程序将项目添加到缓存中,您还将将其添加到存在于同一进程中的客户端缓存中,因为我们现在将其作为 In Proc 运行。 因此,它也将这些项目添加到客户端缓存中,并且还添加到集群缓存中。 所以,一旦它是,我现在要点击进入。 因此,一旦它获取这些项目,它将在本地找到所有这些项目,在同一个过程中。

因此,现在不涉及任何开销,例如进程间通信和序列化、反序列化,所有这些现在都被完全删除了。 它会直接从那里获取数据,然后从本地源获取数据,我们将看到客户端缓存在这种特定场景下使用 InProc 模式的实际性能有多大。 因此,只需等待添加项目。 如果我们回到这里,我们应该会看到一些计数器上下波动。 我们绝对可以看到。

缓存统计

所以,与此同时,如果有任何问题,请让我知道。 Sam 一直在关注问题停靠栏选项卡。 如果有任何问题,他会通知我。

因此,正如我前面提到的列表中的下一件事将是批量操作。 因此,我们将只使用一个单独的测试,即使用批量 API。 但是,不同事物的不同概念与批量操作的执行方式完全相同,我们将在本演示文稿中从理论上涵盖所有这些内容。 让我们实际看看添加了多少项。 因此,已经添加了大约 3000 多个项目。 所以,我们只是在等待完整的 5000 标记到达,然后我们将看看它是如何工作的。 好吧,坚持第一个。 所以,我只是在等待后面执行的操作。 同时,我在这里只讨论批量操作的第一件事。

因此,批量操作的核心概念只是限制您实际进入集群缓存的调用量。 因此,我们实际上可以将这些非常相同的调用作为单个操作的一部分来执行,而不是像我们已经做过的那样在循环中执行所有这些事情。 因此,可以将单个操作发送到集群缓存,然后针对该缓存执行多个操作。 因此,如果您在批量共享的情况下,您需要知道密钥。 因此,例如,您只需提供键和要添加的实际对象,只需一次调用并使用所有这些项目将实际添加到后面的集群缓存中。

所以,我认为他们应该完成,是的,他们现在几乎完成了。 如果我们回到这里,那么,所有这些项目现在都被添加了。 我要点击回车,我们可以看到所有这些项目现在都被检索到了。 看到这一点非常令人惊讶,因为现在消除了很多间接费用。 所以,速度非常快。 因此,如果我们重申我们所做的初始测试,基本测试需要 45 秒,客户端缓存 OutProc 需要大约 33 秒。 但是,在 InProc 客户端缓存的情况下,在这种情况下,所有这些时间都下降到了 0.1 秒。

时间减少

因此,如果您的用例映射到我们在此处进行的用例,那么您可以通过 InProc 客户端缓存看到多少改进。 因此,这是一个很大的改进,您可以看到是否有更多的读取和更多的写入正在进行。

所以,我只是要点击进入。 所以,这就接近了。 我将在此处删除此客户端缓存,并且实际上也已清除。 好的,那么,让我们回到演示文稿。 所以,在这里,所以,我们谈论的是批量操作。

批量获取(基于密钥)

所以,在批量操作的情况下,第一个是一旦你添加,如果你有很多想要添加甚至从缓存中获取的项目,你只需要相应地提供列表和只需一次调用,您就可以在缓存上执行所有这些操作。 所以,一般来说,如果您有更大的对象大小,我们建议将其分解为多个对象,然后使用 NCache 提供对它们进行实际分组,甚至获取它们或将它们添加到缓存中。 因此,可以在这些场景中使用批量 API。 第二个是,例如,如果您不知道这些项目的键,因为批量是基于键的操作,所以,您需要知道所有键。

SQL/LINQ 搜索查询

在 SQL 或 LINQ 类型的搜索查询中,基本上如果您不知道键,您实际上可以根据特定条件进行搜索。 例如,如果您在缓存中添加了产品,您实际上可以根据特定条件从缓存中获取多个产品。 所以,比方说,我用名字运行一个查询 '选择产品 where product.price > 10 AND product.price < 100'. 因此,实际上满足该特定标准并存在于缓存中的所有产品实际上都将返回给我。 所以,在这种情况下,我没有指定任何键,我只是指定了条件,它们被返回给我。

组和子组

下一个是您是否可以在缓存中创建逻辑集合。 我将一起介绍它们,作为组、子组,然后是标签。 所以,你可以这样做。 因此,例如,如果您将客户及其订单放在缓存中,您实际上可以将所有订单组合在一起。 由于缓存中有单独的项目,您实际上也可以保留集合,但我们建议将其分解,因为通常一旦您从缓存中获取项目,您就不需要完整的对象,您需要针对它的特定值。 因此,如果将其分解为多个对象,则可以更有效地使用它。 因此,使用这些逻辑集合功能,您基本上可以对缓存中的项目进行分组。 因此,可以将某个客户的所有订单组合在一起,并且只需一次调用。 假设在组中,您可以按组获取,或者在标签的情况下按标签获取,只需提供客户 ID,缓存中存在的所有这些关联项目实际上都会返回给您。 同样,在这种情况下,您不需要知道键,您只需要知道作为组或标签的特定字符串值,并基于它返回给您,然后它还支持并行查询。

批量操作 - 演示

所以,让我们来看看实际的批量操作示例。 所以,如果你回到这个测试,就在这里。 这是批量测试,即测试 2,我们将实际运行它。 让我们先真正开始它,然后我们可以详细了解它在做什么。 所以,我现在刚刚将其更改为测试 2,并且我已经启动了它。 所以,这个测试所做的基本上是现在将 10,000 个大小为 10 KB 的项目添加到缓存中。 首先,它只是将这些项目添加到缓存中的基本插入,然后它正在获取所有这些项目,它实际上也在记录添加时间和获取部分。

Console.WriteLine("TEST 2\n");
Console.WriteLine("Press anything to add " + objectsCountBulk + " items (10kb Object)");
Console.ReadKey();
Console.WriteLine("Adding items now");
datetime1 = DateTime.Now;
for (int i = 0; i < objectsCountBulk; i++)
{
    cache.Insert(key + i, obj2);
}
datetime2 = DateTime.Now;
Console.WriteLine(objectsCountBulk + " items added. Time to add " + objectsCountBulk + " items in a loop: " + (datetime2 - datetime1).TotalSeconds);
Console.WriteLine("\nPress any key to retrieve them.");
Console.ReadKey();

因此,一旦完成,我们将获得将 10,000 个大小为 10 KB 的项目添加到缓存中所需的时间基线,然后它开始批量操作。 在那些批量操作中,它将所有这 10,000 个项目添加到缓存中,只是同一个调用,并且只通过一个调用以及预定义的键列表和对象列表再次获取。

好的,我要点击进入。 它将开始将这些项目添加到缓存中。 如果我们回到 NCache 经理,我们看到这里有一些活动。 这些项目现在被添加到当前存在的这两个服务器中。

批量操作活动

即使您查看监视器集群,我们也可以看到这里连接了一个客户端,那里连接了一个客户端,然后我们看到这些图表中正在进行一些活动。 因此,使用它,您实际上可以很好地了解缓存中发生的事情、正在使用的内容、此时未使用的内容以及正在使用的内容。 它几乎完成了所有 10,000 个项目,我想现在添加。 是的,我将按 Enter 键检索这 10,000 个项目。 因此,首先,将这些项目添加到缓存中大约需要 37 秒。 现在,它正在做的是从缓存中读取这 10,000 个项目。 因此,如果您看到,在这里我们可以看到这两个服务器节点上每秒都有一些获取。 因此,目前正在提取这些项目。 所以,它现在正在循环中获取。 请记住,一旦它完成将开始批量测试。 因此,基于该批量测试,我们将比较这两个数字并查看它们的实际影响。 因此,在这里检索这 30 个项目大约需要 10,000 秒,并且批量 API 实际上已经完成了添加,并且应该很快完成获取部分,我认为,哦,是的,需要按 ENTER。 好的,让我们真正等待它完成,然后我可以向您展示所有这些东西的样子。 所以,现在它已经完成了。 因此,为了完成这个测试,它使用循环将 10,000 个大小为 10 KB 的项目添加到缓存中,并且花费了大约 37 秒。 检索这 10,000 个项目大约需要 30 秒,再次循环。 通过批量测试,它将这 10,000 个项目添加到缓存中,大约需要 5 秒。

批量测试完成

所以,这是 37 秒和 5 秒之间的一个很大的差距,并且要在缓存中获取这些项目大约需要 6 秒。 因此,6 秒和 30 秒之间又有很大的不同。 因此,这就是批量操作实际上可以为您和您的应用程序带来多少改进,并且使用它您不需要一次又一次地运行相同的调用。 您无需每次都访问集群缓存。 您基本上可以收集所有需要执行的操作,使用批量 API,您可以将它们添加到缓存中。

压缩 - 演示

所以,现在我们的批量测试实际上已经完成了。 所以,回到演示文稿。 所以,下一个是压缩测试。 同样,正如我之前提到的,我们通常建议将对象分解为更小的尺寸,但如果您没有该选项可用,您可以做的是实际压缩,您实际上可以设置某个阈值。 任何大于该值的对象都不会被压缩到更小的尺寸。 让我们现在在我们的环境中启用压缩。 所以,首先,让我们继续清除缓存。 完成。 压缩是可以即时完成的。 因此,不需要停止缓存。 因此,如果我左键单击缓存名称,它将打开所有这些不同的配置。 如果我去这里并在这里打开选项,我需要做的就是单击此启用压缩。 我将其设置为 50 KB。 因此,任何大于 50 KB 的内容都将被压缩。 右键单击缓存名称,然后单击应用配置。 所有这些配置现在都将应用于集群。 因此,任何大于该值的对象实际上都会被压缩。

应用压缩

所以,我将运行我们最初所做的相同测试,即测试 1。将其更改回测试 1,保存它,然后我将按下运行(开始)。 让我们等待它开始,然后我将详细介绍压缩在不同场景中的实际帮助。 因此,压缩是如何工作的,一旦客户端将这些项目发送到缓存,它就会将它们作为压缩发送。 因此,压缩的帮助在于,一旦项目通过网络传输,它的大小就会更小,一旦它停留在集群缓存中,它占用的位置也会更少。

Kal,只是想提醒你一下,我们还有 10 分钟的时间结束会议,所以,请相应地调整自己的节奏。 好的好的,谢谢。 此时有什么问题吗? 不,似乎每个人都很好。 实际上,我们有两个确认,到目前为止一切都很好,所以,我们很好。 好吧,完美。 谢谢你。

好的,所以,我在谈论压缩它是如何帮助的。 因此,在有两件事的情况下,较小尺寸对象的整个网络传输显然比较大尺寸的对象要快,一旦将该对象放入缓存中,单击 Enter 开始检索这些项目. 因此,一旦将其放入缓存中,它实际上也会更小。 因此,它消耗的空间更少。 处理此项目所需的总时间也减少了。 因此,这就是压缩在您的场景中的帮助方式。 添加时客户端会产生开销。 但是,我们现在将注意到的整体净改进实际上比这更大。 因此,您知道,在这些项目上找到整个操作所花费的整个时间实际上会快得多。 因此,使用压缩完成测试 1 大约需要 26 秒。

压缩结果

如果您最初还记得,在我们的第一次测试中,没有任何特殊功能,仅涉及基本 API,我相信 45 秒。 因此,45 秒和 26 秒之间存在很大差异。 所以,这就是压缩实际上有多大帮助,如果这些操作进一步扩展,在这种情况下会有更大的差异。 因此,在这种情况下,这很有帮助。

异步操作 - 演示

所以,让我们真正进入下一个场景,即异步更新。 异步更新基本上是您的应用程序不等待。 您可以为其设置一个单独的任务,该任务将执行这些操作。 您可以设置回调以仅获取项目是否已添加或未针对任何情况添加的信息。 您实际上也可以设置它。 我现在要快速查看样品,我认为它是第 3 次测试,但我可以很快确认。 好的,这是异步更新的第 3 次测试。 让我们真正开始它,然后我们可以查看代码的细节。 一旦我可以控制回来,我将打开代码文件,并实际向您展示测试号 3 中发生的异步更新。 现在开始了。 所以,在异步更新中,也就是测试号 3,发生的事情是它首先使用基本的插入调用将项目添加到缓存中,然后一旦完成添加这些项目,它基本上会在一部分中再次删除它们环形。 因此,每个键都在一次迭代中被删除。

...
else if (args[1].Equals("test3"))//ASYNC API TEST
{
    Console.WriteLine("TEST 3\n");
    Console.WriteLine("Press anything to add " + objectsCount + " items normally (100kb Object)");
    Console.ReadKey();
    Console.WriteLine("Adding items now");

    try
    {
        cache = NCache.InitializeCache(args[0]);
        datetime1 = DateTime.Now;
        for (int i = 0; i < objectsCount; i++)
        {
            cache.Insert(key + i, obj1);
            //cache.InsertAsync(key + i, obj1, OnItemAdded, "", "");
        }
...

我要点击 Enter。 它将 5,000 个项目添加到大小为 100 KB 的缓存中,并且正常执行此操作。 通常在这里,我的意思是一个简单的插入,然后在循环的一部分中再次删除这些项目。 因此,使用它我们将看到这部分需要多少时间,然后我们将使用异步调用进行添加、异步插入,然后删除它们。 在添加这些项目时,让我们实际跳回去看看它们的样子。 所以,在这种情况下,它只是做一个基本的移除,移除这些项目。 在异步测试部分,它正在做的是插入异步调用。 因此,客户端不等待,只是将操作传递到队列中。 队列并不意味着它将是一个缓慢的过程,客户端不会等待它,它作为一个漂亮的,你知道的,作为一个后台进程完成,但它完成得非常快。 因为,缓存中的很多操作实际上都是以异步方式完成的。

...
datetime2 = DateTime.Now;
Console.WriteLine("Time to remove " + objectsCount + " objects normally: " + (datetime2 - datetime1).TotalSeconds);
Console.WriteLine("\nAdding items using Async API now");
datetime1 = DateTime.Now;

for (int i = 0; i < objectsCount; i++)
{
    //cache.Insert(key + i, obj1);
    cache.InsertAsync(key + i, obj1, OnItemAdded, "","");
}
datetime2 = DateTime.Now;
Console.WriteLine("Time to add " + objectsCount + " objects with Async API: " + (datetime2 - datetime1).TotalSeconds);
Console.WriteLine("\nRemoving " + objectsCount + " items with Async API now");
...

让我给你举个例子。 因此,例如,如果谈到复制,如果您还记得在缓存创建过程中我们将其设置为异步。 因此,使用它基本上很多都是作为后台进程完成的。 他们非常可靠。 只是你的应用,主进程,主任务不受它的影响。 因此,它将这些项目添加到缓存中大约需要 49 秒才能将这些项目添加到缓存中。 现在,它实际上是删除了这 5,000 个项目。 现在,一旦完成,我们将看看异步调用是如何进行的。 因此,它必须移动 5,000 件物品。 花了大约 25 秒来删除这些项目,现在它正在通过异步调用添加项目,我们将看看我们在 49 秒和我们现在将获得的数字之间有多少差异。重新将项目添加到缓存中。 它在那里。 因此,在添加部分从 49 秒下降到 28 秒,在删除这些项目的情况下,它从 25 秒下降到 1.6 秒。 所以,这就是一旦你参与其中,我们可以实际看到的性能。 所以,你可以看到有很大的不同。 从基本删除调用中删除项目和从删除异步调用中删除项目之间大约有 25 秒的差异。 因此,您可以从 NCache.

异步 API

双网卡 - 演示

让我们回到演示文稿。 我们已经介绍了异步,下一个是紧凑序列化。 所以,再一次,这只是在那些你没有奢侈在代码中进行更新的场景中涵盖的,使用它你实际上可以将所有这些类标记为可序列化的。 Kal 说完这个评论,我们还有大约 3 分钟的时间,所以……对,对。 我只是要快速掩盖它。 所以,剩下的最后两件事是,一个是紧凑序列化,然后是我们有双 NIC 功能。 所以,正如我之前提到的,如果你看到你的网络资源被用尽了,默认情况下,服务器到服务器的通信和客户端到服务器的通信都发生在同一个网络接口卡上。 但是,如果你看到你的网络资源被用光了,你可以做的是,你可以分离出客户端到服务器之间的通信,然后从服务器到服务器的通信。 这是一个非常简单的任务 NCache 经理。 如果你来这里,要选择它,只需右键单击此处,然后单击选择 NIC。

配置网卡

选择 NIC 后,您实际上可以指定要在此特定 IP 上进行的通信。 因为,我只有一个,所以我有这些选项可用。 如果我有多个 IP,我实际上可以在那里选择它。 所以,我只是要点击取消。

选择网卡

由于时间紧迫,我们没有机会进行紧凑的序列化演示,但我实际上可以与你们分享这个示例,您可以对其进行测试,看看它如何适合您。 山姆交给你。 完美的。 好吧,非常感谢您抽出时间 Kal。

在我们结束今天的会议之前有什么问题吗? 我只想花一点时间看看是否有任何问题。 好的,所以,有一个问题。

您能否分享您将要分享此演示文稿的链接? 所以,Kal,我想它可以在我们的网站上找到,对吧?

是的,它将可用,我在下面记下了他们的电子邮件。 所以,我能做的是,我可以在上传后立即向他们发送电子邮件。 行。 实际上,我们还有一个问题。

我们可以安排一个演示文稿,好的,那么,我们可以为我们的团队安排一个演示吗?

是的,一点没错。 您当然可以安排演示。 您可以联系我们的支持团队 support@alachisoft.com 或我们的销售团队 sales@alachisoft.com 只需让我们知道您的时间偏好,我们将非常乐意为您安排个性化的会议。

好的,Kal,所以我要继续完成这个。 我想我们没有更多的问题了。 感谢大家参加今天的会议,我们对此表示感谢。 就像我说的,如果您有任何问题,请联系我们的支持团队,或者对于与销售相关的问题,请联系我们的销售团队。 我们会在这里提供帮助。 随时给我们打电话。 您也可以通过电话直接联系我们。 它在我们的网站上。 直到下一次,非常感谢你,晚上好,再见。

接下来做什么?

 

联系我们

联系电话
©版权所有 Alachisoft 2002 - 版权所有。 NCache 是 Diyatech Corp. 的注册商标。