zoukankan      html  css  js  c++  java
  • Memcached笔记——(四)应对高并发攻击【转】

    http://snowolf.iteye.com/blog/1677495

    近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源。他们的最好成绩,1秒钟可以并发6次,赶在Database入库前,Cache进行Missing Loading前,强占这其中十几毫秒的时间,进行恶意攻击。

    相关链接: 
    Memcached笔记——(一)安装&常规错误&监控 
    Memcached笔记——(二)XMemcached&Spring集成 
    Memcached笔记——(三)Memcached使用总结 

    Memcached笔记——(四)应对高并发攻击

    为了应对上述情况,做了如下调整:

    1. 更新数据时,先写Cache,然后写Database(双写),如果可以,写操作交给队列后续完成。
    2. 限制统一帐号,同一动作,同一秒钟并发次数,超过1次不做做动作,返回操作失败。
    3. 限制统一用户,每日动作次数,超限返回操作失败。

    要完成上述操作,同事给我支招。用Memcached的add方法,就可以很快速的解决问题。不需要很繁琐的开发,也不需要依赖数据库记录,完全内存操作。

    以下实现一个判定冲突的方法:

    Java代码  收藏代码
    1. /** 
    2.  * 冲突延时 1秒 
    3.  */  
    4. public static final int MUTEX_EXP = 1;  
    5. /** 
    6.  * 冲突键 
    7.  */  
    8. public static final String MUTEX_KEY_PREFIX = "MUTEX_";  
    9.   
    10. /** 
    11.  * 冲突判定 
    12.  *  
    13.  * @param key 
    14.  */  
    15. public boolean isMutex(String key) {  
    16.     return isMutex(key, MUTEX_EXP);  
    17. }  
    18.   
    19. /** 
    20.  * 冲突判定 
    21.  *  
    22.  * @param key 
    23.  * @param exp 
    24.  * @return true 冲突 
    25.  */  
    26. public boolean isMutex(String key, int exp) {  
    27.     boolean status = true;  
    28.     try {  
    29.         if (memcachedClient.add(MUTEX_KEY_PREFIX + key, exp, "true")) {  
    30.             status = false;  
    31.         }  
    32.     } catch (Exception e) {  
    33.         logger.error(e.getMessage(), e);  
    34.     }  
    35.     return status;  
    36. }  

    做个说明:

    选项 说明
    add 仅当存储空间中不存在键相同的数据时才保存
    replace 仅当存储空间中存在键相同的数据时才保存
    set 与add和replace不同,无论何时都保存

    也就是说,如果add操作返回为true,则认为当前不冲突!

    回归场景,恶意用户1秒钟操作6次,遇到上述这个方法,只有乖乖地1秒后再来。别小看这1秒钟,一个数据库操作不过几毫秒。1秒延迟,足以降低系统负载,增加恶意用户成本。

    附我用到的基于XMemcached实现:

    Java代码  收藏代码
    1. import net.rubyeye.xmemcached.MemcachedClient;  
    2.   
    3. import org.apache.log4j.Logger;  
    4. import org.springframework.beans.factory.annotation.Autowired;  
    5. import org.springframework.stereotype.Component;  
    6.   
    7. /** 
    8.  *  
    9.  * @author Snowolf 
    10.  * @version 1.0 
    11.  * @since 1.0 
    12.  */  
    13. @Component  
    14. public class MemcachedManager {  
    15.   
    16.     /** 
    17.      * 缓存时效 1天 
    18.      */  
    19.     public static final int CACHE_EXP_DAY = 3600 * 24;  
    20.   
    21.     /** 
    22.      * 缓存时效 1周 
    23.      */  
    24.     public static final int CACHE_EXP_WEEK = 3600 * 24 * 7;  
    25.   
    26.     /** 
    27.      * 缓存时效 1月 
    28.      */  
    29.     public static final int CACHE_EXP_MONTH = 3600 * 24 * 30 * 7;  
    30.   
    31.     /** 
    32.      * 缓存时效 永久 
    33.      */  
    34.     public static final int CACHE_EXP_FOREVER = 0;  
    35.   
    36.     /** 
    37.      * 冲突延时 1秒 
    38.      */  
    39.     public static final int MUTEX_EXP = 1;  
    40.     /** 
    41.      * 冲突键 
    42.      */  
    43.     public static final String MUTEX_KEY_PREFIX = "MUTEX_";  
    44.     /** 
    45.      * Logger for this class 
    46.      */  
    47.     private static final Logger logger = Logger  
    48.             .getLogger(MemcachedManager.class);  
    49.   
    50.     /** 
    51.      * Memcached Client 
    52.      */  
    53.     @Autowired  
    54.     private MemcachedClient memcachedClient;  
    55.   
    56.     /** 
    57.      * 缓存 
    58.      *  
    59.      * @param key 
    60.      * @param value 
    61.      * @param exp 
    62.      *            失效时间 
    63.      */  
    64.     public void cacheObject(String key, Object value, int exp) {  
    65.         try {  
    66.             memcachedClient.set(key, exp, value);  
    67.         } catch (Exception e) {  
    68.             logger.error(e.getMessage(), e);  
    69.         }  
    70.         logger.info("Cache Object: [" + key + "]");  
    71.     }  
    72.   
    73.     /** 
    74.      * Shut down the Memcached Cilent. 
    75.      */  
    76.     public void finalize() {  
    77.         if (memcachedClient != null) {  
    78.             try {  
    79.                 if (!memcachedClient.isShutdown()) {  
    80.                     memcachedClient.shutdown();  
    81.                     logger.debug("Shutdown MemcachedManager...");  
    82.                 }  
    83.             } catch (Exception e) {  
    84.                 logger.error(e.getMessage(), e);  
    85.             }  
    86.         }  
    87.     }  
    88.   
    89.     /** 
    90.      * 清理对象 
    91.      *  
    92.      * @param key 
    93.      */  
    94.     public void flushObject(String key) {  
    95.         try {  
    96.             memcachedClient.deleteWithNoReply(key);  
    97.         } catch (Exception e) {  
    98.             logger.error(e.getMessage(), e);  
    99.         }  
    100.         logger.info("Flush Object: [" + key + "]");  
    101.     }  
    102.   
    103.     /** 
    104.      * 冲突判定 
    105.      *  
    106.      * @param key 
    107.      */  
    108.     public boolean isMutex(String key) {  
    109.         return isMutex(key, MUTEX_EXP);  
    110.     }  
    111.   
    112.     /** 
    113.      * 冲突判定 
    114.      *  
    115.      * @param key 
    116.      * @param exp 
    117.      * @return true 冲突 
    118.      */  
    119.     public boolean isMutex(String key, int exp) {  
    120.         boolean status = true;  
    121.         try {  
    122.             if (memcachedClient.add(MUTEX_KEY_PREFIX + key, exp, "true")) {  
    123.                 status = false;  
    124.             }  
    125.         } catch (Exception e) {  
    126.             logger.error(e.getMessage(), e);  
    127.         }  
    128.         return status;  
    129.     }  
    130.   
    131.     /** 
    132.      * 加载缓存对象 
    133.      *  
    134.      * @param key 
    135.      * @return 
    136.      */  
    137.     public <T> T loadObject(String key) {  
    138.         T object = null;  
    139.         try {  
    140.             object = memcachedClient.<T> get(key);  
    141.         } catch (Exception e) {  
    142.             logger.error(e.getMessage(), e);  
    143.         }  
    144.         logger.info("Load Object: [" + key + "]");  
    145.         return object;  
    146.     }  
    147.   
    148. }  

    PS:Redis的SETNX(即SET if Not eXists,类似于memcache的add)

    相关链接: 
    Memcached笔记——(一)安装&常规错误&监控 
    Memcached笔记——(二)XMemcached&Spring集成 
    Memcached笔记——(三)Memcached使用总结 

    Memcached笔记——(四)应对高并发攻击

    4 
    2 
    分享到:  
    评论
    8 楼 风吟想飞 2014-04-16  
    [size=medium]您好,我初次使用XMemcached ,现在有个项目的业务和您在“Memcached笔记——(四)应对高并发攻击”中的业务描述一样,我看了您的文章,但是因为基础薄落,没有很好的明白怎么进行冲突判定。想麻烦您讲解一下。谢谢。[/size]
    7 楼 di1984HIT 2014-04-14  
    说的非常好啊
    6 楼 snowolf 2014-02-26  
    richardor 写道
    那个超时一个月的常量,少乘7了

    好眼力
    5 楼 richardor 2014-02-25  
    那个超时一个月的常量,少乘7了
    4 楼 snowolf 2012-12-11  
    zym820910 写道
    snowolf 写道
    CurrentJ 写道
    先写Cache,然后写Database,断电或者故障会导致用户数据丢失。

    各有利弊,需要根据业务需求权衡。


    写得非常好!应对高并发的时候,我们通常的思维是泄洪模式,通过一道又一道的防洪大堤将洪水分流,尤其是在应对数据要求不严厉的SNS这类产品,异步的保存数据值得提倡!

    不过,更好的方式是:通过旁路式架构,解决代码层面的大部分压力。现在很多商城的商品展示和搜索都采用NOSQL技术来应对处理,异步增加或更新,并不显得那么重要了,更多的是通过产品和技术架构来调整,比如通过分析用户喜好,事先静态化搜索结果。

    赞同,感谢分享! 最核心的优化,还是应当在产品层面多下工夫。找到用户-产品-技术,三方都能满足的平衡点。
    3 楼 zym820910 2012-12-11  
    snowolf 写道
    CurrentJ 写道
    先写Cache,然后写Database,断电或者故障会导致用户数据丢失。

    各有利弊,需要根据业务需求权衡。


    写得非常好!应对高并发的时候,我们通常的思维是泄洪模式,通过一道又一道的防洪大堤将洪水分流,尤其是在应对数据要求不严厉的SNS这类产品,异步的保存数据值得提倡! 

    不过,更好的方式是:通过旁路式架构,解决代码层面的大部分压力。现在很多商城的商品展示和搜索都采用NOSQL技术来应对处理,异步增加或更新,并不显得那么重要了,更多的是通过产品和技术架构来调整,比如通过分析用户喜好,事先静态化搜索结果。
    2 楼 snowolf 2012-11-07  
    CurrentJ 写道
    先写Cache,然后写Database,断电或者故障会导致用户数据丢失。

    各有利弊,需要根据业务需求权衡。
    1 楼 CurrentJ 2012-11-07  
    先写Cache,然后写Database,断电或者故障会导致用户数据丢失。
  • 相关阅读:
    在jQuery EasyUI中实现对DataGrid进行编辑
    ASP生成指定范围随机数的公式
    DIV+CSS牛人也得看的15个CSS
    jQuery EasyUI Tabs关闭Tab时不能完全释放内存解决方法
    Easyui的DateBox日期格式化
    HTML语法大全
    DNN之模块建设PA包制作
    JavaScript精华收集典藏
    三层架构浅析
    welcome to my blog
  • 原文地址:https://www.cnblogs.com/fx2008/p/4114975.html
Copyright © 2011-2022 走看看