Maison >développement back-end >tutoriel php >Comment résoudre la haute concurrence en php
Cet article vous explique principalement comment résoudre la concurrence élevée en PHP. Lorsqu'il s'agit d'achats précipités, de ventes flash, de tirages de loterie, de saisie de billets et d'autres activités, afin d'éviter la survente, la quantité de stock est limitée, mais si. le nombre de personnes passant des commandes en même temps dépasse la quantité en stock, ce qui entraînera des problèmes de survente. Alors, comment résoudre ce problème ? Mon idée est la suivante (pseudocode) :
sql1 : interroger l'inventaire des produits
if(库存数量 > 0) { //生成订单... sql2:同时库存-1 }
Quand il n'y a pas de concurrence, le processus ci-dessus ressemble comme Cela semble normal. Supposons que deux personnes passent une commande en même temps et qu'il n'y ait qu'un seul article en stock. Au stade sql1, l'inventaire interrogé par les deux personnes est > 0, donc ils finissent par exécuter sql2, et l'inventaire est enfin terminé. devient -1 , surréservé, ce n'est pas le résultat souhaité.
J'ai résumé les idées les plus populaires pour résoudre ce problème :
1. Utilisez un processus unique supplémentaire pour traiter une file d'attente, mettez les demandes de commande dans la file d'attente et traitez-les une par une, donc là. il n’y aura pas de concurrence. C’est un problème, mais cela nécessite des processus et des retards supplémentaires en arrière-plan, qui ne seront pas pris en compte ici pour l’instant. Ici, je peux utiliser la file d'attente des messages, nous utilisons souvent Memcacheq et Radis. Par exemple : s'il y a 100 tickets à récupérer par les utilisateurs, ils peuvent alors mettre ces 100 tickets dans le cache et ne pas les verrouiller lors de la lecture et de l'écriture. Lorsque le niveau de simultanéité est important, environ 500 personnes peuvent réussir à récupérer des billets, de sorte que les demandes après 500 puissent être directement transférées vers la page statique à la fin de l'événement. Il est impossible pour 400 des 500 personnes qui entrent de se procurer le produit. Par conséquent, seules les 100 premières personnes peuvent acheter avec succès selon l'ordre dans lequel elles entrent dans la file d'attente. Les 400 prochaines personnes accéderont directement à la page de fin de l'événement. Bien entendu, la saisie de 500 personnes n’est qu’un exemple. Vous pouvez ajuster le nombre vous-même. La page de fin d'activité doit utiliser une page statique, pas une base de données. Cela réduit la pression sur la base de données.
2.Le verrouillage optimiste MySQL signifie que, par exemple, l'inventaire total est de 2, et lorsque l'événement d'achat urgent est soumis, l'inventaire est immédiatement +1, puis l'inventaire est 3 à ce moment-là, et puis après la commande généré, l'inventaire est à nouveau interrogé avant de mettre à jour l'inventaire (car bien sûr, lorsqu'une commande est générée, l'inventaire est à -1, mais ne vous inquiétez pas, vérifiez à nouveau l'inventaire et le résultat du retour est 3) pour voir s'il est cohérent avec la quantité d'inventaire attendue (l'inventaire attendu ici est 3) S'il est incohérent, revenez en arrière et indiquez à l'utilisateur que l'inventaire est insuffisant. Ici, nous parlons de verrous pessimistes. Certains amis peuvent demander, alors il doit y avoir des verrous optimistes, non ?? Ici, je vais parler brièvement des verrous pessimistes et optimistes que je connais
Les verrous pessimistes et les verrous optimistes sont deux. les plus courants. L’idée de conception de verrouillage de concurrence de ressources est également un concept très basique en programmation concurrente. Cet article fournira une introduction comparative et systématique à la mise en œuvre de ces deux mécanismes de verrouillage courants sur les données de bases de données.
La caractéristique du verrouillage pessimiste est d'acquérir d'abord le verrou, puis d'effectuer des opérations commerciales. Autrement dit, la vision « pessimiste » est que l'acquisition du verrou est très susceptible d'échouer, il faut donc d'abord s'assurer d'obtenir le verrou avec succès avant d'effectuer des opérations commerciales. L'expression communément appelée « un verrou, deux vérifications et trois mises à jour » fait référence à l'utilisation de verrous pessimistes. De manière générale, le verrouillage pessimiste sur la base de données nécessite la prise en charge de la base de données elle-même, c'est-à-dire que le verrouillage pessimiste est implémenté via l'opération de sélection... pour la mise à jour couramment utilisée. Lorsque la base de données exécute une sélection pour mise à jour, elle acquiert le verrou de ligne de la ligne de données dans la sélection, de sorte que les autres sélections exécutées simultanément Si la mise à jour tente de sélectionner la même ligne, une exclusion se produira (il faudra attendre que le verrou de ligne soit libéré), obtenant ainsi l'effet de verrouillage. Le verrou de ligne acquis par select for update sera automatiquement libéré à la fin de la transaction en cours, il doit donc être utilisé dans la transaction.
Une chose à noter ici est que différentes bases de données ont une implémentation et une prise en charge différentes pour la sélection pour la mise à jour. Par exemple, Oracle prend en charge la sélection pour la mise à jour sans attente, ce qui signifie que si le verrou ne peut pas être obtenu, une erreur sera générée. signalé immédiatement, au lieu d'attendre, mysql n'a pas l'option sans attente. Un autre problème avec MySQL est que toutes les lignes analysées seront verrouillées lors de l'exécution de l'instruction select for update, ce qui peut facilement causer des problèmes. Par conséquent, si vous utilisez le verrouillage pessimiste dans MySQL, veillez à utiliser l'index au lieu d'une analyse complète de la table.
Les caractéristiques du verrouillage optimiste sont d'effectuer d'abord des opérations commerciales et de ne prendre le verrou que lorsque cela est absolument nécessaire. C'est-à-dire que les « optimistes » pensent que la plupart du temps, le verrouillage réussira, il suffit donc de prendre le verrouillage après la dernière étape de mise à jour réelle des données après avoir terminé l'opération commerciale.
La mise en œuvre du verrouillage optimiste sur la base de données est tout à fait logique et ne nécessite pas de support particulier de la base de données. L'approche générale consiste à ajouter un numéro de version ou un horodatage aux données qui doivent être verrouillées, puis à l'implémenter comme suit :
1. SELECT data AS old_data, version AS old_version FROM …;2. 根据获取的数据进行业务操作,得到new_data和new_version3. UPDATE SET data = new_data, version = new_version WHERE version = old_versionif (updated row > 0) { // 乐观锁获取成功,操作完成 } else { // 乐观锁获取失败,回滚并重试 }
乐观锁是否在事务中其实都是无所谓的,其底层机制是这样:在数据库内部update同一行的时候是不允许并发的,即数据库每次执行一条update语句时会获取被update行的写锁,直到这一行被成功更新后才释放。因此在业务操作进行前获取需要锁的数据的当前版本号,然后实际更新数据时再次对比版本号确认与之前获取的相同,并更新版本号,即可确认这之间没有发生并发的修改。如果更新失败即可认为老版本的数据已经被并发修改掉而不存在了,此时认为获取锁失败,需要回滚整个业务操作并可根据需要重试整个过程。好吧,在此唠叨总结下这两个锁:
乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能
乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方
3.根据update结果来判断,我们可以在sql2的时候加一个判断条件update table set 库存=xxx where 库存>0,如果返回false,则说明库存不足,并回滚事务。
4.借助文件排他锁,在处理下单请求的时候,用flock锁定一个文件,如果锁定失败说明有其他订单正在处理,此时要么等待要么直接提示用户"服务器繁忙"
大致代码如下:
阻塞(等待)模式
<?php$fp = fopen("lock.txt", "w+");if(flock($fp,LOCK_EX)) //锁定当前指针,,,{ //..处理订单 flock($fp,LOCK_UN); }fclose($fp);?>
非阻塞模式
<?php$fp = fopen("lock.txt", "w+");if(flock($fp,LOCK_EX | LOCK_NB)) { //..处理订单 flock($fp,LOCK_UN); }else{ echo "系统繁忙,请稍后再试"; } fclose($fp);?>
5.如果是分布式集群服务器,就需要一个或多个队列服务器 小米和淘宝的抢购还是有稍许不同的,小米重在抢的那瞬间,抢到了名额,就是你的,你就可以下单结算。而淘宝则重在付款的时候的过滤,做了多层过滤,比如要卖10件商品,他会让大于10的用户抢到,在付款的时候再进行并发过滤,一层层的减少一瞬间的并发量。
6.使用redis锁 product_lock_key 为票锁key 当product_key存在于redis中时,所有用户都可以进入下单流程。 当进入支付流程时,首先往redis存放sadd(product_lock_key, “1″),如果返回成功,进入支付流程。如果不成,则说明已经有人进入支付流程,则线程等待N秒,递归执行sadd操作。
当然类似于淘宝双11的疯抢架构远远比我说滴这些复杂多啦....更多解决方案需要不停滴去实战中获取心得....大家有好的解决思路清随时共享留言哈。
相关推荐:
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!