Redis Cluster Resharding实践

简介

在Redis Cluster运维过程中,会出现水平扩展集群,而水平扩展集群即新增master节点。Redis Cluster需要就需要重新划分slot,数据迁移等操作,本文只是探讨实现过程,用Redis-cli自带命令实现Resharding。

实践

过程简介

真正开始Resharding之前,会先在源结点和目的结点上执行cluster setslot importing和cluster setslot migrating命令,将要迁移的槽分别标记为迁出中和导入中的状态。然后,执行cluster getkeysinslot获得Slot中的所有Key。最后就可以对每个Key执行migrate命令进行迁移了。槽迁移完成后,执行cluster setslot命令通知整个集群槽的指派已经发生变化。

关于迁移过程中的数据访问,客户端访问源结点时,如果Key还在源结点上就直接操作。如果已经不在源结点了,就向客户端返回一个ASK错误,将客户端重定向到目的结点。

实践过程

1.redis-cli 实现

迁移备注:
实现迁移9013node中952 slot到9015 node上,其中源9013 node_id为a92e4554aa2828b85f50f8f8318429d68f5213ca,目的9015node_id为c725cda7b314701c6892f035224700e9a8336699

  • 详解
    1
    2
    3
    4
    5
    6
    在迁移目的节点执行cluster setslot <slot> IMPORTING <node ID>命令,指明需要迁移的slot和迁移源节点。
    在迁移源节点执行cluster setslot <slot> MIGRATING <node ID>命令,指明需要迁移的slot和迁移目的节点。
    在迁移源节点执行cluster getkeysinslot获取该slot的key列表。
    在迁移源节点执行对每个key执行migrate命令,该命令会同步把该key迁移到目的节点。
    在迁移源节点反复执行cluster getkeysinslot命令,直到该slot的列表为空。
    在迁移源节点或者目的节点执行cluster setslot <slot> NODE <node ID>,完成迁移操作。
  • 实践
    1
    2
    3
    4
    redis-cli -c -p 9015 cluster  setslot 952 importing a92e4554aa2828b85f50f8f8318429d68f5213ca//目的节点执行
    redis-cli -c -p 9013 cluster setslot 952 migrating c725cda7b314701c6892f035224700e9a8336699//源节点执行
    redis-cli -c -h 192.168.0.101 -p 9013 migrate 192.168.0.101 9015 "truman:00000829" 0 1000
    redis-cli -c -p 9015 cluster setslot 952 node c725cda7b314701c6892f035224700e9a8336699
    相关命令参考如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //集群
    CLUSTER INFO 打印集群的信息
    CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。
    //节点
    CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
    CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。
    CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。
    CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。
    //槽(slot)
    CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。
    CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。
    CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
    CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
    CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。
    CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。
    CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。
    //键
    CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。
    CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。
    CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。

2.redis-trib.rb 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
#把127.0.0.1:9013当前master迁移到127.0.0.1:9015上  
redis-trib.rb reshard 127.0.0.1:9013
#根据提示选择要迁移的slot数量(ps:这里选择500)
How many slots do you want to move (from 1 to 16384)? 1(源master的需要迁移slot数量,不能单个指定)
#选择要接受这些slot的node-id(127.0.0.1:9015)
What is the receiving node ID? c725cda7b314701c6892f035224700e9a8336699 (ps:127.0.0.1:9015的node-id)
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1:a92e4554aa2828b85f50f8f8318429d68f5213ca(源master的node-id)
Source node #2:done
#打印被移动的slot后,输入yes开始移动slot以及对应的数据.
#Do you want to proceed with the proposed reshard plan (yes/no)? yes

参考

  1. http://redis.io/commands/cluster-setslot
  2. http://carlosfu.iteye.com/blog/2243056(该博客较详细,本文未参考,只是做记录)

linux 运维

1.后台执行任务

问题描述:

在linux中执行一些服务,我们通常会使用sudo命令,以root权限运行,再以nohup后台运行,但是有的情况下需要交互操作。

解决方案:

1.首先输入命令,

1
sudo nohup commandline

2.使用以下快捷键中断

1
ctrl+z

3.在命令台中输入

1
bg

2.监控linux磁盘IO

可以使用iostat命令,iostat还有一个比较常用的选项-x,该选项将用于显示和io相关的扩展数据。(可以结合grep一起使用便于过滤具体磁盘)

