草庐IT

php - 处理并发问题的最佳方法

coder 2023-06-11 原文

我有一个 LAPP(linux、apache、postgresql 和 php)环境,但问题在 Postgres 或 Mysql 上都非常相同。

我开发了一个 cms 应用程序,用于处理客户、文档(估算、发票等)和其他数据,在 1 个 postgres 数据库中构建,具有许多模式(每个使用该应用程序的客户都有一个);让我们假设大约有 200 个模式,每个模式由 15 人(平均)同时使用。

编辑 :我确实在每个表上都有一个名为 last_update 的时间戳字段,以及一个每次更新行时都会更新时间戳的触发器。

情况是:

  • People Foo 和 Bar 正在编辑文档 0001,使用包含每个文档详细信息的表单。
  • 例如,Foo 更 retrofit 运详细信息。
  • 酒吧更改电话号码,以及文件中的一些项目。
  • Foo 按“保存”按钮,应用程序更新数据库。
  • 栏后按“保存”按钮,重新发送带有旧货件详细信息的表格。
  • 在数据库中,Foo 更改已丢失。

  • 我想要的情况:
  • Foo、Bar、John、Mary、Paoul 正在编辑文档 0001,使用包含每个文档详细信息的表单。
  • 例如,Foo 更 retrofit 运详细信息。
  • 巴和其他人改变了一些东西。
  • Foo 按“保存”按钮,应用程序更新数据库。
  • Bar 和其他人收到警报“警告!此文档已被其他人更改。单击此处加载实际数据'。

  • 我想知道使用 ajax 来做到这一点;只需使用带有文档 id 和上次更新时间戳的隐藏字段,每 5 秒检查上次更新时间是否相同并且什么都不做,否则,显示警告对话框。

    因此,页面 check-last-update.php 应该类似于:
    <?php
    //[connect to db, postgres or mysql]
    $documentId = isset($_POST['document-id']) ? $_POST['document-id'] : 0;
    $lastUpdateTime = isset($_POST['last-update-time']) ? $_POST['last-update-time'] : 0;
    //in the real life i sanitize the data and use prepared statements;
    $qr = pg_query("
        SELECT
            last_update_time
        FROM
            documents
        WHERE
            id = '$documentId'
    ");
    $ray = pg_fetch_assoc($qr);
    if($ray['last_update_time'] > $lastUpdateTime){
        //someone else updated the document since i opened it!
        echo 'reload';
    }else{
        echo 'ok';
    }
    ?>
    

    但我不喜欢每 5 秒为每个打开一个(或多个...)文档的用户强调 db。

    那么,在不破坏数据库的情况下,还有什么有效的解决方案?

    我想使用文件,例如为每个文档创建一个空的 txt 文件,每次更新文档时,我都会“触摸”更新“上次修改时间”的文件......但我想这会更慢比 db 并在我有很多用户编辑同一文档时出现问题。

    如果其他人有更好的想法或任何建议,请详细描述!

    * - - - - - 更新 - - - - *

    我绝对选择不点击数据库来检查“上次更新时间戳”,不要介意查询是否很快,(主)数据库服务器还有其他任务需要完成,不喜欢增加他对那件事的过载的想法.

    所以,我采取这种方式:
  • 每次有人更新文档时,我都必须做一些事情来在数据库环境之外签署新的时间戳,例如不问数据库。我的想法是:
  • 文件系统:对于每个文档,我创建一个名为文档 ID 的空 txt 文件,每次文档更新时,我都会“触摸”该文件。我希望有成千上万的空文件。
  • APC,php 缓存:这可能比第一种更灵活,但我想知道将成千上万的数据永久保存在 apc 中是否不会减慢 php 执行本身,或消耗服务器内存。我有点害怕选择这种方式。
  • 另一个 db、sqlite 或 mysql(使用简单的 db 结构更快更轻)用于仅存储文档 ID 和时间戳。
  • 无论我选择哪种方式(文件、apc、sub-db),我都在认真考虑在子域上使用另一个网络服务器(lighttp?),来处理所有这些......长轮询请求。

  • 另一个编辑:

    该文件的方式不起作用。

    APC 可以成为解决方案。

    命中数据库也可以是解决方案,创建一个表来处理时间戳(只有两列,document_id 和 last_update_timestamp),需要尽可能快和轻。

    长轮询:我会选择这种方式,在apache下使用lighttpd来加载静态文件(图片、css、js等),并且只针对这种类型的长轮询;这将减轻 apache2 的负载,特别是对于轮询。

    Apache 会将所有这些请求代理到 lighttpd。

    现在,我只需要在 db 解决方案和 APC 解决方案之间做出决定..

    ps:感谢所有已经回答我的人,你真的很有用!

    最佳答案

    我同意我可能不会为此访问数据库。我想我会使用 APC 缓存(或其他一些内存缓存)来维护这些信息。您所描述的显然是详细记录级别的乐观锁定。数据库结构中的级别越高,您需要处理的就越少。听起来您想检查结构中的多个表。

    我会维护一个缓存(在 APC 中)的 ID 和由表名键控的上次更新时间的时间戳。例如,我可能有一个表名数组,其中每个条目都以 ID 为键,实际值是最后更新的时间戳。可能有很多方法可以用数组或其他结构来设置它,但你明白了。我可能会向缓存添加超时,以便在一段时间后删除缓存中的条目 - 即,我不希望缓存增长并假设 1 天前的条目不再有用)。

    使用此架构,您需要执行以下操作(除了设置 APC):

  • 在对任何(适用)表进行任何更新时,使用新时间戳更新 APC 缓存条目。
  • 在 ajax 中,只要“返回”到 php(获取 APC 缓存以检查条目),而不是“返回”到数据库的所有方式。
  • 关于php - 处理并发问题的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1779317/

    有关php - 处理并发问题的最佳方法的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

      总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

    3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    5. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

      我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

    6. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

      我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

    7. Ruby 方法() 方法 - 2

      我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

    8. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

      我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

    9. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

      尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

    10. ruby - 如何指定 Rack 处理程序 - 2

      Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

    随机推荐