Memcached笔记——(四)应对高并发攻击
近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源。他们的最好成绩,1秒钟可以并发6次,赶在Database入库前,Cache进行Missing Loading前,强占这其中十几毫秒的时间,进行恶意攻击。
相关链接:
Memcached笔记——(一)安装&常规错误&监控
Memcached笔记——(二)XMemcached&Spring集成
Memcached笔记——(三)Memcached使用总结
为了应对上述情况,做了如下调整:
- 更新数据时,先写Cache,然后写Database,如果可以,写操作交给队列后续完成。
- 限制统一帐号,同一动作,同一秒钟并发次数,超过1次不做做动作,返回操作失败。
- 限制统一用户,每日动作次数,超限返回操作失败。
要完成上述操作,同事给我支招。用Memcached的add方法,就可以很快速的解决问题。不需要很繁琐的开发,也不需要依赖数据库记录,完全内存操作。![]()
以下实现一个判定冲突的方法:
- /**
- * 冲突延时 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;
- }
/**
* 冲突延时 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实现:
- 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;
- }
- }
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笔记——(四)应对高并发攻击【转】
http://snowolf.iteye.com/blog/1677495 近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最 ...
- Memcached理解笔记4---应对高并发攻击
近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最好成绩,1秒钟可以并发6次,赶在Database入库前,Cache进行Mis ...
- 《即时消息技术剖析与实战》学习笔记10——IM系统如何应对高并发
一.IM 系统的高并发场景 IM 系统中,高并发多见于直播互动场景.比如直播间,在直播过程中,观众会给主播打赏.送礼.发送弹幕等,尤其是明星直播间,几十万.上百万人的规模一点也不稀奇.近期随着武汉新型 ...
- SpringCloud应对高并发的思路
一.Eureka的高可用性 Eureka下面的服务实例默认每隔30秒会发送一个HTTP心跳给Eureka,来告诉Eureka服务还活着,每个服务实例每隔30秒也会通过HTTP请求向Eureka获取服务 ...
- 【Redis】1、Jedis对管道、事务以及Watch的操作来应对高并发
对于一个互联网平台来说,高并发是经常会遇到的场景.最有代表性的比如秒杀和抢购.高并发会出现三个特点: 1.高并发读取 2.高并发写入(一致性) 3.出现超卖问题 前端如何应对? 1.缓存静态数据,例如 ...
- java高并发编程(四)高并发的一些容器
摘抄自马士兵java并发视频课程: 一.需求背景: 有N张火车票,每张票都有一个编号,同时有10个窗口对外售票, 请写一个模拟程序. 分析下面的程序可能会产生哪些问题?重复销售?超量销售? /** * ...
- Nginx优化配置,轻松应对高并发
Nginx现在已经是最火的web服务器之一,尤其在静态分离和负载均衡方面,性能十分优越.接下来我们主要看下Nginx在高并发环境下的优化配置,主要是针对 nginx.conf 文件的属性设置.我们打开 ...
- 基于tomcat为了应对高并发模型实现webserver
在博客上,一个简单的AIOweb来样加工.查看AIO异步处理,依靠操作系统完成IO操作Proactor处理模型确实很强大,它可以实现高并发.高响应server一个很好的选择,但在tomcat中间con ...
- Linux下配置tomcat+apr+native应对高并发
摘要:在慢速网络上Tomcat线程数开到300以上的水平,不配APR,基本上300个线程狠快就会用满,以后的请求就只好等待.但是配上APR之后,Tomcat将以JNI的形式调用Apache HTTP服 ...
随机推荐
- Codeforces 1288D - Minimax Problem
题目大意: 给定n个序列,每个序列元素个数严格相等于m 你需要找到两个序列a[i]和a[j],使其每个对应位置的元素取大后得到b序列 b[k]=max(a[i][k],a[j][k]) 且让b序列中 ...
- 用FFmpeg+nginx+rtmp搭建环境实现推流
Windows: 1.下载文件: 链接:https://pan.baidu.com/s/1c2LmIHHw-dwLOlRN6iTIMg 提取码:g7sj 2.解压文件: 解压到nginx-1.7.11 ...
- 计量经济与时间序列_自协方差(AutoCovariance)算法解析(Python)
1 样本的自协方差函数的通式如下: 2 其实,后面要计算的自相关函数也可以用自协方差来表示: # @author: "Thomas.Shih" # @date: 2018/3/5 ...
- Python实现自动处理表格,让你拥有更多的自由时间!
相信有不少朋友日常工作会用到 Excel 处理各式表格文件,更有甚者可能要花大把时间来做繁琐耗时的表格整理工作.最近有朋友问可否编程来减轻表格整理工作量,今儿我们就通过实例来实现 Python 对表格 ...
- Java8必知必会
Java SE 8添加了2个对集合数据进行批量操作的包: java.util.function 包以及 java.util.stream 包. 流(stream)就如同迭代器(iterator),但附 ...
- 深度学习数据集MNIST ImageNet COCO PASCAL VOC介绍
参考文档 深度学习数据集汇总介绍 1. MNIST 深度学习领域的“Hello World!”,入门必备!MNIST是一个手写数字数据库,它有60000个训练样本集和10000个测试样本集,每个样本 ...
- Zabbix常用监控项整理
zabbix常用key:http://blog.51cto.com/ttxsgoto/1771752 linux主机cpu使用率超过90%的时候报警:https://blog.csdn.net/reb ...
- Java--类以及对象
什么是类 就是将一类事物的相同的本质特性抽象出来,类具有属性和方法,属性就是特征(具有什么),方法就是行为(能做什么). 类是一种引用的数据类型,类创建的对象的过程叫做实例化 什么是对象 对象就是类中 ...
- 26)PHP,数据库表格中项的数据类型
类型展示: tinyint-----1个字节 smallint----2个字节 mediumint--3个字节 int------4个字节 bigint---8个字节 字符串类型 最基本最重要的2个: ...
- EX_KMP算法总结
EX_KMP算法总结 By viv 2014-8-9 0:30 吐槽1:字符串神马的我最讨厌了,但不学不行啊.TAT 吐槽2:写这东西差点错过CF(codeforces). 今天学了ex_kmp,故总 ...