运维知识体系

运维知识体系

运维知识体系总结,持续更新,欢迎转载。
缓存知识体系

缓存知识体系

运维知识体系之缓存,分层多级缓存体系。
K8S实践指南

K8S实践指南

Docker和Kubernetes实践指南(每周更新)
新运维课堂

新运维课堂

全新体系化课程,开启运维新征程!

Redis4.0集群

ShenghuiChen 发表了文章 • 0 个评论 • 624 次浏览 • 2019-01-04 14:54 • 来自相关话题

节点信息规划: 准备部署7001-7004 4个实例,但是redis集群提示最少需要3个主节点,6个节点才能完成启动,所以后面2个是后来加的。 注意:这里因为是测试环境,所以将所有实例都放在了一台机器上,生产建议主备节点不要放在一台机器 ...查看全部
节点信息规划:
准备部署7001-7004 4个实例,但是redis集群提示最少需要3个主节点,6个节点才能完成启动,所以后面2个是后来加的。
注意:这里因为是测试环境,所以将所有实例都放在了一台机器上,生产建议主备节点不要放在一台机器上
9.png

1、环境安装
~]# cd /opt/
opt]# wget http://download.redis.io/releases/redis-4.0.11.tar.gz
opt]# tar zxf redis-4.0.11.tar.gz
opt]# cd redis-4.0.11
opt]# make test
#yum 安装tcl
opt]# yum install tcl -y
opt]# make test
#将redis的执行脚本拷贝到PATH变量所在目录或加入全局环境变量
opt]# cp -a src/redis-server src/redis-cli src/redis-sentinel src/redis-trib.rb src/redis-check-aof src/redis-check-rdb src/redis-benchmark /usr/local/bin/
2、配置redis集群文件
opt]# mkdir -p redis-cluster
opt]# mkdir -p /opt/redis-cluster/nodes-{7001,7002,7003,7004}
opt]# ln -s redis-4.0.11 redis
按需修改配置文件(以nodes-7001实例为例)
[root@shenghui-ansible opt]# egrep -v "^#|^$" redis-cluster/nodes-7001/redis.conf 
bind 192.168.56.67
protected-mode yes
port 7001
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile redis_7001.pid
loglevel notice
logfile "/opt/redis-cluster/nodes-7001/redis_7001.log"
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /opt/redis-cluster/nodes-7001/
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush no
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble no
lua-time-limit 5000
cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 5000
cluster-slave-validity-factor 10
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
3、启动redis及创建集群
依次启动各个redis实例
]# redis-server /opt/redis-cluster/nodes-7001/redis.conf
]# redis-server /opt/redis-cluster/nodes-7002/redis.conf
]# redis-server /opt/redis-cluster/nodes-7003/redis.conf
]# redis-server /opt/redis-cluster/nodes-7004/redis.conf
4、创建redis集群
创建redis集群使用redis-trib.rb命令,该命令是基于ruby的脚本,需要安装ruby,ruby-gem以及gem-redis
#如果有老版本,卸载ruby2.0.0,安装ruby2.2.2以上版本
[root@elk01 ~]# ruby -v  #centos7 忽略
ruby 2.0.0p648 (2015-12-16) [x86_64-linux]
[root@elk01 ~]# yum erase ruby
~]# wget https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.3.tar.gz
~]# tar zxf ruby-2.5.3.tar.gz
~]# cd ruby-2.5.3/
ruby-2.5.3]# ./configure
ruby-2.5.3]# make
安装ruby-redis.gem
推荐:如果默认国外的gem源连不上或者很慢,可以试试国内源
添加国内源命令:gem source -a https://gems.ruby-china.com
删除国外源并添加国内源:gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.com/
#检测gem源,注意RubyGems源尽量用新版本,官方建议2.6.X,但是我用2.5.2也没什么问题
[root@shenghui-ansible ~]# gem source -l
*** CURRENT SOURCES ***

