详解与时序数据相关的数据库及其应用操作指南
原文地址:https://blog.****.net/liukuan73/article/details/79950329
1.基础
1.1 时序数据的定义
什么是时间序列数据(Time Series Data,TSD,以下简称时序)从定义上来说,就是一串按时间维度索引的数据。用描述性的语言来解释什么是时序数据,简单的说,就是这类数据描述了某个被测量的主体在一个时间范围内的每个时间点上的测量值。它普遍存在于IT基础设施、运维监控系统和物联网中。
对时序数据进行建模的话,会包含三个重要部分,分别是:主体,时间点和测量值。套用这套模型,你会发现你在日常工作生活中,无时无刻不在接触着这类数据。
如果你是一个股民,某只股票的股价就是一类时序数据,其记录着每个时间点该股票的股价。
如果你是一个运维人员,监控数据是一类时序数据,例如对于机器的CPU的监控数据,就是记录着每个时间点机器上CPU的实际消耗值。
时序数据从时间维度上将孤立的观测值连成一条线,从而揭示软硬件系统的状态变化。孤立的观测值不能叫时序数据,但如果把大量的观测值用时间线串起来,我们就可以研究和分析观测值的趋势及规律。
1.2 时序数据的特点
1.2.1 时序数据的数学模型
上面介绍了时序数据的基本概念,也说明了分析时序数据的意义。那么时序数据该怎样存储呢?数据的存储要考虑其数学模型和特点,时序数据当然也不例外。所以这里先介绍时序数据的数学模型和特点。
下图为一段时序数据,记录了一段时间内的某个集群里各机器上各端口的出入流量,每半小时记录一个观测值。这里以图中的数据为例,介绍下时序数据的数学模型(不同的时序数据库中,基本概念的称谓有可能不同,这里以腾讯CTSDB为准):
measurement: 度量的数据集,类似于关系型数据库中的 table;
point: 一个数据点,类似于关系型数据库中的 row;
timestamp: 时间戳,表征采集到数据的时间点;
tag: 维度列,代表数据的归属、属性,表明是哪个设备/模块产生的,一般不随着时间变化,供查询使用;
field: 指标列,代表数据的测量值,随时间平滑波动,不需要查询。
如上图所示,这组数据的measurement为Network,每个point由以下部分组成:
timestamp:时间戳
两个tag:host、port,代表每个point归属于哪台机器的哪个端口
两个field:bytes_in、bytes_out,代表piont的测量值,半小时内出入流量的平均值
同一个host、同一个port,每半小时产生一个point,随着时间的增长,field(bytes_in、bytes_out)不断变化。如host:host4,port:51514,timestamp从02:00 到02:30的时间段内,bytes_in 从 37.937上涨到38.089,bytes_out从2897.26上涨到3009.86,说明这一段时间内该端口服务压力升高。
1.2.2 时序数据特点
数据模式: 时序数据随时间增长,相同维度重复取值,指标平滑变化:这点从上面的Network表的数据变化可以看出。
写入: 持续高并发写入,无更新操作:时序数据库面对的往往是百万甚至千万数量级终端设备的实时数据写入(如摩拜单车2017年全国车辆数为千万级),但数据大多表征设备状态,写入后不会更新。
查询: 按不同维度对指标进行统计分析,且存在明显的冷热数据,一般只会频繁查询近期数据。
1.3 时序数据的存储
1.3.1 传统关系型数据库存储时序数据的问题
有了时序数据后,该存储在哪里呢?首先我们看下传统的关系型数据库解决方案在存储时序数据时会遇到什么问题。
很多人可能认为在传统关系型数据库上加上时间戳一列就能作为时序数据库。数据量少的时候确实也没问题。但时序数据往往是由百万级甚至千万级终端设备产生的,写入并发量比较高,属于海量数据场景。
MySQL在海量的时序数据场景下存在如下问题:
存储成本大:对于时序数据压缩不佳,需占用大量机器资源;
维护成本高:单机系统,需要在上层人工的分库分表,维护成本高;
写入吞吐低:单机写入吞吐低,很难满足时序数据千万级的写入压力;
查询性能差:适用于交易处理,海量数据的聚合分析性能差。
另外,使用Hadoop生态(Hadoop、Spark等)存储时序数据会有以下问题:
数据延迟高:离线批处理系统,数据从产生到可分析,耗时数小时、甚至天级;
查询性能差:不能很好的利用索引,依赖MapReduce任务,查询耗时一般在分钟级。
可以看到时序数据库需要解决以下几个问题:
时序数据的写入:如何支持每秒钟上千万上亿数据点的写入。
时序数据的读取:如何支持在秒级对上亿数据的分组聚合运算。
成本敏感:由海量数据存储带来的是成本问题。如何更低成本的存储这些数据,将成为时序数据库需要解决的重中之重。
1.3.2 时序数据库
***时序数据库产品的发明都是为了解决传统关系型数据库在时序数据存储和分析上的不足和缺陷,这类产品被统一归类为时序数据库。***针对时序数据的特点对写入、存储、查询等流程进行了优化,这些优化与时序数据的特点息息相关:
存储成本:
利用时间递增、维度重复、指标平滑变化的特性,合理选择编码压缩算法,提高数据压缩比;
通过预降精度,对历史数据做聚合,节省存储空间。
高并发写入:
批量写入数据,降低网络开销;
数据先写入内存,再周期性的dump为不可变的文件存储。
低查询延时,高查询并发:
优化常见的查询模式,通过索引等技术降低查询延时;
通过缓存、routing等技术提高查询并发。
1.3.3 时序数据的存储原理
传统数据库存储采用的都是 B tree,这是由于其在查询和顺序插入时有利于减少寻道次数的组织形式。我们知道磁盘寻道时间是非常慢的,一般在 10ms 左右。磁盘的随机读写慢就慢在寻道上面。对于随机写入 B tree 会消耗大量的时间在磁盘寻道上,导致速度很慢。我们知道 SSD 具有更快的寻道时间,但并没有从根本上解决这个问题。
对于 90% 以上场景都是写入的时序数据库,B tree 很明显是不合适的。
业界主流都是采用 LSM tree 替换 B tree,比如 Hbase, Cassandra 等 nosql 。这里我们详细介绍一下。
LSM tree 包括内存里的数据结构和磁盘上的文件两部分。分别对应 Hbase 里的 MemStore 和 HLog;对应 Cassandra 里的 MemTable 和 sstable。
LSM tree 操作流程如下:
数据写入和更新时首先写入位于内存里的数据结构。为了避免数据丢失也会先写到 WAL 文件中。
内存里的数据结构会定时或者达到固定大小会刷到磁盘。这些磁盘上的文件不会被修改。
随着磁盘上积累的文件越来越多,会定时的进行合并操作,消除冗余数据,减少文件数量。
可以看到 LSM tree 核心思想就是通过内存写和后续磁盘的顺序写入获得更高的写入性能,避免了随机写入。但同时也牺牲了读取性能,因为同一个 key 的值可能存在于多个 HFile 中。为了获取更好的读取性能,可以通过 bloom filter 和 compaction 得到,这里限于篇幅就不详细展开。
###1.3.4 分布式存储
时序数据库面向的是海量数据的写入存储读取,单机是无法解决问题的。所以需要采用多机存储,也就是分布式存储。
分布式存储首先要考虑的是如何将数据分布到多台机器上面,也就是分片(sharding)问题。下面我们就时序数据库分片问题展开介绍。分片问题由分片方法的选择和分片的设计组成。
####分片方法
时序数据库的分片方法和其他分布式系统是相通的。
哈希分片:这种方法实现简单,均衡性较好,但是集群不易扩展。
一致性哈希:这种方案均衡性好,集群扩展容易,只是实现复杂。代表有 Amazon 的 DynamoDB 和开源的 Cassandra。
范围划分:通常配合全局有序,复杂度在于合并和分裂。代表有 Hbase。
分片设计
分片设计简单来说就是以什么做分片,这是非常有技巧的,会直接影响写入读取的性能。
**结合时序数据库的特点,根据 measurement+tags 分片是比较好的一种方式,因为往往会按照一个时间范围查询,这样相同 metric 和 tags 的数据会分配到一台机器上连续存放,顺序的磁盘读取是很快的。**再结合上面讲到的单机存储内容,可以做到快速查询。
进一步我们考虑时序数据时间范围很长的情况,需要根据时间范围再分成几段,分别存储到不同的机器上,这样对于大范围时序数据就可以支持并发查询,优化查询速度。
如下图,第一行和第三行都是同样的 tag(sensor=95D8-7913;city= 上海),所以分配到同样的分片,而第五行虽然也是同样的 tag,但是根据时间范围再分段,被分到了不同的分片。第二、四、六行属于同样的 tag(sensor=F3CC-20F3;city= 北京)也是一样的道理。
1.4 开源时序数据库介绍
1.4.1开源时序数据库对比
目前行业内比较流行的开源时序数据库产品有 InfluxDB、OpenTSDB、Prometheus、Graphite等,其产品特性对比如下图所示:
1.4.2 InfluxDB介绍
InfluxDB是一个开源的时序数据库,使用GO语言开发,特别适合用于处理和分析资源监控数据这种时序相关数据。而InfluxDB自带的各种特殊函数如求标准差,随机取样数据,统计数据变化比等,使数据统计和实时分析变得十分方便。
重要概念
influxdb里面有一些重要概念:database,timestamp,field key, field value, field set,tag key,tag value,tag set,measurement, retention policy ,series,point。结合下面的例子数据来说明这几个概念:
name: census
-————————————
time butterflies honeybees location scientist
2015-08-18T00:00:00Z 12 23 1 langstroth
2015-08-18T00:00:00Z 1 30 1 perpetua
2015-08-18T00:06:00Z 11 28 1 langstroth
2015-08-18T00:06:00Z 3 28 1 perpetua
2015-08-18T05:54:00Z 2 11 2 langstroth
2015-08-18T06:00:00Z 1 10 2 langstroth
2015-08-18T06:06:00Z 8 23 2 perpetua
2015-08-18T06:12:00Z 7 22 2 perpetua
1
2
3
4
5
6
7
8
9
10
11
timestamp
既然是时间序列数据库,influxdb的数据都有一列名为time的列,里面存储UTC时间戳。
field key,field value,field set
butterflies和honeybees两列数据称为字段(fields),influxdb的字段由field key和field value组成。其中butterflies和honeybees为field key,它们为string类型,用于存储元数据。
而butterflies这一列的数据12-7为butterflies的field value,同理,honeybees这一列的23-22为honeybees的field value。field value可以为string,float,integer或boolean类型。field value通常都是与时间关联的。
field key和field value对组成的集合称之为field set。如下:
butterflies = 12 honeybees = 23
butterflies = 1 honeybees = 30
butterflies = 11 honeybees = 28
butterflies = 3 honeybees = 28
butterflies = 2 honeybees = 11
butterflies = 1 honeybees = 10
butterflies = 8 honeybees = 23
butterflies = 7 honeybees = 22
1
2
3
4
5
6
7
8
在influxdb中,字段必须存在。注意,字段是没有索引的。如果使用字段作为查询条件,会扫描符合查询条件的所有字段值,性能不及tag。类比一下,fields相当于SQL的没有索引的列。
tag key,tag value,tag set
location和scientist这两列称为标签(tags),标签由tag key和tag value组成。location这个tag key有两个tag value:1和2,scientist有两个tag value:langstroth和perpetua。tag key和tag value对组成了tag set,示例中的tag set如下:
location = 1, scientist = langstroth
location = 2, scientist = langstroth
location = 1, scientist = perpetua
location = 2, scientist = perpetua
1
2
3
4
tags是可选的,但是强烈建议你用上它,因为tag是有索引的,tags相当于SQL中的有索引的列。tag value只能是string类型 如果你的常用场景是根据butterflies和honeybees来查询,那么你可以将这两个列设置为tag,而其他两列设置为field,tag和field依据具体查询需求来定。
measurement
measurement是fields,tags以及time列的容器,measurement的名字用于描述存储在其中的字段数据,类似mysql的表名。如上面例子中的measurement为census。measurement相当于SQL中的表,本文中我在部分地方会用表来指代measurement。
retention policy
retention policy指数据保留策略,示例数据中的retention policy为默认的autogen。它表示数据一直保留永不过期,副本数量为1。你也可以指定数据的保留时间,如30天。
series
series是共享同一个retention policy,measurement以及tag set的数据集合。示例中数据有4个series,如下:
Arbitrary series number Retention policy Measurement Tag set
series 1 autogen census location = 1,scientist = langstroth
series 2 autogen census location = 2,scientist = langstroth
series 3 autogen census location = 1,scientist = perpetua
series 4 autogen census location = 2,scientist = perpetua
1
2
3
4
5
point
point则是同一个series中具有相同时间的field set,points相当于SQL中的数据行。如下面就是一个point:
name: census
-----------------
time butterflies honeybees location scientist
2015-08-18T00:00:00Z 1 30 1 perpetua
1
2
3
4
database
上面提到的结构都存储在数据库中,示例的数据库为my_database。一个数据库可以有多个measurement,retention policy, continuous queries以及user。influxdb是一个无模式的数据库,可以很容易的添加新的measurement,tags,fields等。而它的操作却和传统的数据库一样,可以使用类SQL语言查询和修改数据。
influxdb不是一个完整的CRUD数据库,它更像是一个CR-ud数据库。它优先考虑的是增加和读取数据而不是更新和删除数据的性能,而且它阻止了某些更新和删除行为使得创建和读取数据更加高效。
更多详细介绍请见:https://www.jianshu.com/p/a1344ca86e9b
2.部署
2.1 influxdb部署
yum部署:
<1> 配置YUM源
cat <<EOF| sudo tee /etc/yum.repos.d/influxdb.repo
[influxdb]
name = InfluxDB Repository- RHEL\$releasever
baseurl = https://repos.influxdata.com/rhel/\$releasever/\$basearch/stable
enabled = 1
gpgcheck = 1
gpgkey = https://repos.influxdata.com/influxdb.key
EOF
1
2
3
4
5
6
7
8
<2> yum安装
yum install influxdb -y
systemctl start influxdb
systemctl enable influxdb
1
2
3
rpm部署:
wget https://dl.influxdata.com/influxdb/releases/influxdb-1.5.2.x86_64.rpm
yum -y localinstall influxdb-1.5.2.x86_64.rpm
1
2
docker部署:
docker run --name=influxdb -d -p 8086:8086 -v /etc/localtime:/etc/localtime daocloud.io/liukuan73/influxdb:1.4
1
2
备注:假如是收集collectd的内容,还需要映射25826端口-p 25826:25826
##2.2 grafana部署
rpm部署:
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.4-1.x86_64.rpm
yum -y localinstall grafana-5.0.4-1.x86_64.rpm
systemctl enable grafana-server
systemctl start grafana-server
1
2
3
4
docker部署:
docker run -d -p 3000:3000 --name=grafana -e "GF_SERVER_HTTP_PORT=3000" -e "GF_AUTH_BASIC_ENABLED=false" -e "GF_AUTH_ANONYMOUS_ENABLED=true" -e "GF_AUTH_ANONYMOUS_ORG_ROLE=Admin" -e "GF_SERVER_ROOT_URL=/" daocloud.io/liukuan73/grafana:5.0.0
1
2
3.使用
有三种方法可以将数据写入InfluxDB,包括:
客户端库
调用restapi
命令行(类sql语句)
##3.1 调用客户端库操作influxdb
以collectd+influxdb+grafana为例介绍通过collectd采集主机性能指标,然后通过influxdb的客户端库写入influxdb,最后在grafana展示的完整过程。
3.1.1 collectd部署
1、yum安装
sudo yum -y install epel-release
sudo yum -y install collectd
1
2
2、数据写入 influxdb ,修改配置
vi /etc/collectd.conf
LoadPlugin network
<Plugin network>
# # client setup:
Server "10.142.232.155" "25826"
# <Server "239.192.74.66" "25826">
</Plugin>
systemctl enable collectd
systemctl start collectd
systemctl status collectd
1
2
3
4
5
6
7
8
9
10
3.1.2 influxdb配置
1、创建collectd数据库
influx -host '10.142.232.155' -port '8086'
Connected to http://127.0.0.1:8086 version 1.5.2
InfluxDB shell version: 1.5.2
> create database collectd
> use collectd
> create user "collectd" with password '123456' with all privileges
1
2
3
4
5
6
2、配置influxdb,开启对collectd数据的接收
vim /etc/influxdb/influxdb.conf
[[collectd]]
enabled = true
port = 25826
database = "collectd" #刚创建的collectd数据库,来自collectd的数据写入这个数据库。没事先创建好的话会启动失败
1
2
3
4
5
3.1.3 grafana配置
1、配置influxdb数据源
点击“Add data source”配置数据源:
2.配置dashboard
网络流量统计
创建graph,切换编辑模式“Toggle Edit Mode”, 然后输入自定义SQL查询
输入查询语句:
SELECT derivative("value") AS "value" FROM "interface_rx" WHERE "host" = 'k8sslave04' AND "type" = 'if_octets' AND "instance" = 'eno16777984'
1
备注:
函数 derivative 意为导数, 微积分中的概念. value 为传输总量(字节), derivative(“value”) 为 value 在时间上的增量.其中:
host = k8sslave04
type = if_octets
instance = eno16777984
系统负载
输入查询语句:
SELECT mean("value") FROM "load_longterm" WHERE "host" = 'k8sslave04' AND $timeFilter GROUP BY time($interval) fill(null)
SELECT mean("value") FROM "load_midterm" WHERE "host" = 'k8sslave04' AND $timeFilter GROUP BY time($interval) fill(null)
SELECT mean("value") FROM "load_shortterm" WHERE "host" = 'k8sslave04' AND $timeFilter GROUP BY time($interval) fill(null)
1
2
3
内存用量
输入查询语句:
SELECT mean("value") FROM "memory_value" WHERE "type_instance" = 'used' AND $timeFilter GROUP BY time($interval) fill(null)
1
效果
3.2 RestAPI操作
3.2.1 实例
创建数据库:
要创建数据库,请将POST请求发送到/query终结点,并将URL参数q设置为CREATE DATABASE。 下面的示例主机上运行的InfluxDB发送请求,并创建数据库test:
curl -i -XPOST http://influxdb-ip:8086/query --data-urlencode "q=CREATE DATABASE test"
1
写入单条数据:
通过向/write端点发送POST请求,HTTP-API是将数据写入InfluxDB的主要方式。下面的例子向test数据库写了一个点。 数据由度量cpu_load_short,标签键host和region和对应的标签值server01和us-west,字段值为0.64的字段键value和时间戳1434055562000000000组成。
curl -i -XPOST 'http://influxdb-ip:8086/write?db=test' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'
1
写入点时,必须在db查询参数中指定一个现有的数据库。 如果您没有使用rp查询参数提供保留策略,则会将点写入数据库的默认保留策略。 请参阅API参考文档以获取可用查询参数的完整列表。
写入多条数据:
一次将多个点Post到不同序列,只需要用行将多个点分隔即可。这种批量方式具有高性能。以下示例将三个点写入数据库mydb。 第一点属于拥有度量cpu_load_short及标签集host = server02且用服务器本地时间戳的序列。第二点属于拥有度量cpu_load_short及标签集host = server02,region =us-west且具有指定时间戳1422568543702900257的序列。第三个点与第二个点具有相同的指定时间戳,但是将其写入拥有度量cpu_load_short和标签集direction=in,host=server01,region=us-west的序列。
curl -i -XPOST 'http://influxdb-ip:8086/write?db=test' --data-binary 'cpu_load_short,host=server02 value=0.67
cpu_load_short,host=server02,region=us-west value=0.55 1422568543702900257
cpu_load_short,direction=in,host=server01,region=us-west value=2.0 1422568543702900257'
1
2
3
写入来自文件的数据:
通过将@filename传给curl来从文件中写入点。文件中的数据应该遵循InfluxDB的行协议语法。格式正确的文件示例(cpu_data.txt):
cpu_load_short,host=server02 value=0.67
cpu_load_short,host=server02,region=us-west value=0.55 1422568543702900257
cpu_load_short,direction=in,host=server01,region=us-west value=2.0 1422568543702900257
1
2
3
将cpu_data.txt中数据写入mydb数据库:
curl -i -XPOST 'http://influxdb-ip:8086/write?db=test' --data-binary @cpu_data.txt
1
注意:如果数据文件中超过5,000个点,可能需要将该文件分成几个文件,以便将数据批量写入InfluxDB。 默认情况下,HTTP请求在五秒钟后超时。 InfluxDB在超时之后仍然会尝试写出这些点,但是不能确认它们是否成功写入。
###3.2.2 HTTP响应总结
2xx:如果你的写请求收到HTTP 204 No Content,那就成功了!
4xx:InfluxDB无法理解请求。
5xx:系统过载或严重受损。
无架构设计
InfluxDB是一个无架构的数据库。 您可以随时添加新的度量,标签和字段。请注意,如果您尝试写入与已写入数据类型不相同的数据(例如,将字符串写入之前接受整数的字段),InfluxDB将拒绝这些数据。
错误响应的例子:
将浮点数写入先前接受布尔值的字段中:
curl -i -XPOST 'https://influxdb-ip:8086/writedb=hamlet' --data-binary 'tobeornottobe booleanonly=true'
curl -i -XPOST 'https://influxdb-ip:8086/writedb=hamlet' --data-binary 'tobeornottobe booleanonly=5'
1
2
3
返回:
HTTP/1.1 400 Bad Request
Content-Type: application/json
Request-Id: [...]
X-Influxdb-Version: 1.4.x
Date: Wed, 01 Mar 2017 19:38:01 GMT
Content-Length: 150
{"error":"field type conflict: input field \"booleanonly\" on measurement \"tobeornottobe\" is type float, already exists as type boolean dropped=1"}
Writing a point to a database that doesn’t exist:
curl -i -XPOST 'https://localhost:8086/writedb=atlantis' --data-binary 'liters value=10'
returns:
HTTP/1.1 404 Not Found
Content-Type: application/json
Request-Id: [...]
X-Influxdb-Version: 1.4.x
Date: Wed, 01 Mar 2017 19:38:35 GMT
Content-Length: 45
{"error":"database not found: \"atlantis\""}
Next steps
Now that you know how to write data with the built-in HTTP API discover how to query them with the Querying Data guide! For more information about writing data with the HTTP API, please see the API reference documentation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
将点写入不存在的数据库
curl -i -XPOST 'https://localhost:8086/writedb=atlantis' --data-binary 'liters value=10'
1
返回:
HTTP/1.1 404 Not Found
Content-Type: application/json
Request-Id: [...]
X-Influxdb-Version: 1.4.x
Date: Wed, 01 Mar 2017 19:38:35 GMT
Content-Length: 45
{"error":"database not found: \"atlantis\""}
1
2
3
4
5
6
7
8
3.3命令行操作
InfluxDB提供类SQL语法,如果熟悉SQL的话会非常容易上手。
一些操作实例请见:https://www.linuxdaxue.com/influxdb-basic-operation.html
参考:
http://www.infoq.com/cn/articles/storage-in-sequential-databases
https://zhuanlan.zhihu.com/p/32627177
https://segmentfault.com/a/1190000006868587
http://www.zhimengzhe.com/shujuku/MySQL/414763.html
https://blog.****.net/a464057216/article/details/53043551
https://blog.****.net/wudufeng/article/details/78567866
https://www.linuxdaxue.com/influxdb-basic-operation.html
https://www.jianshu.com/p/a1344ca86e9b
————————————————
版权声明:本文为****博主「liukuan73」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.****.net/liukuan73/article/details/79950329
推荐阅读
-
什么是数据库事物?为什么需要数据库事物,事物有哪些特征?事物的隔离级别是什么?-1.什么是数据库事务? 1.事务是作为一个逻辑单元执行的一系列操作。一个逻辑工作单元必须具备四个属性,即ACID(原子性、一致性、隔离性和持久性)属性,只有这样才能成为事务: 原子性 2.事务必须是一个原子工作单元;它的数据修改要么全部执行,要么全部不执行。 一致性 3.事务完成时,所有数据必须保持一致。在相关数据库中,所有规则都必须适用于事务的修改,以保持所有数据的完整性。事务结束时,所有内部数据结构(如 B 树索引或双向链接表)必须正确无误。 隔离 4.并发事务的修改必须与其他并发事务的修改隔离。一个事务会在另一个并发事务修改之前或之后查看某一状态下的数据,而不会查看中间状态下的数据。这就是所谓的可序列化,因为它允许重新加载起始数据和重放一系列事务,从而使数据最终处于与原始事务执行时相同的状态。 持久性 5.事务完成后,它对系统的影响是永久性的。即使在系统发生故障的情况下,修改也会保留。 2. 为什么需要数据库事物,事物有哪些特征? 事物对数据库的作用是对数据进行一系列操作,要么全部成功,要么全部失败,防止出现中间状态,确保数据库中的数据始终处于正确、和谐的状态。 特征:原子性、一致性、隔离性、持久性,以及其他特征 原子性(Atomicity):所有操作在事务开始后,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出现错误时,会回滚到事务开始前的状态,所有操作就像没有发生一样。也就是说,事务是一个不可分割的整体,就像化学中的原子一样,是物质的基本单位。 一致性(Consistency):在事务开始之前和结束之后,数据库的完整性约束都没有被破坏。例如,如果 A 转钱给 B,A 不可能扣除这笔钱,但 B 却没有收到这笔钱。 隔离:在同一时间内,只允许一个事务请求相同的数据,不同事务之间没有干扰。例如,甲正在从一张银行卡上取款,在甲取款过程结束之前,乙不能向这张卡转账。 持久性(耐用性):事务完成后,事务对数据库的所有更新都将保存到数据库中,无法回滚 3.事务的隔离级别有哪些? 数据库事务有四种隔离级别,从低到高分别是未提交读取(Read uncommitted)、已提交读取(Read committed)、可重复读取(Repeatable read)、可序列化(Serializable)。此外,事务的并发操作中可能会出现脏读、不可重复读、幽灵读等情况。事务并发问题 脏读:事务 A 读取事务 B 更新的数据,然后事务 B 回滚操作,那么事务 A 读取的数据就是脏数据。 不可重复读取:事务 A 多次读取同一数据,事务 B 在事务 A 多次读取期间更新并提交数据,导致事务 A 多次读取同一数据时结果不一致。 幻影读取:系统管理员 A 将数据库中所有学生的具体分数改为 ABCDE 等级,但系统管理员 B 在此时插入了具体分数的记录,当系统管理员 A 更改结束后发现仍有一条记录未被更改,仿佛发生了幻觉,这称为幻影读取。 小结:不可重复读和幻读容易混淆,不可重复读侧重于修改,幻读侧重于增删。解决不可重复读问题只需锁定满足条件的行,解决幻读问题则需要锁定表 MySQL 事务隔离级别
-
windows下进程间通信的(13种方法)-摘 要 本文讨论了进程间通信与应用程序间通信的含义及相应的实现技术,并对这些技术的原理、特性等进行了深入的分析和比较。 ---- 关键词 信号 管道 消息队列 共享存储段 信号灯 远程过程调用 Socket套接字 MQSeries 1 引言 ---- 进程间通信的主要目的是实现同一计算机系统内部的相互协作的进程之间的数据共享与信息交换,由于这些进程处于同一软件和硬件环境下,利用操作系统提供的的编程接口,用户可以方便地在程序中实现这种通信;应用程序间通信的主要目的是实现不同计算机系统中的相互协作的应用程序之间的数据共享与信息交换,由于应用程序分别运行在不同计算机系统中,它们之间要通过网络之间的协议才能实现数据共享与信息交换。进程间通信和应用程序间通信及相应的实现技术有许多相同之处,也各有自己的特色。即使是同一类型的通信也有多种的实现方法,以适应不同情况的需要。 ---- 为了充分认识和掌握这两种通信及相应的实现技术,本文将就以下几个方面对这两种通信进行深入的讨论:问题的由来、解决问题的策略和方法、每种方法的工作原理和实现、每种实现方法的特点和适用的范围等。 2 进程间的通信及其实现技术 ---- 用户提交给计算机的任务最终都是通过一个个的进程来完成的。在一组并发进程中的任何两个进程之间,如果都不存在公共变量,则称该组进程为不相交的。在不相交的进程组中,每个进程都独立于其它进程,它的运行环境与顺序程序一样,而且它的运行环境也不为别的进程所改变。运行的结果是确定的,不会发生与时间相关的错误。 ---- 但是,在实际中,并发进程的各个进程之间并不是完全互相独立的,它们之间往往存在着相互制约的关系。进程之间的相互制约关系表现为两种方式: ---- (1) 间接相互制约:共享CPU ---- (2) 直接相互制约:竞争和协作 ---- 竞争——进程对共享资源的竞争。为保证进程互斥地访问共享资源,各进程必须互斥地进入各自的临界段。 ---- 协作——进程之间交换数据。为完成一个共同任务而同时运行的一组进程称为同组进程,它们之间必须交换数据,以达到协作完成任务的目的,交换数据可以通知对方可以做某事或者委托对方做某事。 ---- 共享CPU问题由操作系统的进程调度来实现,进程间的竞争和协作由进程间的通信来完成。进程间的通信一般由操作系统提供编程接口,由程序员在程序中实现。UNIX在这个方面可以说最具特色,它提供了一整套进程间的数据共享与信息交换的处理方法——进程通信机制(IPC)。因此,我们就以UNIX为例来分析进程间通信的各种实现技术。 ---- 在UNIX中,文件(File)、信号(Signal)、无名管道(Unnamed Pipes)、有名管道(FIFOs)是传统IPC功能;新的IPC功能包括消息队列(Message queues)、共享存储段(Shared memory segment)和信号灯(Semapores)。 ---- (1) 信号 ---- 信号机制是UNIX为进程中断处理而设置的。它只是一组预定义的值,因此不能用于信息交换,仅用于进程中断控制。例如在发生浮点错、非法内存访问、执行无效指令、某些按键(如ctrl-c、del等)等都会产生一个信号,操作系统就会调用有关的系统调用或用户定义的处理过程来处理。 ---- 信号处理的系统调用是signal,调用形式是: ---- signal(signalno,action) ---- 其中,signalno是规定信号编号的值,action指明当特定的信号发生时所执行的动作。 ---- (2) 无名管道和有名管道 ---- 无名管道实际上是内存中的一个临时存储区,它由系统安全控制,并且独立于创建它的进程的内存区。管道对数据采用先进先出方式管理,并严格按顺序操作,例如不能对管道进行搜索,管道中的信息只能读一次。 ---- 无名管道只能用于两个相互协作的进程之间的通信,并且访问无名管道的进程必须有共同的祖先。 ---- 系统提供了许多标准管道库函数,如: pipe——打开一个可以读写的管道; close——关闭相应的管道; read——从管道中读取字符; write——向管道中写入字符; ---- 有名管道的操作和无名管道类似,不同的地方在于使用有名管道的进程不需要具有共同的祖先,其它进程,只要知道该管道的名字,就可以访问它。管道非常适合进程之间快速交换信息。 ---- (3) 消息队列(MQ) ---- 消息队列是内存中独立于生成它的进程的一段存储区,一旦创建消息队列,任何进程,只要具有正确的的访问权限,都可以访问消息队列,消息队列非常适合于在进程间交换短信息。 ---- 消息队列的每条消息由类型编号来分类,这样接收进程可以选择读取特定的消息类型——这一点与管道不同。消息队列在创建后将一直存在,直到使用msgctl系统调用或iqcrm -q命令删除它为止。 ---- 系统提供了许多有关创建、使用和管理消息队列的系统调用,如: ---- int msgget(key,flag)——创建一个具有flag权限的MQ及其相应的结构,并返回一个唯一的正整数msqid(MQ的标识符); ---- int msgsnd(msqid,msgp,msgsz,msgtyp,flag)——向队列中发送信息; ---- int msgrcv(msqid,cmd,buf)——从队列中接收信息; ---- int msgctl(msqid,cmd,buf)——对MQ的控制操作; ---- (4) 共享存储段(SM) ---- 共享存储段是主存的一部分,它由一个或多个独立的进程共享。各进程的数据段与共享存储段相关联,对每个进程来说,共享存储段有不同的虚拟地址。系统提供的有关SM的系统调用有: ---- int shmget(key,size,flag)——创建大小为size的SM段,其相应的数据结构名为key,并返回共享内存区的标识符shmid; ---- char shmat(shmid,address,flag)——将当前进程数据段的地址赋给shmget所返回的名为shmid的SM段; ---- int shmdr(address)——从进程地址空间删除SM段; ---- int shmctl (shmid,cmd,buf)——对SM的控制操作; ---- SM的大小只受主存限制,SM段的访问及进程间的信息交换可以通过同步读写来完成。同步通常由信号灯来实现。SM非常适合进程之间大量数据的共享。 ---- (5) 信号灯 ---- 在UNIX中,信号灯是一组进程共享的数据结构,当几个进程竞争同一资源时(文件、共享内存或消息队列等),它们的操作便由信号灯来同步,以防止互相干扰。 ---- 信号灯保证了某一时刻只有一个进程访问某一临界资源,所有请求该资源的其它进程都将被挂起,一旦该资源得到释放,系统才允许其它进程访问该资源。信号灯通常配对使用,以便实现资源的加锁和解锁。 ---- 进程间通信的实现技术的特点是:操作系统提供实现机制和编程接口,由用户在程序中实现,保证进程间可以进行快速的信息交换和大量数据的共享。但是,上述方式主要适合在同一台计算机系统内部的进程之间的通信。 3 应用程序间的通信及其实现技术 ---- 同进程之间的相互制约一样,不同的应用程序之间也存在竞争和协作的关系。UNIX操作系统也提供一些可用于应用程序之间实现数据共享与信息交换的编程接口,程序员可以通过自己编程来实现。如远程过程调用和基于TCP/IP协议的套接字(Socket)编程。但是,相对普通程序员来说,它们涉及的技术比较深,编程也比较复杂,实现起来困难较大。 ---- 于是,一种新的技术应运而生——通过将有关通信的细节完全掩盖在某个独立软件内部,即底层的通讯工作和相应的维护管理工作由该软件内部来实现,用户只需要将通信任务提交给该软件去完成,而不必理会它的具体工作过程——这就是所谓的中间件技术。 ---- 我们在这里分别讨论这三种常用的应用程序间通信的实现技术——远程过程调用、会话编程技术和MQSeries消息队列技术。其中远程过程调用和会话编程属于比较低级的方式,程序员参与的程度较深,而MQSeries消息队列则属于比较高级的方式,即中间件方式,程序员参与的程度较浅。 ---- 4.1 远程过程调用(RPC)
-
Prometheus server与被监测应用详解:Grafana接入、MySQL数据库监控、自动发现功能概览及配置指南、以及Alertmanager的角色
-
玩转Java底层:JMX详解 - jconsole与自定义MBean监控工具的实际应用与区别" 在日常JVM调优中,我们熟知的jconsole工具通过JMX包装的bean以图形化形式展示管理数据,而像jstat和jmap这类内建监控工具则由JVM直接支持。本文将以jconsole为例,深入讲解其实质——基于JMX的MBean功能,包括可视化界面上的bean属性查看和操作调用。 MBeans在jconsole中的体现是那些可观察的组件属性和方法,如上图所示,通过名为"Verbose"的属性能看到其值为false,同时还能直接操作该bean的方法,例如"closeJerryMBean"。 尽管jconsole给我们提供了直观的可视化界面,但请注意,这里的MBean并非固定不变,开发者可根据JMX提供的接口将自己的自定义bean展示到jconsole。以下步骤展示了如何创建并注册一个名为"StudyJavaMBean"的自定义MBean: 1. 首先定义接口`StudyJavaMBean`,接口需遵循MBean规范,即后缀为"MBean"且包含getter方法代表属性,如`getApplicationName`,和无返回值的setter方法代表操作,如`closeJerryMBean`。 ```java public interface StudyJavaMBean { String getApplicationName(); void closeJerryMBean(); } ``` 2. 编写接口的实现类`StudyJavaMBeanImpl`,实现接口中的方法: ```java public class StudyJavaMBeanImpl implements StudyJavaMBean { @Override public String getApplicationName() { return "每天学Java"; } @Override public void closeJerryMBean() { System.out.println("关闭Jerry应用"); } } ``` 3. 在代码中注册自定义MBean,涉及的关键步骤包括: - 获取平台MBeanServer - 定义ObjectName,指定唯一的MBean标识符 - 注册MBean到服务器 - 启动RMI连接器服务,以便jconsole能够访问 ```java public void registerMBean() throws Exception { // ... 具体实现省略 ... } ``` 实际运行注册后的MBean,您将在jconsole中发现并查看自定义bean的属性和调用相关方法。然而,这种方式相较于传统的属性/日志查看和HTTP接口,实用性相对有限,可能存在潜在的安全风险。但不可否认的是,JMX及其MBean机制对于获取操作系统信息、内存状态等关键性能指标仍然具有重要价值。例如: 1. **获取操作系统信息**:通过JMX MBean,可以直接获取到诸如CPU使用率、操作系统版本等系统级信息,这对于资源管理和优化工作具有显著帮助。
-
详解与时序数据相关的数据库及其应用操作指南