`
liyuandong
  • 浏览: 331738 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

大量并发的应急处理方案与实践2——使用缓存(转)

阅读更多

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Dreamcode/archive/2010/05/26/5624429.aspx

 

大量并发的应急处理方案与实践2——使用缓存
    《大量并发的应急处理方案与实践》提供的方法,只能做应急时的一种参考,不推荐在设计之初时使用,设计之初我们应该采用更合理的架构,以避免文中所提及的问题发生,关于架构请参考我的另一篇文章《开餐馆与做软件——如何提高大型网站性能》。
      资源可以分成两种,一种为禁止并发访问的资源,另一种为允许并发访问的资源。禁止并发访问的资源如高速公路收费站,每一个收费口一次只处理一个通过请求,当有多个车辆请求通过时,解决的办法有两种,一种是增设收费口,另一种就是让车辆排队等候,即不马上处理请求,让请求等待空闲资源,我把这种解决办法称作后向异步处理,即将需要处理的请求,延后一段时间处理,这种方法适用于用户不需要看到即使效果的情况。关于“后向异步处理” 的例子请参考《大量并发的应急处理方案与实践1——异步处理》。允许并发访问的资源如商场,任何顾客都可以随时购买需要的商品,早先的大部分商场商品前都有一个柜台,顾客通过售货员购买需要的商品,当顾客增多后,售货员就会应接不暇,让顾客排队是一个办法,但是没有哪个商场会强制顾客排队购买商品,这种“后向异步处理”不适合解决这样的问题,于是一种更好的解决方案产生了——“超市”,取出部分商品直接摆放在售货台上,让顾客自己去取,然后只需要安排一个服务人员随时观察,发现商品不全再到库房中取来相应商品进行补充。
      即将如下流程:
 顾客 -> 售货员1 -> 商品1 -> 付费
 顾客 -> 售货员2 -> 商品2 -> 付费
 顾客 -> 售货员3 -> 商品3 -> 付费
      改造为
 库房 -> 服务员 —> 售货台(缓存)(前向异步处理)
 顾客 -> 商品(1、2、3)->  排队付费(后向异步处理)
      这是一个典型例子,顾客对于付费的请求不需要即时响应,我们可以采用后向异步处理的方法。但是对于查看商品的请求越早满足越好,因此我们采用另一种前向异步处理的办法,将商品(数据)提前放到售货台(缓存)里,这样当顾客(请求)需要的时候可以直接取走。下面我们来看一个你可能会遇到的例子:
      有一天你的老板突然接到电话,客户抱怨说当登录人数增加的时候,页面打开的非常慢,这时老板找到你,你竭尽全力向老板解释,老板用无奈的眼神望着你,对你说:"用户很急,全靠你了。"
      你垂头丧气的走回到座位上,开始一点点排查原因,这时你发现原来这些页面在打开时,伴随大量的数据库操作,
这就是页面打开速度慢的原因。遇到这样的问题,比较简单快速的改造方法就是使用缓存。
      即是将如下结构,
 用户-> 页面与逻辑 -> 数据库
      改造为:
 数据库 -> 监控程序 -> 缓存 (前向异步处理)
 用户-> 页面与逻辑 -> 缓存
 

      举例来说你发现需要加速的页面 test.jsp, 其通过TestDB.java 类获取数据。

    public class TestDB{
                 ...
                // 读取数据库 1
                String sql1 = "..."; //查询语句
                List tmplist1 = queryBySQL(sql1); //queryBySQL 方法,执行sql 语句,执行结果放到一个List 中返回
                ...
                // 读取数据库 2
                String sql2 = "..."; //查询语句
                List tmplist2 = queryBySQL(sql2); //queryBySQL 方法,执行sql 语句,执行结果放到一个List 中返回
                ...
                // 读取数据库 3
                String sql3 = "..."; //查询语句
                List tmplist3 = queryBySQL(sql3); //queryBySQL 方法,执行sql 语句,执行结果放到一个List 中返回
                ...
    }

 

       首先,我们创建一个与页面相对应的缓存模块(例如Buffer)。为需要缓存数据的页面创建一个与之对应的类TestBuffer.java 用来存放数据。必须保证TestBuffer.java 中的数据与数据库中相应数据的一一对应关系,因此我们将TestBuffer.java 设计为一个单例。

    #Buffer
           -- TestBuffer.java

 

     public class TestBuffer{
               private volatile static TestBuffer singleton=null;
               private TestBuffer(){}

               public static TestBuffer getInstance()
              {

                     if(singleton==null){
                           synchronized(TestBuffer.class)
                          {
                                  singleton=new TestBuffer();
                           }
                     }
  
                     return singleton;
              }

     }

 

    我们分析需要加速页面的数据库操作模块,找出所有数据库操作点。例如我们分析TestDB.java ,发现如下数据库
操作点:读取数据库 1、读取数据库 2、读取数据库 3。这三个操作点分别返回三个List 对象,这三个List 对象就是我们要缓存的数据。我们将这三个对象加入到testBuffer.java 中。

     public class TestBuffer{
               private volatile static TestBuffer singleton=null;
               private TestBuffer(){}

               private static List tmplist1 = null
               private static List tmplist2 = null
               private static List tmplist3 = null

 

               public static TestBuffer getInstance()
               {

                       if(singleton==null){
                              synchronized(TestBuffer.class)
                              {
                                     singleton=new TestBuffer();
                              }
                       }
  
                       return singleton;
                }


                public List getTmplist1(){
                      return tmplist1;
                }
 
                public List setTmplist1(List tmplist1){
                      this.tmplist1 = tmplist1;
                }

                public List getTmplist2(){
                      return tmplist2;
                }
 
                public List setTmplist2(List tmplist2){
                      this.tmplist2 = tmplist2;
                }

                public List getTmplist3(){
                      return tmplist3;
                }
 
                public List setTmplist3(List tmplist3){
                     this.tmplist3 = tmplist3;
                }

      }

 

   重新改造原先的数据库访问模块TestDB.java ,更改如下:
  
    public class TestDB{
             ...
           //String sql1 = "..."; //查询语句
           //String sql2 = "..."; //查询语句
           //String sql3 = "..."; //查询语句
           //List tmplist1 = queryBySQL(sql1); //queryBySQL 方法,执行sql 语句,执行结果放到一个List 中返回
           //List tmplist2 = queryBySQL(sql2); //queryBySQL 方法,执行sql 语句,执行结果放到一个List 中返回
           //List tmplist3 = queryBySQL(sql3); //queryBySQL 方法,执行sql 语句,执行结果放到一个List 中返回
 
           List tmplist1 = TestBuffer.getTmplist1();
           List tmplist2 = TestBuffer.getTmplist2();
           List tmplist3 = TestBuffer.getTmplist3();

            ...

    }

 

    然后我们添加从数据库到缓存的前向异步处理模块,即我们实现一个提前运行的监控程序,将数据库中的数据放到缓存中,并保持缓存与数据库中的数据同步,我们可以使用线程实现。

 public class testThread implements Runnable{

           private static long interval = 3000; //循环间隔

           @Override
           public void run(){
                 while(true){
                        ...

                       String sql1 = "..."; //查询语句
                       String sql2 = "..."; //查询语句
                       String sql3 = "..."; //查询语句
                       List tmplist1 = queryBySQL(sql1);
                       TestBuffer.setTmplist1(tmplist1);

 

                       List tmplist2 = queryBySQL(sql2);
                       TestBuffer.setTmplist2(tmplist2);

                       List tmplist3 = queryBySQL(sql3);
                       TestBuffer.setTmplist3(tmplist3);
                        ...

                       try {
                              Thread.sleep(interval);
                       } catch (InterruptedException e) {
                              // TODO Auto-generated catch block
                             e.printStackTrace();
                       }

                }

         }

 }

    以上提供的方法只做您遇到类似问题时的一种参考,是术,方法千变万化而道理不离其宗,合理使用缓存和异步处理是解决这一类问题的核心。

 

分享到:
评论

相关推荐

    开涛高可用高并发-亿级流量核心技术

    9.6 缓存使用模式实践 172 9.6.1 Cache-Aside 173 9.6.2 Cache-As-SoR 174 9.6.3 Read-Through 174 9.6.4 Write-Through 176 9.6.5 Write-Behind 177 9.6.6 Copy Pattern 181 9.7 性能测试 181 9.8 参考资料 182 10 ...

    从大型电商架构演进看互联网高可用架构设计——内训方案.pdf

    适用于处理大量并发事件的情况。 5. **服务网格架构**:专注于处理服务间的通信、监控和控制。提高了服务间交互的安全性和可靠性。 **五种架构模型的优缺点分析** - **单体架构**: - 优点:简单易懂,部署容易。...

    系统工程在电商的解决方案中的应用——以拼多多为例.zip

    通过系统工程的方法,拼多多可以识别性能瓶颈,使用性能监控工具进行调优,如数据库查询优化、缓存策略调整等,以提供流畅的用户体验。 9. **风险管理** 系统工程中的风险管理是不可或缺的,拼多多需要预测并应对...

    TCP-IP详解卷2:实现——2

    1.12 中断级别与并发 18 1.13 源代码组织 20 1.14 测试网络 21 1.15 小结 22 第2章 mbuf:存储器缓存 24 2.1 引言 24 2.2 代码介绍 27 2.2.1 全局变量 27 2.2.2 统计 28 2.2.3 内核统计 28 2.3 mbuf的定义 29 2.4 ...

    TCP-IP详解卷2:实现——1

    1.12 中断级别与并发 18 1.13 源代码组织 20 1.14 测试网络 21 1.15 小结 22 第2章 mbuf:存储器缓存 24 2.1 引言 24 2.2 代码介绍 27 2.2.1 全局变量 27 2.2.2 统计 28 2.2.3 内核统计 28 2.3 mbuf的定义 29 2.4 ...

    张孝祥银行调度系统

    《银行调度系统设计与优化——基于“张孝祥”实例解析》 银行调度系统是金融机构中不可或缺的关键组成部分,它负责高效、公平地处理各种客户服务请求,如存款、取款、转账等操作。在这个领域,张孝祥老师的名字常常...

    飞机订票系统 数据结构与算法上机

    在本题目中,我们面临的是一个关于数据结构与算法的实际应用——设计并实现一个飞机订票系统。数据结构是计算机科学中的核心概念,它涉及到如何有效地存储和组织数据,以便于快速访问和处理。而算法则是解决问题的...

    Database tuning principles

    《数据库调优:原理、实验与故障排除技术》是一本全面覆盖数据库调优领域的高级书籍,不仅提供了丰富的理论知识,还包含了大量实践经验和技术细节。通过对本书的学习,读者将能够掌握一系列可迁移的技能,从而有效地...

    Java+TCPIP+Socket编程(中文版)

    Java中如何使用多线程处理并发任务。 - **服务器协议** 多线程在服务器端的应用,例如处理多个客户端的请求。 - **一客户一线程** 为每个客户端分配一个单独的线程进行处理。 - **线程池** 使用线程池管理...

    淘宝技术这十年PDF阅读

    《淘宝技术这十年》这本书深度剖析了中国最大的电商平台——淘宝在技术领域的演进历程,从一个初创公司的简单网站发展到如今的超大规模互联网系统。在这个过程中,淘宝的技术团队面临着无数挑战,他们如何应对并实现...

    安全工程--可靠的分布式系统构建指南

    这类系统需要在多个服务器之间保持数据的一致性,并且能够处理高并发的事务请求。 - **事务处理**:利用两阶段提交等协议确保跨节点操作的一致性。 - **身份验证**:采用多因素认证技术提高安全性。 - **灾难恢复**...

    【CTO训练营】饿了么技术运营经历分享

    此外,针对高峰期的业务需求变化,饿了么还实施了如秒杀活动的改进策略,通过分级保护、用户端缓存等手段,有效应对了高并发场景下的挑战。 #### 经验教训与心得 - **事故处理**:饿了么在过去的发展过程中遇到了...

    Zabbix从入门到精通

    ### Zabbix从入门到精通——核心知识点概览 #### 一、Zabbix简介 - **Zabbix概述**:Zabbix是一款开源的企业级监控工具,它能够监控网络中的各种设备和服务状态,包括但不限于服务器、网络设备、应用程序等。通过...

    Help:云互救app原始码(大学生移动互联网设计大赛)-源码网

    7. **服务器架构**:后端服务器可能采用了分布式架构,保证在高并发情况下仍能稳定运行,处理大量用户的请求。 "失联小助手"app作为另一款参赛作品,其源码可能涵盖了相似但不完全相同的技术点,比如更侧重于离线...

    【白雪红叶】JAVA学习技术栈梳理思维导图.xmind

    多线程与并发 GC机制 GC收集器类型 串行 CMS 并行 G1 算法 复制 标记清理 标记整理 分区 新生代 eden survivor 老年代(old区) 永久代(perm区) 版本变化 1.5 1.6 1.7 1.8 1.9 IO/NIO IO...

    位置信使

    为了处理大量的实时位置数据,位置信使可能采用了缓存技术,如Redis,来减少数据库的读写压力;并可能通过负载均衡和分布式处理,提高系统的可扩展性和稳定性。 9. **消息推送** 实时位置更新需要即时通知用户,...

Global site tag (gtag.js) - Google Analytics