https://gems.ruby-china.com
redis-cluster]# gem install redis -v 3.3.5 #注:不要使用4.x版本,不然后期增加实例,迁移哈希槽会失败
创建集群报错:
root@elk01 redis-cluster]# redis-trib.rb create --replicas 1 192.168.56.67:7001 192.168.56.67:7002 192.168.56.67:7003 192.168.56.67:7004
>>> Creating cluster
*** ERROR: Invalid configuration for cluster creation. #错误表示redis集群至少要3个主,6个节点
*** Redis Cluster requires at least 3 master nodes.
*** This is not possible with 4 nodes and 1 replicas per node.
*** At least 6 nodes are required.
#新增两个节点
redis-cluster]# mkdir -p nodes-{7005,7006}
#拷贝并修改下redis配置ip
redis-cluster]# cp nodes-7001/redis.conf nodes-7005/
redis-cluster]# cp nodes-7001/redis.conf nodes-7006/
启动redis
redis-server /opt/redis-cluster/nodes-7005/redis.conf
redis-server /opt/redis-cluster/nodes-7006/redis.conf
[root@shenghui-ansible ~]# ps -ef|grep redis
root 26651 1 0 Nov13 ? 00:01:10 redis-server 127.0.0.1:7002 [cluster]
root 26656 1 0 Nov13 ? 00:01:10 redis-server 127.0.0.1:7003 [cluster]
root 26661 1 0 Nov13 ? 00:01:09 redis-server 127.0.0.1:7004 [cluster]
root 26666 1 0 Nov13 ? 00:01:10 redis-server 127.0.0.1:7005 [cluster]
root 26671 1 0 Nov13 ? 00:01:09 redis-server 127.0.0.1:7006 [cluster]
root 26725 1 0 Nov13 ? 00:01:11 redis-server 127.0.0.1:7001 [cluster]
#创建集群成功
redis-cluster]# redis-trib.rb create --replicas 1 192.168.56.67:7001 192.168.56.67:7002 192.168.56.67:7003 192.168.56.67:7004 192.168.56.67:7005 192.168.56.67:7006
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.56.67:7001
192.168.56.67:7002
192.168.56.67:7003
Adding replica 192.168.56.67:7004 to 192.168.56.67:7001
Adding replica 192.168.56.67:7005 to 192.168.56.67:7002
Adding replica 1192.168.56.67:7006 to 192.168.56.67:7003
M: 23df12c2bafde34f5bdd53d3463ad20b8ab507d2 192.168.56.67:7001
集群测试:
[root@shenghui-ansible ~]# redis-cli -c -p 7001 #登陆操作集群,-c参数是必须的
127.0.0.1:7001> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:7
cluster_my_epoch:7
cluster_stats_messages_ping_sent:84881
...
127.0.0.1:7001> cluster nodes
21da5db87c968a926ac98db20c6b3e5db98e86b4 192.168.56.67:7001@17001 myself,slave 64f7850f021d1150b41fc654f247e075f8573813 0 1542181496000 1 connected
bbba5557051520f7d825819415a806b8716f811c 127.0.0.1:7002@17002 master - 0 1542181497150 2 connected 5461-10922
f707863e9846cf9e7c68fd7cdae5b72aa4f6839b 127.0.0.1:7004@17004 slave 66ebc6a414a533a9a2ed27fbcdbea88b9d8ed4db 0 1542181498161 4 connected
ecdf34327e274a8294f7225ddbb5d3f4cd0b7bde 127.0.0.1:7006@17006 slave bbba5557051520f7d825819415a806b8716f811c 0 1542181497000 6 connected
64f7850f021d1150b41fc654f247e075f8573813 127.0.0.1:7005@17005 master - 0 1542181495000 7 connected 0-5460
66ebc6a414a533a9a2ed27fbcdbea88b9d8ed4db 127.0.0.1:7003@17003 master - 0 1542181495132 3 connected 10923-16383
127.0.0.1:7001> set liubai 'papa'
-> Redirected to slot [11252] located at 127.0.0.1:7003
OK
127.0.0.1:7003> get liubai
"papa"
nodes-7001宕机查看数据(redis集群去中心化,连接哪一台都可以):
~]# kill -9 26725  #生长不建议使用kill,登陆redis-cli 使用shutdown关闭redis
[root@shenghui-ansible ~]# redis-cli -c -p 7002
127.0.0.1:7002> get liubai
-> Redirected to slot [11252] located at 127.0.0.1:7003 #数据在nodes3,从自动切换选举为主
"papa"
127.0.0.1:7003> cluster nodes
bbba5557051520f7d825819415a806b8716f811c 127.0.0.1:7002@17002 master - 0 1542181782880 2 connected 5461-10922
21da5db87c968a926ac98db20c6b3e5db98e86b4 127.0.0.1:7001@17001 slave,fail 64f7850f021d1150b41fc654f247e075f8573813 1542181666613 1542181664000 7 disconnected
64f7850f021d1150b41fc654f247e075f8573813 127.0.0.1:7005@17005 master - 0 1542181780860 7 connected 0-5460
66ebc6a414a533a9a2ed27fbcdbea88b9d8ed4db 127.0.0.1:7003@17003 myself,master - 0 1542181781000 3 connected 10923-16383
f707863e9846cf9e7c68fd7cdae5b72aa4f6839b 127.0.0.1:7004@17004 slave 66ebc6a414a533a9a2ed27fbcdbea88b9d8ed4db 0 1542181781869 4 connected
ecdf34327e274a8294f7225ddbb5d3f4cd0b7bde 127.0.0.1:7006@17006 slave bbba5557051520f7d825819415a806b8716f811c 0 1542181780000 6 connected
127.0.0.1:7003> get liubai
"papa"

使用ambari快速部署Hadoop集群

赵班长 发表了文章 • 1 个评论 • 3370 次浏览 • 2016-05-05 09:28 • 来自相关话题

    Ambari是 Apache Software Foundation 中的一个顶级项目。Ambari可以创建、管理、监控 Hadoop 的集群。包括整个Hadoop生态圈(例如 Hive,Hbase,Sqoop,Zookeeper 等)。无论是初学者像 ...查看全部
    Ambari是 Apache Software Foundation 中的一个顶级项目。Ambari可以创建、管理、监控 Hadoop 的集群。包括整个Hadoop生态圈(例如 Hive,Hbase,Sqoop,Zookeeper 等)。无论是初学者像快速部署一套Hadoop环境,还是用于生产的自动化部署,Ambari都可以满足。
     你可以在官网http://ambari.apache.org/获取最新的Ambari的内容,目前Ambari还支持流行的 Spark,Storm 等计算框架,Kafka消息队列、以及资源调度平台 YARN 等。
    Ambari 自身也是一个分布式架构的软件,主要由两部分组成:Ambari Server 和 Ambari Agent。我们可以通过 Ambari Server 通知 Ambari Agent 安装对应的软件;甚至连Ambari Agent我们都可以在Web界面上来进行安装和部署。
    Ambari Agent 会定时地发送各个机器每个项目组件的当前状态给 Ambari Server,并在Web界面上进行展示汇总,方面我们及时掌握集群状态。

基础环境准备
    本次实验环境还是使用两台虚拟机来实现,有条件的读者建议使用三台虚拟机来做。首先我们要实现Ambari Server到各个节点之间的SSH无密码登录。
在所有节点都执行ssh-keygen -t rsa 生成Key
[root@linux-node1 ~]# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
    虽然除了Server端之外其它节点可以不执行,但是ssh-keygen命令会帮我们创建相应的目录并设置权限,不在需要我们手动操作。

将Ambari Server的公钥scp到其它节点上
[root@linux-node1 ~]# scp .ssh/id_rsa.pub 192.168.56.12:/root/.ssh/authorized_keys
设置权限
[root@linux-node2 ~]# chmod 600 ~/.ssh/authorized_keys
测试连接
[root@linux-node1 ~]# ssh 192.168.56.12
Last login: Sat Apr 2 16:42:46 2016 from 192.168.56.1
[root@linux-node2 ~]#
设置完毕无密码登录后,我们就可以开始部署ambari-server了。

安装jdk
    由于ambari安装过程中的jdk下载比较缓慢,所以我们可以直接使用yum仓库里面的openjdk
[root@linux-node1 ~]# yum install -y java-1.8.0
部署ambari-server
    ambari-server的部署比较简单,很多实用实用默认即是最好的选择。
安装ambari-server
[root@test-node3 ~]# cd /etc/yum.repos.d/
# wget http://public-repo-1.hortonworks.com/ambari/centos7/2.x/updates/2.2.0.0/ambari.repo
# yum install -y ambari-server


注意:在国内的用户要有心里准备,ambari-server这个包有354M,下载比较慢。


设置ambari-server

    安装完毕后,需要使用ambari-server setup命令进行设置,均可以使用默认设置,直接回车即可。
[root@linux-node1 ~]# ambari-server setup
Using python /usr/bin/python2
Setup ambari-server
Checking SELinux...
SELinux status is 'disabled'
Customize user account for ambari-server daemon [y/n] (n)?
Adjusting ambari-server permissions and ownership...
Checking firewall status...
Redirecting to /bin/systemctl status iptables.service

