diamond简介和使用

简介

diamond是淘宝内部使用的一个管理持久配置的系统,它的特点是简单、可靠、易用,目前淘宝内部绝大多数系统的配置,由diamond来进行统一管理。

diamond为应用系统提供了获取配置的服务,应用不仅可以在启动时从diamond获取相关的配置,而且可以在运行中对配置数据的变化进行感知并获取变化后的配置数据。

持久配置是指配置数据会持久化到磁盘和数据库中。

diamond的特点是简单、可靠、易用:

简单:整体结构非常简单,从而减少了出错的可能性。

可靠:应用方在任何情况下都可以启动,在承载淘宝核心系统并正常运行一年多以来,没有出现过任何重大故障。

易用:客户端使用只需要两行代码,暴露的接口都非常简单,易于理解。

1、作为一个配置中心,diamond的功能分为发布和订阅两部分。因为diamond存放的是持久数据,这些数据的变化频率不会很高,甚至很低,所以发布采用手工的形式,通过diamond后台管理界面发布;订阅是diamond的核心功能,订阅通过diamond-client的API进行。
2、diamond服务端采用mysql加本地文件的形式存放配置数据。发布数据时,数据先写到mysql,再写到本地文件;订阅数据时,直接获取本地文件,不查询数据库,这样可以最大程度减少对数据库的压力。
3、diamond服务端是一个集群,集群中的每台机器连接同一个mysql,集群之间的数据同步通过两种方式进行,一是每台server定时去mysqldump数据到本地文件,二是某一台server接收发布数据请求,在更新完mysql和本机的本地文件后,发送一个HTTP请求(通知)到集群中的其他几台server,其他server收到通知,去mysql中将刚刚更新的数据dump到本地文件。
4、每一台server前端都有一个nginx,用来做流量控制。
5、图中没有将地址服务器画出,地址服务器是一台有域名的机器,上面运行有一个HTTPserver,其中有一个静态文件,存放着diamond服务器的地址列表。客户端启动时,根据自身的域名绑定,连接到地址服务器,取回diamond服务器的地址列表,从中随机选择一台diamond服务器进行连接。
可以看到,整个diamond的架构非常简单,使用的都是最常用的一些技术以及产品,它之所以表现得非常稳定,跟其架构简单是分不开的,当然,稳定的另一个主要原因是它具备一套比较完善的容灾机制,容灾机制将在下一篇文章中讲述。

源码地址

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

服务端安装

  1. 检出源码,修改配置文件 jdbc.properties 中的数据库连接信息,完成之后maven打包
  2. 数据库执行初始化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 ;
    
     
  3. 将打好的包 diamond-server.war 放到tomcat工作目录,启动。启动成功之后,访问  http://localhost:8090/diamond-server/ 
  4. 发布数据,账号密码是user.properties中配置的,默认是 abc=123。登录后进入后台管理界面,然后点击“配置信息管理”—— “添加配置信息”,在输入框中输入dataId、group、内容,最后点击“提交”即可。
    成功后,可以在“配置信息管理”中查询到发布的数据。
  5. 集群安装。修改node.properties,格式为   ip\:port  ,这里面的冒号,一定要通过\转义一下,要不然获取地址不对。当存在node节点的配置,发布修改数据后会通知其他节点更新。
  6. 每台diamond-server 前建议增加nginx转发,方便限流,而且客户端默认请求80端口
  7. 其他配置: system.properties中的dump_config_interval 是多久去更新一次本地缓存的数据 默认是 600秒

客户端安装

客户端获取数据方法:

DiamondManager manager = new DefaultDiamondManager(group, dataId, new ManagerListener() {  
   public Executor getExecutor() {  
       return null;  
   }  
  
   public void receiveConfigInfo(String configInfo) {  
      // 客户端处理数据的逻辑  
  
   }  
});  

 

集成思路:重写PropertyPlaceholderConfigurer,将diamond管理的配置交个spring,spring的xml可以直接使用${}来查询数据,增加工具类PropertiesUtils.java 方便查询diamond管理的数据。具体代码

