提到格里芬—Griffin,大家想到更多的是篮球明星或者战队名,但在大数据领域Apache Griffin(以下简称Griffin)可是数据质量领域响当当的一哥。先说一句:Griffin是大数据质量监控领域唯一的Apache项目,懂了吧。

​ 在不重视数据质量的大数据发展时期,Griffin并不能引起重视,但是随着数据治理在很多企业的全面开展与落地,数据质量的问题开始引起重视。

​ 还是那句话,商用版的解决方案暂时不在本文的讨论范围内,目前大数据流动公众号对于数据治理工具的研究还是在开源方向,希望通过开源+二次开发结合的方式找到适合自己公司的数据治理工具箱。在未来有靠谱的商用方案,我们也会保持关注~

本文将从数据质量,Griffin简介,Griffin架构,Griffin快速入门,Griffin批数据实战,Griffin流数据实战整合六个部分进行介绍,目的是带大家快速的入门数据质量管理工具的使用。

本文档版权属于公众号:大数据流动 所有。未经授权,请勿转载与商用!

考虑到抄袭问题,Griffin后续的高阶技术文章可能会付费,也希望大家能尽早加入数据治理、Griffin等相关技术群,我会将最新的文章与资料实时同步。

一、数据质量

​ 数据质量管理(Data Quality Management),是指对数据从计划、获取、存储、共享、维护、应用、消亡生命周期的每个阶段里可能引发的各类数据质量问题,进行识别、度量、监控、预警等一系列管理活动,并通过改善和提高组织的管理水平使得数据质量获得进一步提高。

数据质量管理不是一时的数据治理手段,而是循环的管理过程。其终极目标是通过可靠的数据,提升数据在使用中的价值,并最终为企业赢得经济效益。

​ 为什么会有数据质量管理呢?

​ 大数据时代数据的核心不是“大”,而在于“有价值”,而有价值的关键在于“质量”。但现实是,数据往往存在很多问题:

  • 数据无法匹配
  • 数据不可识别
  • 时效性不强
  • 数据不一致
  • 。。。。

​ 那么,解决数据质量要达到什么目标呢?

总结来说就是可信和可用

可信就是让数据具有实用性,准确性,及时性,完整性,有效性。

可用就是规范性和可读性。

数据质量可能不是数据治理的最核心部分,但可能会成为数据治理落地的做大障碍。

提高数据质量有多种方式,比如建立统一的数据标准、提高人员的意识与能力等等。

而一个提高数据质量的高生产力方式就是使用数据质量管理工具

数据质量管理工具成熟的并不多,所以本文就不做无用的对比了,我们直接进入正题:Apache Griffin。

二、Griffin简介

​ Griffin是一个开源的大数据数据质量解决方案,由eBay开源,它支持批处理和流模式两种数据质量检测方式,是一个基于Hadoop和Spark建立的数据质量服务平台 (DQSP)。它提供了一个全面的框架来处理不同的任务,例如定义数据质量模型、执行数据质量测量、自动化数据分析和验证,以及跨多个数据系统的统一数据质量可视化。

Griffin于2016年12月进入Apache孵化器,Apache软件基金会2018年12月12日正式宣布Apache Griffin毕业成为Apache顶级项目。

Griffin官网地址:https://griffin.apache.org/

Github地址:https://github.com/apache/griffin

在eBay的数据质量管理实践中,需要花费很长时间去修复数据质量的问题,不管是批处理还是流处理,解决数据质量问题的时间都是巨大的,由此一个统一的数据质量系统就应运而生了。

在官网的定义中,Apache Griffin也早就更新为了批和流(Batch and Streaming)数据质量解决方案。Apache Griffin已经在朝着数据质量的统一管理平台而努力了。