Checking JDK...
[1] Oracle JDK 1.8 + Java Cryptography Extension (JCE) Policy Files 8
[2] Oracle JDK 1.7 + Java Cryptography Extension (JCE) Policy Files 7
[3] Custom JDK
===========================================================================
Enter choice (1): 3
WARNING: JDK must be installed on all hosts and JAVA_HOME must be valid on all hosts.
WARNING: JCE Policy files are required for configuring Kerberos security. If you plan to use Kerberos,please make sure JCE Unlimited Strength Jurisdiction Policy Files are valid on all hosts.
Path to JAVA_HOME: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.77-0.b03.el7_2.x86_64/jre/
Validating JDK on Ambari Server...done.
Completing setup...
Configuring database...
Enter advanced database configuration [y/n] (n)?
Configuring database...
Default properties detected. Using built-in database.
Configuring ambari database...
Checking PostgreSQL...
Running initdb: This may take upto a minute.
Initializing database ... OK
About to start PostgreSQL
Configuring local database...
Connecting to local database...done.
Configuring PostgreSQL...
Restarting PostgreSQL
Extracting system views...
ambari-admin-2.2.0.0.1310.jar
......
Adjusting ambari-server permissions and ownership...
Ambari Server 'setup' completed successfully.

  • 1)    检测SELinux2)    询问是否自定义用户,默认否-(可以安装完毕之后再进行用户管理。)3)    检测iptables选择JDK版本,默认Oracle JDK 1.8。如果你已经安装了jdk,可以选择自定义jdk。如果你是yum安装的openjdk,那么路径位于/usr/lib/jvm/java-1.8.0-openjdk-xxx.x86_64/jre/4)    目录下。5)    询问是否打开高级的数据库配置,默认-否


启动ambari-server
[root@linux-node1 ~]# ambari-server start
查看监听端口
[root@linux-node1 ~]# netstat -ntlp | grep 8080
tcp6 0 0 :::8080 :::* LISTEN 24168/java

访问ambari server

现在可以在浏览器访问你的ambari server了。注意端口是8080。
http://192.168.56.11:8080/

默认的用户名和密码都是admin


创建Hadoop集群

登录 Ambari 之后,点击按钮“Launch Install Wizard”,就可以开始创建属于自己的大数据平台。
1.png


1.设置集群的名称
1.png


2.选择一个Stack,默认使用最新版本。
2.png


3.填写你环境的所有主机名,并上传验证的公钥。注意使用FQDN名称,并且主机名要能够解析。

4.选择需要安装的组件
5.png


5.角色分配
6.png


其它步骤均使用默认配置即可。

【转载】时间序列数据库的秘密(1)—— 介绍

赵班长 发表了文章 • 1 个评论 • 2364 次浏览 • 2016-04-23 10:51 • 来自相关话题

作者 陶文 发布于 2015年8月11日  转载自:http://www.infoq.com/cn/articles/database-timestamp-01 什么是时间序列数据?最简单的定义就是数据格式里包含timestamp ...查看全部
作者 陶文 发布于 2015年8月11日  转载自:http://www.infoq.com/cn/articles/database-timestamp-01

什么是时间序列数据?最简单的定义就是数据格式里包含timestamp字段的数据。比如股票市场的价格,环境中的温度,主机的CPU使用率等。但 是又有什么数据是不包含timestamp的呢?几乎所有的数据都可以打上一个timestamp字段。时间序列数据更重要的一个属性是如何去查询它。在 查询的时候,对于时间序列我们总是会带上一个时间范围去过滤数据。同时查询的结果里也总是会包含timestamp字段。

选择什么样的时间序列数据库

时间序列数据无处不在。而几乎任意数据库都可以存时间序列数据。但是不同的数据能支持的查询类型并不相同。按照能支持的查询类型,我们可以把时间序列数据库分为两类,第一类的数据库按照关系型数据库的说法,其表结构是这样的:
[metric_name] [timestamp] [value]

其优化的查询方式是:
SELECT value FROM metric WHERE metric_name=”A” AND timestamp >= B AND timestamp < C

也就说这类数据库是什么样子的数据存进去,就什么样子取出来。

1.jpg


在这种模式下,首先要知道你需要的图表是什么样子的。然后按照这个图表的数据,去把数据入库。查询的字段,就是数据库存储的字段。然后再按照数据库存储的 字段,去从原始数据里采集上报。存储什么字段,就上报什么字段。这种模式很容易优化,可以做到非常快。但是这种模式有两个弊端。
  1. 无法快速响应变化:如果需要的图表有变更,需要从上报的源头重新来一遍。而且要等新数据过来之后,才能查看这些新数据。
  2. 存储膨胀:总有一些数据是需要从不同维度查询的要求。比如广告点击流数据,需要按省份聚合,按运营商聚合,按点击人的喜好聚合等。这些维度的交叉组合会产生非常巨大的组合数量,要预先把所有的维度组合都变成数据库里的表存储起来会很浪费空间。


这类时间序列数据库最多,使用也最广泛。一般人们谈论时间序列数据库的时候指代的就是这一类存储。按照底层技术不同可以划分为三类。

直接基于文件的简单存储:RRD Tool,Graphite Whisper。这类工具附属于监控告警工具,底层没有一个正规的数据库引擎。只是简单的有一个二进制的文件结构。
基于K/V数据库构建:opentsdb(基于hbase),blueflood,kairosDB(基于cassandra),influxdb,prometheus(基于leveldb)
基于关系型数据库构建:mysql,postgresql 都可以用来保存时间序列数据
另外一类数据库其表结构是:

[timestamp] [d1] [d2] .. [dn] [v1] [v2] .. [vn]

其优化的查询方式不限于查询原始数据,而是可以组合查询条件并且做聚合计算,比如:
SELECT d2, sum(v1) / sum(v2) FROM metric WHERE d1 =
“A” AND timestamp >= B AND timestamp < C GROUP BY d2

2.jpg


我们希望时间序列数据库不仅仅可以提供原始数据的查询,而且要支持对原始数据的聚合能力。这种聚合可以是在入库阶段完成的,所谓物化视图。也可以是在查询阶段完成,所谓实时聚合。根据实际情况,可以在这两种方式中进行取舍。

想要在在查询阶段做数据的聚合和转换,需要能够支持以下三点。

  • 用索引检索出行号:能够从上亿条数据中快速过滤出几百万的数据。

  • 从主存储按行号加载:能够快速加载这过滤出的几百万条数据到内存里。

  • 分布式计算:能够把这些数据按照GROUP BY 和 SELECT 的要求计算出最终的结果集。




3.jpg


要想尽可能快的完成整个查询过程,需要在三个环节上都有绝招。传统上说,这三个步骤是三个不同的技术领域。

  • 检索:这是搜索引擎最擅长的领域。代表产品是Lucene。其核心技术是基于高效率数据结构和算法的倒排索引。

  • 加载:这是分析型数据库最擅长的领域。代表产品是C-store和Monetdb。其核心技术是按列组织的磁盘存储结构。

  • 分布式计算:这是大数据计算引擎最擅长的领域。代表产品是Hadoop和spark。其核心技术是sharding 和 map/reduce等等。



