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