Griffin主要有如下的功能特点:

  • 度量:精确度、完整性、及时性、唯一性、有效性、一致性。
  • 异常监测:利用预先设定的规则,检测出不符合预期的数据,提供不符合规则数据的下载。
  • 异常告警:通过邮件或门户报告数据质量问题。
  • 可视化监测:利用控制面板来展现数据质量的状态。
  • 实时性:可以实时进行数据质量检测,能够及时发现问题。
  • 可扩展性:可用于多个数据系统仓库的数据校验。
  • 可伸缩性:工作在大数据量的环境中,目前运行的数据量约1.2PB(eBay环境)。
  • 自助服务:Griffin提供了一个简洁易用的用户界面,可以管理数据资产和数据质量规则;同时用户可以通过控制面板查看数据质量结果和自定义显示内容。

Apache Giffin目前的数据源包括HIVE, CUSTOM, AVRO, KAFKA。Mysql和其他关系型数据库的扩展根据需要进行扩展。

当然Giffin也不是万能的,目前Griffin还是有很多的问题的,选择也要慎重:

Griffin的社区并不太活跃,可以共同讨论的人不多。

目前最新版本还是0.6,可能会有一些问题。

网上技术文档很少,当然这方面大数据流动也会不断的输出新的技术文档帮助大家。

三、Griffin架构

​ 数据质量模块是大数据平台中必不可少的一个功能组件,以下Griffin作为一个开源的大数据数据质量解决方案,它支持批处理和流模式两种数据质量检测方式,可以从不同维度(比如离线任务执行完毕后检查源端和目标端的数据数量是否一致、源表的数据空值数量等)度量数据资产,从而提升数据的准确度、可信度。

在Griffin的架构中,主要分为Define、Measure和Analyze三个部分,如下图所示:

各部分的职责如下:

  • Define:主要负责定义数据质量统计的维度,比如数据质量统计的时间跨度、统计的目标(源端和目标端的数据数量是否一致,数据源里某一字段的非空的数量、不重复值的数量、最大值、最小值、top5的值数量等)
  • Measure:主要负责执行统计任务,生成统计结果
  • Analyze:主要负责保存与展示统计结果

听起来有些晦涩,我们来看一下一个完整的Griffin任务的执行流程。

  • 注册数据,把想要检测数据质量的数据源注册到griffin。
  • 配置度量模型,可以从数据质量维度来定义模型,如:精确度、完整性、及时性、唯一性等。
  • 配置定时任务提交spark集群,定时检查数据。
  • 在门户界面上查看指标,分析数据质量校验结果。

Griffin 系统主要分为:数据收集处理层(Data Collection&Processing Layer)、后端服务层(Backend Service Layer)和用户界面(User Interface)

数据处理和存储层:

对于批量分析,数据质量模型将根据 hadoop 中的数据源计算 Spark 集群中的数据质量指标。

对于近实时分析,使用来自消息传递系统的数据,然后数据质量模型将基于 Spark 集群计算实时数据质量指标。对于数据存储,可以在后端使用Elasticsearch来满足前端请求。

Apache Griffin 服务:

项目有提供Restful 服务来完成 Apache Griffin 的所有功能,例如探索数据集、创建数据质量度量、发布指标、检索指标、添加订阅等。因此,开发人员可以基于这些 Web 开发自己的用户界面服务。

这种灵活性也让Griffin 得到了越来越多的应用。

四、Griffin快速入门

Griffin的最新版本为0.6.0,本文的安装部署也基于这个版本进行。

依赖准备

JDK (1.8 or later versions)

MySQL(version 5.6及以上)

Hadoop (2.6.0 or later)

Hive (version 2.x)

Spark (version 2.2.1)

Livy(livy-0.5.0-incubating)

ElasticSearch (5.0 or later versions)

大部分CDH已经自带,这里特别说一下Livy和ElasticSearch如何部署。

Livy是一个Spark的Rest服务器。

https://livy.apache.org/

准备livy安装包。

  1. 将livy安装包解压到/opt/目录下
  2. 创建livy用户、log目录并将livy的home目录属主修改为livy:hadoop