命令解释:
参数 -d 表示,显示设备(磁盘)使用状态;-k某些使用block为单位的列强制使用Kilobytes为单位(同样可以用m表示兆);2表示,数据显示每隔2秒刷新一次。

1
iostat -d -k 2

输出信息解释

1
2
3
4
5
6
tps:该设备每秒的传输次数(Indicate the number of transfers per second that were issued to the device.)。"一次传输"意思是"一次I/O请求"。多个逻辑请求可能会被合并为"一次I/O请求"。"一次传输"请求的大小是未知的。

kB_read/s:每秒从设备(drive expressed)读取的数据量;
kB_wrtn/s:每秒向设备(drive expressed)写入的数据量;
kB_read:读取的总数据量;
kB_wrtn:写入的总数量数据量;这些单位都为Kilobytes。

简介

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎。Kibanna是针对ElasticSearch一个界面UI。Packetbeat是监控网络数据包一个工具,分布式wireshark。

Packetbeat 是一个实时的网络数据包分析器,通过结合ES可以构建一个应用监控和性能分析系统。Packetbeat 可以将监控数据发送到es,或者redis,logstash中。目前支持以下协议:

  • ICMP (v4 and v6)
  • DNS
  • HTTP
  • Mysql
  • PostgreSQL
  • Redis
  • Thrift-RPC
  • MongoDB
  • Memcache

搭建

搭建Es

  1. 下载
    1
    wget https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/2.3.4/elasticsearch-2.3.4.tar.gz
  2. 解压
    1
    tar -xvf elasticsearch-2.3.4.tar.gz
  3. 配置 ES
    默认配置即可正常使用,但配置config/elasticsearch.yml使用效果更好。
    配置如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    cluster.name: my-application
    node.name: node-1
    node.master: true
    node.data: true
    path.logs: /data/truman/elasticsearch-2.3.4/logs
    bootstrap.mlockall: true

    network.host: 192.168.1.42

    http.port: 9200

    discovery.zen.ping.multicast.enabled: false
    discovery.zen.ping.unicast.hosts: ["192.168.1.42"]

    discovery.zen.fd.ping_interval: 1s
    discovery.zen.fd.ping_timeout: 30s
    discovery.zen.fd.ping_retries: 5

    action.auto_create_index: true
    action.disable_delete_all_indices: true
    indices.memory.index_buffer_size: 30%
    indices.memory.min_shard_index_buffer_size: 12mb
    indices.memory.min_index_buffer_size: 96mb
    action.write_consistency: one
    index.number_of_shards: 3
    index.number_of_replicas: 1
    threadpool:
    bulk:
    type: fixed
    queue_size: 300

    index.translog.flush_threshold_period: 10m
  4. 启动
    在使用root账户启动脚本可能会报错,在次修改一下elasticsearch启动脚本,增加以下内容:
    1
    ES_JAVA_OPTS="-Des.insecure.allow.root=true"
    然后后台启动脚本
    1
    nohup bin/elasticsearch &
    访问 http://192.168.1.42:9200/即可查看是否启动成功。
  5. 安装head plugin
    head 插件能够可视化操作index与数据,在http://192.168.1.42:9200/_plugin/head/上进行操作

安装

1
bin/plugin install mobz/elasticsearch-head

移除

1
bin/plugin remove head

安装kibana

  1. 下载
    1
    wget https://download.elastic.co/kibana/kibana/kibana-4.5.2-linux-x64.tar.gz
  2. 启动
    1
    2
    3
    tar -xvf kibana-4.5.2-linux-x64.tar.gz
    cd kibana-4.5.2-linux-x64
    bin/kibana
    在浏览器中访问http://192.168.1.42:5601查看是否成功。

