近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源。他们的最好成绩,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. What is Pay Me to Learn——Google Summer of Code 2013

    原文链接:http://zhchbin.github.io/2013/10/17/what-is-pay-me-to-learn/ 背景 今天早上才想起来,自己还欠着一件事情没有做完.很久在人人上之前 ...

  2. alpha七天冲刺计划(更新ing)

    alpha七天冲刺计划 第一天: http://note.youdao.com/noteshare?id=ff0c24feec21b1d74a176a0d88815933 第二天: http://no ...

  3. [Zend Mail]发送中文名附件出现乱码解决方案

    Zend Framework 1.0.* “=?UTF-8?B?”.base64_encode($title).“?=” 发送中文名附件,结果如图: 英文名附件,结果截图: 解决办法就是将中文文件名拼 ...

  4. 拷贝构造函数——防篡改

    对于普通类型的对象来说,他们之间的复制是简单的,比如: int a = 88; int b = a; 而类和普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量. #include <io ...

  5. 使用回调方式写POI导入excel工具类

    场景是这样的:为了做一个excel导入的功能,为了尽可能的写一个通用的工具类,将与poi有关的东西都封装起来,以便以其他人员只用关心自己的业务,不用和poi打交道. 写到最后,现在还是会有poi的东西 ...

  6. Asp.net MVC + Redis(Linux安装Redis)

    最近有幸在工作中用到了redis,玩的还算开心.但是发现Redis在Windows上并不是满血状态的,所以决定安装一个Linux的虚拟机,让Redis在Linux上运行. 虚拟环境 虚拟机,我已经玩了 ...

  7. 从 exe.config 读取appSettings 中的配置数据

    右键解决方案,添加引用--> System.Configuration.dll 在exe.config 中添加数据 <appSettings> <add key=" ...

  8. 在sqlite中,如何删除字段? how to drop a column in sqlite

    在sqlite中可以使用ALTER TABLE语法对表结构进行修改,从官方的文档说明中,语法如下图: 从图中可以看出,ALTER TABLE仅仅支持表名重命名,添加字段,却没有删除字段的方法.那么该如 ...

  9. Day 26封装

    一.封装 广义上的封装: 属于一个类的静态和动态属性,总是出现在一个类中. 使用的永远用类名或者对象名调用. 狭义上的封装:就是把变量和方法私有化,在类的外部以及子类中不能直接使用了 . class ...

  10. 二,mysql优化——sql优化基本概念

    1,SQL优化的一般步骤 (1)通过show status命令了解各种SQL执行效率. (2)通过执行效率较低的SQL语句(重点select). (3)通过explain分析低效率的SQL语句的执行情 ...