1

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

我的应用程序的流程是这样的:

js -> ajax 调用 -> php -> vb6 dll -> vb6 代码查询字典并执行 CPU 密集型工作 -> 回复 php -> 回复 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

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

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

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

所以这个 mysql 表的大小会逐渐增长,达到 3-4 百万行,并且随着请求的东西在数据库中的机会的增加,它也会增长,理论上这应该比执行cpu 密集型调用(每个任何地方)更快从 50 到 750 毫秒长)。

你认为这是实现我想要的好方法吗?或者当 mysql 表达到 3-4 百万个条目时,它也会变慢吗?

提前感谢您的意见。

编辑

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

1) AFAIK 它只在 .php 文件变得“热”时缓存它(许多查询)。

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

4

3 回答 3

1

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

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

加快静态请求。这个想法是尽可能早地处理传入的请求并发送回回复(理想情况下甚至在 Web 服务器开始发挥作用之前)。我建议您使用输出缓存,因为它会以更高性能的方式在内部执行您打算在 php&mysql 中执行的操作。一些选项是:

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

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

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

于 2013-09-02T20:10:54.693 回答
1

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

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

然后有几个想法:

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

作为人类,大多数单词请求可能只涉及几千个单词,因此您可能会发现大部分正在完成的工作很快就会重复工作。那么创建一个可索引的数据库是有意义的。

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

如果您非常聪明,您可以确定前 10000 个左右可能的问题和响应,并将它们存储在单独的表中以便更快地响应。(大师评论?)

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

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

于 2013-08-30T08:45:02.580 回答
1

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

  1. 您对在给定的小时、天、周内将重复多少次这些查询有任何想法/感觉吗?因为......“更常见的缓存技术”(即我见过和/或阅读最多的技术)是使用 APC 之类的东西,或者为了可扩展性,使用 Memcache 之类的东西。不过,我所看到的是,这些通常用于< 12 小时长的缓存。这就是我所看到的。好处:自动清理未使用的项目。

  2. 你能估计一下单个“任务”可能需要多长时间吗?因为...这会让您知道缓存是否/何时变得无效 - 即缓存机制何时比任务慢。

这就是我提出的解决方案 - 全部从 PHP 中完成(不足为奇)。在您的工作流程中,这将是两个PHP 点:js -> ajax 调用 -> php -> vb6 dll -> vb6 代码查询字典并执行 CPU 密集型工作 -> 回复php -> 回复 js -> html分...

像这样的东西:

  1. 创建一个包含列的表:__id、key、output、count、modified

    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 'output' =TEXT因为 VB6 代码会多一点

    1.5 'count' =INT(8)左右

  2. 散列查询字符串(“word=blahblah&tense=2&voice=active”)。我在想这样的事情:$key = md5(var_export($_GET, TRUE)); 基本上,散列任何会产生独特输出的东西。从给出的示例推断,如果大小写无关紧要,也许最好将“单词”小写。

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

    3.1。$结果 =SELECT output, count FROM my_cache_table_name WHERE key = "$key"

    3.2. if (empty($result)) {
                $output = 运行 VB6 任务的结果
                $count = 1
          else
                $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”

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

所以我没有直接说明的是:以上内容将起作用(并且几乎是您的建议)。通过添加“计数”列,您将能够看到哪些查询做了很多和/或很少,并且可以在需要时返回并修剪。

如果您想查看查询需要多长时间,您可以创建另一个包含“key”、“duration”和“modified”的表(如上所示)。在 3.1 和 3.3 之前,获取microtime()。如果这是缓存命中,则减去 microtime() 并存储在这个新表中,其中 'key' = $key 和 'duration' = 2nd microtime() - 1st microtime()。然后您可以稍后再回来,按“修改后的 DESC”排序,然后查看查询需要多长时间。如果您有大量数据并且最新的“持续时间”仍然不错,则可以拉动整个持续时间记录机制。或者,如果无聊,只存储 $key 以字母结尾的持续时间(只是为了减少它在服务器上的负载)

于 2013-09-01T23:45:30.880 回答