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

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

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

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

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

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

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

  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. }

做个说明:

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

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

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

附我用到的基于XMemcached实现:

  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 * 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. @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. }

转载地址:http://snowolf.iteye.com/blog/1677495

Memcached理解笔记4---应对高并发攻击的更多相关文章

  1. Memcached笔记——(四)应对高并发攻击【转】

    http://snowolf.iteye.com/blog/1677495 近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最 ...

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

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

  3. Memcached理解笔记3---Memcached使用总结

    为了将N个前端数据同步,通过Memcached完成数据打通,但带来了一些新问题: 使用iBatis整合了Memcached,iBatis针对每台server生成了唯一标识,导致同一份数据sql会产生不 ...

  4. 《即时消息技术剖析与实战》学习笔记10——IM系统如何应对高并发

    一.IM 系统的高并发场景 IM 系统中,高并发多见于直播互动场景.比如直播间,在直播过程中,观众会给主播打赏.送礼.发送弹幕等,尤其是明星直播间,几十万.上百万人的规模一点也不稀奇.近期随着武汉新型 ...

  5. SpringCloud应对高并发的思路

    一.Eureka的高可用性 Eureka下面的服务实例默认每隔30秒会发送一个HTTP心跳给Eureka,来告诉Eureka服务还活着,每个服务实例每隔30秒也会通过HTTP请求向Eureka获取服务 ...

  6. 应对Memcached缓存失效,导致高并发查询DB的四种思路(l转)

    当Memcached缓存失效时,容易出现高并发的查询DB,导致DB压力骤然上升. 这篇blog主要是探讨如何在缓存将要失效时,及时地更新缓存,而不是如何在缓存失效之后,如何防止高并发的DB查询. 解决 ...

  7. 应对Memcached缓存失效,导致高并发查询DB的几种思路

    原文地址: http://blog.csdn.net/hengyunabc/article/details/20735701 当Memcached缓存失效时,容易出现高并发的查询DB,导致DB压力骤然 ...

  8. 【Redis】1、Jedis对管道、事务以及Watch的操作来应对高并发

    对于一个互联网平台来说,高并发是经常会遇到的场景.最有代表性的比如秒杀和抢购.高并发会出现三个特点: 1.高并发读取 2.高并发写入(一致性) 3.出现超卖问题 前端如何应对? 1.缓存静态数据,例如 ...

  9. Linux下配置tomcat+apr+native应对高并发

    摘要:在慢速网络上Tomcat线程数开到300以上的水平,不配APR,基本上300个线程狠快就会用满,以后的请求就只好等待.但是配上APR之后,Tomcat将以JNI的形式调用Apache HTTP服 ...

随机推荐

  1. java细节问题

    保留两位小数:1.234, 1.23, 1.2, 1.0, 1. package test; import java.math.BigDecimal; import java.text.Decimal ...

  2. (原创)Hibernate 使用过程中(尤其是多对多关联中的级联保存和级联删除)的注意事项(基于项目的总结)

    一.先上知识点: 1.hibernate多对多关联关系中最重要的参数是(基于配置文件xxx.hbm.xml文件形式): 1):inverse属性,如果设置inverse=“true”就代表让对方参与维 ...

  3. 集合(一)ArrayList

    前言 这个分类中,将会写写Java中的集合.集合是Java中非常重要而且基础的内容,因为任何数据必不可少的就是该数据是如何存储的,集合的作用就是以一定的方式组织.存储数据.这里写的集合,一部分是比较常 ...

  4. java 集合stream操作

    分组 Map<Integer, List<T>> group = List.stream().collect(Collectors.groupingBy(T::getField ...

  5. DataAnnotations 验证

    转自:http://blog.sina.com.cn/s/blog_c21a857b0102wcus.html 常用的 DataAnnotations 1.Required :属性值必须非空或者不能只 ...

  6. Http请求基本方法

    1.Http请求基本方法 /// <summary> /// Http请求基本方法 /// </summary> /// <param name="conten ...

  7. Unity运行时保存prefab的方法一则

    unity编辑器在运行状态时,prefab的apply按钮就消失了,其实此时代码访问的话是有效的. 代码如下,将会给transform的右键增加一个save prefab的选项. using Unit ...

  8. jzoj4424

    20%:暴力枚舉每一條邊有沒有被選到,然後使用并查集判斷聯通性 這樣子有20分,但是我考試寫掛了所以1分也沒有 100%:這道題2000的數據範圍,使用指數級搜索會tle,需要更加好的方法 這道題中, ...

  9. jQuery基础笔记(4)

    day55 参考:https://www.cnblogs.com/liwenzhou/p/8178806.html#autoid-1-9-3 文本操作 HTML代码: html()// 取得第一个匹配 ...

  10. 程序猿的日常——JVM内存模型与垃圾回收

    Java开发有个很基础的问题,虽然我们平时接触的不多,但是了解它却成为Java开发的必备基础--这就是JVM.在C++中我们需要手动申请内存然后释放内存,否则就会出现对象已经不再使用内存却仍被占用的情 ...