Apache atlas 元数据管理治理平台使用和架构

1、前言

Apache Atlas 是托管于 Apache 旗下的一款元数据管理和治理的产品,目前在大数据领域应用颇为广泛,可以很好的帮助企业管理数据资产,并对这些资产进行分类和治理,为数据分析,数据治理提供高质量的元数据信息。

随着企业业务量的逐渐膨胀,数据日益增多,不同业务线的数据可能在多种类型的数据库中存储,最终汇集到企业的数据仓库中进行整合分析,这个时候如果想要追踪数据来源,理清数据之间的关系将会是一件异常头疼的事情,倘若某个环节出了问题,追溯的成本将是巨大的,于是 Atlas 在这种背景下应运而生了,通过它,我们可以非常方便的管理元数据,并且可以追溯表级别,列级别之间的关系(血缘关系),为企业的数据资产提供强有力的支撑和保障。Atlas 支持从 HBase 、Hive、Sqoop、Storm、Kafka 中提取和管理元数据,同时也可以通过 Rest Api 的方式自行定义元数据模型,生成元数据。

本文我们着重介绍一下 Atlas 的相关概念,帮助大家更好的理解 Atlas,同时详细讲解如何通过 Rest Api 的方式自定义数据模型,生成血缘关系,以便开发自己的个性化需求。

2、Atlas 原理及相关概念

元数据

元数据其实就是描述数据的数据,比如表,字段,视图等,每个业务系统可能都会自己定义表,字段,视图,这些数据从哪来到往哪去,数据之间是否存在关联,和其他系统的数据是否存在重复和矛盾字段,这些就是元数据管理要解决的问题,也是 Atlas 要解决的问题。

运行原理

Atlas 的原理其实并不难理解,主要是通过内部提供的脚本读取数仓中的数据库结构,生成数据模型,存储到 Atlas的 Hbase 中,同时通过 hook 的方式监听数仓中的数据变化,分析执行的 sql 语句,从而生成表与表,列与列的血缘关系依赖,在前台展示给用户查看。

数仓支持

Atlas 对 Hive 支持最好,我们都知道,Hive 是依赖于 Hadoop 的,数据存储在 HDFS 中,Atlas 有专门的 shell 脚本可以直接运行读取 Hive 的表结构等元数据信息同步到 Atlas 的存储库中,自动生成元数据模型,同时 Atlas 提供的 HiveHook 可以监听 Hive 的数据变化,根据 Hive 执行的 sql 推断出数据与数据之间的关系,生成血缘关系图,如果我们想要分析其他数据存储介质的元数据和血缘关系,Atlas 的支持并不是很理想。但通常情况下,我们会定时把业务库如 mysql,oracle 中的数据定时同步到数仓中整合分析,而数仓我们一般都会采用 Hadoop 的生态体系,所以这一点并不是问题。

架构图解

以下是 Atlas 的架构图解,可以看出,Atlas 所依赖的生态体系是异常庞大的,这也直接导致了它部署起来十分繁琐,本文不再讲解 Atlas 的部署,网上相关的教程有很多,感兴趣的朋友可以自己搜索尝试。
在这里插入图片描述

核心组件概念

Atlas 中主要有以下核心组件,这些需要我们着重了解,接下来我们通过 Rest Api 自定义建模其实就是对以下组件的增删查改操作。

1. Type

元数据类型定义,这里可以是数据库,表,列等,还可以细分 mysql 表( mysql_table ),oracle 表( oracle_table )等,atlas自带了很多类型,如 DataSet,Process 等,一般情况下,数据相关的类型在定义类型的时候都会继承 DataSet,而流程相关的类型则会继承 Process,便于生成血缘关系。我们也可以通过调用 api 自定义类型。这是一切的起点,定义完类型之后,才能生成不同类型的元数据实体,生成血缘关系,我个人更喜欢把元数据类型称之为建模。

2. Classification

分类,通俗点就是给元数据打标签,分类是可以传递的,比如 A 视图是基于 A 表生成的,那么如果 A 表打上了 a 这个标签,A 视图也会自动打上 a 标签,这样的好处就是便于数据的追踪。

3. Entity

实体,表示具体的元数据,Atlas 管理的对象就是各种 Type 的 Entity。

4. Lineage

数据血缘,表示数据之间的传递关系,通过 Lineage 我们可以清晰的知道数据的从何而来又流向何处,中间经历了哪些操作,这样一旦数据出现问题,可以迅速追溯,定位是哪个环节出现错误。

