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使用總結
相關文章
- 高併發設計筆記筆記
- EF Code 如何應對高併發
- 《筆記》之學習高併發筆記
- Laravel 高併發調優筆記Laravel筆記
- 高併發設計筆記(續篇)筆記
- Java併發程式設計實戰--筆記四Java程式設計筆記
- 勒索病毒攻擊事件頻發,企業上雲應如何應對事件
- 高併發秒殺專案隨手筆記筆記
- Memcached筆記——(三)Memcached使用總結筆記
- 自適應安全策略對於阻止高階攻擊至關重要
- 攻擊面分析及應對實踐
- 預防SQL隱碼攻擊筆記SQL筆記
- (四)Java高併發秒殺API之高併發優化JavaAPI優化
- 瞭解cc攻擊才能對應解決
- CC攻擊的原理和應對的策略
- Java 併發程式設計實踐 讀書筆記四Java程式設計筆記
- 應對高併發,伺服器如何笑而不“崩”伺服器
- 怎麼發現植入式攻擊入侵併解決
- 一種有效應對側通道記憶體攻擊的新方法記憶體
- 網路攻擊盯上民生領域,應對DDoS和APT攻擊,如何有效防禦?APT
- FireEye遭APT攻擊?!針對企業的APT攻擊是如何發生的?APT
- 幾種常見的DDOS攻擊應對策略
- 醫療行業如何應對網路攻擊?行業
- DNS攻擊型別及應對措施大盤點DNS型別
- Go 筆記之併發Go筆記
- WCF筆記–併發管理筆記
- SSM框架實現高併發秒殺API學習筆記SSM框架API筆記
- [分散式][高併發]限流的四種策略分散式
- 攻擊JavaWeb應用[3]-SQL隱碼攻擊[1]JavaWebSQL
- 攻擊JavaWeb應用[4]-SQL隱碼攻擊[2]JavaWebSQL
- 針對 VoIP 伺服器發動 DDoS 攻擊伺服器
- memcached 原始碼閱讀筆記原始碼筆記
- 天懋資訊談“豐田網路攻擊事件”應對事件
- 印度藉助企業力量應對網路攻擊
- Go高階併發 09 | 同步原語:sync 包讓你對併發控制得心應手Go
- 雲解析DNS如何有效應對頻發的DDoS攻擊?(中科三方)DNS
- JUC併發程式設計學習筆記(四)8鎖現象程式設計筆記
- 全球最大肉類供應商JBS遭駭客攻擊!企業如何應對日益頻繁的網路攻擊?