服务器端缓存CPU密集型web应用程序的ajax请求


server side caching of ajax requests for CPU intensive web app

我有一个相当占用CPU的web应用程序(它基本上是字典的集合,但它们不仅仅是简单的字典,它们做了很多事情,无论如何这并不重要)。因此,在一个CPU密集型的网络应用程序中,你会遇到缩放问题,同时使用的用户太多,响应速度也很慢。

我的应用程序的流程是:

js->ajax调用->php->vb6-dll->vb6代码查询字典并做CPU密集型的工作->reply-to-php->reply-to js->html-div用新内容更新。显然是在带有IIS 7.5的windows环境中。PHP只是访问.dll的一种方式,不做任何其他事情。

回复/显示的内容是html格式的文本。该应用程序有许多php文件,这些文件在.dll.中调用不同的函数

因此,为了避免每次请求都调用vb6 dll,这是CPU密集型的部分,我考虑这样做:

ajax请求示例:

php file: displayconjugationofword.php
parameter: word=lol&tense=2&voice=active

因此,当用户发出上面的请求来显示conditionofword.php时,我调用vb6 dll,然后在向客户端返回回复之前,我可以在MYSQL表中添加这样的请求数据:

filename, request, content
displayconjugationofword.php, word=blahblah&tense=2&voice=active, blahblahblah

因此,下次用户发出EXACT相同的ajax请求时,displayconjunctionofword.php代码不会调用vb6 dll,而是首先检查mysql表,看看那里是否存在请求,如果存在,则从那里获取请求。

因此,这个mysql表的大小将逐渐增加,达到300-400万行,随着请求在数据库中的可能性的增加,它也会增加,理论上应该比执行cpu密集型调用更快(每个调用的长度从50到750ms不等)。

你认为这是实现我想要的东西的好方法吗?或者当mysql表达到300-400万个条目时,它也会很慢?

提前感谢您的意见。

编辑

我知道iis输出缓存,但我认为它对我的情况没有用处,因为:

1) AFAIK它只在.php文件变为"热"(许多查询)时缓存该文件。

2) 我确实有一些php文件调用vb6,但每次的回复都是随机的。

我喜欢这些情况/谜题!以下是我首先要问的问题,以确定哪些选项是可行的:

  1. 你知道/知道在一个给定的小时、一天、一周内会重复多少这样的查询吗?因为"更常见的缓存技术"(即我见过和/或读过最多的技术)是使用类似APC的东西,或者为了可扩展性,使用类似Memcache的东西。然而,我所看到的是,这些通常用于<12小时长的缓存。这正是我所看到的。优点:自动清理未使用的项目。

  2. 你能估计一下一项"任务"可能需要多长时间吗?因为这将让您知道缓存是否/何时变得无效,也就是说,缓存机制何时比任务慢。

以下是我提出的解决方案——全部使用PHP(毫不奇怪)。在您的工作流程中,这将是两个PHP点:js->ajax调用->PHP->vb6 dll->vb6代码查询字典并做CPU密集型的事情->回复PHP->回复js->htmldiv…

