ZooKeeper服務發現客戶端
單位想把那套ZooKeeper叢集用起來.
作為配置中心,一旦出現問題,所有服務都是中斷的.
尤其又涉及ACL
想來想去,我覺得這個客戶端還是自己封裝,安全係數大些.
好長時間也沒有寫過程式碼了,確實感覺很生疏.寫的邏輯稍微有點亂.
別到時候上線了,因為自己的客戶端引發問題.那就尷尬了.
要求:
1.在客戶端實現負載均衡
2.客戶端ACL密碼加密
3.在客戶端實現快取,如果ZK掛了,還能繼續提供服務
4.如果服務提供方在ZK正常註冊,但是服務呼叫方出現呼叫異常,需要將這個服務在快取做一個標識.在一段時間內,不提供這個服務地址.(預設5分鐘)
5.這段程式碼憋出事兒..心中默唸一百遍..
程式碼結構:
zoo.properties
server=192.168.1.105:2181,192.168.1.106:2181,192.168.1.107:2181,192.168.1.108:2181,192.168.1.109:2181,192.168.1.110:2181
invoker.vdfs=/service/vdfs/upload/dx
r=pqrMCxdhQUhKEgMFZoJG3vM2tDdIGqbA/rlZt9RkL8s=
rw=MqnMrPsX3c8RX7b+NES4mQ==
provider./service/vdfs/upload/dx=http://192.168.1.111
nodename=192.168.16.114:8080
Metadata,提供配置檔案加解密和配置檔案提取
ServiceProvider 服務提供方呼叫,將自己註冊到配置中心
ServiceInvoker 服務呼叫方使用,獲取服務連線地址
MAVEN配置:
作為配置中心,一旦出現問題,所有服務都是中斷的.
尤其又涉及ACL
想來想去,我覺得這個客戶端還是自己封裝,安全係數大些.
好長時間也沒有寫過程式碼了,確實感覺很生疏.寫的邏輯稍微有點亂.
別到時候上線了,因為自己的客戶端引發問題.那就尷尬了.
要求:
1.在客戶端實現負載均衡
2.客戶端ACL密碼加密
3.在客戶端實現快取,如果ZK掛了,還能繼續提供服務
4.如果服務提供方在ZK正常註冊,但是服務呼叫方出現呼叫異常,需要將這個服務在快取做一個標識.在一段時間內,不提供這個服務地址.(預設5分鐘)
5.這段程式碼憋出事兒..心中默唸一百遍..
程式碼結構:
zoo.properties
server=192.168.1.105:2181,192.168.1.106:2181,192.168.1.107:2181,192.168.1.108:2181,192.168.1.109:2181,192.168.1.110:2181
invoker.vdfs=/service/vdfs/upload/dx
r=pqrMCxdhQUhKEgMFZoJG3vM2tDdIGqbA/rlZt9RkL8s=
rw=MqnMrPsX3c8RX7b+NES4mQ==
provider./service/vdfs/upload/dx=http://192.168.1.111
nodename=192.168.16.114:8080
Metadata,提供配置檔案加解密和配置檔案提取
- package com.vv.zkClient;
- import java.io.IOException;
- import java.io.InputStream;
- import java.security.SecureRandom;
- import java.util.Enumeration;
- import java.util.Map;
- import java.util.Properties;
- import javax.crypto.Cipher;
- import javax.crypto.SecretKey;
- import javax.crypto.SecretKeyFactory;
- import javax.crypto.spec.DESKeySpec;
- import org.apache.commons.codec.binary.Base64;
- import org.jboss.netty.util.internal.ConcurrentHashMap;
- public class Metadata {
- private static volatile Metadata META = null;
- public static String decrypt(byte[] content, String key) {
- try {
- SecureRandom random = new SecureRandom();
- DESKeySpec desKey = new DESKeySpec(key.getBytes());
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
- SecretKey securekey = keyFactory.generateSecret(desKey);
- Cipher cipher = Cipher.getInstance("DES");
- cipher.init(Cipher.DECRYPT_MODE, securekey, random);
- byte[] result = cipher.doFinal(content);
- return new String(result);
- } catch (Throwable e) {
- e.printStackTrace();
- }
- return null;
- }
- public static byte[] encrypt(String content, String key) {
- try {
- SecureRandom random = new SecureRandom();
- DESKeySpec desKey = new DESKeySpec(key.getBytes());
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
- SecretKey securekey = keyFactory.generateSecret(desKey);
- Cipher cipher = Cipher.getInstance("DES");
- cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
- byte[] result = cipher.doFinal(content.getBytes());
- return result;
- } catch (Throwable e) {
- e.printStackTrace();
- }
- return null;
- }
- public static Metadata getInstance() {
- if (META == null) {
- synchronized (Metadata.class) {
- if (META == null) {
- META = new Metadata();
- }
- }
- }
- return META;
- }
- private String connectionString = null;
- private Map<String, String> invokerMap = new ConcurrentHashMap<String, String>();
- private String key = "12344321";
- private String nodename = null;
- private Properties p = new Properties();
- private Map<String, String> providerMap = new ConcurrentHashMap<String, String>();
- private String readOnlyPassword = null;
- private String readwritePassword = null;
- public Metadata() {
- InputStream in = Metadata.class.getClassLoader().getResourceAsStream("zoo.properties");
- init(in);
- }
- public String getConnectionString() {
- return connectionString;
- }
- public Map<String, String> getInvokerMap() {
- return invokerMap;
- }
- public String getLocal() {
- return nodename;
- }
- public Map<String, String> getProviderMap() {
- return providerMap;
- }
- public String getReadOnlyPassword() {
- String password = new String(decrypt(Base64.decodeBase64(this.readOnlyPassword.getBytes()), this.key));
- return password;
- }
- public String getReadwritePassword() {
- String password = new String(decrypt(Base64.decodeBase64(this.readwritePassword.getBytes()), this.key));
- return password;
- }
- private void init(InputStream in) {
- try {
- p.load(in);
- connectionString = p.getProperty("server", "");
- readOnlyPassword = p.getProperty("r", "");
- readwritePassword = p.getProperty("rw", "");
- nodename = p.getProperty("nodename", "");
- Enumeration<Object> enums = p.keys();
- while (enums.hasMoreElements()) {
- String key = (String) enums.nextElement();
- if (key.startsWith("invoker.")) {
- invokerMap.put(key.replace("invoker.", ""), p.getProperty(key));
- } else if (key.startsWith("provider.")) {
- providerMap.put(key.replace("provider.", ""), p.getProperty(key));
- }
- }
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) {
- }
- }
ServiceProvider 服務提供方呼叫,將自己註冊到配置中心
- package com.vv.zkClient;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.concurrent.ScheduledThreadPoolExecutor;
- import java.util.concurrent.TimeUnit;
- import org.apache.curator.framework.CuratorFramework;
- import org.apache.curator.framework.CuratorFrameworkFactory;
- import org.apache.curator.retry.RetryUntilElapsed;
- import org.apache.zookeeper.CreateMode;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public class ServiceProvider implements Runnable {
- private static Logger LOGGER = LoggerFactory.getLogger(ServiceProvider.class);
- private static volatile ServiceProvider SERVICEPROVIDER = null;
- public static ServiceProvider getInstance() {
- if (SERVICEPROVIDER == null) {
- synchronized (ServiceProvider.class) {
- if (SERVICEPROVIDER == null) {
- SERVICEPROVIDER = new ServiceProvider();
- }
- }
- }
- return SERVICEPROVIDER;
- }
- private CuratorFramework client;
- private Metadata meta;
- private ScheduledThreadPoolExecutor threadPool = new ScheduledThreadPoolExecutor(1);
- private ServiceProvider() {
- this.meta = Metadata.getInstance();
- connection();
- threadPool.scheduleAtFixedRate(this, 1, 5, TimeUnit.SECONDS);
- }
- private void connection() {
- try {
- this.client = CuratorFrameworkFactory.newClient(meta.getConnectionString(),
- new RetryUntilElapsed(2000, 1000));
- client.start();
- client.getZookeeperClient().getZooKeeper().addAuthInfo("digest", meta.getReadwritePassword().getBytes());
- } catch (Exception e) {
- e.printStackTrace();
- LOGGER.error(e.getMessage());
- }
- }
- public void run() {
- try {
- for (String serviceNode : meta.getProviderMap().keySet()) {
- String serviceURL = meta.getProviderMap().get(serviceNode);
- String serviceName = serviceNode + "/" + meta.getLocal();
- if (client.checkExists().forPath(serviceName) == null) {
- String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "||" + serviceURL;
- client.create().withMode(CreateMode.EPHEMERAL).forPath(serviceName, date.getBytes());
- LOGGER.info("Created Node->\"{}\",Node Data->\"{}\"", serviceName,date);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- client.close();
- connection();
- LOGGER.error(e.getMessage());
- }
- }
- public static void main(String[] args) throws InterruptedException {
- ServiceProvider.getInstance();
- Thread.sleep(Integer.MAX_VALUE);
- }
- }
ServiceInvoker 服務呼叫方使用,獲取服務連線地址
- package com.vv.zkClient;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.CopyOnWriteArrayList;
- import java.util.concurrent.CountDownLatch;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import org.apache.curator.framework.CuratorFramework;
- import org.apache.curator.framework.CuratorFrameworkFactory;
- import org.apache.curator.framework.recipes.cache.PathChildrenCache;
- import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
- import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
- import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
- import org.apache.curator.retry.RetryUntilElapsed;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- class Service {
- private long lastErrorTime = -1;
- private String name = null;
- private String url = null;
- @Override
- public boolean equals(Object obj) {
- Service s = (Service) obj;
- return (this.getName() + this.getUrl()).equals(s.getName() + s.getUrl());
- }
- public long getLastErrorTime() {
- return lastErrorTime;
- }
- public String getName() {
- return name;
- }
- public String getUrl() {
- return url;
- }
- public void setLastErrorTime(long lastErrorTime) {
- this.lastErrorTime = lastErrorTime;
- }
- public void setName(String name) {
- this.name = name;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- }
- public class ServiceInvoker {
- private static ServiceInvoker INVOKER = null;
- private static Logger LOGGER = LoggerFactory.getLogger(ServiceInvoker.class);
- public static ServiceInvoker getInstance() {
- if (INVOKER == null) {
- synchronized (ServiceInvoker.class) {
- if (INVOKER == null) {
- INVOKER = new ServiceInvoker();
- }
- }
- }
- return INVOKER;
- }
- private CuratorFramework client;
- private CountDownLatch isInitialized = new CountDownLatch(1);
- private Map<String, Iterator<Service>> itMap = new ConcurrentHashMap<String, Iterator<Service>>();
- private Metadata meta;
- private Map<String, List<Service>> providerMap = new ConcurrentHashMap<String, List<Service>>();
- private ExecutorService threadPool = Executors.newSingleThreadExecutor();
- private ServiceInvoker() {
- this.meta = Metadata.getInstance();
- connection();
- listener();
- }
- private void connection() {
- try {
- this.client = CuratorFrameworkFactory.newClient(meta.getConnectionString(),
- new RetryUntilElapsed(2000, 1000));
- client.start();
- client.getZookeeperClient().getZooKeeper().addAuthInfo("digest", meta.getReadOnlyPassword().getBytes());
- } catch (Exception e) {
- e.printStackTrace();
- LOGGER.error(e.getMessage());
- }
- }
- public String get(final String serviceNode) {
- Callable<String> c = new Callable<String>() {
- public String call() throws Exception {
- List<Service> list = providerMap.get(serviceNode);
- if (list == null) {
- list = new CopyOnWriteArrayList<Service>();
- providerMap.put(serviceNode, list);
- }
- Iterator<Service> it = itMap.get(serviceNode);
- if (it == null || !it.hasNext()) {
- it = list.iterator();
- itMap.put(serviceNode, it);
- }
- if (!it.hasNext()) {
- LOGGER.error("節點:\"{}\",沒有任何可用服務", serviceNode);
- return "";
- }
- Service service = it.next();
- long now = System.currentTimeMillis();
- int retryCount = 5;
- while (service.getLastErrorTime() != -1 && (now - service.getLastErrorTime()) < 1000 * 60 * 5) {
- retryCount--;
- if (retryCount == 0) {
- LOGGER.error("節點:\"{}\",沒有任何可用服務", serviceNode);
- return "";
- }
- if (it.hasNext()) {
- service = it.next();
- } else {
- it = providerMap.get(serviceNode).iterator();
- itMap.put(serviceNode, it);
- }
- }
- return service.getUrl();
- }
- };
- String serviceUrl = "";
- try {
- isInitialized.await();
- serviceUrl = threadPool.submit(c).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- return serviceUrl;
- }
- private void listener() {
- for (String serviceNode : meta.getInvokerMap().values()) {
- PathChildrenCache cache = new PathChildrenCache(client, serviceNode, true);
- try {
- cache.start(StartMode.POST_INITIALIZED_EVENT);
- } catch (Exception e) {
- e.printStackTrace();
- }
- cache.getListenable().addListener(new PathChildrenCacheListener() {
- public void childEvent(CuratorFramework arg0, final PathChildrenCacheEvent event) throws Exception {
- final String type = event.getType().name();
- if (type.equals("INITIALIZED")) {
- LOGGER.info("ZooKeeper資料初始化完成:INITIALIZED");
- isInitialized.countDown();
- return;
- }
- final String data = event.getData().getPath();
- final String serviceNode = data.substring(0, data.lastIndexOf("/"));
- final String serviceUrl = new String(event.getData().getData()).split("\\|\\|")[1];
- Runnable r = new Runnable() {
- public void run() {
- List<Service> list = providerMap.get(serviceNode);
- if (list == null) {
- list = new CopyOnWriteArrayList<Service>();
- providerMap.put(serviceNode, list);
- }
- Service s = new Service();
- s.setName(serviceNode);
- s.setUrl(serviceUrl);
- if (type.equals("CHILD_ADDED")) {
- list.add(s);
- LOGGER.info("新增節點:\"{}\",服務地址:\"{}\"", data, serviceUrl);
- } else if (type.equals("CHILD_REMOVED")) {
- for (int i = 0; i < list.size(); i++) {
- Service service = list.get(i);
- if (service.equals(s)) {
- list.remove(i);
- LOGGER.info("刪除節點:\"{}\",服務地址:\"{}\"", data, serviceUrl);
- }
- }
- }
- }
- };
- threadPool.submit(r);
- }
- });
- }
- }
- public void setLastErrorTime(final String url) {
- Runnable r = new Runnable() {
- public void run() {
- for (List<Service> list : providerMap.values()) {
- Iterator<Service> it = list.iterator();
- while (it.hasNext()) {
- Service service = it.next();
- if (service.getUrl().equals(url)) {
- service.setLastErrorTime(System.currentTimeMillis());
- LOGGER.error("節點:\"{}\",呼叫URL:\"{}\"異常,該節點停止服務5分鐘", service.getName(), service.getUrl());
- }
- }
- }
- }
- };
- threadPool.submit(r);
- }
- public static void main(String[] args) throws Exception {
- ServiceInvoker s = ServiceInvoker.getInstance();
- while (true) {
- String str = s.get("/service/vdfs/upload/dx");
- s.setLastErrorTime(str);
- Thread.sleep(5000);
- }
- }
- }
MAVEN配置:
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.apache.curator</groupId>
- <artifactId>curator-framework</artifactId>
- <version>2.4.2</version>
- <exclusions>
- <exclusion>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </exclusion>
- <exclusion>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.apache.curator</groupId>
- <artifactId>curator-recipes</artifactId>
- <version>2.4.2</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>20041127.091804</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-core</artifactId>
- <version>1.1.7</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <version>1.1.7</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.7.7</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>log4j-over-slf4j</artifactId>
- <version>1.7.7</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>jcl-over-slf4j</artifactId>
- <version>1.7.7</version>
- <scope>runtime</scope>
- </dependency>
- </dependencies>
- <build>
- <resources>
- <resource>
- <directory>src/main/java</directory>
- <includes>
- <include>**/*.properties</include>
- </includes>
- </resource>
- <resource>
- <directory>src/main/resources</directory>
- </resource>
- </resources>
- </build>
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-2108223/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ZooKeeper服務發現客戶端--重連認證客戶端
- 客戶端,服務端客戶端服務端
- 服務端,客戶端服務端客戶端
- golang實現tcp客戶端服務端程式GolangTCP客戶端服務端
- 【zookeeper之七】Zookeeper客戶端客戶端
- Zookeeper 客戶端 API客戶端API
- Android實現Thrift服務端與客戶端Android服務端客戶端
- Zookeeper Java 客戶端搭建Java客戶端
- ZooKeeper客戶端CRUD命令客戶端
- Zookeeper--Java客戶端Java客戶端
- 模板,從服務端到客戶端服務端客戶端
- 服務端渲染和客戶端渲染服務端客戶端
- Java建立WebService服務及客戶端實現JavaWeb客戶端
- 實現客戶端與服務端的HTTP通訊客戶端服務端HTTP
- 【Zookeeper】zookeeper客戶端KeeperErrorCode = ConnectionLoss客戶端Error
- Java建立WebService服務及客戶端實現(轉)JavaWeb客戶端
- Qt實現網路聊天室(客戶端,服務端)QT客戶端服務端
- zookeeper的Java客戶端APIJava客戶端API
- Java服務端和客戶端開發輔助工具UtilsJava服務端客戶端
- 從客戶端向服務端發起請求(3種)客戶端服務端
- PC客戶端安全測試服務客戶端
- Go基於gRPC實現客戶端連入服務端GoRPC客戶端服務端
- Java的oauth2.0 服務端與客戶端的實現JavaOAuth服務端客戶端
- OSSEC服務端配置客戶端批次部署方案服務端客戶端
- python建立tcp服務端和客戶端PythonTCP服務端客戶端
- Zookeeper之Zookeeper底層客戶端架構實現原理(轉載)客戶端架構
- TCP程式設計之服務端和客戶端的開發TCP程式設計服務端客戶端
- 【2】Windows C++ Redis服務端搭建與客戶端開發WindowsC++Redis服務端客戶端
- 使用多種客戶端消費WCF RestFul服務(一)——服務端客戶端REST服務端
- Zookeeper C客戶端庫編譯客戶端編譯
- zookeeper 開源客戶端ZkClient使用客戶端client
- zookeeper 開源客戶端Curator使用客戶端
- Zookeeper--客戶端基礎命令客戶端
- Zookeeper實現服務註冊/發現
- HTML轉PDF的純客戶端和純服務端實現方案HTML客戶端服務端
- php原生socket實現客戶端與服務端資料傳輸PHP客戶端服務端
- SSLSocket實現服務端和客戶端雙向認證的例子服務端客戶端
- macOS 自帶的ftp服務端&vnc客戶端MacFTP服務端VNC客戶端