Dynomite 简介

Dynomite是NetFlix对亚马逊分布式引擎Dynamo的一个开源通用实现,它不仅支持基于内存K/V数据库,
还支持持久化的MySQL、BerkeleyDb、LevelDb等数据库,并具有简单、高效、支持跨数据中心的数据复制功能等优点。
Dynomite的最终目标是提供数据库存储引擎不能提供的简单、高效、跨数据中心的数据复制功能。目前,Dynomite已经实现了对Redis和Memcached的支持。

Dynomite 安装配置

Build

从源代码构建Dynomite并启用调试日志,禁用assertions:

$ git clone git@github.com:Netflix/dynomite.git
$ cd dynomite
$ autoreconf -fvi
$ ./configure --enable-debug=yes    // 开发环境需要,生产环境不需要
$ make
$ src/dynomite -h

调试模式构建Dynomite:

$ git clone git@github.com:Netflix/dynomite.git
$ cd dynomite
$ autoreconf -fvi
$ CFLAGS="-ggdb3 -O0" ./configure --enable-debug=full
$ make
$ sudo make install

Help

Usage: dynomite [-?hVdDt] [-v verbosity level] [-o output file]
                  [-c conf file] [-s stats port] [-a stats addr]
                  [-i stats interval] [-p pid file] 
Options:
  -h, --help              : this help
  -V, --version           : show version and exit
  -t, --test-conf         : test configuration for syntax errors and exit
  -g, --gossip            : enable gossip (default: disabled)
  -d, --daemonize         : run as a daemon
  -D, --describe-stats    : print stats description and exit
  -v, --verbosity=N       : set logging level (default: 5, min: 0, max: 11)
  -o, --output=S          : set logging file (default: stderr)
  -c, --conf-file=S       : set configuration file (default: conf/dynomite.yml)
  -p, --pid-file=S        : set pid file (default: off)
  -x, --admin-operation=N : set size of admin operation (default: 0)

Configuration

Dynomite可以通过进程启动时通过-c或--conf-file命令行参数指定的YAML文件进行配置。 配置文件可解析并理解以下关键字:

  • env 指定节点的环境。 目前支持aws和网络(用于物理数据中心)。
  • datacenter 数据中心的名称。 请参考架构文档
  • rack 机架的名称。 请参考架构文档.
  • dyn_listen dynomite节点用于进行内部通信和gossip的端口。
  • enable_gossip 启用gossip而不是静态tokens(默认值:false)。gossip是实验性的。
  • gos_interval 在gossip round结束时的睡眠时间(以毫秒为单位)。
  • tokens 节点拥有的令牌。目前,我们不支持vnode,所以现在只能使用一个令牌。
  • dyn_seed_provider 提供seed节点列表的seed提供者实现。
  • dyn_seeds seed节点列表,格式如下:address:port:rack:dc:tokens(目前不支持vnode的节点)。
  • listen 该服务器池的监听地址和端口(名称:port或ip:port)
  • timeout 我们等待与服务器建立连接或从服务器接收响应的以msec为单位的超时值。默认情况下,我们无限期地等待。
  • preconnect 一个布尔值,用于控制dynomite是否应在进程启动时预先连接到此池中的所有服务器。默认为false。
  • data_store一个整数值,用于控制服务器池是否使用redis(0)或memcached(1)或其他协议。默认为redis(0)。
  • auto_eject_hosts 一个布尔值,用于控制在连续失败server_failure_limit次时是否应暂时弹出该服务器。默认为false。
  • server_retry_timeout 当auto_eject_host设置为true时,在临时弹出的服务器上重试之前等待的超时值(以毫秒为单位)。 默认为30000毫秒。
  • server_failure_limit 服务器上连续发生故障的次数,当auto_eject_host设置为true时,达到该次数会导致临时弹出。默认为2。
  • servers 服务器池的本地服务地址,端口和权重的列表(名称:port:weight或ip:port:weight)。目前只有一个。
  • secure_server_option 加密通信。 必须是“none”,“rack”,“datacenter”或“all”之一。 datacenter意味着数据中心之间的所有通信都是加密的,但在datacenter内则不是。 rack表示机架和区域之间的所有通信都已加密,但同一机架内节点之间的通信未加密。 all意味着所有节点之间的所有通信都被加密。 而none表示没有任何通信被加密。
  • stats_listen REST端点的地址和端口号以及访问统计信息。
  • stats_interval 以msec为单位设置统计间隔(默认值:30000毫秒)。
  • mbuf_size mbuf块的大小(以字节为单位)(默认值:16384字节)。
  • max_msgs 要分配的最大消息数(默认值:200000)。

可参考官方配置文件示例.

最后,为了更容易地编写语法正确的配置文件,dynomite提供了一个命令行参数-t或--test-conf,可用于测试YAML配置文件是否存在任何语法错误。

Dyno客户端

  • Dyno封装了利用Dynomite扩展客户端应用所需的功能。
  • 这篇博客可以查看介绍信息。
  • wiki查看文献和实例。