<!-- 引入依赖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要连接的环境:" + 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;
        }

        /**
         * 根据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文件内容失败:" + 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) {
                                //数据发生变更时,更新数据
                                putAndUpdateProperties(configInfo);
                            }
                        }, diamondIpList);
                        String configInfo = manager.getAvailableConfigureInfomation(TIME_OUT);
                        logger.debug("从diamond取到的数据是:" + configInfo);
                        putAndUpdateProperties(configInfo);
                    } else {
                        logger.error("diamond数据配置properties异常: DataId:" + dataId + ",Group:" + groupId);
                    }
                }
            } else {
                logger.error("diamond数据配置properties异常: diamondBeanList is null or diamondIpList is null");
            }
        }

        /**
         * 更新properties中数据*/
        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("根据diamond数据流转成properties异常" + e.getMessage(), e);
                }
            } else {
                logger.error("从diamond取出的数据为空,请检查配置");
            }
        }

        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>

 

 

容灾机制

是diamond具有一套完备的容灾机制,容灾机制涉及到client和server两部分,主要包括以下几个方面:
1、server存储数据的方式。
server存储数据是“数据库+本地文件”的方式,集群间的数据同步我们在之前的文章中讲过(请参考专题二的原理部分),client订阅数据时,访问的是本地文件,不查询数据库,这样即使数据库出问题了,仍然不影响client的订阅。
2、server是一个集群。
这是一个基本的容灾机制,集群中的一台server不可用了,client发现后可以自动切换到其他server上进行访问,自动切换在client内部实现。
3、client保存snapshot
client每次从server获取到数据后,都会将数据保存在本地文件系统,diamond称之为snapshot,即数据快照。当client下次启动发现在超时时间内所有server均不可用(可能是网络故障),它会使用snapshot中的数据快照进行启动。
4、client校验MD5
client每次从server获取到数据后,都会进行MD5校验(数据保存在responsebody,MD5保存在responseheader),以防止因网络故障造成的数据不完整,MD5校验不通过直接抛出异常。
5、client与server分离
client可以和server完全分离,单独使用,diamond定义了一个“容灾目录”的概念,client在启动时会创建这个目录,每次主动获取数据(即调用getAvailableConfigInfomation()方法),都会优先从“容灾目录”获取数据,如果client按照一个固定的规则,在“容灾目录”下配置了需要的数据,那么client直接获取到数据返回,不再通过网络从diamond-server获取数据。同样的,在每次轮询时,都会优先轮询“容灾目录”,如果发现配置还存在于其中,则不再向server发出轮询请求。以上的情形,会持续到“容灾目录”的配置数据被删除为止。
根据以上的容灾机制,我们可以总结一下diamond整个系统完全不可用的条件:
1、数据库不可用。
2、所有server均不可用。
3、client主动删除了snapshot
4、client没有备份配置数据,导致其不能配置“容灾目录”。
同时满足以上4个条件的概率,在生产环境中是极小的。
以上就是diamond的容灾机制

其他相关

Xdiamond
1、基于数据库做配置存储
2、相对于diamond增加了权限设计,结合Secret key,保证配置的安全
3、配置缓存在本地,防止应用因为网络问题而不能启动


disconf是来自百度的分布式配置管理平台,包括百度、滴滴出行、银联、网易、拉勾网、苏宁易购、顺丰科技 等知名互联网公司正在使用!  https://github.com/knightliao/disconf

 

