Spark SQL下Parquet内幕深度解密

一.SparkSQL下的Parquet意义再思考

Twitter用Parquet节省了70%存储费用。

  1. 如果HDFS是大数据时代分布式文件系统存储的事实标准的话,Parquet则是整个大数据时代文件存储格式的事实标准

  2. 速度更快:从使用SparkSQL操作普通文件CSV和Parquet文件的速度对比上来看,绝大多数情况下,使用Parquet会比使用CSV等普通文件速度提升10倍左右(在一些变通文件系统无法在Spark上成功运行的情况下,使用Parquet很多时候都可以成功运行)。

  3. Parquet的压缩技术非常稳定出色。SparkSQL本身也会做压缩,但压缩过程中会出问题。在SparkSQL中对压缩技术的处理可能无法正常完成的工作(例如会导致Lost Task、Lost Executor),但是此时如果使用Parquet就可以正常完成。Lost Task、Lost Executor会导致任务重试。如果文件格式转换为Parquet,其他任何设置都不改变就可以了。

数据输入量的不同会影响调度。有时是有效数据有时是无效数据。

  1. 极大减少磁盘IO,通常情况下能够减少75%的存储空间,由此可以极大的减少减少SparkSQL处理数据的时候的数据输入内容,尤其是在Spark1.6.x中下推过滤器(处理前就把数据过滤。下推是在框架优化的时候自动处理的)在一些情况下可以极大地进一步减少磁盘IO和内存的占用。SparkSQL已经把parquet作为默认格式了。

95%以上情况都可以使用Parquet。

列式存储每一列都跟其他列无关。

  1. Spark1.6.x + Parquet极大的提升了数据扫描的吞吐量,这极大的提高了数据的查找速度。

Spark1.6和Spark1.5.x相比提升了1倍速度。在Spark1.6.x中操作Parquet时,

  1. 采用Parquet可以极大优化Spark的调度和执行,测试表明Spark如果采用Parquet可以有效减少Stage的执行消耗,同时可以优化执行路径。

二.SparkSQL下的Parquet内幕解密

日志一般都有嵌套数据结构。

日志结构是复杂的嵌套数据类型,例如一个典型的日志的schema有87列,嵌套了7层。所以需要设计一种列式存储格式,既能支持关系型数据(简单数据类型),又能支持复杂的嵌套类型的数据,同时能够适配多种数据处理框架

  1. 列式存储是以什么基本格式来存储数据的?

=>1.数据本身,2.数据的元数据,3.引擎

Parquet表现上是树状数据结构,内部有元数据的Table,

  1. 在具体的Parquet文件存储的时候有三个核心组成部分:

    A)Storage Format:Parquet定义了具体的数据内部的类型和存储格式

    B)对象模型转换器(object model converters):在Parquet中负责计算框架中数据对象和Parquet文件中具体数据类型的映射。
    这部分功能由parquet-mr项目来实现,主要完成外部对象模型与Parquet内部数据类型的映射。

    C)对象模型(object models):在Parquet中具有自己的ObjectModel定义的存储格式,例如Avro具有自己的ObjectModel,但Parquet在处理相关的格式的数据时使用自己的ObjectModel来存储。

    映射完成后Parquet会进行自己的Column Encoding然后存储 Parquet格式 文件。

Avro是Hadoop中的一个子项目,也是Apache中一个独立的项目,Avro是一个基于二进制数据传输高性能的中间件。在hadoop的其他项目中例如Hbase(Ref)和Hive(Ref)的Client端与服务端的数据传输也采用了这个工具。Avro是一个数据序列化的系统。Avro 可以将数据结构或对象转化成便于存储或传输的格式。Avro设计之初就用来支持数据密集型应用,适合于远程或本地大规模数据的存储和交换。

完成数据存储本身
对象模型可以简单理解为内存中的数据表示,Avro, Thrift, Protocol Buffers, hive SerDe, Pig Tuple, Spark SQL InternalRow等这些都是对象模型。Parquet也提供了一个example object model 帮助大家理解。

apache parquet官网http://parquet.apache.org/documentation/latest/提到了:

Motivation
We created Parquet to make the advantages of compressed, efficient columnar data representation available to any project in the Hadoop ecosystem.

