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

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

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

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

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

  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. 在mybatis框架中,延迟加载与连表查询的差异

    1.引子 mybatis的延迟加载,主要应用于一个实体类中有复杂数据类型的属性,包括一对一和一对多的关系(在xml中用collection.association标签标识).这个种属性往往还对应着另一 ...

  2. oracle学习(二)pl/sql基础

    pl/sql组成:DDL DML DCL pl/sql特点: SQL&PL/SQL编译器集成PL/SQL,支持SQL所有范围的语法 支持CASE语句和表达式 继承和动态方法释放 类型进化.属性 ...

  3. Graph & Trees3 - 二分图

    \[二分图略解\] \[By\;TYQ\] 二分图定义: \(f(i,L) = [a \in L\;\text{&}\;\forall b \in a.to \;\text{,}\; b \n ...

  4. 吴裕雄--天生自然 PYTHON3开发学习:数据库连接 - PyMySQL 驱动

    import pymysql # 打开数据库连接 db = pymysql.connect("localhost","testuser","test1 ...

  5. Docker相关学习地址

    菜鸟教程:http://www.runoob.com/docker/docker-image-usage.html 官方文档:https://docs.docker.com/

  6. IMX6开发板Qtopia2.2.0开发环境搭建以及编译镜像

    搭建 Qtopia2.2.0 开发环境,需要先搭建 Android 的编译环境,然后在 Android 编译环境的基础上,再搭建 Qtopia2.2.0 编译环境.以下内容基于迅为-iMX6开发板.Q ...

  7. 三、linux-mysql mysql的多实例

    1.什么是mysql多实例 一个机器开通多个端口,运行多个mysql服务器进程,这些服务进程通过不同的socket监听不同的服务端口提供各自的服务,但它们共用一台mysql安装程序,使用不同的my.c ...

  8. LeetCode No.121,122,123

    No.121 MaxProfit 买卖股票的最佳时机 题目 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你 ...

  9. PAT甲级——1012 The Best Rank

    PATA1012 The Best Rank To evaluate the performance of our first year CS majored students, we conside ...

  10. vue实现动态绑定class--多个按钮点击一个有一个

    <template> //v-for循环出来多个按钮,便于获取index         <span v-for="(item,index) in list" : ...