摘要:高可用的首要想法就是雙機(jī)熱備,故障時(shí)自動(dòng)切換,所以我們要給加一個(gè)備機(jī)。注下面實(shí)現(xiàn)高可用都用的是雙機(jī)熱備,為了方便,把調(diào)度服務(wù)器簡(jiǎn)稱為主機(jī),把調(diào)度服務(wù)器的備機(jī)簡(jiǎn)稱為備機(jī)。
我之前在一片文章 用Nginx+Redis實(shí)現(xiàn)session共享的均衡負(fù)載 中做了一個(gè)負(fù)載均衡的實(shí)驗(yàn),其主要架構(gòu)如下:
把debian1作為調(diào)度服務(wù)器承擔(dān)請(qǐng)求分發(fā)的任務(wù),即用戶訪問的是debian1,然后debain1把請(qǐng)求按照一定的策略發(fā)送給應(yīng)用服務(wù)器:debian2或者debain3,甚至更多的debain4、5、6......
狀態(tài)和數(shù)據(jù)可以放在外部的分布式緩存服務(wù)和分布式數(shù)據(jù)庫(kù)服務(wù)中,這樣應(yīng)用服務(wù)本身就是無狀態(tài)的,所以機(jī)器增減都是很容易的,應(yīng)用的高可用是有保證的(對(duì)于有狀態(tài)的高可用不僅要注意機(jī)器增減與切換、還要注意備份冗余、數(shù)據(jù)一致性等問題)。但是當(dāng)時(shí)忽略了一個(gè)地方,那就是調(diào)度服務(wù)器debian1本身的高可用性沒有考慮到,存在單點(diǎn)問題。
高可用的首要想法就是雙機(jī)熱備,故障時(shí)自動(dòng)切換,所以我們要給debian1加一個(gè)備機(jī)debain1"。我現(xiàn)在按照自己的知識(shí)粗淺的把解決方案分為兩類:客戶端有感知的高可用、對(duì)客戶端透明的高可用,并分別挑選一個(gè)示例做一下實(shí)驗(yàn)。
注:下面實(shí)現(xiàn)高可用都用的是雙機(jī)熱備,為了方便,把調(diào)度服務(wù)器debian1簡(jiǎn)稱為主機(jī),把調(diào)度服務(wù)器debian1的備機(jī)debian1"簡(jiǎn)稱為備機(jī)。
客戶端有感知的高可用客戶端有感知的高可用,也就是需要客戶端的配合,客戶端自己去確認(rèn)服務(wù)器的變更并切換訪問的目標(biāo)。比如說我們的主機(jī)、備機(jī)都在ZooKeeper(或者其他類似的注冊(cè)中心比如redis)中進(jìn)行注冊(cè),客戶端監(jiān)聽ZooKeeper中服務(wù)器的信息,發(fā)現(xiàn)主機(jī)下線自己就切換訪問備機(jī)即可。
ZooKeeper偽集群搭建首先在本機(jī)搭建包含3個(gè)節(jié)點(diǎn)的ZooKeeper偽集群。在官網(wǎng)下載版本3.5.4-beta,解壓,然后復(fù)制3份,每一份都要做如下操作:
進(jìn)入conf文件夾 創(chuàng)建一個(gè)配置文件zoo.cfg。代碼如下:
initLimit=10 syncLimit=5 clientPort=2181(每個(gè)節(jié)點(diǎn)不同:2181,3181,4181) tickTime=2000 dataDir=E:/zookeeper-3.5.4-1/data(每個(gè)節(jié)點(diǎn)不同:3.5.4-2,3.5.4-3) dataLogDir=E:/zookeeper-3.5.4-1/datalog(每個(gè)節(jié)點(diǎn)不同,同上) server.1=192.168.*.*::2888:3888(實(shí)驗(yàn)機(jī)器的局域網(wǎng)IP或者直接localhost) server.2=192.168.*.*::4888:5888 server.3=192.168.*.*::6888:7888
創(chuàng)建上面的dataDir和dataLogDir,并在dataDir目錄下必須創(chuàng)建myid文件,寫入不同的整數(shù)ID,也就是上面的server.x的x,比如1
分別進(jìn)入bin目錄,在zkServer.cmd中call之前加入set ZOOCFG=../conf/zoo.cfg 并用其啟動(dòng)。
順帶一提,代碼開發(fā)我就使用我之前的項(xiàng)目CHKV了,因?yàn)檫@個(gè)項(xiàng)目中的NameNode或者DataNode也可以用ZooKeeper實(shí)現(xiàn)高可用,歡迎和我一起完善這個(gè)項(xiàng)目,一塊進(jìn)步。
調(diào)度服務(wù)端開發(fā)調(diào)度服務(wù)器主要向ZooKeeper注冊(cè)自己,并向客戶端提供服務(wù)。我們使用curator框架來和ZooKeeper交互,特別要注意版本問題。
主要代碼如下:
public static void main(String... arg) throws Exception { thisNode = ManagementFactory.getRuntimeMXBean().getName(); logger.debug("my pid: {}",thisNode); // 構(gòu)造連接 CuratorFramework curator = CuratorFrameworkFactory .builder() .connectString(CONNECT_ADDR) .connectionTimeoutMs(CONNECTION_TIMEOUT)//連接創(chuàng)建超時(shí)時(shí)間 .sessionTimeoutMs(SESSION_TIMEOUT)//會(huì)話超時(shí)時(shí)間 .retryPolicy(policy) .build(); curator.start(); // 創(chuàng)建節(jié)點(diǎn)也就是成為master,阻塞等待 boolean result = becomeMaster(curator); if (result){ logger.info("Successfully Became Master"); }else { logger.info("Failed to Became Master"); } // 監(jiān)聽 NodeCache cache = new NodeCache(curator, MASTER_NODE_PATH,false); cache.getListenable().addListener(()->{ ChildData data = cache.getCurrentData(); if (data != null){ String path = data.getPath(); Stat stat = data.getStat(); String dataString = new String(data.getData()); logger.debug("masterNode info, path:{},data:{},stat,{}",path,dataString,stat); }else { logger.info("masterNode is down, try to become Master"); if (becomeMaster(curator)){ logger.info("Successfully tried to Became Master"); }else { logger.info("Failed to try to Became Master"); } } }); cache.start(true); } // 確認(rèn)master private static boolean confirm(CuratorFramework curator) throws Exception { masterNode = new String(curator.getData().forPath(MASTER_NODE_PATH)); logger.info("masterNode: {}",masterNode); return thisNode.equals(masterNode); } // 成為master private static boolean becomeMaster(CuratorFramework curator) throws Exception { String path= ""; try { path = curator.create() .creatingParentContainersIfNeeded() .withMode(CreateMode.EPHEMERAL) .forPath(MASTER_NODE_PATH,thisNode.getBytes()); logger.debug(path); }catch (Exception e){ logger.error(e.getMessage()); } return MASTER_NODE_PATH.equals(path); }
完整代碼在GitHub上。
客戶端開發(fā)客戶端主要向ZooKeeper監(jiān)聽調(diào)度服務(wù)器變更事件,并向其發(fā)起應(yīng)用請(qǐng)求。實(shí)際上應(yīng)用服務(wù)器也可以使用這部分代碼來監(jiān)聽調(diào)度服務(wù)器的變化。
主要代碼如下:
public static void main(String... arg) throws Exception { CuratorFramework curator = CuratorFrameworkFactory .builder() .connectString(CONNECT_ADDR) .connectionTimeoutMs(CONNECTION_TIMEOUT) .sessionTimeoutMs(SESSION_TIMEOUT) .retryPolicy(policy) .build(); curator.start(); NodeCache cache = new NodeCache(curator, MASTER_NODE_PATH,false); cache.getListenable().addListener(()->{ ChildData data = cache.getCurrentData(); if (data != null){ String path = data.getPath(); Stat stat = data.getStat(); String dataString = new String(data.getData()); logger.debug("masterNode info, path:{},data:{},stat,{}",path,dataString,stat); masterInfo = dataString; }else { logger.info("masterNode is down, waiting"); } }); cache.start(true); // 獲得主機(jī),阻塞等待 try { masterInfo = new String(curator.getData().forPath(MASTER_NODE_PATH)); }catch (Exception e){ logger.error("no masterInfo"); masterInfo = null; } while (masterInfo==null); logger.info("masterInfo:{}",masterInfo); }
完整代碼在GitHub上。
對(duì)客戶端透明的高可用對(duì)客戶端透明的高可用,也就是客戶端不需要做什么工作,服務(wù)器切換不切換客戶端根本不知道也不關(guān)心。主要實(shí)現(xiàn)方式有兩種,一種是客戶端通過域名訪問主機(jī),那么監(jiān)控主機(jī)下線后就把域名重新分配給備機(jī),當(dāng)然這個(gè)切換會(huì)有時(shí)間成本,視定義的DNS緩存時(shí)間而定;第二種就是客戶端通過IP訪問主機(jī),監(jiān)控到主機(jī)下線后就通過IP漂移技術(shù)把對(duì)外的IP(或者說虛擬IP)分配給備機(jī),這樣就能做到及時(shí)的切換。
實(shí)際環(huán)境中常常使用keepalived來實(shí)現(xiàn)IP漂移。
搭建過程參考了The keepalived solution for LVS和官網(wǎng)文檔
首先主機(jī)、備機(jī)都要安裝keepalived,然后配置主機(jī)/etc/keepalived/keepalived.conf:
vrrp_instance VI_1 { state MASTER # MASTER表示此實(shí)例是主機(jī),BACKUP表示此實(shí)例是備機(jī) interface eth0 # 網(wǎng)卡名稱,亦即網(wǎng)絡(luò)接口 virtual_router_id 51 priority 100 advert_int 1 # 心跳檢查時(shí)間間隔,單位秒 authentication { # 認(rèn)證方式 是 密碼的方式 auth_type PASS auth_pass 1111 } virtual_ipaddress {# 虛擬IP地址,也就是對(duì)外開放的IP 10.23.8.80 } } virtual_server 10.23.8.80 80 { # 虛擬服務(wù)器,也就是對(duì)外開放的IP與端口 delay_loop 6 lb_algo wlc # 負(fù)載均衡調(diào)度算法 此處是 加權(quán)最少連接 lb_kind NAT # 有 DR,NAT,TUN三種 persistence_timeout 600 protocol TCP real_server 172.18.1.11 80 {# 后端的 應(yīng)用服務(wù)器 weight 100 # 節(jié)點(diǎn)的權(quán)重 TCP_CHECK { connect_timeout 3 # 3秒超時(shí) } } real_server 172.18.1.12 80 {# 后端的 應(yīng)用服務(wù)器 weight 100 TCP_CHECK { connect_timeout 3 } } real_server 172.18.1.13 80 {# 后端的 應(yīng)用服務(wù)器 weight 100 TCP_CHECK { connect_timeout 3 } } }
配置備機(jī)/etc/keepalived/keepalived.conf,與主機(jī)類似,但是state是backup,且權(quán)重較低即可:
vrrp_instance VI_1 { state BACKUP interface eth1 virtual_router_id 51 priority 90 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 10.23.8.80 } }反思
說白了,這兩種高可用的實(shí)現(xiàn)方式前者是在應(yīng)用層實(shí)現(xiàn)的,而后者是在傳輸層實(shí)現(xiàn)的,那么我們就可以想到,計(jì)算機(jī)網(wǎng)絡(luò)的每一層其實(shí)都是可以做負(fù)載均衡和高可用的。
查看原文,來自MageekChiu
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/69420.html
摘要:以集群部署的方式提供服務(wù),確保高可用。無狀態(tài)服務(wù),一樣可以通過負(fù)載均衡加心跳檢測(cè)等手段去部署集群,確保故障轉(zhuǎn)移來做到高可用。初步原理的一致性可用性分區(qū)容錯(cuò)性。高可用開發(fā)流程服務(wù)發(fā)布通過切流量的方式一臺(tái)臺(tái)灰度發(fā)布。用于預(yù)發(fā)布驗(yàn)證。 架構(gòu)和架構(gòu)師,可以說是大部分技術(shù)人的目標(biāo)或追求吧。 但架構(gòu)類比于內(nèi)功或修為,它不是一門武功,不能學(xué)一招走天下。 同一個(gè)架構(gòu)方案在不同公司甚至不同團(tuán)隊(duì)都不一定能...
摘要:鑒于目前大多數(shù)服務(wù)器環(huán)境都是,提前接觸能夠相輔相成。正則也是必須要掌握的一個(gè)知識(shí)點(diǎn)。有多種創(chuàng)建多線程的方式,不過目前使用線程池的多一些。 原創(chuàng):小姐姐味道(微信公眾號(hào)ID:xjjdog),歡迎分享,轉(zhuǎn)載請(qǐng)保留出處。 你可能有所感悟。零散的資料讀了很多,但是很難有提升。到處是干貨,但是并沒什么用,簡(jiǎn)單來說就是缺乏系統(tǒng)化。另外,噪音太多,雷同的框架一大把,我不至于全都要去學(xué)了吧。 這里,我...
閱讀 3058·2021-11-23 09:51
閱讀 3836·2021-11-22 15:29
閱讀 3297·2021-10-08 10:05
閱讀 1624·2021-09-22 15:20
閱讀 1046·2019-08-30 15:56
閱讀 1139·2019-08-30 15:54
閱讀 791·2019-08-26 11:54
閱讀 2692·2019-08-26 11:32