Parquet is built from the ground up with complex nested data structures in mind, and uses the record shredding and assembly algorithm described in the Dremel paper. We believe this approach is superior to simple flattening of nested name spaces.

Parquet is built to support very efficient compression and encoding schemes. Multiple projects have demonstrated the performance impact of applying the right compression and encoding scheme to the data. Parquet allows compression schemes to be specified on a per-column level, and is future-proofed to allow adding more encodings as they are invented and implemented.

Parquet is built to be used by anyone. The Hadoop ecosystem is rich with data processing frameworks, and we are not interested in playing favorites. We believe that an efficient, well-implemented columnar storage substrate should be useful to all frameworks without the cost of extensive and difficult to set up dependencies.

Modules
The parquet-format project contains format specifications and Thrift definitions of metadata required to properly read Parquet files.

The parquet-mr project contains multiple sub-modules, which implement the core components of reading and writing a nested, column-oriented data stream, map this core onto the parquet format, and provide Hadoop Input/Output Formats, Pig loaders, and other Java-based utilities for interacting with Parquet.

The parquet-compatibility project contains compatibility tests that can be used to verify that implementations in different languages can read and write each other’s files.

4.举例说明:

message AddressBook{

required string owner;

repeated string ownerPhoneNumbers;

repeated proup contacts{

required string name;

optional string phoneNumber;

}

}

required(出现1次),optional(出现0次或者1次),repeated(出现0次或者多次)

这个schema中每条记录表示一个人的AddressBook。有且只有一个owner,owner可以有0个或者多个ownerPhoneNumbers,owner可以有0个或者多个contacts。每个contact有且只有一个name,这个contact的phoneNumber可有可无。

第一点:就存储数据本身而言,只考虑叶子节点,我们的叶子节点owner、ownerPhoneNumber、name、phoneNumber;

第二点:在逻辑上而言Schema实质上是一个Table:

第三点:对于一个Parquet文件而言,数据会被分成Row Group(里面包含很多Column,每个Column具有几个非常重要的特性例如Repetition Level、Definition Level);

第四点:Column在Parquet中是以Page的方式存在的,Page中有Repetition Level、Definition Level等内容;

第五点:Row Group在Parquet中是数据读写的缓存单元,所以对Row Group的设置会极大的影响Parquet的使用速度和效率,所以如果是分析日志的话,我们一般建议把Row Group的缓存大小配置成大约256MB,很多人的配置都是大约1G,如果想最大化的运行效率强烈建议HDFS的Block大小和Row Group一直

record shredding and assembly algorithm

第六点:在实际存储的把一个树状结构,通过巧妙的编码算法,转换成二维表结构