useradd livy -g hadoop
mkdir /var/log/livy
mkdir /var/run/livy
chown livy:hadoop /var/log/livy
chown livy:hadoop /var/run/livy
chown -R livy:hadoop /opt/cloudera/apache-livy-0.6.0-incubating-bin/

3.进入livy home目录,在conf目录下创建livy.conf、livy-env.sh、spark-blacklist.conf配置文件

livy.conf、livy-env.sh、spark-blacklist.conf

4.修改配置文件livy.conf,添加如下内容

livy.spark.master = yarn
livy.spark.deployMode = cluster
livy.environment = production
livy.impersonation.enabled = true
livy.server.csrf_protection.enabled false
livy.server.port = 8998
livy.server.session.timeout = 3600000
livy.server.recovery.mode = recovery
livy.server.recovery.state-store=filesystem
livy.server.recovery.state-store.url=/tmp/livy

5.修改配置文件livy-env.sh,增加hadoop和Spark的配置信息,如下

export JAVA_HOME=/usr/java/jdk1.8.0_181
export HADOOP_HOME=/opt/cloudera/parcels/CDH/lib/hadoop
export SPARK_CONF_DIR=/etc/spark2/conf
export SPARK_HOME=/opt/cloudera/parcels/SPARK2-2.3.0.cloudera2-1.cdh6.3.2.p0.1041012/lib/spark2
export HADOOP_CONF_DIR=/etc/hadoop/conf
export LIVY_LOG_DIR=/var/log/livy
export LIVY_PID_DIR=/var/run/livy
export LIVY_SERVER_JAVA_OPTS="-Xmx2g"

6.修改配置文件spark-blacklist.conf

# Configuration override / blacklist. Defines a list of properties that users are not allowed
# to override when starting Spark sessions.
#
# This file takes a list of property names (one per line). Empty lines and lines starting with "#"
# are ignored.
#
# Disallow overriding the master and the deploy mode.
spark.master
spark.submit.deployMode
# Disallow overriding the location of Spark cached jars.
spark.yarn.jar
spark.yarn.jars
spark.yarn.archive
# Don't allow users to override the RSC timeout.
livy.rsc.server.idle-timeout
  1. core-site.xml 的群集范围高级配置代码段(安全阀)”配置项增加如下内容

    <property>
    <name>hadoop.proxyuser.livy.groups</name>
    <value>*</value>
    </property>
    <property>
    <name>hadoop.proxyuser.livy.hosts</name>
    <value>*</value>
    </property>

    8.在HDFS上创建livy的home目录

    sudo -u hdfs hadoop fs -mkdir /user/livy
    sudo -u hdfs hadoop fs -chown livy:supergroup /user/livy

    9、启动livy服务

livy-server start

elasticsearch5安装,安装包也已下载在资料包中。

 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.15.tar.gz

# tar -zxvf elasticsearch-5.6.15

# cd elasticsearch-5.6.15

# sh ./bin/elasticsearch

配置准备

1、首先在mysql中初始化quartz数据库,这里需要用到脚本Init_quartz_mysql_innodb.sql。

脚本可以加griffin群,领取资料包下载。

mysql -u <username> -p <password> < Init_quartz_mysql_innodb.sql

2、Hadoop和Hive:

从Hadoop服务器拷贝配置文件到Livy服务器上,这里假设将配置文件放在/usr/data/conf目录下。

在Hadoop服务器上创建/home/spark_conf目录,并将Hive的配置文件hive-site.xml上传到该目录下:

#创建/home/spark_conf目录
hadoop fs -mkdir -p /home/spark_conf
#上传hive-site.xml
hadoop fs -put hive-site.xml /home/spark_conf/

3、设置环境变量:

#!/bin/bash
export JAVA_HOME=/data/jdk1.8.0_192 #spark目录
export SPARK_HOME=/usr/data/spark-2.1.1-bin-2.6.3
#livy命令目录
export LIVY_HOME=/usr/data/livy/bin
#hadoop配置文件目录
export HADOOP_CONF_DIR=/usr/data/conf

