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

    近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源。他们的最好成绩,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. * @param key
    13. */
    14. public boolean isMutex(String key) {
    15. return isMutex(key, MUTEX_EXP);
    16. }
    17. /**
    18. * 冲突判定
    19. *
    20. * @param key
    21. * @param exp
    22. * @return true 冲突
    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. }
    	/**
    	 * 冲突延时 1秒
    	 */
    	public static final int MUTEX_EXP = 1;
    	/**
    	 * 冲突键
    	 */
    	public static final String MUTEX_KEY_PREFIX = "MUTEX_";
    
    	/**
    	 * 冲突判定
    	 * 
    	 * @param key
    	 */
    	public boolean isMutex(String key) {
    		return isMutex(key, MUTEX_EXP);
    	}
    
    	/**
    	 * 冲突判定
    	 * 
    	 * @param key
    	 * @param exp
    	 * @return true 冲突
    	 */
    	public boolean isMutex(String key, int exp) {
    		boolean status = true;
    		try {
    			if (memcachedClient.add(MUTEX_KEY_PREFIX + key, exp, "true")) {
    				status = false;
    			}
    		} catch (Exception e) {
    			logger.error(e.getMessage(), e);
    		}
    		return status;
    	}

    做个说明:

    选项 说明
    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. * @author Snowolf
    8. * @version 1.0
    9. * @since 1.0
    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;
    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. @Autowired
    46. private MemcachedClient memcachedClient;
    47. /**
    48. * 缓存
    49. *
    50. * @param key
    51. * @param value
    52. * @param exp
    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. * @param key
    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. * @param key
    95. */
    96. public boolean isMutex(String key) {
    97. return isMutex(key, MUTEX_EXP);
    98. }
    99. /**
    100. * 冲突判定
    101. *
    102. * @param key
    103. * @param exp
    104. * @return true 冲突
    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. * @param key
    121. * @return
    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. }
    import net.rubyeye.xmemcached.MemcachedClient;
    
    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    /**
     * 
     * @author Snowolf
     * @version 1.0
     * @since 1.0
     */
    @Component
    public class MemcachedManager {
    
    	/**
    	 * 缓存时效 1天
    	 */
    	public static final int CACHE_EXP_DAY = 3600 * 24;
    
    	/**
    	 * 缓存时效 1周
    	 */
    	public static final int CACHE_EXP_WEEK = 3600 * 24 * 7;
    
    	/**
    	 * 缓存时效 1月
    	 */
    	public static final int CACHE_EXP_MONTH = 3600 * 24 * 30;
    
    	/**
    	 * 缓存时效 永久
    	 */
    	public static final int CACHE_EXP_FOREVER = 0;
    
    	/**
    	 * 冲突延时 1秒
    	 */
    	public static final int MUTEX_EXP = 1;
    	/**
    	 * 冲突键
    	 */
    	public static final String MUTEX_KEY_PREFIX = "MUTEX_";
    	/**
    	 * Logger for this class
    	 */
    	private static final Logger logger = Logger
    			.getLogger(MemcachedManager.class);
    
    	/**
    	 * Memcached Client
    	 */
    	@Autowired
    	private MemcachedClient memcachedClient;
    
    	/**
    	 * 缓存
    	 * 
    	 * @param key
    	 * @param value
    	 * @param exp
    	 *            失效时间
    	 */
    	public void cacheObject(String key, Object value, int exp) {
    		try {
    			memcachedClient.set(key, exp, value);
    		} catch (Exception e) {
    			logger.error(e.getMessage(), e);
    		}
    		logger.info("Cache Object: [" + key + "]");
    	}
    
    	/**
    	 * Shut down the Memcached Cilent.
    	 */
    	public void finalize() {
    		if (memcachedClient != null) {
    			try {
    				if (!memcachedClient.isShutdown()) {
    					memcachedClient.shutdown();
    					logger.debug("Shutdown MemcachedManager...");
    				}
    			} catch (Exception e) {
    				logger.error(e.getMessage(), e);
    			}
    		}
    	}
    
    	/**
    	 * 清理对象
    	 * 
    	 * @param key
    	 */
    	public void flushObject(String key) {
    		try {
    			memcachedClient.deleteWithNoReply(key);
    		} catch (Exception e) {
    			logger.error(e.getMessage(), e);
    		}
    		logger.info("Flush Object: [" + key + "]");
    	}
    
    	/**
    	 * 冲突判定
    	 * 
    	 * @param key
    	 */
    	public boolean isMutex(String key) {
    		return isMutex(key, MUTEX_EXP);
    	}
    
    	/**
    	 * 冲突判定
    	 * 
    	 * @param key
    	 * @param exp
    	 * @return true 冲突
    	 */
    	public boolean isMutex(String key, int exp) {
    		boolean status = true;
    		try {
    			if (memcachedClient.add(MUTEX_KEY_PREFIX + key, exp, "true")) {
    				status = false;
    			}
    		} catch (Exception e) {
    			logger.error(e.getMessage(), e);
    		}
    		return status;
    	}
    
    	/**
    	 * 加载缓存对象
    	 * 
    	 * @param key
    	 * @return
    	 */
    	public <T> T loadObject(String key) {
    		T object = null;
    		try {
    			object = memcachedClient.<T> get(key);
    		} catch (Exception e) {
    			logger.error(e.getMessage(), e);
    		}
    		logger.info("Load Object: [" + key + "]");
    		return object;
    	}
    
    }

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

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

  • 相关阅读:
    POJ-1330 Nearest Common Ancestors(倍增的LCA)
    POJ-1442 Black Box(手写堆优化)
    POJ-2442 Sequence(手写堆优化)
    BZOJ2506 calc
    BZOJ3396 [Usaco2009 Jan]Total flow 水流
    BZOJ3570 DZY Loves Physics I
    BZOJ1101 [POI2007]Zap
    BZOJ1110 [POI2007]砝码Odw
    BZOJ1555 KD之死
    BZOJ3476 [Usaco2014 Mar]The Lazy Cow
  • 原文地址:https://www.cnblogs.com/yangkai-cn/p/4016754.html
Copyright © 2011-2022 走看看