日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

diamond简介和使用

發(fā)布時間:2023/12/13 综合教程 45 生活家
生活随笔 收集整理的這篇文章主要介紹了 diamond简介和使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

簡介

diamond是淘寶內(nèi)部使用的一個管理持久配置的系統(tǒng),它的特點是簡單、可靠、易用,目前淘寶內(nèi)部絕大多數(shù)系統(tǒng)的配置,由diamond來進(jìn)行統(tǒng)一管理。

diamond為應(yīng)用系統(tǒng)提供了獲取配置的服務(wù),應(yīng)用不僅可以在啟動時從diamond獲取相關(guān)的配置,而且可以在運(yùn)行中對配置數(shù)據(jù)的變化進(jìn)行感知并獲取變化后的配置數(shù)據(jù)。

持久配置是指配置數(shù)據(jù)會持久化到磁盤和數(shù)據(jù)庫中。

diamond的特點是簡單、可靠、易用:

簡單:整體結(jié)構(gòu)非常簡單,從而減少了出錯的可能性。

可靠:應(yīng)用方在任何情況下都可以啟動,在承載淘寶核心系統(tǒng)并正常運(yùn)行一年多以來,沒有出現(xiàn)過任何重大故障。

易用:客戶端使用只需要兩行代碼,暴露的接口都非常簡單,易于理解。

1、作為一個配置中心,diamond的功能分為發(fā)布和訂閱兩部分。因為diamond存放的是持久數(shù)據(jù),這些數(shù)據(jù)的變化頻率不會很高,甚至很低,所以發(fā)布采用手工的形式,通過diamond后臺管理界面發(fā)布;訂閱是diamond的核心功能,訂閱通過diamond-client的API進(jìn)行。
2、diamond服務(wù)端采用mysql加本地文件的形式存放配置數(shù)據(jù)。發(fā)布數(shù)據(jù)時,數(shù)據(jù)先寫到mysql,再寫到本地文件;訂閱數(shù)據(jù)時,直接獲取本地文件,不查詢數(shù)據(jù)庫,這樣可以最大程度減少對數(shù)據(jù)庫的壓力。
3、diamond服務(wù)端是一個集群,集群中的每臺機(jī)器連接同一個mysql,集群之間的數(shù)據(jù)同步通過兩種方式進(jìn)行,一是每臺server定時去mysqldump數(shù)據(jù)到本地文件,二是某一臺server接收發(fā)布數(shù)據(jù)請求,在更新完mysql和本機(jī)的本地文件后,發(fā)送一個HTTP請求(通知)到集群中的其他幾臺server,其他server收到通知,去mysql中將剛剛更新的數(shù)據(jù)dump到本地文件。
4、每一臺server前端都有一個nginx,用來做流量控制。
5、圖中沒有將地址服務(wù)器畫出,地址服務(wù)器是一臺有域名的機(jī)器,上面運(yùn)行有一個HTTPserver,其中有一個靜態(tài)文件,存放著diamond服務(wù)器的地址列表。客戶端啟動時,根據(jù)自身的域名綁定,連接到地址服務(wù)器,取回diamond服務(wù)器的地址列表,從中隨機(jī)選擇一臺diamond服務(wù)器進(jìn)行連接。
可以看到,整個diamond的架構(gòu)非常簡單,使用的都是最常用的一些技術(shù)以及產(chǎn)品,它之所以表現(xiàn)得非常穩(wěn)定,跟其架構(gòu)簡單是分不開的,當(dāng)然,穩(wěn)定的另一個主要原因是它具備一套比較完善的容災(zāi)機(jī)制,容災(zāi)機(jī)制將在下一篇文章中講述。

源碼地址

https://github.com/takeseem/diamond.git

服務(wù)端安裝

檢出源碼,修改配置文件 jdbc.properties 中的數(shù)據(jù)庫連接信息,完成之后maven打包
數(shù)據(jù)庫執(zhí)行初始化sql