4、配置启动Livy

更新livy/conf下的livy.conf配置文件:

livy.server.host = 127.0.0.1
livy.spark.master = yarn
livy.spark.deployMode = cluster
livy.repl.enable-hive-context = true

启动livy:

livy-server start

5、Elasticsearch配置:

在ES里创建griffin索引:

curl -XPUT http://es:9200/griffin -d '
{
"aliases": {},
"mappings": {
"accuracy": {
"properties": {
"name": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"tmst": {
"type": "date"
}
}
}
},
"settings": {
"index": {
"number_of_replicas": "2",
"number_of_shards": "5"
}
}
}
'

接下来进行源码编译打包。

Griffin的源码结构很清晰,主要包括griffin-doc、measure、service和ui四个模块,其中griffin-doc负责存放Griffin的文档,measure负责与spark交互,执行统计任务,service使用spring boot作为服务实现,负责给ui模块提供交互所需的restful api,保存统计任务,展示统计结果。

源码导入构建完毕后,需要修改配置文件,具体修改的配置文件如下:

application.properties:mysql,hive,es配置

quartz.properties

sparkProperties.json

配置文件修改好后,在idea里的terminal里执行如下maven命令进行编译打包:

mvn -Dmaven.test.skip=true clean install

命令执行完成后,会在service和measure模块的target目录下分别看到service-0.6.0.jar和measure-0.6.0.jar两个jar,将这两个jar分别拷贝到服务器目录下。

1、使用如下命令将measure-0.4.0.jar这个jar上传到HDFS的/griffin文件目录里:

#改变jar名称
mv measure-0.6.0.jar griffin-measure.jar
#上传griffin-measure.jar到HDFS文件目录里
hadoop fs -put measure-0.6.0.jar /griffin/

2、运行service-0.6.0.jar,启动Griffin管理后台:

nohup java -jar service-0.6.0.jar>service.out 2>&1 &

几秒钟后,我们可以访问Apache Griffin的默认UI(默认情况下,spring boot的端口是8080)。

http://IP:8080

部分结果展示界面如下:

五、Griffin批数据实战

官网给出了批处理数据的例子。

1、在hive里创建表demo_src和demo_tgt:

--create hive tables here. hql script
--Note: replace hdfs location with your own path
CREATE EXTERNAL TABLE `demo_src`(
`id` bigint,
`age` int,
`desc` string)
PARTITIONED BY (
`dt` string,
`hour` string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '|'
LOCATION
'hdfs:///griffin/data/batch/demo_src'; --Note: replace hdfs location with your own path
CREATE EXTERNAL TABLE `demo_tgt`(
`id` bigint,
`age` int,
`desc` string)
PARTITIONED BY (
`dt` string,
`hour` string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '|'
LOCATION
'hdfs:///griffin/data/batch/demo_tgt';

2、生成测试数据:

从http://griffin.apache.org/data/batch/地址下载所有文件到Hadoop服务器上,然后使用如下命令执行gen-hive-data.sh脚本:

nohup ./gen-hive-data.sh>gen.out 2>&1 &

注意观察gen.out日志文件,如果有错误,视情况进行调整。这里我的测试环境Hadoop和Hive安装在同一台服务器上,因此直接运行脚本。

3、通过UI界面创建统计任务

选择DataAssets

在该页面可以看到数据资产展示

点击Measures,创建度量页面

通过下面的步骤来一步步创建

选择数据源

选择目标

将两者关联

设置一些参数

配置好提交

新增定时任务

用cron表达式建立任务

点击DQ Metrics,看到效果。

六、Griffin流数据实战

还会参考官网的例子。

示例流数据如下:

{"id": 1, "name": "Apple", "color": "red", "time": "2018-09-12_06:00:00"}
{"id": 2, "name": "Banana", "color": "yellow", "time": "2018-09-12_06:01:00"}
...

官方也提供了测试数据的脚本https://griffin.apache.org/data/streaming/(已存资料包)

通过脚本可以源源不断将数据写入Kafka

#!/bin/bash

#create topics
kafka-topics.sh --create --zookeeper hadoop101:2181 --replication-factor 1 --partitions 1 --topic source
kafka-topics.sh --create --zookeeper hadoop101:2181 --replication-factor 1 --partitions 1 --topic target #every minute
set +e
while true
do
/opt/module/data/gen-data.sh
sleep 90
done
set -e

Flink部分就是简单接收Kafka数据,然后再发向下游,部分代码片段如下:

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
FlinkKafkaConsumer010<String> kafkaconsumer =
new FlinkKafkaConsumer010<String>(inputTopic, new SimpleStringSchema(), properties);
DataStream<String> dataStream = env.addSource(kafkaconsumer); DataStream<String> target = dataStream.add...//具体处理逻辑 target..addSink(new FlinkKafkaProducer010<String>(
"hadoop101:9092",
"target",
new SimpleStringSchema()
));
outMap.print();
env.execute();

