精华内容
下载资源
问答
  • 解决高并发的几种方法

    万次阅读 2017-08-07 11:00:26
    一、将数据存到redis缓存 二、使用高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web...在电商项目中,会有某一件商品许多用户去访问,这个时候就会产生高并发,我解决的方式就是使用redis缓存去解决

    一、将数据存到redis缓存

    二、使用高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器.

    三、使用Ngnix负载均衡

    电商如何处理高并发

    为了解决高并发访问量我们采用了HttpClient页面静态化技术对首页的信息进行缓存,

    因为首页的页面相对复杂,freemarker需要制作模板会比较麻烦,而httpclient直接将jsp页面的数据拿过来以流的形式生成静态页面

    缓存方面我们使用了eccach。商品搜索方面为了避免传统的SQL搜索带来的耗时大,IO操作频繁等缺点,使用Lucene全文索引技术,

    而在电商项目中,会有某一件商品许多用户去访问,这个时候就会产生高并发,我解决的方式就是使用redis缓存去解决

    展开全文
  • 在秒杀,抢购等并发场景下,可能会出现超卖的现象,在 PHP 语言中并没有原生提供并发解决方案,因此就需要借助其他方式来实现并发控制,其实方案有很多,今天只是举个栗子抛砖引玉,有其他更好的方案你可以自己...

    在秒杀,抢购等并发场景下,可能会出现超卖的现象,在 PHP 语言中并没有原生提供并发的解决方案,因此就需要借助其他方式来实现并发控制,其实方案有很多种,今天只是举个栗子抛砖引玉,有其他更好的方案你可以自己去玩一玩就好了。

    列出常见的3个解决方案有:

    使用队列,额外起一个进程处理队列,并发请求都放到队列中,由额外进程串行处理,并发问题就不存在了,但是要额外进程支持以及处理延迟严重,本文不先不讨论这种方法。

    利用数据库事务特征,做原子更新,此方法需要依赖数据库的事务特性。

    借助文件排他锁,在处理下单请求的时候,用 flock 锁定一个文件,成功拿到锁的才能处理订单。

    一、利用 Redis 事务特征

    redis 事务是原子操作,可以保证订单处理的过程中数据没有被其它并发的进程修改。

    示例代码:

    <?php
    $http = new swoole_http_server("0.0.0.0", 9509);   // 监听 9509
    $http->set(array(
     'reactor_num' => 2,  //reactor thread num
     'worker_num' => 4    //worker process num
    ));
    $http->on('request', function (swoole_http_request $request, swoole_http_response $response) {
     $uniqid = uniqid('uid-', TRUE);    // 模拟唯一用户ID
     $redis = new Redis();
     $redis->connect('127.0.0.1', 6379);    // 连接 redis
     $redis->watch('rest_count');  // 监测 rest_count 是否被其它的进程更改
     $rest_count = intval($redis->get("rest_count"));  // 模拟唯一订单ID
     if ($rest_count > 0){
     $value = "{$rest_count}-{$uniqid}";  // 表示当前订单,被当前用户抢到了
     // do something ... 主要是模拟用户抢到单后可能要进行的一些密集运算
     $rand = rand(100, 1000000);
     $sum = 0;
     for ($i = 0; $i < $rand; $i++) {$sum += $i;}
     // redis 事务
     $redis->multi();
     $redis->lPush('uniqids', $value);
     $redis->decr('rest_count');
     $replies = $redis->exec();  // 执行以上 redis 事务
     // 如果 rest_count 的值被其它的并发进程更改了,以上事务将回滚
     if (!$replies) {
     echo "订单 {$value} 回滚" . PHP_EOL;
     }
     }
     $redis->unwatch();
    });
    $http->start();
    

    使用 ab 测试

    $ ab -t 20 -c 10 http://192.168.1.104:9509/
    

    二、利用文件排他锁 (阻塞模式)

    阻塞模式下,如果进程在获取文件排他锁时,其它进程正在占用锁的话,此进程会挂起等待其它进程释放锁后,并自己获取到锁后,再往下执行。

    示例代码:

    <?php
    $http = new swoole_http_server("0.0.0.0", 9510);
    $http->set(array(
     'reactor_num' => 2,  //reactor thread num
     'worker_num' => 4    //worker process num
    ));
    $http->on('request', function (swoole_http_request $request, swoole_http_response $response) {
     $uniqid = uniqid('uid-', TRUE);
     $redis = new Redis();
     $redis->connect('127.0.0.1', 6379);
     $fp = fopen("lock.txt", "w+");
     // 阻塞(等待)模式, 要取得独占锁定(写入的程序)
     if (flock($fp,LOCK_EX)) {  //锁定当前指针
     // 成功取得锁后,放心处理订单
     $rest_count = intval($redis->get("rest_count"));
     $value = "{$rest_count}-{$uniqid}";
     if ($rest_count > 0) {
     // do something ...
     $rand = rand(100, 1000000);
     $sum = 0;
     for ($i = 0; $i < $rand; $i++) {$sum += $i;}
     $redis->lPush('uniqids', $value);
     $redis->decr('rest_count');
     }
     // 订单处理完成后,再释放锁
     flock($fp, LOCK_UN);
     }
     fclose($fp);
    });
    $http->start();
    

    使用 ab 测试

    $ ab -t 20 -c 10 http://192.168.1.104:9510/
    

    三、利用文件排他锁 (非阻塞模式)

    非阻塞模式下,如果进程在获取文件排他锁时,其它进程正在占用锁的话,此进程会马上判断获取锁失败,并且继续往下执行。\

    示例代码:

    <?php
    $http = new swoole_http_server("0.0.0.0", 9511);
    $http->set(array(
     'reactor_num' => 2,  //reactor thread num
     'worker_num' => 4    //worker process num
    ));
    $http->on('request', function (swoole_http_request $request, swoole_http_response $response) {
     $uniqid = uniqid('uid-', TRUE);
     $redis = new Redis();
     $redis->connect('127.0.0.1', 6379);
     $fp = fopen("lock.txt", "w+");
     // 非阻塞模式, 如果不希望 flock() 在锁定时堵塞,则给 lock 加上 LOCK_NB
     if(flock($fp,LOCK_EX | LOCK_NB))   //锁定当前指针
     {
     // 成功取得锁后,放心处理订单
     $rest_count = intval($redis->get("rest_count"));
     $value = "{$rest_count}-{$uniqid}";
     if($rest_count > 0){
     // do something ...
     $rand = rand(100, 1000000);
     $sum=0;
     for ($i=0;$i<$rand;$i++){ $sum+=$i; }
     $redis->lPush('uniqids', $value);
     $redis->decr('rest_count');
     }
     // 订单处理完成后,再释放锁
     flock($fp,LOCK_UN);
     } else {
     // 如果获取锁失败,马上进入这里执行
     echo "{$uniqid} - 系统繁忙,请稍后再试".PHP_EOL;
     }
     fclose($fp);
    });
    $http->start();
    

    使用 ab 测试

    $ ab -t 20 -c 10 http://192.168.1.104:9511/
    

    最后给出三种处理方式的测试结果比较

    redis 事务方式:

    Concurrency Level:      10
    Time taken for tests:   20.005 seconds
    Complete requests:      17537
    Failed requests:        0
    Total transferred:      2578380 bytes
    HTML transferred:       0 bytes
    Requests per second:    876.62 [#/sec] (mean)
    Time per request:       11.407 [ms] (mean)
    Time per request:       1.141 [ms] (mean, across all concurrent requests)
    Transfer rate:          125.86 [Kbytes/sec] received
    

    文件排他锁(阻塞模式):

    Concurrency Level:      10
    Time taken for tests:   20.003 seconds
    Complete requests:      8205
    Failed requests:        0
    Total transferred:      1206282 bytes
    HTML transferred:       0 bytes
    Requests per second:    410.19 [#/sec] (mean)
    Time per request:       24.379 [ms] (mean)
    Time per request:       2.438 [ms] (mean, across all concurrent requests)
    Transfer rate:          58.89 [Kbytes/sec] received
    

    文件排他锁(非阻塞模式):

    Concurrency Level:      10
    Time taken for tests:   20.002 seconds
    Complete requests:      8616
    Failed requests:        0
    Total transferred:      1266846 bytes
    HTML transferred:       0 bytes
    Requests per second:    430.77 [#/sec] (mean)
    Time per request:       23.214 [ms] (mean)
    Time per request:       2.321 [ms] (mean, across all concurrent requests)
    Transfer rate:          61.85 [Kbytes/sec] received
    

    经测试结果对比,redis 事务方式优于文件排他锁方式,而文件排他锁方式中,非阻塞模式优于阻塞模式。

    以上内容希望帮助到大家, 很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家 ,需要戳这里 PHP进阶架构师>>>实战视频、大厂面试文档免费获取

    展开全文
  • sub=7A1C2FA465364079A3377E5CA...优点:数据库并发性更好; 缺点:未解决超卖问题。 方案2、缓存加version结合数据库乐观锁 对于采用乐观锁场景可以减少数据库读操作; 同时解决了双写不一致问题。 优点.

    redis使用方法创新,独创使用方法(转载请说明出处):
    http://note.youdao.com/noteshare?id=ff42f6b4148298d97dc3ef36af963d6f&sub=7A1C2FA465364079A3377E5CA35765E3

    关于Redis使用的思考-创新

    方案1、多线程写入场景下,redis缓存和数据库数据的最终一致性思考

    (解决双写不一致问题)

    优点:数据库并发性更好;

    缺点:未解决超卖问题。

    ps:数据库version不用作数据库修改的乐观锁,对数据库性能无影响。

    version仅用作更新缓存时的版本校验,向上增加允许,向下修改不允许。

    (Redis缓存加version,数据库冗余一个version字段,基本实现了canal的功能)

    1

     

    方案2、缓存加version结合数据库乐观锁

    对于采用乐观锁场景可以减少数据库读操作;

    同时解决了双写不一致问题。

    优点:

    1、解决双写不一致问题;

    2、更新数据前不需要从数据库io读取获得version;

    ps:解决了超卖问题(乐观锁本来就可以解决)。

     

    缺点:可能出现大量失败的更新,容易影响数据库性能。

    改进:结合分布式锁,可以避免大量失败更新。

    2

    方案3、高并发强数据一致性场景提升服务并发性能

    优点:

    1、提升了数据库使用乐观锁高并发场景下服务性能:大量失败的更新操作提前到服务层发现。

    ps:双写问题在分布式锁场景下本不存在。

    解决了超卖问题(乐观锁本来就可以解决)。

    有数据库乐观锁version控制,不用担心redis主从切换情况下可能出现多个客户端获得同一个分布式锁。(少部分在version校验时会退回到获取缓存逻辑,大部分在执行数据库更新时会失败,此时可能会涉及其他数据库数据回滚处理问题)

     

    缺点:

    复杂度增加,分布式锁,version比较,缓存带version。

    在非(高并发&强数据一致)场景下,没有必要。在高并发&强数据一致)场景下使用。

    1

     

    PS:

    向缓存中添加商品key数量时加上version【过期时间:+随机数】[避免缓存失效(击穿)]

    set product_1006 {50,3} 【ex 30 + random】

     

    Lua脚本类似CAS语义:

    eval "local x=string.len(ARGV[1]); if redis.call('GETRANGE', KEYS[1], 0, x-1) < ARGV[1] then redis.call('SET', KEYS[1], ARGV[2]); return 1; end; return 0" 1 version 3 3

    就这,怎么使用看场景。
    谁说redis一致性不行,看怎么使用。
    欢迎来拍砖!据说思想的碰撞能引发智慧。

     

    展开全文
  • 三种方法: 之所以会出现上边报出的错误,往往都是因为数据连接对象是静态、全局的对象,相应有很多朋友为了避免多次的声明、创建对象,干脆将该数据连接对象设置为静态的全局的,这样做的确可以省下不少的功夫,...

    第三种方法:

    之所以会出现上边报出的错误,往往都是因为数据连接对象是静态、全局的对象,相应有很多朋友为了避免多次的声明、创建对象,干脆将该数据连接对象设置为静态的全局的,这样做的确可以省下不少的功夫,但是带来的弊端也是显而易见的,也就是再高并发操作的情况下,会出现上边提到的错误。

    因此,这里建议,将数据连接对象设置为局部的,且每次都new一个对象出来,这样做不过是多创建了几个对象,开了几个连接罢了,但是,即使是高并发也不会出现DataReader未关闭的情况。此外,事实上只有在第一次进行数据连接比较耗费时间和性能之外,以后进行的连接操作,所耗费的时间几乎是可以忽略不计的,因为SqlConnection还有连接池的机制,这也是下边要讲的一个内容

    展开全文
  • 高并发系统限流方法

    2018-03-18 23:03:00
    开发高并发系统时有把利器用来保护系统:缓存、降级和限流。缓存的目的是提升系统访问速度和增大系统能处理的容量,可谓是抗高并发流量的银弹;而降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉,待...
  • 分布式锁应该具备的条件 1、在分布式系统环境下,一个方法在同一时间只能被一...分布式锁的三种实现方式 目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。分...
  • 多线程高并发解决办法

    万次阅读 2015-05-03 13:28:51
    网上关于这个问题五花八门,其实有很多解决办法,现在提供以下三种解决方法,供参考。每个方法详细实现等有时间再补充。1 線程間的代碼併做好同步工作,防止鎖的氾濫2 用線程池,解决多线程高并发3还有使用异步的...
  • * 解决ArrayList的三种方法 */ //1. 线程安全 add 方法使用的是 synchronized 修饰,但其效率并不 //List<String> list = new Vector<>(); //2. Collections 工具类转换成线程安全 //List&...
  • 点击关注,快速进阶高级架构师原创: 徐刘根分布式锁解决并发三种实现方式在很多场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。有的时候,我们需要保证一个方法...
  • 解决高并发超卖现象的方法三种 之前我写了两种 然后就忘了这个 【哭笑不得】 首先我们要知道什么是行锁与表锁 注意:MyISAM引擎只支持表锁,而InnoDB既支持表锁又支持行锁 【行锁是什么,什么时候触发行锁】 行锁...
  • 二、线程封闭的三种方式:Ad-hoc线程封闭:程序控制实现,最糟糕,忽略堆栈封闭:局部变量,无并发问题ThreadLocal线程封闭:特别好的封闭方法 三、有的人会有疑问:之前没有学过并发,为什么我的程序大部分执行也...
  • MySQL并发时经典常见的死锁原因及解决方法 1.mysql都有什么锁 MySQL有三种锁的级别:页级、表级、行级。 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 行级锁:开销大,...
  • Mysql并发时经典常见的死锁原因及解决方法1.mysql都有什么锁MySQL有三种锁的级别:页级、表级、行级。表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。行级锁:开销大,加锁慢...
  • MySQL有三种锁的级别:页级、表级、行级。 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,...
  • │ 高并发编程第二阶段03讲、介绍三种高效优雅的Singleton实现方式.wmv │ 高并发编程第二阶段04讲、多线程的休息室WaitSet详细介绍与知识点总结.mp4 │ 高并发编程第二阶段05讲、一个解释volatile关键字作用最好...

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 320
精华内容 128
关键字:

高并发三种解决方法