create database diamond;  
grant all on diamond.* to CK@'%' identified by 'abc';  
use diamond  
create table config_info (
`id` bigint(64) unsigned NOT NULL auto_increment,
`data_id` varchar(255) NOT NULL default ' ',
`group_id` varchar(128) NOT NULL default ' ',
`content` longtext NOT NULL,
`md5` varchar(32) NOT NULL default ' ',
`gmt_create` datetime NOT NULL default '2010-05-05 00:00:00',
`gmt_modified` datetime NOT NULL default '2010-05-05 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_config_datagroup` (`data_id`,`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

 

將打好的包diamond-server.war 放到tomcat工作目錄,啟動。啟動成功之后,訪問 http://localhost:8090/diamond-server/
發(fā)布數(shù)據(jù),賬號密碼是user.properties中配置的,默認(rèn)是 abc=123。登錄后進(jìn)入后臺管理界面,然后點擊“配置信息管理”—— “添加配置信息”,在輸入框中輸入dataId、group、內(nèi)容,最后點擊“提交”即可。
成功后,可以在“配置信息管理”中查詢到發(fā)布的數(shù)據(jù)。
集群安裝。修改node.properties,格式為 ip:port ,這里面的冒號,一定要通過轉(zhuǎn)義一下,要不然獲取地址不對。當(dāng)存在node節(jié)點的配置,發(fā)布修改數(shù)據(jù)后會通知其他節(jié)點更新。
每臺diamond-server 前建議增加nginx轉(zhuǎn)發(fā),方便限流,而且客戶端默認(rèn)請求80端口
其他配置: system.properties中的dump_config_interval 是多久去更新一次本地緩存的數(shù)據(jù) 默認(rèn)是 600秒

客戶端安裝

客戶端獲取數(shù)據(jù)方法:

DiamondManager manager = new DefaultDiamondManager(group, dataId, new ManagerListener() {  
   public Executor getExecutor() {  
       return null;  
   }  
  
   public void receiveConfigInfo(String configInfo) {  
      // 客戶端處理數(shù)據(jù)的邏輯  
  
   }  
});  

集成思路:重寫PropertyPlaceholderConfigurer,將diamond管理的配置交個spring,spring的xml可以直接使用${}來查詢數(shù)據(jù),增加工具類PropertiesUtils.java 方便查詢diamond管理的數(shù)據(jù)。具體代碼

<!-- 引入依賴diamond -->
<dependency>
    <groupId>com.taobao.diamond</groupId>
    <artifactId>diamond-client</artifactId>
    <version>2.0.5.4.taocode-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>com.taobao.diamond</groupId>
    <artifactId>diamond-utils</artifactId>
    <version>2.0.5.4.taocode-SNAPSHOT</version>
</dependency>

重寫PropertyPlaceholderConfigurer

package com.zyx.demo.common.spring;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

import java.util.Iterator;
import java.util.List;
import java.util.Properties;

/**
 * <p>重寫PropertyPlaceholderConfigurer,將diamond配置信息交給spring</p>
 */

public class SpringPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

    private List<String> diamondList;

    public List<String> getDiamondList() {
        return diamondList;
    }

    public void setDiamondList(List<String> diamondList) {
        this.diamondList = diamondList;
    }

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
        Properties properties = PropertiesUtils.getProperties(diamondList);
        if (properties == null) {
            String diamondFilePath = PropertiesUtils.DIAMOND_FILEPATH;//System.getProperty("user.home") + System.getProperty("file.separator") + ".diamond.domain";
            throw new RuntimeException("從diamond獲取配置為空(dataId和group是" + diamondList + "),請檢查diamond要連接的環(huán)境:" + diamondFilePath);
        }
        this.setProperties(properties);
        for (Iterator<Object> iterator = properties.keySet().iterator(); iterator.hasNext();) {
            String key = (String) iterator.next();
            String value = (String) properties.get(key);
            props.setProperty(key, value);
        }
        super.processProperties(beanFactoryToProcess, properties);
    }

}

PropertiesUtils.java工具類

package com.zyx.demo.common.spring;

import com.taobao.diamond.manager.ManagerListener;
import com.taobao.diamond.manager.ManagerListenerAdapter;
import com.taobao.diamond.manager.impl.DefaultDiamondManager;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * <p>工具類,獲取diamond配置</p>
 */

public class PropertiesUtils {

        public static Properties properties;

        private static Logger logger = Logger.getLogger(PropertiesUtils.class);
        private static final long TIME_OUT = 5000L;
        private static String diamondIpList;
        private static List<String> diamondIdgroupList;
        protected static final String DIAMOND_FILEPATH="diamond.data";

        public static Properties getProperties(List<String> diamondList) {
            diamondIdgroupList = diamondList;
            if (null == properties) {
                init();
            }
            return properties;
        }

        public static Properties getProperties() {
            if (null == properties) {
                init();
            }
            return properties;
        }