配合env.json

{
"spark": {
"log.level": "WARN",
"checkpoint.dir": "hdfs:///griffin/checkpoint",
"batch.interval": "20s",
"process.interval": "1m",
"init.clear": true,
"config": {
"spark.default.parallelism": 4,
"spark.task.maxFailures": 5,
"spark.streaming.kafkaMaxRatePerPartition": 1000,
"spark.streaming.concurrentJobs": 4,
"spark.yarn.maxAppAttempts": 5,
"spark.yarn.am.attemptFailuresValidityInterval": "1h",
"spark.yarn.max.executor.failures": 120,
"spark.yarn.executor.failuresValidityInterval": "1h",
"spark.hadoop.fs.hdfs.impl.disable.cache": true
}
},
"sinks": [
{
"type": "console"
},
{
"type": "hdfs",
"config": {
"path": "hdfs:///griffin/persist"
}
},
{
"type": "elasticsearch",
"config": {
"method": "post",
"api": "http://es:9200/griffin/accuracy"
}
}
],
"griffin.checkpoint": [
{
"type": "zk",
"config": {
"hosts": "zk:2181",
"namespace": "griffin/infocache",
"lock.path": "lock",
"mode": "persist",
"init.clear": true,
"close.clear": false
}
}
]
}

dq.json

{
"name": "streaming_accu",
"process.type": "streaming",
"data.sources": [
{
"name": "src",
"baseline": true,
"connectors": [
{
"type": "kafka",
"version": "0.8",
"config": {
"kafka.config": {
"bootstrap.servers": "kafka:9092",
"group.id": "griffin",
"auto.offset.reset": "largest",
"auto.commit.enable": "false"
},
"topics": "source",
"key.type": "java.lang.String",
"value.type": "java.lang.String"
},
"pre.proc": [
{
"dsl.type": "df-opr",
"rule": "from_json"
}
]
}
],
"checkpoint": {
"type": "json",
"file.path": "hdfs:///griffin/streaming/dump/source",
"info.path": "source",
"ready.time.interval": "10s",
"ready.time.delay": "0",
"time.range": ["-5m", "0"],
"updatable": true
}
}, {
"name": "tgt",
"connectors": [
{
"type": "kafka",
"version": "0.8",
"config": {
"kafka.config": {
"bootstrap.servers": "kafka:9092",
"group.id": "griffin",
"auto.offset.reset": "largest",
"auto.commit.enable": "false"
},
"topics": "target",
"key.type": "java.lang.String",
"value.type": "java.lang.String"
},
"pre.proc": [
{
"dsl.type": "df-opr",
"rule": "from_json"
}
]
}
],
"checkpoint": {
"type": "json",
"file.path": "hdfs:///griffin/streaming/dump/target",
"info.path": "target",
"ready.time.interval": "10s",
"ready.time.delay": "0",
"time.range": ["-1m", "0"]
}
}
],
"evaluate.rule": {
"rules": [
{
"dsl.type": "griffin-dsl",
"dq.type": "accuracy",
"out.dataframe.name": "accu",
"rule": "src.id = tgt.id AND src.name = tgt.name AND src.color = tgt.color AND src.time = tgt.time",
"details": {
"source": "src",
"target": "tgt",
"miss": "miss_count",
"total": "total_count",
"matched": "matched_count"
},
"out":[
{
"type":"metric",
"name": "accu"
},
{
"type":"record",
"name": "missRecords"
}
]
}
]
},
"sinks": ["CONSOLE", "HDFS"]
}

