大量并發(fā)的應急解決方案與實踐 收藏 此文于2010-05-26被推薦到CSDN首頁
如何被推薦?
往往我們會遇到這樣的問題,以前一直運行良好的系統(tǒng)由于突然遇到大量并發(fā)訪問而崩潰,這時你的客戶和老板全都急上了房。情況緊急重新改造系統(tǒng)架構非常困難需要時間。這時你非常后悔,如果當時采用分布式架構那么現(xiàn)在只要水平增加應用或數(shù)據(jù)服務器就好了,所有現(xiàn)存數(shù)據(jù)和應用也不會受到任何影響。關于系統(tǒng)架構可參考我的另一篇文章:《開餐館與做軟件——如何提高大型網(wǎng)站性能》
http://blog.csdn.net/Dreamcode/archive/2009/09/10/4540153.aspx 現(xiàn)在我們只好采用一些應急的解決方案。 舉例來說,一個房間只能容納500人,現(xiàn)在突然來了1000人這時我們該怎么辦?
辦法有兩個:一是增加房間面積,這個辦法如同水平增加應用或數(shù)據(jù)服務器,需要對架構進行重新設計,因此將涉及很多問題,或許并不比重新造省時間。另一個辦法就是讓客人排隊,當屋里有人出去,再讓別人進來,即異步處理。
異步處理,當資源不足的情況下對已經(jīng)到來的訪問請求并不馬上處理而是讓這些請求排隊等候,直到有可用的資源再進行處理。這種辦法的代價就是時間,不能及時返回處理結果。但是當我們沒有條件改造房屋的時候這是唯一的辦法。
現(xiàn)在有個問題,我們讓客人在哪里排隊,大廳(硬盤)還是門口(內(nèi)存)。答案似乎很明顯,哪里離房間近最好就在哪里等,但是,速度快的地方往往空間不富裕。將用戶請求以某種方式先保存在硬盤上是一種比較常用的方法,當然也因此多了一步將數(shù)據(jù)加載到內(nèi)存地過程。
在內(nèi)存中將數(shù)據(jù)排隊的方法,可使用數(shù)組,哈希表,鏈表等數(shù)據(jù)結構,也可使用消息隊列等現(xiàn)成的組件如ActiveMQ 。如我們使用一個單例模式的Map 對象,保存來自多個并發(fā)的請求。
import java.util.Map;
public class TestMap {
private volatile static TestMap singleton=null;
private static Map testmap = null;
private TestMap(){}
public static TestMap getInstance()
{
if(singleton==null){
synchronized(TestMap.class)
{
singleton=new TestMap();
}
}
return singleton;
}
public Map getTestmap() {
return testmap;
}
public void setTestmap(Map testmap) {
TestMap.testmap = testmap;
}
}
在硬盤中排隊,就是將數(shù)據(jù)直接寫到硬盤里,例如在Java 中可將對象直接保存到硬盤中,代碼如下:
public static boolean writeObject(String filePath, Object entity)
{
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filePath);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
ObjectOutputStream oos;
try {
oos = new ObjectOutputStream(fos);
oos.writeObject(entity);
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
return true;
}
public static Object readObject(String filePath)
{
Object entity = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(filePath);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ObjectInputStream ois;
try {
ois = new ObjectInputStream(fis);
try {
entity = ois.readObject();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return entity;
}
最后我們需要一個監(jiān)控模塊(如一個線程)進行調(diào)度, 例如:
public class testThread implements Runnable{
private static long interval = 3000; //循環(huán)間隔
@Override
public void run(){
while(true)
{
... //這里是需要執(zhí)行的代碼
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}