前面提到的时间序列库(比如opentsdb)有不少从功能上来说是没有问题。它们都支持过滤,也支持过滤之后的聚合计算。在数据量小的时候勉强是可用的。但是如果要实时从十亿条里取百万记录出来,再做聚合运算,对于这样的数据量可能就勉为其难了。满足海量数据实时聚合要求的数据库不多,比较常见的有这么几种:

  • 基于Lucene构建的“搜索引擎”:Elasticsearch, Crate.io(虽然是基于Elasticsearch,但是聚合逻辑是自己实现的),Solr;

  • 列式存储数据库:Vertica(C-store的后裔)Actian(Monetdb的后裔)等;

  • Druid.io。



其中Elasticsearch是目前市场上比较很少有的,能够在检索加载和分布式计算三个方面都做得一流的数据库。而且是开源并且免费的。它使用了很多技术来达到飞一般的速度。这些主要的优化措施可以列举如下。

  • Lucene的inverted index可以比mysql的b-tree检索更快。

  • 在 Mysql中给两个字段独立建立的索引无法联合起来使用,必须对联合查询的场景建立复合索引。而lucene可以任何AND或者OR组合使用索引进行检索。

  • Elasticsearch支持nested document,可以把一批数据点嵌套存储为一个document block,减少需要索引的文档数。

  • Opentsdb不支持二级索引,只有一个基于hbase rowkey的主索引,可以按行的排序顺序scan。这使得Opentsdb的tag实现从检索效率上来说很慢。

  • Mysql 如果经过索引过滤之后仍然要加载很多行的话,出于效率考虑query planner经常会选择进行全表扫描。所以Mysql的存储时间序列的最佳实践是不使用二级索引,只使用clustered index扫描主表。类似于Opentsdb。

  • Lucene 从 4.0 开始支持 DocValues,极大降低了内存的占用,减少了磁盘上的尺寸并且提高了加载数据到内存计算的吞吐能力。

  • Lucene支持分segment,Elasticsearch支持分index。Elasticsearch可以把分开的数据当成一张表来查询和聚合。相比之下Mysql如果自己做分库分表的时候,联合查询不方便。

  • Elasticsearch 从1.0开始支持aggregation,基本上有了普通SQL的聚合能力。从 2.0 开始支持 pipeline aggregation,可以支持类似SQL sub query的嵌套聚合的能力。这种聚合能力相比Crate.io,Solr等同门师兄弟要强大得多。



最后,再次推荐下INFOQ,作为运维工程师,要时刻关注,上面有很多好文章。

【转载】InfluxDB 开源分布式时序、事件和指标数据库

赵班长 发表了文章 • 0 个评论 • 1946 次浏览 • 2016-04-23 10:33 • 来自相关话题

本文转载自:https://segmentfault.com/a/1190000000444617 InfluxDB 是一个开源分布式时序、事件和指标数据库。使用 Go 语言编写,无需外部依赖。其设计目标是实现分布式和水平伸缩扩展 ...查看全部
本文转载自:https://segmentfault.com/a/1190000000444617

InfluxDB 是一个开源分布式时序、事件和指标数据库。使用 Go 语言编写,无需外部依赖。其设计目标是实现分布式和水平伸缩扩展。

特点:
  1. schemaless(无结构),可以是任意数量的列
  2. Scalable
  3. min, max, sum, count, mean, median 一系列函数,方便统计
  4. Native HTTP API, 内置http支持,使用http读写
  5. Powerful Query Language 类似sql
  6. Built-in Explorer 自带管理工具


管理界面:

1.png


API

InfluxDB 支持两种api方式
  1. HTTP API
  2. Protobuf API


Protobuf 还未开发完成, 官网文档都没有

如何使用 http api 进行操作?

比如对于foo_production这个数据库,插入一系列数据,可以发现POST 请求到 /db/foo_production/series?u=some_user&p=some_password, 数据放到body里。

数据看起来是这样的:

下面的"name": "events", 其中"events"就是一个series,类似关系型数据库的表table
[
{
"name": "events",
"columns": ["state", "email", "type"],
"points": [
["ny", "paul@influxdb.org", "follow"],
["ny", "todd@influxdb.org", "open"]
]
},
{
"name": "errors",
"columns": ["class", "file", "user", "severity"],
"points": [
["DivideByZero", "example.py", "someguy@influxdb.org", "fatal"]
]
}
]
格式是json,可以在一个POST请求发送多个 series, 每个 series 里的 points 可以是多个,但索引要和columns对应。

上面的数据里没有包含time 列,InfluxDB会自己加上,不过也可以指定time,比如:
[
{
"name": "response_times",
"columns": ["time", "value"],
"points": [
[1382819388, 234.3],
[1382819389, 120.1],
[1382819380, 340.9]
]
}
]
time 在InfluxDB里是很重要的,毕竟InfluxDB是time series database
在InfluxDB里还有个sequence_number字段是数据库维护的,类似于mysql的 主键概念

InfluxDB 增删更查都是用http api来完成,甚至支持使用正则表达式删除数据,还有计划任务。

比如:

发送POST请求到 /db/:name/scheduled_deletes, body如下,
{
"regex": "stats\..*",
"olderThan": "14d",
"runAt": 3
}
这个查询会删除大于14天的数据,并且任何以stats开头的数据,并且每天3:00 AM运行。

更加详细查看官方文档: http://influxdb.org/docs/api/http.html

查询语言

InfluxDB 提供了类似sql的查询语言

看起来是这样的:
select * from events where state == 'NY';

select * from log_lines where line =~ /error/i;

select * from events where customer_id == 23 and type == 'click';

select * from response_times where value > 500;

select * from events where email !~ /.*gmail.*/;

select * from nagios_checks where status != 0;

select * from events
where (email =~ /.*gmail.* or email =~ /.*yahoo.*/) and state == 'ny';

delete from response_times where time > now() - 1h
非常容易上手, 还支持Group By, Merging Series, Joining Series, 并内置常用统计函数,比如max, min, mean 等

文档: http://influxdb.org/docs/query_language/



常用语言的库都有,因为api简单,也很容易自己封装。

InfluxdDB作为很多监控软件的后端,这样监控数据就可以直接存储在InfluxDB
StatsD, CollectD, FluentD

还有其它的可视化工具支持InfluxDB, 这样就可以基于InfluxDB很方便的搭建监控平台

InfluxDB 数据可视化工具