提交任务

spark-submit --class org.apache.griffin.measure.Application --master yarn --deploy-mode client --queue default \
--driver-memory 1g --executor-memory 1g --num-executors 3 \
<path>/griffin-measure.jar \
<path>/env.json <path>/dq.json

七、总结

数据管理工具目前来说还是非常匮乏的,Griffin提供的不仅仅是实现,还有数据质量管理的思路,这对于我们自研数据质量管理系统也是非常的宝贵的。

数据治理道路任重道远,欢迎加入相关交流群,我们共同学习进步~

进入学习交流群领取学习资料包:

更专注效率才能更高,所以目前数据治理相关学习交流群按不同方向做了区分:

另外 数据治理工具箱 知识星球也已成立,这是一个数据治理落地实践方向的知识星球。大数据流动发布的数据治理相关文章与资料(包括付费内容)都将在知识星球进行长期同步。星球的目标是收集数据治理实践工具的相关资料,并定期组织实战学习小组,让数据治理的相关资料可以长久的保存,同时也解决文章被频繁抄袭的问题,欢迎大家加入。

最后提醒,文档版权为公众号 大数据流动 所有,请勿商用。相关技术问题以及安装包可以联系笔者独孤风加入相关技术交流群讨论获取。

开源数据质量解决方案——Apache Griffin入门宝典的更多相关文章

  1. 数据治理之元数据管理的利器——Atlas入门宝典

    随着数字化转型的工作推进,数据治理的工作已经被越来越多的公司提上了日程.作为Hadoop生态最紧密的元数据管理与发现工具,Atlas在其中扮演着重要的位置.但是其官方文档不是很丰富,也不够详细.所以整 ...

  2. 深度对比Apache CarbonData、Hudi和Open Delta三大开源数据湖方案

    摘要:今天我们就来解构数据湖的核心需求,同时深度对比Apache CarbonData.Hudi和Open Delta三大解决方案,帮助用户更好地针对自身场景来做数据湖方案选型. 背景 我们已经看到, ...

  3. Apache Hudi:云数据湖解决方案

    1. 引入 开源Apache Hudi项目为Uber等大型组织提供流处理能力,每天可处理数据湖上的数十亿条记录. 随着世界各地的组织采用该技术,Apache开源数据湖项目已经日渐成熟. Apache ...

  4. 一站式元数据治理平台——Datahub入门宝典

    随着数字化转型的工作推进,数据治理的工作已经被越来越多的公司提上了日程.作为新一代的元数据管理平台,Datahub在近一年的时间里发展迅猛,大有取代老牌元数据管理工具Atlas之势.国内Datahub ...

  5. Apache Curator入门实战

    Apache Curator入门实战 Curator是Netflix公司开源的一个Zookeeper客户端,与Zookeeper提供的原生客户端相比,Curator的抽象层次更高,简化了Zookeep ...

  6. TOP100summit:【分享实录-Microsoft】基于Kafka与Spark的实时大数据质量监控平台

    本篇文章内容来自2016年TOP100summit Microsoft资深产品经理邢国冬的案例分享.编辑:Cynthia 邢国冬(Tony Xing):Microsoft资深产品经理.负责微软应用与服 ...

  7. 数据在千万级别上进行全文检索有哪些技术?强大的大数据全文索引解决方案-ClouderaSearch

    数据在千万级别上进行全文检索有哪些技术?强大的大数据全文索引解决方案-ClouderaSearch1.lucene (solr, elasticsearch 都是基于它) 2.sphinx3.elas ...

  8. 大数据最后一公里——2021年五大开源数据可视化BI方案对比

    个人非常喜欢这种说法,最后一公里不是说目标全部达成,而是把整个路程从头到尾走了一遍. 大数据在经过前几年的野蛮生长以后,开始与数据中台的概念一同向着更实际的方向落地.有人问,数据可视化是不是等同于数据 ...

  9. HDFS数据迁移解决方案之DistCp工具的巧妙使用

    前言 在当今每日信息量巨大的社会中,源源不断的数据需要被安全的存储.等到数据的规模越来越大的时候,也许瓶颈就来了,没有存储空间了.这时候怎么办,你也许会说,加机器解决,显然这是一个很简单直接但是又显得 ...