转载于:https://www.cnblogs.com/zhangyaxiao/p/8183617.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Lattice Diamond是一款用于FPGA设计的综合工具,以下是使用教程: 1. 安装Lattice Diamond软件,打开软件后选择“New Project”创建新项目。 2. 在“New Project”窗口中选择“FPGA Project”,然后选择FPGA型号和开发板型号。 3. 在“Project Navigator”窗口中,右键点击“Sources”文件夹,选择“New Source”创建新的源文件。 4. 在“New Source”窗口中选择“VHDL”或“Verilog”语言,输入文件名并点击“Finish”创建源文件。 5. 在“Project Navigator”窗口中,右键点击“Constraints”文件夹,选择“New Constraint Set”创建新的约束文件。 6. 在“New Constraint Set”窗口中输入约束文件名并点击“Finish”创建约束文件。 7. 在约束文件中添加时钟约束、输入输出约束等约束条件。 8. 在“Project Navigator”窗口中,右键点击“Run”文件夹,选择“New Configuration”创建新的配置文件。 9. 在“New Configuration”窗口中选择FPGA型号、开发板型号和约束文件,并点击“Finish”创建配置文件。 10. 在“Project Navigator”窗口中,右键点击“Run”文件夹,选择“Start Compilation”开始编译。 11. 编译完成后,在“Project Navigator”窗口中,右键点击“Run”文件夹,选择“Program Device”将设计下载到FPGA开发板中。 以上就是Lattice Diamond使用教程,希望对您有所帮助。 ### 回答2: Lattice Diamond是Lattice Semiconductor公司开发的集成电路设计软件,用于FPGA、CPLD等电路的设计、仿真和综合。本文将为大家提供Lattice Diamond使用教程。 一、Lattice Diamond的安装 1.首先要从Lattice Semiconductor公司网站下载Lattice Diamond的安装文件。 2.运行安装文件,按照提示完成安装。 3. 安装完成后,在Windows系统的桌面可以找到Lattice Diamond的快捷方式。 二、项目创建 1. 打开Lattice Diamond,点击“File”选项卡,选择“New Project”来创建一个新项目。 2. 输入项目名称,选择项目的保存位置,点击“Next”。 3. 选择相应的FPGA器件类型和产品系列,点击“Next”。 4. 选择FPGA器件的封装类型,点击“Next”。 5. 选择FPGA器件的速度等级、工作温度等级,点击“Finish”。 三、设计流程 1. 打开设计界面,可以新建或打开已有的设计文件。 2. 在设计界面上进行原理图绘制,可以使用工具栏中提供的元件、连接等功能进行设计。 3. 设计完成后,进行电路仿真,验证电路功能是否正常。 4. 采用逻辑综合工具将设计代码转换成FPGA的硬件描述语言,生成出逻辑包络图文件。 5. 使用逻辑实现工具对逻辑包络图进行分区、综合等处理,将设计代码和FPGA硬件资源进行映射。 6. 使用时序约束工具,根据设计目的和FPGA器件的速度等级,制定时序要求。 7. 运行后仿真检查; 8. 生成配置文件。 四、FPGA编程 1. 将开发板上的FPGA和PC机通过USB线连接。 2. 打开Lattice Diamond的Programmer工具。 3. 选择FPGA器件类型和设备品牌。 4. 选择配置文件,点击“Program”进行FPGA编程。 五、总结 通过以上步骤,我们可以使用Lattice Diamond完成FPGA电路设计、仿真、综合、编程等工作。该软件具有功能强大、使用简单等优点,但需要掌握的知识点较多,需要花费一定时间学习和实践才能熟练掌握。 ### 回答3: Lattice Diamond是一种集成电路设计软件,在数字信号处理、数据记录、图像处理及控制等领域得到广泛应用。对于初学者来说,使用这种软件进行电路设计可能会有些困难。下面将为大家介绍Lattice Diamond使用教程。 首先,安装Lattice Diamond软件。在安装之前,需要先下载Lattice Diamond安装包并解压。安装包解压后,将打开“diamond-x.x-win32.exe”程序并按照指示进行安装即可。 接下来,打开Lattice Diamond软件。首次打开软件时,可能需要进行一些初步设置,例如选择默认的工作目录和设置选项。 在打开软件后,可以创建新的工程。要创建新的工程,首先需要选择Lattice设备系列。之后,选择要使用的开发板,以及所需的开发工具和编程器。在设备选项中设置好后,即可创建新工程。 在创建好的工程中,可以创建模块。模块可以由门级元器件或其他复杂电路构成。在创建模块时,可以使用Lattice Diamond中提供的各种元器件库,例如计数器、加法器、寄存器等。之后,将门级元件拖动到窗口中,进行电路设计。 在完成电路设计后,可以对电路进行仿真。在仿真之前,需要编写程序或使用已有的仿真脚本来进行仿真。在完成仿真脚本后,可以使用Lattice Diamond中提供的仿真器,例如ModelSim等,对设计的电路进行仿真。 最后,在完成工程的设计和仿真后,可以进行电路布局和布线。在布局和布线时,需要根据设计要求进行布线,并避免出现地线或电源线等干扰。在完成布线后,即可进行电路的验证和测试,以确保电路的正常工作。 综上所述,Lattice Diamond是一款功能强大的电路设计软件,通过良好的使用方法和操作技巧,可以轻松完成各种数字电路设计任务。诸如电路设计、仿真、布局、布线和测试等各种功能,可以帮助工程师们更好地完成数字电路的设计任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值