InfluxDB 用于存储基于时间的数据,比如监控数据,因为InfluxDB本身提供了Http API,所以可以使用InfluxDB很方便的搭建了个监控数据存储中心。

对于InfluxDB中的数据展示,官方admin有非常简单的图表, 看起来是这样的

2.jpg


除了自己写程序展示数据还可以选择:

tasseo https://github.com/obfuscurity/tasseo/
grafana https://github.com/torkelo/grafana

tasseo

tasseo,为Graphite写的Live dashboard,现在也支持InfluxDB,tasseo 比较简单, 可以配置的选项很少。

3.png


Grafana

Grafana是一个纯粹的html/js应用,访问InfluxDB时不会有跨域访问的限制。只要配置好数据源为InfluxDB之后就可以,剩 下的工作就是配置图表。Grafana 功能非常强大。使用ElasticsSearch保存DashBoard的定义文件,也可以Export出JSON文件(Save ->Advanced->Export Schema),然后上传回它的/app/dashboards目录。

配置数据源:
datasources: {      
influx: {
default: true,
type: 'influxdb',
url: 'http://<your_influx_db_server>:8086/db/<db_name>',
username: 'test',
password: 'test',
}
},

4.png






 

【转载】 LevelDb日知录之七如何根据Key读取记录?

赵班长 发表了文章 • 0 个评论 • 1666 次浏览 • 2016-04-23 07:56 • 来自相关话题

郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84       LevelDb是针对大规模Key/Value数据的单机存储库,从应用的角度来看,Le ...查看全部
郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84
      LevelDb是针对大规模Key/Value数据的单机存储库,从应用的角度来看,LevelDb就是一个存储工具。而作为称职的存储工具,常见 的调用接口无非是新增KV,删除KV,读取KV,更新Key对应的Value值这么几种操作。LevelDb的接口没有直接支持更新操作的接口,如果需要 更新某个Key的Value,你可以选择直接生猛地插入新的KV,保持Key相同,这样系统内的key对应的value就会被更新;或者你可以先删除旧的 KV,之后再插入新的KV,这样比较委婉地完成KV的更新操作。     假设应用提交一个Key值,下面我们看看LevelDb是如何从存储的数据中读出其对应的Value值的。图7-1是LevelDb读取过程的整体示意图。

1.JPG


LevelDb首先会去查看内存中的Memtable,如果Memtable中包含key及其对应的value,则返回value值即可;如果在 Memtable没有读到key,则接下来到同样处于内存中的Immutable Memtable中去读取,类似地,如果读到就返回,若是没有读到,那么只能万般无奈下从磁盘中的大量SSTable文件中查找。因为SSTable数量 较多,而且分成多个Level,所以在SSTable中读数据是相当蜿蜒曲折的一段旅程。总的读取原则是这样的:首先从属于level 0的文件中查找,如果找到则返回对应的value值,如果没有找到那么到level 1中的文件中去找,如此循环往复,直到在某层SSTable文件中找到这个key对应的value为止(或者查到最高level,查找失败,说明整个系统 中不存在这个Key)。    那么为什么是从Memtable到Immutable Memtable,再从Immutable Memtable到文件,而文件中为何是从低level到高level这么一个查询路径呢?道理何在?之所以选择这么个查询路径,是因为从信息的更新时间 来说,很明显Memtable存储的是最新鲜的KV对;Immutable Memtable中存储的KV数据对的新鲜程度次之;而所有SSTable文件中的KV数据新鲜程度一定不如内存中的Memtable和 Immutable Memtable的。对于SSTable文件来说,如果同时在level L和Level L+1找到同一个key,level L的信息一定比level L+1的要新。也就是说,上面列出的查找路径就是按照数据新鲜程度排列出来的,越新鲜的越先查找。

     为啥要优先查找新鲜的数据呢?这个道理不言而喻,举个例子。比如我们先往levelDb里面插入一条数据 {key="www.samecity.com"  value="朗格科技"},过了几天,samecity网站改名为:69同城,此时我们插入数据{key="www.samecity.com"  value="69同城"},同样的key,不同的value;逻辑上理解好像levelDb中只有一个存储记录,即第二个记录,但是在levelDb中 很可能存在两条记录,即上面的两个记录都在levelDb中存储了,此时如果用户查询key="www.samecity.com",我们当然希望找到最 新的更新记录,也就是第二个记录返回,这就是为何要优先查找新鲜数据的原因。

    前文有讲:对于SSTable文件来说,如果同时在level L和Level L+1找到同一个key,level L的信息一定比level L+1的要新。这是一个结论,理论上需要一个证明过程,否则会招致如下的问题:为神马呢?从道理上讲呢,很明白:因为Level L+1的数据不是从石头缝里蹦出来的,也不是做梦梦到的,那它是从哪里来的?Level L+1的数据是从Level L 经过Compaction后得到的(如果您不知道什么是Compaction,那么........也许以后会知道的),也就是说,您看到的现在的 Level L+1层的SSTable数据是从原来的Level L中来的,现在的Level L比原来的Level L数据要新鲜,所以可证,现在的Level L比现在的Level L+1的数据要新鲜。

   证毕。

   如果您没看明白上面的证明过程,那么请记得往您的IQ卡内充值。

    SSTable文件很多,如何快速地找到key对应的value值?在LevelDb中,level 0一直都爱搞特殊化,在level 0和其它level中查找某个key的过程是不一样的。因为level 0下的不同文件可能key的范围有重叠,某个要查询的key有可能多个文件都包含,这样的话LevelDb的策略是先找出level 0中哪些文件包含这个key(manifest文件中记载了level和对应的文件及文件里key的范围信息,LevelDb在内存中保留这种映射表), 之后按照文件的新鲜程度排序,新的文件排在前面,之后依次查找,读出key对应的value。而如果是非level 0的话,因为这个level的文件之间key是不重叠的,所以只从一个文件就可以找到key对应的value。

    最后一个问题,如果给定一个要查询的key和某个key range包含这个key的SSTable文件,那么levelDb是如何进行具体查找过程的呢?levelDb一般会先在内存中的Cache中查找是否 包含这个文件的缓存记录,如果包含,则从缓存中读取;如果不包含,则打开SSTable文件,同时将这个文件的索引部分加载到内存中并放入Cache中。 这样Cache里面就有了这个SSTable的缓存项,但是只有索引部分在内存中,之后levelDb根据索引可以定位到哪个内容Block会包含这条 key,从文件中读出这个Block的内容,在根据记录一一比较,如果找到则返回结果,如果没有找到,那么说明这个level的SSTable文件并不包 含这个key,所以到下一级别的SSTable中去查找。

    从之前介绍的LevelDb的写操作和这里介绍的读操作可以看出,相对写操作,读操作处理起来要复杂很多,所以写的速度必然要远远高于读数据的速度,也就 是说,LevelDb比较适合写操作多于读操作的应用场合。而如果应用是很多读操作类型的,那么顺序读取效率会比较高,因为这样大部分内容都会在缓存中找 到,尽可能避免大量的随机读取操作。

 

