COSCon'19 | 如何設計新一代的圖數(shù)據(jù)庫 Nebula
1003
2025-04-02
Zookeeper 是一個高可用的分布式數(shù)據(jù)管理與協(xié)調框架,基于ZAB協(xié)議算法的實現(xiàn),該框架能夠很好的保證分布式環(huán)境中數(shù)據(jù)的一致性。Zookeeper的典型應用場景主要有:數(shù)據(jù)發(fā)布/訂閱、負載均衡、命名服務、分布式協(xié)調/通知、集群管理、Master選舉、分布式鎖和分布式隊列等。
本文主要介紹如何利用Zookeeper實現(xiàn)Master選舉。
Master選舉
Master選舉在分布式系統(tǒng)中是一個非常常見的場景。在分布式系統(tǒng)中,常常采用主從模式的方式避免單點故障,提高系統(tǒng)服務的可用性。正常情況下,Master節(jié)點用來協(xié)調集群中其他系統(tǒng)單元,維護系統(tǒng)狀態(tài)信息,或者負責一些復雜的邏輯,再將處理結果同步給其他節(jié)點。當Master節(jié)點宕機,或者由于其他問題導致無法提供服務時,系統(tǒng)將發(fā)起一次Master選舉,從候選節(jié)點中選出一個新的Master節(jié)點,以繼續(xù)提供服務。
譬如在一些讀寫分離的應用中,Master節(jié)點負責客戶端的寫請求,處理完畢之后再將結果同步給從節(jié)點。
選舉算法?
著名的選舉算法有 Paxos算法、Raft算法、Bully算法等,但在業(yè)務系統(tǒng)的開發(fā)中,實現(xiàn)選舉算法并不是我們工作的重心。
Zookeeper有一個非常重要的特性即強一致性,能夠很好地保證在分布式高并發(fā)情況下節(jié)點的創(chuàng)建一定能夠保證全局唯一性,即Zookeeper將會保證客戶端無法重復創(chuàng)建一個已經(jīng)存在的數(shù)據(jù)節(jié)點。也就是說,如果同時有多個客戶端請求創(chuàng)建同一個節(jié)點,那么最終一定只有一個客戶端請求能夠創(chuàng)建成功。利用這個特性,就能很容易地在分布式環(huán)境中進行Master選舉了。
利用Zookeeper實現(xiàn)Master選舉
Apache Curator是一個Zookeeper的開源客戶端,它提供了Zookeeper各種應用場景(Recipe,如共享鎖服務、master選舉、分布式計數(shù)器等)的抽象封裝,本文使用 Curator 提供的Recipe來實現(xiàn)Master選舉。
Curator提供了兩種選舉方案:Leader Latch 和 Leader Election。下面分別介紹這兩種選舉方案。
Leader Latch
使用 Leader Latch 方案進行Master選舉,系統(tǒng)將隨機從候選者中選出一臺作為 leader,直到調用 close() 釋放leadship,此時再重新隨機選舉 leader,否則其他的候選者無法成為 leader。
下面的程序將啟動 N 個線程用來模擬分布式系統(tǒng)中的節(jié)點,每個線程將創(chuàng)建一個Zookeeper客戶端和一個 LeaderLatch 對象用于選舉;每個線程有一個名稱,名稱中有一個編號用于區(qū)分;每個線程的存活時間為 number * 10秒 ,存活時間結束后將關閉 LeaderLatch 對象和客戶端,表示該 '節(jié)點' 宕機,如果該節(jié)點為 Master節(jié)點,這時系統(tǒng)將重新發(fā)起 Master選舉。
public?class?LeaderLatchTest?{
private?static?final?String?zkServerIps?=?"master:2181,hadoop2:2181";
private?static?final?String?masterPath?=?"/testZK/leader_latch";
public?static?void?main(String[]?args)?{
final?int?clientNums?=?5;??//?客戶端數(shù)量,用于模擬
final?CountDownLatch?countDownLatch?=?new?CountDownLatch(clientNums);
List
List
AtomicInteger?atomicInteger?=?new?AtomicInteger(1);
try?{
for?(int?i?=?0;?i?
new?Thread(new?Runnable()?{
@Override
public?void?run()?{
CuratorFramework?client?=?getClient();??//?創(chuàng)建客戶端
clientList.add(client);
int?number?=?atomicInteger.getAndIncrement();
final?LeaderLatch?latch?=?new?LeaderLatch(client,?masterPath,?"client#"?+?number);
System.out.println("創(chuàng)建客戶端:"?+?latch.getId());
//?LeaderLatch?添加監(jiān)聽事件
latch.addListener(new?LeaderLatchListener()?{
@Override
public?void?isLeader()?{
System.out.println(latch.getId()?+?":?我現(xiàn)在被選舉為Leader!我開始工作了....");
}
@Override
public?void?notLeader()?{
System.out.println(latch.getId()?+?":?我遺憾地落選了,我到一旁休息去吧...");
}
});
latchList.add(latch);
try?{
latch.start();
//?隨機等待?number?*?10秒,之后關閉客戶端
Thread.sleep(number?*?10000);
}?catch?(Exception?e)?{
System.out.println(e.getMessage());
}?finally?{
System.out.println("客戶端?"?+?latch.getId()?+?"?關閉");
CloseableUtils.closeQuietly(latch);
CloseableUtils.closeQuietly(client);
countDownLatch.countDown();
}
}
}).start();
}
countDownLatch.await();?//?等待,只有所有線程都退出
}?catch?(Exception?e)?{
e.printStackTrace();
}
}
private?static?synchronized?CuratorFramework?getClient()?{
CuratorFramework?client?=?CuratorFrameworkFactory.builder().connectString(zkServerIps)
.sessionTimeoutMs(6000).connectionTimeoutMs(3000)?//.namespace("LeaderLatchTest")
.retryPolicy(new?ExponentialBackoffRetry(1000,?3)).build();
client.start();
return?client;
}
}
控制臺輸出的日志
創(chuàng)建客戶端:client#1
創(chuàng)建客戶端:client#2
創(chuàng)建客戶端:client#3
創(chuàng)建客戶端:client#4
創(chuàng)建客戶端:client#5
client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#1?關閉
客戶端?client#2?關閉
client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#3?關閉
客戶端?client#4?關閉
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#5?關閉
系統(tǒng)運行過程中查看 masterPath 可以看見客戶端注冊的臨時節(jié)點,當客戶端關閉時,臨時節(jié)點也會被刪除
LeaderLatch選舉時的ZK節(jié)點
Leader Election
通過 Leader Election 選舉方案進行 Master選舉,需添加 LeaderSelectorListener -對領導權進行控制,當節(jié)點被選為leader之后,將調用 takeLeadership 方法進行業(yè)務邏輯處理,處理完成會立即釋放 leadship,重新進行Master選舉,這樣每個節(jié)點都有可能成為 leader。autoRequeue() 方法的調用確保此實例在釋放領導權后還可能獲得領導權。
public?class?LeaderSelectorTest?{
private?static?final?String?zkServerIps?=?"master:2181,hadoop2:2181";
private?static?final?String?masterPath?=?"/testZK/leader_selector";
public?static?void?main(String[]?args)?{
final?int?clientNums?=?5;??//?客戶端數(shù)量,用于模擬
final?CountDownLatch?countDownLatch?=?new?CountDownLatch(clientNums);
List
List
AtomicInteger?atomicInteger?=?new?AtomicInteger(1);
try?{
for?(int?i?=?0;?i?
new?Thread(new?Runnable()?{
@Override
public?void?run()?{
CuratorFramework?client?=?getClient();??//?創(chuàng)建客戶端
clientList.add(client);
int?number?=?atomicInteger.getAndIncrement();
final?String?name?=?"client#"?+?number;
final?LeaderSelector?selector?=?new?LeaderSelector(client,?masterPath,?new?LeaderSelectorListener()?{
@Override
public?void?takeLeadership(CuratorFramework?client)?throws?Exception?{
System.out.println(name?+?":?我現(xiàn)在被選舉為Leader!我開始工作了....");
Thread.sleep(3000);
}
@Override
public?void?stateChanged(CuratorFramework?curatorFramework,?ConnectionState?connectionState)?{
}
});
System.out.println("創(chuàng)建客戶端:"?+?name);
try?{
selector.autoRequeue();
selector.start();
selectorList.add(selector);
//?隨機等待?number?*?10秒,之后關閉客戶端
Thread.sleep(number?*?10000);
}?catch?(Exception?e)?{
System.out.println(e.getMessage());
}?finally?{
countDownLatch.countDown();
System.out.println("客戶端?"?+?name?+?"?關閉");
CloseableUtils.closeQuietly(selector);
if?(!client.getState().equals(CuratorFrameworkState.STOPPED))?{
CloseableUtils.closeQuietly(client);
}
}
}
}).start();
}
countDownLatch.await();?//?等待,只有所有線程都退出
}?catch?(Exception?e)?{
e.printStackTrace();
}
}
private?static?synchronized?CuratorFramework?getClient()?{
CuratorFramework?client?=?CuratorFrameworkFactory.builder().connectString(zkServerIps)
.sessionTimeoutMs(6000).connectionTimeoutMs(3000)?//.namespace("LeaderLatchTest")
.retryPolicy(new?ExponentialBackoffRetry(1000,?3)).build();
client.start();
return?client;
}
}
控制臺輸出的日志信息
創(chuàng)建客戶端:client#2
創(chuàng)建客戶端:client#1
創(chuàng)建客戶端:client#3
創(chuàng)建客戶端:client#5
創(chuàng)建客戶端:client#4
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#1?關閉
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#2?關閉
client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#3?關閉
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#4?關閉
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#5?關閉
LeaderSelectorListener類繼承了ConnectionStateListener。一旦LeaderSelector啟動,它會向curator客戶端添加-。使用LeaderSelector必須時刻注意連接的變化。一旦出現(xiàn)連接問題如 SUSPENDED,curator實例必須確保它不再是leader,直至它重新收到 RECONNECTED。如果 LOST 出現(xiàn),curator實例不再是 leader 并且其 takeLeadership() 應該直接退出。
推薦的做法是,如果發(fā)生 SUSPENDED 或者 LOST 連接問題,最好直接拋CancelLeadershipException,此時,leaderSelector實例會嘗試中斷并且取消正在執(zhí)行 takeLeadership() 方法的線程。 建議擴展LeaderSelectorListenerAdapter,LeaderSelectorListenerAdapter中已經(jīng)提供了推薦的處理方式 。
后序
代碼:https://github.com/whirlys/BigData-In-Practice/tree/master/curator-example/src/main/java/com/whirly/recipes
參考:
《從Paxos到Zookeeper分布式一致性原理與實踐》
Zookeeper開源客戶端Curator之Master/Leader選舉
關注_小旋鋒_微信公眾號
Zookeeper 是一個高可用的分布式數(shù)據(jù)管理與協(xié)調框架,基于ZAB協(xié)議算法的實現(xiàn),該框架能夠很好的保證分布式環(huán)境中數(shù)據(jù)的一致性。Zookeeper的典型應用場景主要有:數(shù)據(jù)發(fā)布/訂閱、負載均衡、命名服務、分布式協(xié)調/通知、集群管理、Master選舉、分布式鎖和分布式隊列等。
本文主要介紹如何利用Zookeeper實現(xiàn)Master選舉。
Master選舉
Master選舉在分布式系統(tǒng)中是一個非常常見的場景。在分布式系統(tǒng)中,常常采用主從模式的方式避免單點故障,提高系統(tǒng)服務的可用性。正常情況下,Master節(jié)點用來協(xié)調集群中其他系統(tǒng)單元,維護系統(tǒng)狀態(tài)信息,或者負責一些復雜的邏輯,再將處理結果同步給其他節(jié)點。當Master節(jié)點宕機,或者由于其他問題導致無法提供服務時,系統(tǒng)將發(fā)起一次Master選舉,從候選節(jié)點中選出一個新的Master節(jié)點,以繼續(xù)提供服務。
譬如在一些讀寫分離的應用中,Master節(jié)點負責客戶端的寫請求,處理完畢之后再將結果同步給從節(jié)點。
著名的選舉算法有 Paxos算法、Raft算法、Bully算法等,但在業(yè)務系統(tǒng)的開發(fā)中,實現(xiàn)選舉算法并不是我們工作的重心。
Zookeeper有一個非常重要的特性即強一致性,能夠很好地保證在分布式高并發(fā)情況下節(jié)點的創(chuàng)建一定能夠保證全局唯一性,即Zookeeper將會保證客戶端無法重復創(chuàng)建一個已經(jīng)存在的數(shù)據(jù)節(jié)點。也就是說,如果同時有多個客戶端請求創(chuàng)建同一個節(jié)點,那么最終一定只有一個客戶端請求能夠創(chuàng)建成功。利用這個特性,就能很容易地在分布式環(huán)境中進行Master選舉了。
利用Zookeeper實現(xiàn)Master選舉
Apache Curator是一個Zookeeper的開源客戶端,它提供了Zookeeper各種應用場景(Recipe,如共享鎖服務、master選舉、分布式計數(shù)器等)的抽象封裝,本文使用 Curator 提供的Recipe來實現(xiàn)Master選舉。
Curator提供了兩種選舉方案:Leader Latch 和 Leader Election。下面分別介紹這兩種選舉方案。
使用 Leader Latch 方案進行Master選舉,系統(tǒng)將隨機從候選者中選出一臺作為 leader,直到調用 close() 釋放leadship,此時再重新隨機選舉 leader,否則其他的候選者無法成為 leader。
下面的程序將啟動 N 個線程用來模擬分布式系統(tǒng)中的節(jié)點,每個線程將創(chuàng)建一個Zookeeper客戶端和一個 LeaderLatch 對象用于選舉;每個線程有一個名稱,名稱中有一個編號用于區(qū)分;每個線程的存活時間為 number * 10秒 ,存活時間結束后將關閉 LeaderLatch 對象和客戶端,表示該 '節(jié)點' 宕機,如果該節(jié)點為 Master節(jié)點,這時系統(tǒng)將重新發(fā)起 Master選舉。
public?class?LeaderLatchTest?{
private?static?final?String?zkServerIps?=?"master:2181,hadoop2:2181";
private?static?final?String?masterPath?=?"/testZK/leader_latch";
public?static?void?main(String[]?args)?{
final?int?clientNums?=?5;??//?客戶端數(shù)量,用于模擬
final?CountDownLatch?countDownLatch?=?new?CountDownLatch(clientNums);
List
List
AtomicInteger?atomicInteger?=?new?AtomicInteger(1);
try?{
for?(int?i?=?0;?i?
new?Thread(new?Runnable()?{
@Override
public?void?run()?{
CuratorFramework?client?=?getClient();??//?創(chuàng)建客戶端
clientList.add(client);
int?number?=?atomicInteger.getAndIncrement();
final?LeaderLatch?latch?=?new?LeaderLatch(client,?masterPath,?"client#"?+?number);
System.out.println("創(chuàng)建客戶端:"?+?latch.getId());
//?LeaderLatch?添加監(jiān)聽事件
latch.addListener(new?LeaderLatchListener()?{
@Override
public?void?isLeader()?{
System.out.println(latch.getId()?+?":?我現(xiàn)在被選舉為Leader!我開始工作了....");
}
@Override
public?void?notLeader()?{
System.out.println(latch.getId()?+?":?我遺憾地落選了,我到一旁休息去吧...");
}
});
latchList.add(latch);
try?{
latch.start();
//?隨機等待?number?*?10秒,之后關閉客戶端
Thread.sleep(number?*?10000);
}?catch?(Exception?e)?{
System.out.println(e.getMessage());
}?finally?{
System.out.println("客戶端?"?+?latch.getId()?+?"?關閉");
CloseableUtils.closeQuietly(latch);
CloseableUtils.closeQuietly(client);
countDownLatch.countDown();
}
}
}).start();
}
countDownLatch.await();?//?等待,只有所有線程都退出
}?catch?(Exception?e)?{
e.printStackTrace();
}
}
private?static?synchronized?CuratorFramework?getClient()?{
CuratorFramework?client?=?CuratorFrameworkFactory.builder().connectString(zkServerIps)
.sessionTimeoutMs(6000).connectionTimeoutMs(3000)?//.namespace("LeaderLatchTest")
.retryPolicy(new?ExponentialBackoffRetry(1000,?3)).build();
client.start();
return?client;
}
}
控制臺輸出的日志
創(chuàng)建客戶端:client#1
創(chuàng)建客戶端:client#2
創(chuàng)建客戶端:client#3
創(chuàng)建客戶端:client#4
創(chuàng)建客戶端:client#5
client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#1?關閉
客戶端?client#2?關閉
client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#3?關閉
客戶端?client#4?關閉
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#5?關閉
系統(tǒng)運行過程中查看 masterPath 可以看見客戶端注冊的臨時節(jié)點,當客戶端關閉時,臨時節(jié)點也會被刪除
通過 Leader Election 選舉方案進行 Master選舉,需添加 LeaderSelectorListener -對領導權進行控制,當節(jié)點被選為leader之后,將調用 takeLeadership 方法進行業(yè)務邏輯處理,處理完成會立即釋放 leadship,重新進行Master選舉,這樣每個節(jié)點都有可能成為 leader。autoRequeue() 方法的調用確保此實例在釋放領導權后還可能獲得領導權。
public?class?LeaderSelectorTest?{
private?static?final?String?zkServerIps?=?"master:2181,hadoop2:2181";
private?static?final?String?masterPath?=?"/testZK/leader_selector";
public?static?void?main(String[]?args)?{
final?int?clientNums?=?5;??//?客戶端數(shù)量,用于模擬
final?CountDownLatch?countDownLatch?=?new?CountDownLatch(clientNums);
List
List
AtomicInteger?atomicInteger?=?new?AtomicInteger(1);
try?{
for?(int?i?=?0;?i?
new?Thread(new?Runnable()?{
@Override
public?void?run()?{
CuratorFramework?client?=?getClient();??//?創(chuàng)建客戶端
clientList.add(client);
int?number?=?atomicInteger.getAndIncrement();
final?String?name?=?"client#"?+?number;
final?LeaderSelector?selector?=?new?LeaderSelector(client,?masterPath,?new?LeaderSelectorListener()?{
@Override
public?void?takeLeadership(CuratorFramework?client)?throws?Exception?{
System.out.println(name?+?":?我現(xiàn)在被選舉為Leader!我開始工作了....");
Thread.sleep(3000);
}
@Override
public?void?stateChanged(CuratorFramework?curatorFramework,?ConnectionState?connectionState)?{
}
});
System.out.println("創(chuàng)建客戶端:"?+?name);
try?{
selector.autoRequeue();
selector.start();
selectorList.add(selector);
//?隨機等待?number?*?10秒,之后關閉客戶端
Thread.sleep(number?*?10000);
}?catch?(Exception?e)?{
System.out.println(e.getMessage());
}?finally?{
countDownLatch.countDown();
System.out.println("客戶端?"?+?name?+?"?關閉");
CloseableUtils.closeQuietly(selector);
if?(!client.getState().equals(CuratorFrameworkState.STOPPED))?{
CloseableUtils.closeQuietly(client);
}
}
}
}).start();
}
countDownLatch.await();?//?等待,只有所有線程都退出
}?catch?(Exception?e)?{
e.printStackTrace();
}
}
private?static?synchronized?CuratorFramework?getClient()?{
CuratorFramework?client?=?CuratorFrameworkFactory.builder().connectString(zkServerIps)
.sessionTimeoutMs(6000).connectionTimeoutMs(3000)?//.namespace("LeaderLatchTest")
.retryPolicy(new?ExponentialBackoffRetry(1000,?3)).build();
client.start();
return?client;
}
}
控制臺輸出的日志信息
創(chuàng)建客戶端:client#2
創(chuàng)建客戶端:client#1
創(chuàng)建客戶端:client#3
創(chuàng)建客戶端:client#5
創(chuàng)建客戶端:client#4
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#1?關閉
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#2?關閉
client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#3?關閉
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#4?關閉
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....
客戶端?client#5?關閉
LeaderSelectorListener類繼承了ConnectionStateListener。一旦LeaderSelector啟動,它會向curator客戶端添加-。使用LeaderSelector必須時刻注意連接的變化。一旦出現(xiàn)連接問題如 SUSPENDED,curator實例必須確保它不再是leader,直至它重新收到 RECONNECTED。如果 LOST 出現(xiàn),curator實例不再是 leader 并且其 takeLeadership() 應該直接退出。
推薦的做法是,如果發(fā)生 SUSPENDED 或者 LOST 連接問題,最好直接拋CancelLeadershipException,此時,leaderSelector實例會嘗試中斷并且取消正在執(zhí)行 takeLeadership() 方法的線程。 建議擴展LeaderSelectorListenerAdapter,LeaderSelectorListenerAdapter中已經(jīng)提供了推薦的處理方式 。
代碼:https://github.com/whirlys/BigData-In-Practice/tree/master/curator-example/src/main/java/com/whirly/recipes
參考:
《從Paxos到Zookeeper分布式一致性原理與實踐》
Zookeeper開源客戶端Curator之Master/Leader選舉
大數(shù)據(jù) ZooKeeper
版權聲明:本文內容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內刪除侵權內容。
版權聲明:本文內容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內刪除侵權內容。