安装Packetbeat

  1. 下载
    1
    wget https://download.elastic.co/beats/packetbeat/packetbeat-1.2.3-x86_64.tar.gz
  2. 解压
    1
    tar -xvf packetbeat-1.2.3-x86_64.tar.gz
  3. 配置 Packetbeat
    修改es输出即可,默认是localhost,将该内容修改为es所在的主机ip,即可使用默认配置运行了。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    output:
    ### Elasticsearch as output
    elasticsearch:
    # Array of hosts to connect to.
    hosts: ["192.168.1.42:9200"]
    template:

    # Template name. By default the template name is packetbeat.
    #name: "packetbeat"

    # Path to template file
    path: "packetbeat.template.json"

    # Overwrite existing template
    #overwrite: false
    修改完成后,可以通过以下命令检验修改配置是否正确(该shell需要root权限)
    1
    sudo ./packetbeat -configtest -e
  4. 加载索引模板(index template)到es
  • 加载
    1
    curl -XPUT 'http://192.168.1.42:9200/_template/packetbeat' -d@/etc/packetbeat/packetbeat.template.json
    加载成功后,访问以下网址,看packetbeat索引模板是否加上。
    1
    http://192.168.1.42:9200/_template/packetbeat
  • 删除模板文件
    1
    curl -XDELETE 'http://192.168.1.42:9200/_template/packetbeat'
  1. 启动
    1
    sudo nohup ./packetbeat &
  2. 测试
    模拟简单http请求
    1
    curl http://www.aibibang.com > /dev/null
    查询数据
    1
    curl -XGET 'http://192.168.1.42:9200/packetbeat-*/_search?pretty'
    查询出数据,即可证明安装成功!

经验总结

  1. 索引未创建成功

在搭建过程中,可能由于索引模板配置错误,导致索引未创建成功。但还存在一种情况,即没有数据采集进去。采集到数据以后才会根据索引模板创建索引
2. thrift 监控配置

目前对thrift监控仅支持binary协议,详细配置如下

1
2
3
4
5
6
7
8
9
10
11
thrift:
# Configure the ports where to listen for Thrift-RPC traffic. You can disable
# the Thrift-RPC protocol by commenting out the list of ports.
ports: [9090]
transport_type: framed
protocol_type: binary
string_max_size: 200
collection_max_size: 20
capture_reply: true
obfuscate_strings: true
drop_after_n_struct_fields: 100
  1. 修改采集字段
    使用过程中,希望采集自定义字段,当前版本未发现。但在最新版本5.0.0-alpha4中可通过修改yml配置文件删除掉不需要采集的字段。
    在5.0.0-alpha4中配置如下:
    1
    2
    3
    filters:
    - drop_fields:
    fields: ["request", "query","server","proc","client_server"]
    其实老的版本在index template中也是可以设置的。通过设置_source,例如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    "_source": {
    "excludes": [
    "request",
    "query",
    "server",
    "proc",
    "params",
    "beat.hostname",
    "client_server"
    ]
    },

RedisCluster搭建

前言

现在越来越多的公司开始使用redis cluster,这就要求大家能够学会快速搭建redis cluster集群,在官网上也是有很详细的入门指导,本文章只是自己搭建后总结,主要使用两种方式搭建:1. 官网上使用的redis-trib.rb脚本构建集群;2. 使用shel 命令搭建。

准备

因为两种方式都需要提前启动好相应的redis实例,因为将公共步骤放在准备工作中。这一步比较简单,主要是按端口新建不同文件夹,然后复制redis.conf,修改其中port对应的端口。集群高可用需要至少三个node,本次采用3 master、3slave架构。步骤如下:
1.

1
2
mkdir 9000
cp redis.conf 9000/
  1. 修改复制后的redis.conf:
    cluster-enabled yes
    port 9000

  2. 1
    src/redis-server 9000/redis.conf

    然后重复以上操作 9001-9005

rb脚本创建

准备操作中已经建立了6个独立的node,接下来执行以下脚本:

1
/src/redis-trib.rb create --replicas 1 127.0.0.1:9000 127.0.0.1:9001 127.0.0.1:9002 127.0.0.1:9003 127.0.0.1:9004 127.0.0.1:9005

在执行脚本后,确认自动计算的分配方案,即可搭建好redis cluster集群

shell创建

1.集群meet

1
2
3
4
5
src/redis-cli -p 9000 cluster meet 127.0.0.1 9001
src/redis-cli -p 9000 cluster meet 127.0.0.1 9002
src/redis-cli -p 9000 cluster meet 127.0.0.1 9003
src/redis-cli -p 9000 cluster meet 127.0.0.1 9004
src/redis-cli -p 9000 cluster meet 127.0.0.1 9005

2.划分master,slave