【转载】 LevelDb日知录之六 写入与删除记录

赵班长 发表了文章 • 0 个评论 • 1516 次浏览 • 2016-04-23 07:54 • 来自相关话题

郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84 在之前的五节LevelDb日知录中,朗格科技介绍了LevelDb的一些静态文件及其详 ...查看全部
郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84

在之前的五节LevelDb日知录中,朗格科技介绍了LevelDb的一些静态文件及其详细布局,从本节开始,我们看看LevelDb的一些动态操作,比如读写记录,Compaction,错误恢复等操作。       本节介绍levelDb的记录更新操作,即插入一条KV记录或者删除一条KV记录。levelDb的更新操作速度是非常快的,源于其内部机制决定了这种更新操作的简单性。

1.JPG


图6.1是levelDb如何更新KV数据的示意图,从图中可以看出,对于一个插入操作Put(Key,Value)来说,完成插入操作包含两个具 体步骤:首先是将这条KV记录以顺序写的方式追加到之前介绍过的log文件末尾,因为尽管这是一个磁盘读写操作,但是文件的顺序追加写入效率是很高的,所 以并不会导致写入速度的降低;第二个步骤是:如果写入log文件成功,那么将这条KV记录插入内存中的Memtable中,前面介绍过,Memtable 只是一层封装,其内部其实是一个Key有序的SkipList列表,插入一条新记录的过程也很简单,即先查找合适的插入位置,然后修改相应的链接指针将新 记录插入即可。完成这一步,写入记录就算完成了,所以一个插入记录操作涉及一次磁盘文件追加写和内存SkipList插入操作,这是为何levelDb写 入速度如此高效的根本原因。        从上面的介绍过程中也可以看出:log文件内是key无序的,而Memtable中是key有序的。

那么如果是删除一条KV记录呢?对于levelDb来说,并不存在立即删除的操作,而是与插入操作相同的,区别是,插入操作插入的是Key:Value 值,而删除操作插入的是“Key:删除标记”,并不真正去删除记录,而是后台Compaction的时候才去做真正的删除操作。

        levelDb的写入操作就是如此简单。真正的麻烦在后面将要介绍的读取操作中。
 

【转载】LevelDb日知录之五 MemTable

赵班长 发表了文章 • 0 个评论 • 1516 次浏览 • 2016-04-23 07:53 • 来自相关话题

郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84  LevelDb日知录前述小节大致讲述了磁盘文件相关的重要静态结构,本小节讲述内存中的数据结构Me ...查看全部
郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84
 LevelDb日知录前述小节大致讲述了磁盘文件相关的重要静态结构,本小节讲述内存中的数据结构Memtable,Memtable在整个体系 中的重要地位也不言而喻。总体而言,所有KV数据都是存储在Memtable,Immutable Memtable和SSTable中的,Immutable Memtable从结构上讲和Memtable是完全一样的,区别仅仅在于其是只读的,不允许写入操作,而Memtable则是允许写入和读取的。当 Memtable写入的数据占用内存到达指定数量,则自动转换为Immutable Memtable,等待Dump到磁盘中,系统会自动生成新的Memtable供写操作写入新数据,理解了Memtable,那么Immutable Memtable自然不在话下。     LevelDb的MemTable提供了将KV数据写入,删除以及读取KV记录的操作接口,但是事实上Memtable并不存在真正的删除操作,删除某 个Key的Value在Memtable内是作为插入一条记录实施的,但是会打上一个Key的删除标记,真正的删除操作是Lazy的,会在以后的 Compaction过程中去掉这个KV。

     需要注意的是,LevelDb的Memtable中KV对是根据Key大小有序存储的,在系统插入新的KV时,LevelDb要把这个KV插到合适的 位置上以保持这种Key有序性。其实,LevelDb的Memtable类只是一个接口类,真正的操作是通过背后的SkipList来做的,包括插入操作 和读取操作等,所以Memtable的核心数据结构是一个SkipList。

     SkipList是由William Pugh发明。他在Communications of the ACM June 1990, 33(6) 668-676 发表了Skip lists: a probabilistic alternative to balanced trees,在该论文中详细解释了SkipList的数据结构和插入删除操作。

SkipList是平衡树的一种替代数据结构,但是和红黑树不相同的是,SkipList对于树的平衡的实现是基于一种随机化的算法的,这样也就是说SkipList的插入和删除的工作是比较简单的。

关于SkipList的详细介绍可以参考这篇文章:http://www.cnblogs.com/xuqiang/archive/2011/05/22/2053516.html,讲述的很清楚,LevelDb的SkipList基本上是一个具体实现,并无特殊之处。

SkipList不仅是维护有序数据的一个简单实现,而且相比较平衡树来说,在插入数据的时候可以避免频繁的树节点调整操作,所以写入效率是很高 的,LevelDb整体而言是个高写入系统,SkipList在其中应该也起到了很重要的作用。Redis为了加快插入操作,也使用了SkipList来 作为内部实现数据结构。

【转载】 LevelDb日知录之四 SSTable文件

赵班长 发表了文章 • 0 个评论 • 1997 次浏览 • 2016-04-23 07:52 • 来自相关话题

郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84 SSTable是Bigtable中至关重要的一块,对于LevelDb来说也是如此,对LevelD ...查看全部
郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84
SSTable是Bigtable中至关重要的一块,对于LevelDb来说也是如此,对LevelDb的SSTable实现细节的了解也有助于了解Bigtable中一些实现细节。本节内容主要讲述SSTable的静态布局结构,朗格科技曾在“LevelDb日知录之二:整体架构”中说过,SSTable文件形成了不同Level的 层级结构,至于这个层级结构是如何形成的我们放在后面Compaction一节细说。本节主要介绍SSTable某个文件的物理布局和逻辑布局结构,这对 了解LevelDb的运行过程很有帮助。

LevelDb不同层级有很多SSTable文件(以后缀.sst为特征),所有.sst文件内部布局都是一样的。上节介绍Log文件是物理分块 的,SSTable也一样会将文件划分为固定大小的物理存储块,但是两者逻辑布局大不相同,根本原因是:Log文件中的记录是Key无序的,即先后记录的 key大小没有明确大小关系,而.sst文件内部则是根据记录的Key由小到大排列的,从下面介绍的SSTable布局可以体会到Key有序是为何如此设 计.sst文件结构的关键。


1.JPG