        /**
         * 根據(jù)key從map中取值
         */
        public static Object getValueByKey(String key) {
            if (null == properties) {
                init();
            }
            return properties.get(key);
        }

        public static String getStringValueByKey(String key) {
            return (String) getValueByKey(key);
        }

        public static int getIntValueByKey(String key) {
            return Integer.parseInt((String) getValueByKey(key));
        }

        public static double getDoubleValueByKey(String key) {
            return Double.parseDouble((String) getValueByKey(key));
        }

        public static boolean getBooleanValueByKey(String key) {
            return Boolean.parseBoolean((String) (getValueByKey(key)));
        }

        public static String getStringValueByKey(String key, String defaultV) {
            Object value = getValueByKey(key);
            if (value == null) {
                return defaultV;
            }
            return (String) value;
        }

        public static int getIntValueByKey(String key, int defaultV) {
            Object value = getValueByKey(key);
            if (value == null) {
                return defaultV;
            }
            return Integer.parseInt((String) value);
        }

        public static double getDoubleValueByKey(String key, double defaultV) {
            Object value = getValueByKey(key);
            if (value == null) {
                return defaultV;
            }
            return Double.parseDouble((String) value);
        }

        public static boolean getBooleanValueByKey(String key, boolean defaultV) {
            Object value = getValueByKey(key);
            if (value == null) {
                return defaultV;
            }
            return Boolean.parseBoolean((String) (value));
        }

        /**
         * init(讀取多個dataId 與 groupId )*/
        private static void init() {

            String diamondFilePath = PropertiesUtils.class.getClassLoader().getResource(DIAMOND_FILEPATH).getPath() ;//System.getProperty("user.home") + "/.diamond.domain";
            try {

                List<String> contentList = FileUtils.readLines(new File(diamondFilePath), "UTF-8");
                for (String ipList : contentList) {
                    if (!ipList.contains("#")) {
                        diamondIpList = ipList.trim();
                        break;
                    }
                }
            } catch (Exception e) {
                logger.error("獲取diamond文件內(nèi)容失敗:" + e.getMessage(), e);
            }
            logger.info("diaond-->filePath:" + diamondFilePath + " change diamondIpList:" + diamondIpList);
            if (diamondIdgroupList != null && diamondIpList != null) {
                for (String str : diamondIdgroupList) {
                    // dataid
                    String dataId = "";
                    String groupId = "";
                    if (str.indexOf(":") > -1) {
                        dataId = str.substring(0, str.indexOf(":"));
                    }
                    if (str.lastIndexOf(":") > -1) {
                        groupId = str.substring(str.indexOf(":") + 1,str.length());
                    }
                    if (!StringUtils.isEmpty(dataId) && !StringUtils.isEmpty(groupId)) {
                        DefaultDiamondManager manager = new DefaultDiamondManager(dataId, groupId, new ManagerListenerAdapter() {
                            public void receiveConfigInfo(String configInfo) {
                                //數(shù)據(jù)發(fā)生變更時,更新數(shù)據(jù)
                                putAndUpdateProperties(configInfo);
                            }
                        }, diamondIpList);
                        String configInfo = manager.getAvailableConfigureInfomation(TIME_OUT);
                        logger.debug("從diamond取到的數(shù)據(jù)是:" + configInfo);
                        putAndUpdateProperties(configInfo);
                    } else {
                        logger.error("diamond數(shù)據(jù)配置properties異常: DataId:" + dataId + ",Group:" + groupId);
                    }
                }
            } else {
                logger.error("diamond數(shù)據(jù)配置properties異常: diamondBeanList is null or diamondIpList is null");
            }
        }

        /**
         * 更新properties中數(shù)據(jù)*/
        public static void putAndUpdateProperties(String configInfo) {
            if (StringUtils.isNotEmpty(configInfo)) {
                if (properties == null) {
                    properties = new Properties();
                }
                try {
                    properties.load(new ByteArrayInputStream(configInfo.getBytes()));
                } catch (IOException e) {
                    logger.error("根據(jù)diamond數(shù)據(jù)流轉(zhuǎn)成properties異常" + e.getMessage(), e);
                }
            } else {
                logger.error("從diamond取出的數(shù)據(jù)為空,請檢查配置");
            }
        }

        public static List<String> getDiamondIdgroupList() {
            return diamondIdgroupList;
        }