Dyno客户端特征

  • 永久连接的连接池 - 这有助于减少客户端连接重用时Dynomite服务器上的连接流失。
  • 支持拓扑的负载平衡(令牌感知),用于避免向不是指定数据所有者的Dynomite协调节点跳转。
  • 当本地Dynomite机架节点发生故障时,通过智能故障切换到远程机架实现应用程序弹性。
  • 通过不断监控连接健康状况并回收不健康的连接,应对弹回的网络故障。
  • 通过surgically将流量从任何需要离线维护的节点路由出去的能力。
  • 灵活的重试策略,如指数退避等。
  • 洞察连接池指标。
  • 高度可配置和可插拔的连接池组件,用于实现您的高级功能。

maven依赖

可直接将下面的maven依赖代码拷贝到pom.xml文件中。

    <!-- dyno客户端核心包 -->
    <dependency>
      <groupId>com.netflix.dyno</groupId>
      <artifactId>dyno-core</artifactId>
      <version>1.6.3</version>
    </dependency>
    <!-- dyno客户端整合jedis的包 -->
    <dependency>
      <groupId>com.netflix.dyno</groupId>
      <artifactId>dyno-jedis</artifactId>
      <version>1.6.3</version>
    </dependency>

示例代码

package com.linuxcoming.dyno;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import com.netflix.dyno.connectionpool.Host;
import com.netflix.dyno.connectionpool.Host.Status;
import com.netflix.dyno.connectionpool.HostSupplier;
import com.netflix.dyno.connectionpool.OperationResult;
import com.netflix.dyno.connectionpool.TokenMapSupplier;
import com.netflix.dyno.connectionpool.impl.lb.HostToken;
import com.netflix.dyno.jedis.DynoJedisClient;

public class DynoDemo {
    
    protected DynoJedisClient client;
    protected final String rack;
    protected final String clusterName;
    
    public DynoDemo(String clusterName,String localRack){
        this.rack = localRack;
        this.clusterName = clusterName;
    }
    
    public void initWithHost(){
        //Dynomite监听端口
        final int port = 8102;
        //配置主机
        final HostSupplier localHostSupplier = new HostSupplier(){
            final Host hostSupplierHost = new Host("localhost",port,rack,Status.Up);
            public List<Host> getHosts() {
                return Collections.singletonList(hostSupplierHost);
            }
        };
        
        //自定义TokenMapSupplier,关联token与host
        final TokenMapSupplier tokenSupplier = new TokenMapSupplier(){
            final Host tokenHost = new Host("localhost",port,rack,Status.Up);
            final HostToken localHostToken = new HostToken(100000l,tokenHost);
            public List<HostToken> getTokens(Set<Host> activeHosts) {
                return Collections.singletonList(localHostToken);
            }

            public HostToken getTokenForHost(Host host, Set<Host> activeHosts) {
                return localHostToken;
            }
        };
        init(localHostSupplier,port,tokenSupplier);
    }
    
    public void init(HostSupplier hostSupplier,int port,final TokenMapSupplier tokenSupplier){
        client = new DynoJedisClient.Builder().withApplicationName("demo")
                .withHostSupplier(hostSupplier).withTokenMapSupplier(tokenSupplier).build();
    }
    
    
    public void runSimpleTest(){
        int numKeys = 10;
        System.out.println("Simple test");
        
        for(int i=0;i<numKeys;i++){
            System.out.println("writing key/value=>DynoClientTest:"+i+" / "+i);
            client.set("DynoClientTest-"+i,""+i);
        }
        
        for(int i=0;i<numKeys;i++){
            OperationResult<String> result = client.d_get("DynoClientTest-"+i);
            System.out.println("Reading key: "+i+",value:"+result.getResult());
        }
        client.stopClient();
        
    }
    
    
    public static void main(String[] args){
        DynoDemo demo = new DynoDemo("clustTest","rack1");
        demo.initWithHost();
        demo.runSimpleTest();
    }
}

运行结果

    Simple test
    writing key/value=>DynoClientTest:0 / 0
    writing key/value=>DynoClientTest:1 / 1
    writing key/value=>DynoClientTest:2 / 2
    writing key/value=>DynoClientTest:3 / 3
    writing key/value=>DynoClientTest:4 / 4
    writing key/value=>DynoClientTest:5 / 5
    writing key/value=>DynoClientTest:6 / 6
    writing key/value=>DynoClientTest:7 / 7
    writing key/value=>DynoClientTest:8 / 8
    writing key/value=>DynoClientTest:9 / 9
    Reading key: 0,value:0
    Reading key: 1,value:1
    Reading key: 2,value:2
    Reading key: 3,value:3
    Reading key: 4,value:4
    Reading key: 5,value:5
    Reading key: 6,value:6
    Reading key: 7,value:7
    Reading key: 8,value:8
    Reading key: 9,value:9

参考链接

【腾讯云】境外1核2G服务器低至2折,半价续费券限量免费领取!
https://cloud.tencent.com/act/cps/redirect?redirect=1068&cps_key=e4b50f6c64a4480367f8a8d16fd07c5a&from=console

标签: cache, redis, 分布式缓存, dynomite, memcache

添加新评论