上图展示了一个.sst文件的物理划分结构,同Log文件一样,也是划分为固定大小的存储块,每个Block分为三个部分,红色部分是数据存储区,蓝色 的Type区用于标识数据存储区是否采用了数据压缩算法(Snappy压缩或者无压缩两种),CRC部分则是数据校验码,用于判别数据是否在生成和传输中 出错。    以上是.sst的物理布局,下面介绍.sst文件的逻辑布局,所谓逻辑布局,就是说尽管大家都是物理块,但是每一块存储什么内容,内部又有什么结构等。图4.2展示了.sst文件的内部逻辑解释。


2.JPG


从图4.2可以看出,从大的方面,可以将.sst文件划分为数据存储区和数据管理区,数据存储区存放实际的Key:Value数据,数据管理区则提供一些 索引指针等管理数据,目的是更快速便捷的查找相应的记录。两个区域都是在上述的分块基础上的,就是说文件的前面若干块实际存储KV数据,后面数据管理区存 储管理数据。管理数据又分为四种不同类型:紫色的Meta Block,红色的MetaBlock 索引和蓝色的数据索引块以及一个文件尾部块。

    LevelDb 1.2版对于Meta Block尚无实际使用,只是保留了一个接口,估计会在后续版本中加入内容,下面我们看看数据索引区和文件尾部Footer的内部结构。

3.JPG


图4.3是数据索引的内部结构示意图。再次强调一下,Data Block内的KV记录是按照Key由小到大排列的,数据索引区的每条记录是对某个Data Block建立的索引信息,每条索引信息包含三个内容,以图4.3所示的数据块i的索引Index i来说:红色部分的第一个字段记载大于等于数据块i中最大的Key值的那个Key,第二个字段指出数据块i在.sst文件中的起始位置,第三个字段指出 Data Block i的大小(有时候是有数据压缩的)。后面两个字段好理解,是用于定位数据块在文件中的位置的,第一个字段需要详细解释一下,在索引里保存的这个Key值未 必一定是某条记录的Key,以图4.3的例子来说,假设数据块i 的最小Key=“samecity”,最大Key=“the best”;数据块i+1的最小Key=“the fox”,最大Key=“zoo”,那么对于数据块i的索引Index i来说,其第一个字段记载大于等于数据块i的最大Key(“the best”)同时要小于数据块i+1的最小Key(“the fox”),所以例子中Index i的第一个字段是:“the c”,这个是满足要求的;而Index i+1的第一个字段则是“zoo”,即数据块i+1的最大Key。

 文件末尾Footer块的内部结构见图4.4,metaindex_handle指出了metaindex block的起始位置和大小;inex_handle指出了index Block的起始地址和大小;这两个字段可以理解为索引的索引,是为了正确读出索引值而设立的,后面跟着一个填充区和魔数。


4.JPG


上面主要介绍的是数据管理区的内部结构,下面我们看看数据区的一个Block的数据部分内部是如何布局的(图4.1中的红色部分),图4.5是其内部布局示意图。


6.JPG


从图中可以看出,其内部也分为两个部分,前面是一个个KV记录,其顺序是根据Key值由小到大排列的,在Block尾部则是一些“重启点”(Restart Point),其实是一些指针,指出Block内容中的一些记录位置。

“重启点”是干什么的呢?我们一再强调,Block内容里的KV记录是按照Key大小有序的,这样的话,相邻的两条记录很可能Key部分存在重叠,比如 key i=“the Car”,Key i+1=“the color”,那么两者存在重叠部分“the c”,为了减少Key的存储量,Key i+1可以只存储和上一条Key不同的部分“olor”,两者的共同部分从Key i中可以获得。记录的Key在Block内容部分就是这么存储的,主要目的是减少存储开销。“重启点”的意思是:在这条记录开始,不再采取只记载不同的 Key部分,而是重新记录所有的Key值,假设Key i+1是一个重启点,那么Key里面会完整存储“the color”,而不是采用简略的“olor”方式。Block尾部就是指出哪些记录是这些重启点的。


7.JPG


在Block内容区,每个KV记录的内部结构是怎样的?图4.6给出了其详细结构,每个记录包含5个字段:key共享长度,比如上面的“olor”记录, 其key和上一条记录共享的Key部分长度是“the c”的长度,即5;key非共享长度,对于“olor”来说,是4;value长度指出Key:Value中Value的长度,在后面的Value内容字 段中存储实际的Value值;而key非共享内容则实际存储“olor”这个Key字符串。

上面讲的这些就是.sst文件的全部内部奥秘。
 

【转载】LevelDb日知录之三 log文件

赵班长 发表了文章 • 0 个评论 • 1869 次浏览 • 2016-04-23 07:46 • 来自相关话题

郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84         上节内容讲到log文件在LevelDb中的主要作用是系统故障恢复时,能够保证不会丢 ...查看全部
郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84
        上节内容讲到log文件在LevelDb中的主要作用是系统故障恢复时,能够保证不会丢失数据。因为在将记录写入内存的Memtable之前,会先 写入Log文件,这样即使系统发生故障,Memtable中的数据没有来得及Dump到磁盘的SSTable文件,LevelDB也可以根据log文件恢 复内存的Memtable数据结构内容,不会造成系统丢失数据,在这点上LevelDb和Bigtable是一致的。     下面朗格科技带大家看看log文件的具体物理和逻辑布局是怎样的,LevelDb对于一个log文件,会把它切割成以32K为单位的物理Block,每次 读取的单位以一个Block作为基本读取单位,下图展示的log文件由3个Block构成,所以从物理布局来讲,一个log文件就是由连续的32K大小 Block构成的。

3.JPG


在应用的视野里是看不到这些Block的,应用看到的是一系列的Key:Value对,在LevelDb内部,会将一个Key:Value对看做一条记录 的数据,另外在这个数据前增加一个记录头,用来记载一些管理信息,以方便内部处理,图3.2显示了一个记录在LevelDb内部是如何表示的。


4.JPG