        public static void setDiamondIdgroupList(List<String> diamondIdgroupList) {
            PropertiesUtils.diamondIdgroupList = diamondIdgroupList;
        }

        public String getDiamondIpList() {
            return diamondIpList;
        }

}

spring配置

    <!-- diamond管理配置文件 -->
    <bean id = "propertyConfigurer"  class="com.zyx.demo.common.spring.SpringPropertyPlaceholderConfigurer">
        <property name="diamondList">
            <list>
                <value>com-zyx-demo:com-zyx-demo</value>
            </list>
        </property>
    </bean>

容災(zāi)機(jī)制

是diamond具有一套完備的容災(zāi)機(jī)制,容災(zāi)機(jī)制涉及到client和server兩部分,主要包括以下幾個方面:
1、server存儲數(shù)據(jù)的方式。
server存儲數(shù)據(jù)是“數(shù)據(jù)庫+本地文件”的方式,集群間的數(shù)據(jù)同步我們在之前的文章中講過(請參考專題二的原理部分),client訂閱數(shù)據(jù)時,訪問的是本地文件,不查詢數(shù)據(jù)庫,這樣即使數(shù)據(jù)庫出問題了,仍然不影響client的訂閱。
2、server是一個集群。
這是一個基本的容災(zāi)機(jī)制,集群中的一臺server不可用了,client發(fā)現(xiàn)后可以自動切換到其他server上進(jìn)行訪問,自動切換在client內(nèi)部實現(xiàn)。
3、client保存snapshot
client每次從server獲取到數(shù)據(jù)后,都會將數(shù)據(jù)保存在本地文件系統(tǒng),diamond稱之為snapshot,即數(shù)據(jù)快照。當(dāng)client下次啟動發(fā)現(xiàn)在超時時間內(nèi)所有server均不可用(可能是網(wǎng)絡(luò)故障),它會使用snapshot中的數(shù)據(jù)快照進(jìn)行啟動。
4、client校驗MD5
client每次從server獲取到數(shù)據(jù)后,都會進(jìn)行MD5校驗(數(shù)據(jù)保存在responsebody,MD5保存在responseheader),以防止因網(wǎng)絡(luò)故障造成的數(shù)據(jù)不完整,MD5校驗不通過直接拋出異常。
5、client與server分離
client可以和server完全分離,單獨使用,diamond定義了一個“容災(zāi)目錄”的概念,client在啟動時會創(chuàng)建這個目錄,每次主動獲取數(shù)據(jù)(即調(diào)用getAvailableConfigInfomation()方法),都會優(yōu)先從“容災(zāi)目錄”獲取數(shù)據(jù),如果client按照一個固定的規(guī)則,在“容災(zāi)目錄”下配置了需要的數(shù)據(jù),那么client直接獲取到數(shù)據(jù)返回,不再通過網(wǎng)絡(luò)從diamond-server獲取數(shù)據(jù)。同樣的,在每次輪詢時,都會優(yōu)先輪詢“容災(zāi)目錄”,如果發(fā)現(xiàn)配置還存在于其中,則不再向server發(fā)出輪詢請求。以上的情形,會持續(xù)到“容災(zāi)目錄”的配置數(shù)據(jù)被刪除為止。
根據(jù)以上的容災(zāi)機(jī)制,我們可以總結(jié)一下diamond整個系統(tǒng)完全不可用的條件:
1、數(shù)據(jù)庫不可用。
2、所有server均不可用。
3、client主動刪除了snapshot
4、client沒有備份配置數(shù)據(jù),導(dǎo)致其不能配置“容災(zāi)目錄”。
同時滿足以上4個條件的概率,在生產(chǎn)環(huán)境中是極小的。
以上就是diamond的容災(zāi)機(jī)制

其他相關(guān)

Xdiamond
1、基于數(shù)據(jù)庫做配置存儲
2、相對于diamond增加了權(quán)限設(shè)計,結(jié)合Secret key,保證配置的安全
3、配置緩存在本地,防止應(yīng)用因為網(wǎng)絡(luò)問題而不能啟動

disconf是來自百度的分布式配置管理平臺,包括百度、滴滴出行、銀聯(lián)、網(wǎng)易、拉勾網(wǎng)、蘇寧易購、順豐科技 等知名互聯(lián)網(wǎng)公司正在使用! https://github.com/knightliao/disconf

總結(jié)

以上是生活随笔為你收集整理的diamond简介和使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。