http://snowolf.iteye.com/blog/1677495

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

PS:Redis的SETNX(即SET if Not eXists,类似于memcache的add)

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

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

4 
2 
分享到:  
评论
8 楼 风吟想飞 2014-04-16  
[size=medium]您好,我初次使用XMemcached ,现在有个项目的业务和您在“Memcached笔记——(四)应对高并发攻击”中的业务描述一样,我看了您的文章,但是因为基础薄落,没有很好的明白怎么进行冲突判定。想麻烦您讲解一下。谢谢。[/size]
7 楼 di1984HIT 2014-04-14  
说的非常好啊
6 楼 snowolf 2014-02-26  
richardor 写道
那个超时一个月的常量,少乘7了

好眼力

5 楼 richardor 2014-02-25  
那个超时一个月的常量,少乘7了
4 楼 snowolf 2012-12-11  
zym820910 写道
snowolf 写道
CurrentJ 写道
先写Cache,然后写Database,断电或者故障会导致用户数据丢失。

各有利弊,需要根据业务需求权衡。

写得非常好!应对高并发的时候,我们通常的思维是泄洪模式,通过一道又一道的防洪大堤将洪水分流,尤其是在应对数据要求不严厉的SNS这类产品,异步的保存数据值得提倡!

不过,更好的方式是:通过旁路式架构,解决代码层面的大部分压力。现在很多商城的商品展示和搜索都采用NOSQL技术来应对处理,异步增加或更新,并不显得那么重要了,更多的是通过产品和技术架构来调整,比如通过分析用户喜好,事先静态化搜索结果。

赞同,感谢分享! 最核心的优化,还是应当在产品层面多下工夫。找到用户-产品-技术,三方都能满足的平衡点。

3 楼 zym820910 2012-12-11  
snowolf 写道
CurrentJ 写道
先写Cache,然后写Database,断电或者故障会导致用户数据丢失。

各有利弊,需要根据业务需求权衡。

写得非常好!应对高并发的时候,我们通常的思维是泄洪模式,通过一道又一道的防洪大堤将洪水分流,尤其是在应对数据要求不严厉的SNS这类产品,异步的保存数据值得提倡!

不过,更好的方式是:通过旁路式架构,解决代码层面的大部分压力。现在很多商城的商品展示和搜索都采用NOSQL技术来应对处理,异步增加或更新,并不显得那么重要了,更多的是通过产品和技术架构来调整,比如通过分析用户喜好,事先静态化搜索结果。

2 楼 snowolf 2012-11-07  
CurrentJ 写道
先写Cache,然后写Database,断电或者故障会导致用户数据丢失。

各有利弊,需要根据业务需求权衡。

1 楼 CurrentJ 2012-11-07  
先写Cache,然后写Database,断电或者故障会导致用户数据丢失。

Memcached笔记——(四)应对高并发攻击【转】的更多相关文章

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

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

  2. Memcached理解笔记4---应对高并发攻击

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

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

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

  4. SpringCloud应对高并发的思路

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

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

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

  6. java高并发编程(四)高并发的一些容器

    摘抄自马士兵java并发视频课程: 一.需求背景: 有N张火车票,每张票都有一个编号,同时有10个窗口对外售票, 请写一个模拟程序. 分析下面的程序可能会产生哪些问题?重复销售?超量销售? /** * ...

  7. Nginx优化配置,轻松应对高并发

    Nginx现在已经是最火的web服务器之一,尤其在静态分离和负载均衡方面,性能十分优越.接下来我们主要看下Nginx在高并发环境下的优化配置,主要是针对 nginx.conf 文件的属性设置.我们打开 ...

  8. 基于tomcat为了应对高并发模型实现webserver

    在博客上,一个简单的AIOweb来样加工.查看AIO异步处理,依靠操作系统完成IO操作Proactor处理模型确实很强大,它可以实现高并发.高响应server一个很好的选择,但在tomcat中间con ...

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

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

随机推荐

  1. BZOJ 1668: [Usaco2006 Oct]Cow Pie Treasures 馅饼里的财富

    Description 最近,奶牛们热衷于把金币包在面粉里,然后把它们烤成馅饼.第i块馅饼中含有Ni(1<=Ni<=25)块金币,并且,这个数字被醒目地标记在馅饼表面. 奶牛们把所有烤好的 ...

  2. Java ,单实例 多线程 ,web容器,servlet与struts1-2.x系列,线程安全的解决

    1.Servlet是如何处理多个请求同时访问呢? 回答:servlet是默认采用单实例,多线程的方式进行.只要webapp被发布到web容器中的时候,servlet只会在发布的时候实例化一次,serv ...

  3. 【技术帖】解决 Hudson jenkins 连接等待中 - Waiting for next av

    今天构建项目发现如下问题: jenkins 连接等待中 - Waiting for next available executor 左下角那块一直不运行构建,一直在连接等待. 于是,进入一级页面, 右 ...

  4. hdu 4764 && 2013长春网赛题解

    一个组合游戏题. 解答: 从后面往前面推,首先n-1是必胜位,然后前面的k位是必败位,如此循环下去.所以题目就容易了! 代码: #include<cstdio> using namespa ...

  5. 【HDOJ】2732 Leapin' Lizards

    贪心+网络流.对于每个结点,构建入点和出点.对于每一个lizard>0,构建边s->in position of lizard, 容量为1.对于pillar>0, 构建边in pos ...

  6. dom4j修改xml文件

    @SuppressWarnings("unchecked") @Override public void insertCustomInfo(File file, String mo ...

  7. POJ_2104_Kth_(主席树)

    描述 http://poj.org/problem?id=2104 给出一个n个数的数列,m次询问,每次询问求区间[l,r]中第k小的数,无修改操作. K-th Number Time Limit: ...

  8. 在Windows Azure公有云环境部署企业应用

    作者 王枫 发布于 2014年4月5日 企业内部应用转换为在线服务 Windows Azure已经成为众多IT服务提供商们热议的话题,其中,有的认为只有提供互连网用户服务的应用才适合放在公有云环境内运 ...

  9. 应用程序域 z

    应用程序域(AppDomain)已经不是一个新名词了,只要熟悉.net的都知道它的存在,不过我们还是先一起来重新认识下应用程序域吧,究竟它是何方神圣. 应用程序域 众所周知,进程是代码执行和资源分配的 ...

  10. Python生成器 yield

    迭代器与list相比较,就for in句型循环拿数据而言: 用list写很简洁,但如果list数据过大,会很消耗资源. 用iteration 迭代器写,则不会消耗那么多资源.他会随用随取,用一个拿一个 ...