如何搞定高并发攻击java代码

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

 

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

 

  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. [email protected]
  13.  */
  14. public boolean isMutex(String key) {
  15.     return isMutex(key, MUTEX_EXP);
  16. }
  17. /**
  18.  * 冲突判定
  19.  *
  20. [email protected]
  21. [email protected]
  22. [email protected]
  23.  */
  24. public boolean isMutex(String key, int exp) {
  25.     boolean status = true;
  26.     try {
  27.         if (memcachedClient.add(MUTEX_KEY_PREFIX + key, exp, “true”)) {
  28.             status = false;
  29.         }
  30.     } catch (Exception e) {
  31.         logger.error(e.getMessage(), e);
  32.     }
  33.     return status;
  34. }

 

做个说明:

 

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

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

 

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

 

附我用到的基于XMemcached实现:

 

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

Tagged: , ,

Comments are closed.