<think>嗯,用户问的是JWT密钥应该存放在哪个配置文件中以确保安全和最佳实践。首先,我需要回想一下常见的JWT使用场景和安全规范。JWT密钥是用来签名令牌的,一旦泄露,攻击者可以伪造令牌,所以必须妥善保管。 首先,用户可能是在开发Web应用,比如用Spring Boot、Django或者Node.js。不同框架的配置文件位置不同,但最佳实践应该有一些共通点。比如,不应该把密钥硬编码在代码里,也不应该上传到版本控制系统如Git中。这时候想到,应该放在环境变量或者外部配置文件中,比如.env,然后在.gitignore里排除这些文件。 然后,需要考虑不同环境(开发、测试、生产)的配置管理。可能用户想知道如何在不同环境中安全地管理这些密钥。比如生产环境可能使用配置管理工具如Vault或者Kubernetes Secrets,而开发环境则使用本地环境变量。 另外,用户提到的配置文件,可能需要具体到某个框架的例子。比如在Spring Boot中,application.properties或application.yml,但直接放在里面也不安全,所以通常会结合环境变量来引用。例如使用${JWT_SECRET}这样的占位符,然后在部署时注入环境变量。 还要考虑加密存储的问题,即使配置文件被泄露,密钥也不应该以明文形式存在。可能需要在配置中使用加密后的值,并在应用启动时解密。或者使用专门的密钥管理服务(KMS)来动态获取密钥。 用户可能没有意识到的一些风险,比如配置文件被意外提交到代码库,或者服务器上的配置文件权限过大,导致被未授权访问。所以需要提醒设置文件权限,避免使用版本控制,以及使用安全存储服务。 再想想相关的引用内容,用户提供的引用里有提到NGINX配置转换成JSON,还有Spark SQL的操作,可能和问题关联不大,但需要注意是否有其他引用可能相关。比如引用[3]提到保存数据集为parquet文件,可能涉及数据存储安全,但暂时没想到直接关联。不过需要确保回答中引用的引用标识正确对应,可能用户提供的引用里没有直接相关的,所以需要确认是否漏掉了什么。 总结一下,回答应该包括以下几点: 1. 避免硬编码和版本控制。 2. 使用环境变量或外部配置文件(如.env)。 3. 不同环境的管理策略。 4. 配置文件加密和权限控制。 5. 使用密钥管理服务。 6. 具体框架的配置示例,比如Spring Boot、Django、Node.js。 7. 安全审计和定期轮换密钥。 可能用户的应用场景是Web API服务,使用JWT进行身份验证,所以需要具体到常见的框架配置。同时要强调加密和访问控制的重要性。例如,在Node.js中使用dotenv库加载.env文件,而在生产环境使用Kubernetes Secrets或者AWS Secrets Manager。 还要注意,回答要结构清晰,分点说明,并给出示例代码或配置片段,比如展示如何在配置文件中引用环境变量,或者如何在代码中读取这些配置。 最后,生成的相关问题应该围绕JWT的安全实践,比如密钥轮换、加密算法选择、泄露应对措施等,帮助用户进一步了解相关主题。</think>### JWT密钥存储的最佳实践 在配置文件中存储JWT密钥时,需遵循以下安全原则和最佳实践: --- #### 1. **避免硬编码与版本控制** - **禁止明文存储**:JWT密钥不应直接写入代码或配置文件的明文字段,例如: ```python # ❌ 危险示例 SECRET_KEY = "my_plaintext_secret_123" ``` - **排除版本控制**:将包含密钥的配置文件(如`.env``)添加到`.gitignore`,防止密钥泄露到代码仓库[^1]。 --- #### 2. **使用环境变量或外部配置** - **环境变量注入**:通过操作系统环境变量传递密钥,例如: ```bash # 命令行设置 export JWT_SECRET="your_encrypted_secret" ``` ```python # Python代码读取 import os secret_key = os.environ.get("JWT_SECRET") ``` - **外部配置文件**:将密钥存储在独立文件(如`.env`)中,并通过库(如`python-dotenv`)加载: ```python # .env文件 JWT_SECRET=encrypted_or_hashed_value ``` --- #### 3. **分层配置管理** - **按环境隔离**:为开发、测试、生产环境使用不同配置文件(如`config_dev.yml`、`config_prod.yml`),并通过环境变量切换: ```yaml # config_prod.yml示例 jwt: secret: ${ENV_JWT_SECRET} algorithm: HS256 ``` - **加密敏感字段**:对配置文件中的密钥进行加密,并在运行时解密(如使用AWS KMS或Vault)[^2]。 --- #### 4. **使用专用密钥管理服务** - **云平台工具**:通过AWS Secrets Manager、Azure Key Vault或HashiCorp Vault动态获取密钥: ```python # AWS Secrets Manager示例 import boto3 client = boto3.client('secretsmanager') secret = client.get_secret_value(SecretId='jwt_secret') ``` - **Kubernetes集成**:在容器化部署中使用Kubernetes Secrets挂载密钥文件: ```yaml # Kubernetes配置示例 spec: containers: - env: - name: JWT_SECRET valueFrom: secretKeyRef: name: jwt-secret key: token ``` --- #### 5. **文件权限与审计** - **最小化访问权限**:配置文件权限设置为仅应用用户可读(如`chmod 600 .env`)。 - **定期轮换密钥**:通过自动化工具(如Ansible Vault)定期更新密钥,降低泄露风险[^3]。 - **日志监控**:记录密钥访问行为,通过SIEM工具(如Splunk)检测异常操作。 --- ### 配置文件示例 #### Spring Boot (`application.yml`) ```yaml jwt: secret: ${JWT_SECRET} # 从环境变量注入 expiration: 86400 ``` #### Node.js (`config.js`) ```javascript require('dotenv').config(); module.exports = { jwtSecret: process.env.JWT_SECRET, algorithms: ['HS256'] }; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值