记录头包含三个字段,ChechSum是对“类型”和“数据”字段的校验码,为了避免处理不完整或者是被破坏的数据,当 LevelDb读取记录数据时候会对数据进行校验,如果发现和存储的CheckSum相同,说明数据完整无破坏,可以继续后续流程。“记录长度”记载了数 据的大小,“数据”则是上面讲的Key:Value数值对,“类型”字段则指出了每条记录的逻辑结构和log文件物理分块结构之间的关系,具体而言,主要 有以下四种类型:FULL/FIRST/MIDDLE/LAST。        如果记录类型是FULL,代表了当前记录内容完整地存储在一个物理Block里,没有被不同的物理Block切割开;如果记录被相邻的物理Block切割开,则类型会是其他三种类型中的一种。我们以图3.1所示的例子来具体说明。

       假设目前存在三条记录,Record A,Record B和Record C,其中Record A大小为10K,Record B 大小为80K,Record C大小为12K,那么其在log文件中的逻辑布局会如图3.1所示。Record A是图中蓝色区域所示,因为大小为10K<32K,能够放在一个物理Block中,所以其类型为FULL;Record B 大小为80K,而Block 1因为放入了Record A,所以还剩下22K,不足以放下Record B,所以在Block 1的剩余部分放入Record B的开头一部分,类型标识为FIRST,代表了是一个记录的起始部分;Record B还有58K没有存储,这些只能依次放在后续的物理Block里面,因为Block 2大小只有32K,仍然放不下Record B的剩余部分,所以Block 2全部用来放Record B,且标识类型为MIDDLE,意思是这是Record B中间一段数据;Record B剩下的部分可以完全放在Block 3中,类型标识为LAST,代表了这是Record B的末尾数据;图中黄色的Record C因为大小为12K,Block 3剩下的空间足以全部放下它,所以其类型标识为FULL。

     从这个小例子可以看出逻辑记录和物理Block之间的关系,LevelDb一次物理读取为一个Block,然后根据类型情况拼接出逻辑记录,供后续流程处理。
 

【转载】LevelDb日知录之二整体架构

赵班长 发表了文章 • 0 个评论 • 2038 次浏览 • 2016-04-23 07:43 • 来自相关话题

郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84     LevelDb本质上是一套存储系统以及在这套存储系统上提供的一些操作接口。为了便于理解整个 ...查看全部
郑重声明:本文转载自郎格科技系列博客,原文地址:http://www.samecity.com/blog/Article.asp?ItemID=84
    LevelDb本质上是一套存储系统以及在这套存储系统上提供的一些操作接口。为了便于理解整个系统及其处理流程,我们可以从两个不同的角度来看待 LevleDb:静态角度和动态角度。从静态角度,可以假想整个系统正在运行过程中(不断插入删除读取数据),此时我们给LevelDb照相,从照片可以 看到之前系统的数据在内存和磁盘中是如何分布的,处于什么状态等;从动态的角度,主要是了解系统是如何写入一条记录,读出一条记录,删除一条记录的,同时 也包括除了这些接口操作外的内部操作比如compaction,系统运行时崩溃后如何恢复系统等等方面。
      本节所讲的整体架构主要从静态角度来描述,之后接下来的几节内容会详述静态结构涉及到的文件或者内存数据结构,LevelDb日知录后半部分主要介绍动态视角下的LevelDb,就是说整个系统是怎么运转起来的。    LevelDb作为存储系统,数据记录的存储介质包括内存以及磁盘文件,如果像上面说的,当LevelDb运行了一段时间,此时我们给LevelDb进行透视拍照,那么您会看到如下一番景象:
   
1.JPG


从图中可以看出,构成LevelDb静态结构的包括六个主要部分:内存中的MemTable和Immutable MemTable以及磁盘上的几种主要文件:Current文件,Manifest文件,log文件以及SSTable文件。当然,LevelDb除了这 六个主要部分还有一些辅助的文件,但是以上六个文件和数据结构是LevelDb的主体构成元素。LevelDb的Log文件和Memtable与Bigtable论文中介绍的是一致的,当应用写入一条Key:Value记录的时候,LevelDb会 先往log文件里写入,成功后将记录插进Memtable中,这样基本就算完成了写入操作,因为一次写入操作只涉及一次磁盘顺序写和一次内存写入,所以这 是为何说LevelDb写入速度极快的主要原因。

Log文件在系统中的作用主要是用于系统崩溃恢复而不丢失数据,假如没有Log文件,因为写入的记录刚开始是保存在内存中的,此时如果系统崩溃,内存中的 数据还没有来得及Dump到磁盘,所以会丢失数据(Redis就存在这个问题)。为了避免这种情况,LevelDb在写入内存前先将操作记录到Log文件 中,然后再记入内存中,这样即使系统崩溃,也可以从Log文件中恢复内存中的Memtable,不会造成数据的丢失。

当Memtable插入的数据占用内存到了一个界限后,需要将内存的记录导出到外存文件中,LevleDb会生成新的Log文件和Memtable,原先 的Memtable就成为Immutable Memtable,顾名思义,就是说这个Memtable的内容是不可更改的,只能读不能写入或者删除。新到来的数据被记入新的Log文件和 Memtable,LevelDb后台调度会将Immutable Memtable的数据导出到磁盘,形成一个新的SSTable文件。SSTable就是由内存中的数据不断导出并进行Compaction操作后形成 的,而且SSTable的所有文件是一种层级结构,第一层为Level 0,第二层为Level 1,依次类推,层级逐渐增高,这也是为何称之为LevelDb的原因。

    SSTable中的文件是Key有序的,就是说在文件中小key记录排在大Key记录之前,各个Level的SSTable都是如此,但是这里需要 注意的一点是:Level 0的SSTable文件(后缀为.sst)和其它Level的文件相比有特殊性:这个层级内的.sst文件,两个文件可能存在key重叠,比如有两个 level 0的sst文件,文件A和文件B,文件A的key范围是:{bar, car},文件B的Key范围是{blue,samecity},那么很可能两个文件都存在key=”blood”的记录。对于其它Level的 SSTable文件来说,则不会出现同一层级内.sst文件的key重叠现象,就是说Level L中任意两个.sst文件,那么可以保证它们的key值是不会重叠的。这点需要特别注意,后面您会看到很多操作的差异都是由于这个原因造成的。    SSTable中的某个文件属于特定层级,而且其存储的记录是key有序的,那么必然有文件中的最小key和最大key,这是非常重要的信 息,LevelDb应该记下这些信息。Manifest就是干这个的,它记载了SSTable各个文件的管理信息,比如属于哪个Level,文件名称叫 啥,最小key和最大key各自是多少。下图是Manifest所存储内容的示意:

   
2.JPG


图中只显示了两个文件(manifest会记载所有SSTable文件的这些信息),即Level 0的test.sst1和test.sst2文件,同时记载了这些文件各自对应的key范围,比如test.sstt1的key范围是“an”到 “banana”,而文件test.sst2的key范围是“baby”到“samecity”,可以看出两者的key范围是有重叠的。

Current文件是干什么的呢?这个文件的内容只有一个信息,就是记载当前的manifest文件名。因为在LevleDb的运行过程中,随着 Compaction的进行,SSTable文件会发生变化,会有新的文件产生,老的文件被废弃,Manifest也会跟着反映这种变化,此时往往会新生 成Manifest文件来记载这种变化,而Current则用来指出哪个Manifest文件才是我们关心的那个Manifest文件。