本文源碼:GitHub·點這裏 || GitEE·點這裏java
Zookeeper是一個Apache開源的分佈式的應用,爲系統架構提供協調服務。從設計模式角度來審視:該組件是一個基於觀察者模式設計的框架,負責存儲和管理數據,接受觀察者的註冊,一旦數據的狀態發生變化,Zookeeper就將負責通知已經在Zookeeper上註冊的觀察者作出相應的反應,從而實現集羣中相似Master/Slave管理模式。ZooKeeper的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。node
ZooKeeper記錄數據的結構與Linux文件系統類似,總體能夠看做一棵樹,每一個節點稱ZNode。每一個Znode默認可以存儲1MB的數據,每一個ZNode均可以經過其路徑惟一標識。git
短暫(ephemeral):客戶端和服務器端斷開鏈接後,建立的節點自動刪除。
持久(persistent):客戶端和服務器端斷開鏈接後,建立的節點持久化保存。github
在Zookeeper集羣服務是由一個領導者(leader),多個跟隨者(follower)組成的集羣。領導者負責進行投票的發起和決議,更新集羣服務狀態。跟隨者用於接收客戶請求並向客戶端返回結果,在選舉Leader過程當中參與投票。集羣中只要有半數以上節點存活,Zookeeper集羣就能正常服務。apache
每一個server保存一份相同的數據拷貝,客戶端不管請求到被集羣中哪一個server處理,獲得的數據都是一致的。設計模式
ZooKeeper的節點有5種操做權限:CREATE(增)、READ(查)、WRITE(改)、DELETE(刪)、ADMIN(管理)等相關權限,這5種權限集合能夠簡寫爲crwda,每一個單詞的首字符拼接而成。緩存
默認方式,開放的權限,意解爲全世界都能隨意訪問。安全
已經受權且認證經過的用戶才能夠訪問。服務器
用戶名:密碼方式認證,實際業務開發中最經常使用的方式。session
受權指定的Ip地址,和指定的權限點,控制訪問。
addauth digest 用戶名:密碼
setAcl /path auth:用戶名:密碼:權限
getAcl /path
-- 添加受權用戶 [zk: localhost:2181] addauth digest smile:123456 -- 建立節點 [zk: localhost:2181] create /cicada cicada -- 節點受權 [zk: localhost:2181] setAcl /cicada auth:smile:123456:cdrwa -- 查看受權 [zk: localhost:2181] getAcl /cicada
Curator是Apache開源的一個Zookeeper客戶端鏈接和操做的組件,Curator框架在Zookeeper原生API接口上進行二次包裝。提供ZooKeeper各類應用場景:好比:分佈式鎖服務、集羣領導選舉、共享計數器、緩存機制、分佈式隊列等API封裝。
<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.12.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.12.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-client</artifactId> <version>2.12.0</version> </dependency>
zoo: keeper: #開啓標誌 enabled: true #服務器地址 server: 127.0.0.1:2181 #命名空間,被稱爲ZNode namespace: cicada #權限控制,加密 digest: smile:123456 #會話超時時間 sessionTimeoutMs: 3000 #鏈接超時時間 connectionTimeoutMs: 60000 #最大重試次數 maxRetries: 2 #初始休眠時間 baseSleepTimeMs: 1000
@Configuration public class ZookeeperConfig { private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperConfig.class) ; @Resource private ZookeeperParam zookeeperParam ; private static CuratorFramework client = null ; /** * 初始化 */ @PostConstruct public void init (){ //重試策略,初試時間1秒,重試10次 RetryPolicy policy = new ExponentialBackoffRetry( zookeeperParam.getBaseSleepTimeMs(), zookeeperParam.getMaxRetries()); //經過工廠建立Curator client = CuratorFrameworkFactory.builder() .connectString(zookeeperParam.getServer()) .authorization("digest",zookeeperParam.getDigest().getBytes()) .connectionTimeoutMs(zookeeperParam.getConnectionTimeoutMs()) .sessionTimeoutMs(zookeeperParam.getSessionTimeoutMs()) .retryPolicy(policy).build(); //開啓鏈接 client.start(); LOGGER.info("zookeeper 初始化完成..."); } public static CuratorFramework getClient (){ return client ; } public static void closeClient (){ if (client != null){ client.close(); } } }
public interface ZookeeperService { /** * 判斷節點是否存在 */ boolean isExistNode (final String path) ; /** * 建立節點 */ void createNode (CreateMode mode,String path ) ; /** * 設置節點數據 */ void setNodeData (String path, String nodeData) ; /** * 建立節點 */ void createNodeAndData (CreateMode mode, String path , String nodeData) ; /** * 獲取節點數據 */ String getNodeData (String path) ; /** * 獲取節點下數據 */ List<String> getNodeChild (String path) ; /** * 是否遞歸刪除節點 */ void deleteNode (String path,Boolean recursive) ; /** * 獲取讀寫鎖 */ InterProce***eadWriteLock getReadWriteLock (String path) ; }
@Service public class ZookeeperServiceImpl implements ZookeeperService { private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperServiceImpl.class); @Override public boolean isExistNode(String path) { CuratorFramework client = ZookeeperConfig.getClient(); client.sync() ; try { Stat stat = client.checkExists().forPath(path); return client.checkExists().forPath(path) != null; } catch (Exception e) { LOGGER.error("isExistNode error...", e); e.printStackTrace(); } return false; } @Override public void createNode(CreateMode mode, String path) { CuratorFramework client = ZookeeperConfig.getClient() ; try { // 遞歸建立所需父節點 client.create().creatingParentsIfNeeded().withMode(mode).forPath(path); } catch (Exception e) { LOGGER.error("createNode error...", e); e.printStackTrace(); } } @Override public void setNodeData(String path, String nodeData) { CuratorFramework client = ZookeeperConfig.getClient() ; try { // 設置節點數據 client.setData().forPath(path, nodeData.getBytes("UTF-8")); } catch (Exception e) { LOGGER.error("setNodeData error...", e); e.printStackTrace(); } } @Override public void createNodeAndData(CreateMode mode, String path, String nodeData) { CuratorFramework client = ZookeeperConfig.getClient() ; try { // 建立節點,關聯數據 client.create().creatingParentsIfNeeded().withMode(mode) .forPath(path,nodeData.getBytes("UTF-8")); } catch (Exception e) { LOGGER.error("createNode error...", e); e.printStackTrace(); } } @Override public String getNodeData(String path) { CuratorFramework client = ZookeeperConfig.getClient() ; try { // 數據讀取和轉換 byte[] dataByte = client.getData().forPath(path) ; String data = new String(dataByte,"UTF-8") ; if (StringUtils.isNotEmpty(data)){ return data ; } }catch (Exception e) { LOGGER.error("getNodeData error...", e); e.printStackTrace(); } return null; } @Override public List<String> getNodeChild(String path) { CuratorFramework client = ZookeeperConfig.getClient() ; List<String> nodeChildDataList = new ArrayList<>(); try { // 節點下數據集 nodeChildDataList = client.getChildren().forPath(path); } catch (Exception e) { LOGGER.error("getNodeChild error...", e); e.printStackTrace(); } return nodeChildDataList; } @Override public void deleteNode(String path, Boolean recursive) { CuratorFramework client = ZookeeperConfig.getClient() ; try { if(recursive) { // 遞歸刪除節點 client.delete().guaranteed().deletingChildrenIfNeeded().forPath(path); } else { // 刪除單個節點 client.delete().guaranteed().forPath(path); } } catch (Exception e) { LOGGER.error("deleteNode error...", e); e.printStackTrace(); } } @Override public InterProce***eadWriteLock getReadWriteLock(String path) { CuratorFramework client = ZookeeperConfig.getClient() ; // 寫鎖互斥、讀寫互斥 InterProce***eadWriteLock readWriteLock = new InterProce***eadWriteLock(client, path); return readWriteLock ; } }
@Api("Zookeeper接口管理") @RestController public class ZookeeperApi { @Resource private ZookeeperService zookeeperService ; @ApiOperation(value="查詢節點數據") @GetMapping("/getNodeData") public String getNodeData (String path) { return zookeeperService.getNodeData(path) ; } @ApiOperation(value="判斷節點是否存在") @GetMapping("/isExistNode") public boolean isExistNode (final String path){ return zookeeperService.isExistNode(path) ; } @ApiOperation(value="建立節點") @GetMapping("/createNode") public String createNode (CreateMode mode, String path ){ zookeeperService.createNode(mode,path) ; return "success" ; } @ApiOperation(value="設置節點數據") @GetMapping("/setNodeData") public String setNodeData (String path, String nodeData) { zookeeperService.setNodeData(path,nodeData) ; return "success" ; } @ApiOperation(value="建立並設置節點數據") @GetMapping("/createNodeAndData") public String createNodeAndData (CreateMode mode, String path , String nodeData){ zookeeperService.createNodeAndData(mode,path,nodeData) ; return "success" ; } @ApiOperation(value="遞歸獲取節點數據") @GetMapping("/getNodeChild") public List<String> getNodeChild (String path) { return zookeeperService.getNodeChild(path) ; } @ApiOperation(value="是否遞歸刪除節點") @GetMapping("/deleteNode") public String deleteNode (String path,Boolean recursive) { zookeeperService.deleteNode(path,recursive) ; return "success" ; } }
GitHub·地址 https://github.com/cicadasmile/middle-ware-parent GitEE·地址 https://gitee.com/cicadasmile/middle-ware-parent