3、Altas安装

(参考链接,请结合实际情况使用)
1、https://blog.csdn.net/hshudoudou/article/details/123899947
2、https://blog.csdn.net/javaThanksgiving/article/details/130505251

4、Altas使用

Altas 成功部署之后,使用还是很简单的,这是登录界面,用户名密码默认是 admin,admin:
在这里插入图片描述进入主页,点击右上角 switch to new ,使用新版界面,更直观:
在这里插入图片描述
在这里插入图片描述
页面左侧便是 Atlas 的类型树,点击树节点的某个类型,可以查看下面的实体,这里我们点击 mysql_table:
在这里插入图片描述可以看到下面有很多表,这些都是我之前自己利用 Rest Api 上传定义的。

下面我们来讲解一下如何通过 Rest Api 的方式自定义类型,生成实体,创建血缘关系。

5、Atlas Rest Api 详解及示例

我们点击主页上方的 Help-》API Documentation,便可以查看 Atlas 所有的开放接口:
在这里插入图片描述在这里插入图片描述
有一点我们需要注意,Atlas 的接口在使用的时候是需要鉴权的,所以我们构建 http 请求的时候需要带上用户名和密码认证信息,本次示例中我们使用 atlas-client-v2 开源组件来进行 Atlas 的 api 调用。

本次示例我们定义一个 my_db 类型,my_table 类型,并且让 my_db 一对多 my_table,然后创建 test_db 实体到 my_db 下,创建 test_table_source 和 test_table_target 实体到 my_table 下,并且定义 test_table_target 的数据来自 test_table_source,生成两个实体的血缘关系依赖。

自定义 my_db 和 my_table 类型

我们对 my_db 和 my_table 类型进行定义,在 Atlas 的Rest Api 中,允许一个请求定义多种类型,在这里我们先构建 json 请求体,然后再通过编码方式实现,二者对比,更容易理解,json 请求体如下(关键地方有注释):

{"enumDefs": [],"structDefs": [],"classificationDefs": [],//类型定义"entityDefs": [{"name": "my_db",//数据类型的定义,约定俗成,继承Atlas自带的DataSet"superTypes": ["DataSet"],//服务类型(便于在界面分组显示类型)"serviceType": "my_type","typeVersion": "1.1","attributeDefs": []},{"name": "my_table","superTypes": ["DataSet"],"serviceType": "my_type","typeVersion": "1.1","attributeDefs": []}],//定义类型之间的关系"relationshipDefs": [{"name": "my_table_db","serviceType": "my_type","typeVersion": "1.1",//关系类型:ASSOCIATION:关联关系,没有容器存在,1对1 //AGGREGATION:容器关系,1对多,而且彼此可以相互独立存在 //COMPOSITION:容器关系,1对多,但是容器中的实例不能脱离容器存在"relationshipCategory": "AGGREGATION",//节点一"endDef1": {"type": "my_table",//表中关联的属性名称,对应下面的 my_db"name": "db",//代表这头是不是容器"isContainer": false,//cardinality: 三种类型SINGLE, LIST, SET"cardinality": "SINGLE"},// 节点2"endDef2": {"type": "my_db","name": "tables","isContainer": true,// db 包含 table,table不能重复,所以类型设置为 SET"cardinality": "SET"},// 推导tag NONE 不推导"propagateTags": "NONE"}]
}

编码实现:

引入 pom 依赖,注意,如果要集成到自己的业务系统之中,业务系统如果使用了其他的日志框架,需要去除 slf4j-log4j12 依赖,否则日志框架会起冲突,导致启动失败,另外 atlas-client-common 中依赖了 commons-configuration 1.10,如果业务系统中有低版本依赖,记得排除,不然二者会冲突,导致 client 初始化失败。

<dependencies><!-- Apache Atlas --><dependency><groupId>org.apache.atlas</groupId><artifactId>atlas-client-common</artifactId><version>2.1.0</version><exclusions><exclusion><artifactId>slf4j-log4j12</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions></dependency><!-- Apache Atlas Client  Version2 --><dependency><groupId>org.apache.atlas</groupId><artifactId>atlas-client-v2</artifactId><version>2.1.0</version><exclusions><exclusion><artifactId>slf4j-log4j12</artifactId><groupId>org.slf4j</groupId></exclusion><exclusion><artifactId>log4j</artifactId><groupId>log4j</groupId></exclusion></exclusions></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency></dependencies>