类似这样的东西:

  1. 创建一个包含列的表:__id、键、输出、计数、修改的

    1.1.列'__id'是自动递增列(例如INT(11) AUTO_INCREMENT),因此也是PRIMARY INDEX

    1.2"modified"列在MySQL中是这样创建的:modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

    1.3'key'=CHAR(32),它是MD5散列的字符串长度。'key'还有一个UNIQUE INDEX(非常重要!!对于下面的3.3)

    1.4"输出"=TEXT,因为VB6代码将不仅仅是一个小

    1.5‘计数’=INT(8)左右

  2. 散列查询字符串("word=blashblah&时态=2&voice=active")。我想的是:$key = md5(var_export($_GET, TRUE));基本上,散列任何会给出唯一输出的东西。从给出的例子中推断,如果大小写无关紧要,也许最好将"单词"小写。

  3. 对键的SELECT结果运行条件。在伪代码中:

    3.1.$result=SELECT output, count FROM my_cache_table_name WHERE key = "$key"

    3.2.if(空($result)){
     nbsp nbsp nbsp$output=运行VB6任务的结果
     nbsp nbsp nbsp$count=1
     nbsp 其他
     nbsp nbsp nbsp$count=$result['count']+1

    3.3.运行查询'INSERT INTO my_cache_table_name (key, output, count) VALUES ($key, $output, $count) ON DUPLICATE KEY UPDATE count = $count'

    3.4.返回$output作为"回复js"

从长远来看,您不仅会有一个缓存,而且还知道哪些查询运行最少,并可以在需要时对其进行修剪。就我个人而言,我认为这样的查询永远不会那么耗时。当然,您可以做一些事情来优化缓存/查询(这超出了我的能力范围)。

所以我没有直接说明的是:上面的内容会起作用(这几乎是你的建议)。通过添加"count"列,您将能够看到哪些查询做了很多和/或一点,如果需要,可以返回并进行修剪。

如果您想查看查询需要多长时间,可以创建另一个包含"key"、"duration"answers"modified"的表(如上所述)。在3.1和3.3之前,获取microtime()。如果这是一个缓存命中,减去microtime()并存储在这个新表中,其中"key"=$key,"duration"=第二个microtime(。然后,您可以稍后返回,按照"修改的DESC"进行排序,并查看查询需要多长时间。如果你有一吨数据,但最新的"持续时间"还不错,你可以提取整个持续时间记录机制。或者,如果无聊,只存储$key以字母结尾的持续时间(只是为了减少服务器上的负载)

我不是专家,但这是一个有趣的逻辑问题。希望我在下面列出的内容能有所帮助,或者至少能激发一些可能有用也可能不有用的评论。

在某种程度上,答案将取决于您可能有多少查询,一次有多少查询以及mysql索引是否会比您的最终解决方案更快。

然后有几个想法:

可以很容易地将缓存请求传递到另一台服务器,这将允许基本上无限的扩展。

作为人类,大多数单词请求可能只涉及几千个单词,所以你可能很快就会发现大多数正在做的工作都是重复的。创建一个可索引的数据库是有意义的。

散列在过去曾被认为是一种加快数据索引的好方法。这是否有用在一定程度上取决于你答案的长度。

如果你很聪明,你可以确定前10000个左右可能的问题和答案,并将它们存储在一个单独的表中,以获得更快的答案。(大师评论?)

你的dll已经缓存请求了吗?如果是这样,那么任何进一步的工作都可能会降低您的服务速度。

该解决方案适用于使用JS或php生成多个请求的简单测试,以测试使用或不使用缓存的响应速度。无论你决定哪一个,我认为你都应该用大量的样本数据来测试它。

为了获得示例的最大性能,您需要遵循基本的缓存优化原则。

我不确定应用程序逻辑是否允许,但如果允许,它将给您带来巨大的好处:您需要区分可以缓存(静态)的请求和返回动态(随机)响应的请求。使用一些文件命名规则或提供一些自定义的http头或请求参数,即可以用于判断是否缓存请求的任何部分。

加速静态请求。这个想法是处理传入的请求并尽早发回回复(理想情况下甚至在网络服务器开始运行之前)。我建议您使用输出缓存,因为它可以在php&mysql内部以更高性能的方式运行。一些选项包括:

  1. 使用IIS输出缓存功能(快速搜索显示它可以根据请求的文件名和查询字符串缓存查询)
  2. 在web服务器前面放置一个缓存层。清漆(https://www.varnish-cache.org/)是一个灵活而强大的开源工具,您可以根据数据的大小(使用内存与磁盘、可以使用多少内存等)优化配置缓存策略

加速动态请求。如果它们在内部是完全随机的(没有可以缓存的dll调用),那么就没有什么可做的了。如果有一些dll调用可以缓存,就按照你描述的那样做:从缓存中提取数据,如果数据在那里,那就很好,如果没有,就从dll中提取数据并保存到缓存中。

但使用更适合缓存任务的东西——像Redis或memcached这样的键/值存储是不错的。他们速度极快。Redis可能是一个更好的选择,因为数据可以持久化到磁盘(而memcached在重新启动时会丢弃整个缓存,因此需要重新填充)。