1
2
3
4
5
6
7
src/redis-cli -c -h 127.0.0.1 -p 9001 cluster nodes
14fca7a90ad3f680c9466c018cb890b5a8717c15 127.0.0.1:9005 master - 0 1468651448427 0 connected
a3fb3e01351afad2aa67affaaef5e2f689c3a007 127.0.0.1:9001 myself,master - 0 0 5 connected
fcb1557f223b6a7e34d1653e3e255f60eedf8d1f 127.0.0.1:9002 master - 0 1468651450831 0 connected
0966d47c01d6725206fa04c0d673072a87cbc76a 127.0.0.1:9003 master - 0 1468651449829 2 connected
5ba760249e5dfc478f5066a98922e0f3268075fd 127.0.0.1:9000 master - 0 1468651448827 1 connected
c0688867266abd0e08781a1acff4d12bf140b017 127.0.0.1:9004 master - 0 1468651451871 3 connected

根绝ID指定为哪个node的slave

1
2
3
src/redis-cli -c -h 127.0.0.1 -p 9003 cluster replicate 5ba760249e5dfc478f5066a98922e0f3268075fd
src/redis-cli -c -h 127.0.0.1 -p 9004 cluster replicate a3fb3e01351afad2aa67affaaef5e2f689c3a007
src/redis-cli -c -h 127.0.0.1 -p 9005 cluster replicate fcb1557f223b6a7e34d1653e3e255f60eedf8d1f

3.分配slot
因为cluster addslots命令不支持区间分配slot,因此只能借助shell实现分配slot
redis.sh如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#/bin/sh
function addslots()
{
for i in `seq $2 $3`;do
src/redis-cli -p $1 cluster addslots $i
done
}
case $1 in
addslots)
echo "add slots ..."
addslots $2 $3 $4;
;;
*)
echo "Usage: inetpanel [addslots]"
;;
esac

执行shell

1
2
3
./redis.sh addslots 9000 0 5460
./redis.sh addslots 9001 5461 10921
./redis.sh addslots 9002 10922 16383

至此redis cluster 搭建完毕!

开源项目学习记录

  1. Twemproxy
    -简介:应用于redis代理服务,做客户端与服务端实例代理,数据自动分片,在redis cluster不成熟前被业界大量使用。
    -地址:https://github.com/twitter/twemproxy
  2. divlote collector
    -简介:用来收集web用户点击行为数据,并将数据发送到kafka,hadoop中,高效简单便捷。
    -地址:http://divolte.io/
  3. cachecloud
    -简介: CacheCloud提供一个Redis云管理平台:实现多种类型(Redis Standalone、Redis Sentinel、Redis Cluster)自动部署、解决Redis实例碎片化现象、提供完善统计、监控、运维功能、减少运维成本和误操作,提高机器的利用率,提供灵活的伸缩性,提供方便的接入客户端。
    -地址:https://github.com/sohutv/cachecloud
  4. ElasticSearch+Kibanna+Packetbeat
    -简介:ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎。Kibanna是针对ElasticSearch一个界面UI。Packetbeat是监控网络数据包一个工具,分布式wireshar。
    -地址:https://www.elastic.co/downloads/beats

一、注解解释

  1. @controller 控制器(注入服务)
  2. @service 服务(注入dao)
  3. @repository dao(实现dao访问)
  4. @component (把普通pojo实例化到spring容器中,相当于配置文件中的

@Component,@Service,@Controller,@Repository注解的类,并把这些类纳入进spring容器中管理。
下面写这个是引入component的扫描组件

1
<context:component-scan base-package=”com.mmnc”>   

其中base-package为需要扫描的包(含所有子包)

  • @Service用于标注业务层组件
  • @Controller用于标注控制层组件(如struts中的action)
  • @Repository用于标注数据访问组件,即DAO组件.
  • @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

Shell学习

1.流程控制

  • for
    使用格式如下:
    1
    2
    3
    4
    for loop in 1 2 3 4 5
    do
    echo "The value is: $loop"
    done
    其中需要循环的数据用空格分离开
  • while
    1
    2
    3
    4
    5
    6
    int=1
    while(( $int<=5 ))
    do
    echo $int
    let "int++"
    done
  • if/else
    以下实例判断两个变量是否相等:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    a=10
    b=20
    if [ $a == $b ]
    then
    echo "a 等于 b"
    elif [ $a -gt $b ]
    then
    echo "a 大于 b"
    elif [ $a -lt $b ]
    then
    echo "a 小于 b"
    else
    echo "没有符合的条件"
    fi

2.数组

  • 数组定义
    1
    array_name=(value1 ... valuen)
    数组用括号来表示,元素用”空格”符号分割开
  • 读取数组
    1
    ${array_name[index]}
  • 数组长度
    1
    ${#my_array[*]}
  • 遍历数组
    1
    2
    3
    4
    5
    arr=(1 2 3 4 5)
    for var in ${arr[@]};
    do
    echo $var
    done
    循环输出
    1
    2
    3
    4
    5
    for j in $(seq 7000 7005)
    do
    echo $j
    done

3.函数

  • 函数传参
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #/bin/sh
    function addslots()
    {
    for i in `seq $2 $3`;do
    src/redis-cli -p $1 cluster addslots $i
    done
    }
    case $1 in
    addslots)
    echo "add slots ..."
    addslots $2 $3 $4;
    ;;
    *)
    echo "Usage: inetpanel [addslots]"
    ;;
    esac