随机推荐

  1. 漏洞复现:MS12-020 远程桌面协议RDP远程代码执行漏洞

    漏洞复现:MS12-020 远程桌面协议RDP远程代码执行漏洞 攻击机:Kali2019 靶机:Win7 64位 解题步骤: 1.打开Kali2019和Win7 64位 ,确定IP地址是多少 2.确定 ...

  2. 团队Beta演示

    组长博客 本组(组名)所有成员 短学号 姓名 2236 王耀鑫(组长) 2210 陈超颖 2209 陈湘怡 2228 许培荣 2204 滕佳 2205 何佳琳 2237 沈梓耀 2233 陈志荣 22 ...

  3. 史上最全Redis面试题(2020最新版)

    一个执着于技术的公众号 导读:2020 年最新版 Redis面试题,两万字干货,为方便读者阅读,已整理为PDF文档,后台回复『redis』即可领取.希望对大家有帮助! 概述 1. 什么是Redis? ...

  4. epoll 函数解析

    本文参考社长的 TinyWebServer 庖丁解牛 epoll 常用API epoll_create 函数 #include <sys/epoll.h> int epoll_create ...

  5. Blazor和Vue对比学习(基础1.4):事件和子传父

    Blazor和Vue的组件事件,都使用事件订阅者模式.相对于上一章的组件属性,需要多绕一个弯,无论Blazor还是Vue,都是入门的第一个难点.要突破这个难点,一是要熟悉事件订阅模式<其实不难& ...

  6. awk应用场景之过滤举例

    以/etc/passwd举例,passwd文本 [root@196 tmp]# cat /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bi ...

  7. 记一次Tomcat卡死在 Deploying web application 步骤的问题

    公司有一个历史的遗留项目是传统的MVC架构的前后不分离的项目,一开始使用JDK1.7写的,后来前一阵老板说想在这个远古项目上加点功能,顺带换换皮,于是乎一帮程序员们就用JDK1.8重新翻新了一遍项目顺 ...

  8. goose消元

    ps.改了标题 魔板 思路:按序消除变量,用当前行(i)[行i消\(x_i\)元素],消后面的每一行的i元素 最后按逆序回代值 注意若有i~n行i元素系数都为0说明没有唯一解(其余x的解跟i元素有关) ...

  9. Flask 之 高可用IP代理网站

    高可用代理IP网站 目标:提供高可用代理IP 步骤一:通过爬虫获取代理IP 步骤二:对代理IP进行检测,判断代理是否可用 步骤三:将可用的代理IP写入mongodb数据库 步骤四:创建网站,从数据库获 ...

  10. Python 空间名称与闭包函数

    空间名称与闭包函数 名称空间 名称空间 namespaces:存放名字的地方,是对栈区的划分 名称空间在栈区中分为三种,详细的划分不同的空间,不同空间可以存放相同名字的名字 内置名称空间 存放的名字: ...