引入 atlas-application.properties(必须得有,否则会初始化失败):

atlas.rest.address=http://127.0.0.1:21000

代码实现如下(对照json非常容易理解):

		AtlasClientV2 atlasClientV2 = new AtlasClientV2(new String[]{"http://127.0.0.1:21000"}, new String[]{"admin", "admin"});//父类集合Set<String> superTypes = new HashSet<>();superTypes.add(AtlasBaseTypeDef.ATLAS_TYPE_DATASET);//定义myTypeAtlasTypesDef myType = new AtlasTypesDef();//定义myDbAtlasEntityDef myDb = new AtlasEntityDef();myDb.setName("my_db");myDb.setServiceType("my_type");myDb.setSuperTypes(superTypes);myDb.setTypeVersion("1.1");//定义mytableAtlasEntityDef myTable = new AtlasEntityDef();myTable.setName("my_table");myTable.setServiceType("my_type");myTable.setSuperTypes(superTypes);myTable.setTypeVersion("1.1");//定义relationshipDefAtlasRelationshipDef relationshipDef = new AtlasRelationshipDef();relationshipDef.setName("my_table_db");relationshipDef.setServiceType("my_type");relationshipDef.setTypeVersion("1.1");relationshipDef.setRelationshipCategory(AtlasRelationshipDef.RelationshipCategory.AGGREGATION);relationshipDef.setPropagateTags(AtlasRelationshipDef.PropagateTags.NONE);//定义endDef1AtlasRelationshipEndDef endDef1 = new AtlasRelationshipEndDef();endDef1.setType("my_table");endDef1.setName("db");endDef1.setIsContainer(false);endDef1.setCardinality(AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE);relationshipDef.setEndDef1(endDef1);//定义endDef2AtlasRelationshipEndDef endDef2 = new AtlasRelationshipEndDef();endDef2.setType("my_db");endDef2.setName("tables");endDef2.setIsContainer(true);endDef2.setCardinality(AtlasStructDef.AtlasAttributeDef.Cardinality.SET);relationshipDef.setEndDef2(endDef2);//entityDefsList<AtlasEntityDef> entityDefs = new ArrayList<>(2);entityDefs.add(myDb);entityDefs.add(myTable);myType.setEntityDefs(entityDefs);//relationshipDefsList<AtlasRelationshipDef> relationshipDefs = new ArrayList<>(1);relationshipDefs.add(relationshipDef);myType.setRelationshipDefs(relationshipDefs);//查询是否已有my_db类型,没有则创建SearchFilter filter = new SearchFilter();filter.setParam("name", "my_db");AtlasTypesDef allTypeDefs = atlasClientV2.getAllTypeDefs(filter);if (allTypeDefs.getEntityDefs().isEmpty()) {//请求 rest apiatlasClientV2.createAtlasTypeDefs(myType);}

执行以上代码,执行完毕后,前往 Atlas 主页查看,类型已成功创建:
在这里插入图片描述查看类型模型图:
在这里插入图片描述类型创建完毕,接下来我们进行实体的创建。

创建实体 test_db,test_table_source 和 test_table_target

json 如下:

//my_db 实体
{"typeName": "my_db","attributes": {"qualifiedName": "test_db","name": "test_db","description": "测试创建db"}
}
//test_table_source 实体
{"typeName": "my_table","attributes": {"qualifiedName": "test_table_source","name": "test_table_source","description": "测试创建test_table_source"},"relationshipAttributes": {"db": {"typeName": "my_db",//my_db的guid(创建完my_db后会返回)"guid": "xxxx"}}
}
//test_table_target 实体
{"typeName": "my_table","attributes": {"qualifiedName": "test_table_target","name": "test_table_target","description": "测试创建test_table_target"},"relationshipAttributes": {"db": {"typeName": "my_db","guid": "xxx"}}
}

代码实现如下:

		//创建实体 test_dbAtlasEntity testDb = new AtlasEntity();testDb.setTypeName("my_db");Map<String, Object> attributes = new HashMap<>();attributes.put("qualifiedName", "test_db");attributes.put("name", "test_db");attributes.put("description", "测试创建db");testDb.setAttributes(attributes);Map<String, String> queryAttributes = new HashMap<>();queryAttributes.put("qualifiedName", "test_db");String myDbGuid = null;try {//查询不到会报错AtlasEntity.AtlasEntityWithExtInfo extInfo = atlasClientV2.getEntityByAttribute("my_db", queryAttributes);myDbGuid = extInfo.getEntity().getGuid();} catch (AtlasServiceException e) {if (ClientResponse.Status.NOT_FOUND.equals(e.getStatus())) {AtlasEntity.AtlasEntityWithExtInfo extInfo = new AtlasEntity.AtlasEntityWithExtInfo(testDb);//请求EntityMutationResponse response = atlasClientV2.createEntity(extInfo);myDbGuid = response.getGuidAssignments().values().toArray(new String[]{})[0];}}//创建与db的关系Map<String, Object> relationShipAttr = new HashMap<>();Map<String, String> dbMap = new HashMap<>();dbMap.put("guid", myDbGuid);dbMap.put("typeName", "my_db");relationShipAttr.put("db", dbMap);//创建实体 test_table_sourceAtlasEntity testTableSource = new AtlasEntity();testTableSource.setTypeName("my_table");attributes.put("qualifiedName", "test_table_source");attributes.put("name", "test_table_source");attributes.put("description", "测试创建test_table_source");testTableSource.setAttributes(attributes);testTableSource.setRelationshipAttributes(relationShipAttr);queryAttributes.put("qualifiedName", "test_table_source");try {//atlasClientV2.updateEntity(new AtlasEntity.AtlasEntityWithExtInfo(testTableSource));AtlasEntity.AtlasEntityWithExtInfo extInfo = atlasClientV2.getEntityByAttribute("my_table", queryAttributes);testTableSource = extInfo.getEntity();} catch (AtlasServiceException e) {if (ClientResponse.Status.NOT_FOUND.equals(e.getStatus())) {AtlasEntity.AtlasEntityWithExtInfo extInfo = new AtlasEntity.AtlasEntityWithExtInfo(testTableSource);//请求EntityMutationResponse response = atlasClientV2.createEntity(extInfo);testTableSource.setGuid(response.getGuidAssignments().values().toArray(new String[]{})[0]);}}//创建实体 test_table_targetAtlasEntity testTableTarget = new AtlasEntity();testTableTarget.setTypeName("my_table");attributes.put("qualifiedName", "test_table_target");attributes.put("name", "test_table_target");attributes.put("description", "测试创建test_table_target");testTableTarget.setAttributes(attributes);testTableTarget.setRelationshipAttributes(relationShipAttr);queryAttributes.put("qualifiedName", "test_table_target");try {//atlasClientV2.updateEntity(new AtlasEntity.AtlasEntityWithExtInfo(testTableTarget));AtlasEntity.AtlasEntityWithExtInfo extInfo = atlasClientV2.getEntityByAttribute("my_table", queryAttributes);testTableTarget = extInfo.getEntity();} catch (AtlasServiceException e) {if (ClientResponse.Status.NOT_FOUND.equals(e.getStatus())) {AtlasEntity.AtlasEntityWithExtInfo extInfo = new AtlasEntity.AtlasEntityWithExtInfo(testTableTarget);//请求EntityMutationResponse response = atlasClientV2.createEntity(extInfo);testTableTarget.setGuid(response.getGuidAssignments().values().toArray(new String[]{})[0]);}}

执行代码完毕后,查看类的树形图,发现已经产生了实体:

在这里插入图片描述我们点击右侧的 test_db 实体,可以看到它的基本信息,也可以看到它的 relationship 信息,包含了 test_table_source 和 test_table_target 两个实体:
在这里插入图片描述查看 relationship 信息,包含 test_table_source 和 test_table_target:

在这里插入图片描述创建 test_table_source 和 test_table_target 的血缘关系依赖

前面我们提到,定义 test_table_target 的数据来自 test_table_source,血缘关系依赖在 Atlas 中其实也是作为实体 Entity 存在,只不过继承的父类是 Process,这样可以定义 inputs 和 outputs 属性,构建血缘关系,json 如下:

{"typeName": "Process","attributes": {"name": "test_process","qualifiedName": "test_process","description": "test_table_target 的数据来自 test_table_source","inputs": [{"typeName": "my_table",//test_table_source的guid,创建实体从返回的信息中获取"guid": "xxx"}],"outputs": [{"typeName": "my_table",test_table_target的guid,创建实体从返回的信息中获取"guid": "xxx"}]}
}

代码实现如下:

		AtlasEntity lineage = new AtlasEntity();//设置为process类型构建血缘lineage.setTypeName(AtlasBaseTypeDef.ATLAS_TYPE_PROCESS);attributes.put("qualifiedName", "test_process");attributes.put("name", "test_process");attributes.put("description", "test_table_target 的数据来自 test_table_source");attributes.put("inputs", getLineAgeInfo(testTableSource));attributes.put("outputs", getLineAgeInfo(testTableTarget));lineage.setAttributes(attributes);queryAttributes.put("qualifiedName", "test_process");System.out.println(SingletonObject.OBJECT_MAPPER.writeValueAsString(lineage));try {//查询是否存在atlasClientV2.getEntityByAttribute(AtlasBaseTypeDef.ATLAS_TYPE_PROCESS, queryAttributes);} catch (AtlasServiceException e)  {if (ClientResponse.Status.NOT_FOUND.equals(e.getStatus())) {//创建AtlasEntity.AtlasEntityWithExtInfo extInfo = new AtlasEntity.AtlasEntityWithExtInfo(lineage);atlasClientV2.createEntity(extInfo);}}//构建inputs和outputsprivate static List<Map<String, String>> getLineAgeInfo(AtlasEntity entity) {List<Map<String, String>> list = new ArrayList<>();Map<String, String> map = new HashMap<>();map.put("guid", entity.getGuid());map.put("typeName", entity.getTypeName());list.add(map);return list;}

执行以上代码,然后打开主页,点击 my_table 中的 test_table_source,查看 lineage 标签,血缘关系已成功构建:
在这里插入图片描述至此,我们通过 Atlas Rest Api 的方式自行建模,创建实体,构建血缘关系就完成了。

元数据管理,数据治理,在当下仍然是一个热门的话题,同时,它也可以帮助我们更好的支撑企业的数据资产,更好的分析数据,为企业的发展决策提供有效的帮助。

引用链接:
1、https://blog.csdn.net/hshudoudou/article/details/123899947
2、https://blog.csdn.net/javaThanksgiving/article/details/130505251
3、原文 https://blog.csdn.net/m0_37719874/article/details/124245209

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/103770.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业电子招投标采购系统——功能模块功能描述+数字化采购管理 采购招投标

功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查看所…

OJ第三篇

文章目录 随机链表的复制 随机链表的复制 链接:随机链表的复制 这个题简单而言就是它给一个链表&#xff0c;每个结点包含两个指针&#xff0c;分别指向下一个和一个随机的结点&#xff08;也有可能指向空&#xff09;&#xff0c;你要做的就是复制这个链表&#xff0c;使你创…

深入了解基数排序:原理、性能分析与 Java 实现

基数排序&#xff08;Radix Sort&#xff09;是一种非比较性排序算法&#xff0c;它根据元素的每个位上的值来进行排序。基数排序适用于整数或字符串等数据类型的排序。本文将详细介绍基数排序的原理、性能分析及java实现。 基数排序原理 基数排序的基本原理是按照低位先排序&…

基于PLC的机械手控制系统设计

目录 摘 要......................................................................................................................... 1 第一章 绪论.............................................................................................................…

【Acwing187】导弹防御系统(LIS+剪枝+贪心+dfs+迭代加深)

题目描述 看本文需要准备的知识 1.最长上升子序列&#xff08;lis&#xff09;的算法思想和算法模板 2.acwing1010拦截导弹&#xff08;lis贪心&#xff09;题解 本题题解&#xff0c;需要知道这种贪心算法 3.简单了解dfs暴力搜索、剪枝、搜索树等概念 思路讲解 dfs求最…

TCP/IP(七)TCP的连接管理(四)全连接

一 全连接队列 nginx listen 参数backlog的意义 nginx配置文件中listen后面的backlog配置 ① TCP全连接队列概念 全连接队列: 也称 accept 队列 ② 查看应用程序的 TCP 全连接队列大小 实验1&#xff1a; ss 命令查看 LISTEN状态下 Recv-Q/Send-Q 含义附加&#xff1a;…

clone()方法使用时遇到的问题解决方法(JAVA)

我们平时在自定义类型中使用这个方法时会连续遇到 4 个问题。 基础代码如下&#xff1a; class A {int[] a {1,2,3}; }public class Test {public static void main(String[] args) {} } 第一个&#xff1a; 当我们直接调用时报错原因是Object类中的clone方法是被protecte…

Umi + React + Ant Design Pro + TS 项目搭建

新建项目目录 mkdir 【项目名称】在对应目录 D:\react\demo 中&#xff0c;安装 Umi 脚手架&#xff1a; yarn create umi接下来&#xff0c;安装将要用到的相关依赖 umijs/plugins&#xff1a; npm i umijs/plugins -Dumijs/plugins 是 Umi 的官方插件集&#xff0c;包含了…

排序算法——冒泡排序

一、介绍&#xff1a; 冒泡排序原理就是从第一个元素开始&#xff0c;比较其后边的一个元素的大小&#xff0c;按照排序方式进行交换位置&#xff0c;直到将所有元素的顺序排列好为止。演示如下&#xff1a; 视频演示&#xff1a; 冒泡排序演示_网络游戏热门视频 (bilibili.co…

【Spring Boot】RabbitMQ消息队列 — RabbitMQ入门

💠一名热衷于分享知识的程序员 💠乐于在CSDN上与广大开发者交流学习。 💠希望通过每一次学习,让更多读者了解我 💠也希望能结识更多志同道合的朋友。 💠将继续努力,不断提升自己的专业技能,创造更多价值。🌿欢迎来到@"衍生星球"的CSDN博文🌿 🍁本…

GEO生信数据挖掘(七)差异基因分析

上节&#xff0c;我们使用结核病基因数据&#xff0c;做了一个数据预处理的实操案例。例子中结核类型&#xff0c;包括结核&#xff0c;潜隐进展&#xff0c;对照和潜隐&#xff0c;四个类别。本节延续上个数据&#xff0c;进行了差异分析。 差异分析 计算差异指标step12 加载…

蓝桥杯 题库 简单 每日十题 day13

01 乘积尾零 题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将 所填结果输出即可。如下的10行数据&#xff0c;每行有10个整数&#xff0c;请你求出它们的乘积的末尾有多少个零&#xff1f; 5650 4542 3554 473 946 4114 3871 9073 90 …

Flink之DataStream API开发Flink程序过程与Flink常见数据类型

开发Flink程序过程与Flink常见数据类型 DataStream APIFlink三层APIDataStream API概述 开发Flink程序过程添加依赖创建执行环境执行模式创建Data Source应用转换算子创建Data Sink触发程序执行示例 Flink常见数据类型基本数据类型字符串类型时间和日期类型数组类型元组类型列表…

1.1 向量与线性组合

一、向量的基础知识 两个独立的数字 v 1 v_1 v1​ 和 v 2 v_2 v2​&#xff0c;将它们配对可以产生一个二维向量 v \boldsymbol{v} v&#xff1a; 列向量 v v [ v 1 v 2 ] v 1 v 的第一个分量 v 2 v 的第二个分量 \textbf{列向量}\,\boldsymbol v\kern 10pt\boldsymbol …

GPIO子系统(三)

1&#xff0c;简述 GPIO 资源是相对来说较为简单&#xff0c;而且比较通用&#xff08;比如 LED 灯&#xff09;&#xff0c;而 Linux 的 GPIO 驱动属于 Linux Driver 中较为容易上手的部分&#xff0c;但是简单归简单&#xff0c;在 Linux 系统中&#xff0c;要使用 GPIO 资源…

高级网络调试技巧:使用Charles Proxy捕获和修改HTTP/HTTPS请求

今天我将与大家分享一种强大的网络调试技巧&#xff0c;那就是使用Charles Proxy来捕获和修改HTTP/HTTPS请求。如果您是一位开发人员或者网络调试爱好者&#xff0c;那么这个工具肯定对您有着很大的帮助。接下来&#xff0c;让我们一起来学习如何使用Charles Proxy进行高级网络…

区块链加密虚拟货币交易平台安全解决方案

区块链机密货币交易锁遭入侵&#xff0c;安全存在隐患。使用泰雷兹Protect server HSM加密机&#xff0c;多方位保护您的数据&#xff0c;并通过集中化管理&#xff0c;安全的存储密钥。 引文部分&#xff1a; 损失7000万美元!黑客入侵香港区块链加密货币交易所 2023年9月&…

计算机毕业设计选什么题目好?springboot 健身房管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

github创建个人网页登录后404无法显示的问题

1.首先必须要有内容&#xff0c;默认是会找index.html文件&#xff0c;找不到该文件会找readme.md文件&#xff0c;也就是说最简单的方法是&#xff0c;创建了与用户名同名的repository后username.github.io后&#xff0c;添加一个readme.md文件&#xff0c;得在readme里打点字…