4.$0,$?,$!等的特殊用法

变量 说明
$$ Shell本身的PID(ProcessID)
$! Shell最后运行的后台Process的PID
$? 最后运行的命令的结束代码(返回值)
$- 使用Set命令设定的Flag一览
$* 所有参数列表。如”$*”用「”」括起来的情况、以”$1 $2 … $n”的形式输出所有参数。
$@ 所有参数列表。如”$@”用「”」括起来的情况、以”$1” “$2” … “$n” 的形式输出所有参数。
$# 添加到Shell的参数个数
$0 Shell本身的文件名
$1~$n 添加到Shell的各参数值。$1是第1参数、$2是第2参数…

5.变量判断

  • -n
    可以使用-n来判断一个string不是NULL值
    1
    2
    3
    if [ ! -f "/bin/redis-cli" ]; then 
    ln -s $LOGSTASH_HOME/bin/redis-cli /bin/redis-cli
    fi
  • -f
    可以使用-f来判断一个文件是否存在
    1
    2
    3
    4
    5
    PID=`cat logs/$confName.pid`
    if [ -n "$PID" ];then
    kill -9 $PID
    rm -f logs/$confName.pid
    fi
  • 更多
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [ -f "$file" ] 判断$file是否是一个文件

    [ $a -lt 3 ] 判断$a的值是否小于3,同样-gt和-le分别表示大于或小于等于

    [ -x "$file" ] 判断$file是否存在且有可执行权限,同样-r测试文件可读性

    [ -n "$a" ] 判断变量$a是否有值(空),测试空串用-z

    [ -n $a ] 判断变量$a是否为null

    [ "$a" = "$b" ] 判断$a和$b的取值是否相等

    [ cond1 -a cond2 ] 判断cond1和cond2是否同时成立,-o表示cond1和cond2有一成立

6.写文件

  • 两种方式

两种方式:>重写>>追加

  • 写log
    1
    2
    3
    4
    5
    6
    7
    shell上:
    0表示标准输入
    1表示标准输出
    2表示标准错误输出
    > 默认为标准输出重定向,与 1> 相同
    2>&1 意思是把 标准错误输出 重定向到 标准输出.
    &>file 意思是把 标准输出 和 标准错误输出 都重定向到文件file中

HBase – Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。
HBase访问接口如下:

  1. Native Java API,最常规和高效的访问方式,适合Hadoop MapReduce Job并行批处理HBase表数据
  2. HBase Shell,HBase的命令行工具,最简单的接口,适合HBase管理使用
  3. Thrift Gateway,利用Thrift序列化技术,支持C++,PHP,Python等多种语言,适合其他异构系统在线访问HBase表数据
  4. REST Gateway,支持REST 风格的Http API访问HBase, 解除了语言限制
  5. Pig,可以使用Pig Latin流式编程语言来操作HBase中的数据,和Hive类似,本质最终也是编译成MapReduce Job来处理HBase表数据,适合做数据统计
  6. Hive,当前Hive的Release版本尚没有加入对HBase的支持,在Hive 0.7.0中支持HBase,可以使用类似SQL语言来访问HBase
    本文针对HBase Shell,做一个详细讲解。
阅读全文 »

HBase是Google Bigtable的开源实现,类似Google Bigtable利用GFS作为其文件存储系统,HBase利用Hadoop HDFS作为其文件存储系统;Google运行MapReduce来处理Bigtable中的海量数据,HBase同样利用Hadoop MapReduce来处理HBase中的海量数据;Google Bigtable利用 Chubby作为协同服务,HBase利用Zookeeper作为对应。

阅读全文 »
0%