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笔记——(四)应对高并发攻击

  • 相关阅读:
    VScode 修改中文字体
    missing KW_END at ')' near '<EOF>'
    SQL inner join, join, left join, right join, full outer join
    SQL字符替换函数translater, replace
    SQL COOKBOOK SQL经典实例代码 笔记第一章代码
    sqlcook sql经典实例 emp dept 创建语句
    dateutil 2.5.0 is the minimum required version python
    安装postgresql后找不到服务 postgresql service
    Postgres psql: 致命错误: 角色 "postgres" 不存在
    【西北师大-2108Java】第十六次作业成绩汇总
  • 原文地址:https://www.cnblogs.com/yangkai-cn/p/4016754.html
Copyright © 2011-2022 走看看