华为云用户手册

  • 步骤:3:检查网络 检查源Redis、目标Redis、迁移任务资源所在VPC是否在同一个VPC内。 如果是,则执行步骤4:创建在线迁移任务;如果不是,执行2。 检查源Redis的VPC、目标Redis的VPC、迁移任务资源所在VPC的网络是否打通,确保迁移任务的虚拟机资源能访问源Redis和目标Redis。 如果已打通,则执行步骤4:创建在线迁移任务;如果没打通,则执行3。 执行相应操作,打通网络。 当源Redis和目标Redis属于华为云同一Region,请参考VPC对等连接说明,查看和创建对等连接,打通网络。 当源Redis和目标Redis属于华为云不同Region,请参考云连接,查看和创建云连接,打通网络。 当源Redis和目标Redis属于不同的云厂商,请参考云专线打通网络。
  • 场景描述 在满足源Redis和目标Redis的网络相通、源Redis已放通SYNC和PSYNC命令这两个前提下,使用在线迁移的方式,将源Redis中的数据全量迁移或增量迁移到目标Redis中。 如果源Redis禁用了SYNC和PSYNC命令,请务必放通后再执行在线迁移,否则迁移失败,选择华为云Redis实例进行在线迁移时,会自动放开SYNC命令。 在线迁移不支持公网方式直接迁移。 进行在线迁移时,建议将源端实例的参数repl-timeout配置为300秒,client-output-buffer-limit配置为实例最大内存的20%。 在线迁移过程中,在源端执行FLUSHDB、FLUSHALL命令不会同步到目标端。
  • 前提条件 在迁移之前,请先阅读迁移方案概览,选择正确的迁移方案,了解当前DCS支持的在线迁移能力,选择适当的目标实例。 如果是单机/主备/读写分离实例迁移到Proxy集群实例,Proxy集群默认不开启多DB,仅有一个DB0,请先确保单机/主备实例DB0以外的DB是否有数据,如果有,请先参考开启多DB操作开启Proxy集群多DB设置。 如果是单机/主备/读写分离实例迁移到Cluster集群实例,Cluster集群不支持多DB,仅有一个DB0,请先确保单机/主备实例DB0以外的DB是否有数据,如果有,请将数据转存到DB0,否则会出现迁移失败,将数据转存到DB0的操作请参考使用Rump在线迁移。
  • 返回值 正常 200 异常 返回值 说明 400 Bad Request 服务器未能处理请求。 401 Unauthorized 被请求的页面需要用户名和密码。 403 Forbidden 对被请求的页面访问禁止。 404 Not Found 服务器无法找到被请求的页面。 405 Method Not Allowed 请求中指定的方法不被允许。 406 Not Acceptable 服务器生成的响应无法被客户端所接受。 407 Proxy Authentication Required 用户必须首先使用代理服务器进行验证,这样请求才会被处理。 408 Request Timeout 请求超出了服务器的等待时间。 409 Conflict 由于冲突,请求无法被完成。 500 Internal Server Error 请求未完成。服务异常。 501 Not Implemented 请求未完成。服务器不支持所请求的功能。 502 Bad Gateway 请求未完成。服务器从上游服务器收到一个无效的响应。 503 Service Unavailable 请求未完成。系统暂时异常。 504 Gateway Timeout 网关超时。
  • 响应示例 { "scaling_configuration": { "tenant": "ce061903a53545dcaddb300093b477d2", "scaling_configuration_id": "6afe46f9-7d3d-4046-8748-3b2a1085ad86", "scaling_configuration_name": " config_name_1", "instance_config": { "disk": [ { "size": 40, "volume_type": "SATA", "disk_type": "SYS" }, { "size": 100, "volume_type": "SATA", "disk_type": "DATA" } ], "adminPass": "***", "personality": null, "instance_name": null, "instance_id": null, "flavorRef": "103", "imageRef": "37ca2b35-6fc7-47ab-93c7-900324809c5c", "key_name": "keypair01", "key_fingerprint" : "SHA256:qlvdUkYgSjKUxcr2uJgJJRMCKMLkJO5BPLooBcgsF8k", "public_ip": null, "user_data": null, "metadata": {}, "security_groups": [{ "id": "6c22a6c0-b5d2-4a84-ac56-51090dcc33be" }], "multi_flavor_priority_policy": "PICK_FIRST" }, "create_time": "2015-07-23T01:04:07Z" } }
  • 响应消息 响应参数 表2 响应参数 参数 参数类型 描述 scaling_configuration scaling_configurations object 伸缩配置详情 表3 scaling_configurations字段数据结构说明 参数 参数类型 描述 scaling_configuration_id String 伸缩配置ID,全局唯一。 tenant String 租户ID。 scaling_configuration_name String 伸缩配置名称。 支持模糊匹配。 instance_config instance_config object 实例配置信息。 create_time String 创建伸缩配置时间,遵循UTC时间。 scaling_group_id String 绑定该伸缩配置的伸缩组ID。 表4 instance_config字段数据结构说明 参数 参数类型 描述 flavorRef String 云服务器的规格ID。 imageRef String 镜像ID,同image_id。 disk Array of disk objects 磁盘组信息。 key_name String 登录云服务器的SSH密钥名称。 key_fingerprint String 登录云服务器的SSH密钥指纹。 instance_name String 该参数为预留字段。 说明: 使用已有云服务器规格为模板创建的伸缩配置,查询伸缩配置和列表接口时instance_name为空 instance_id String 该参数为预留字段。 adminPass String 该参数为预留字段。 personality Array of personality objects 注入文件信息。 public_ip public_ip object 云服务器的弹性IP信息。 user_data String cloud-init用户数据,base64格式编码。 metadata metadata object 创建云服务器元数据,详情见表11。 security_groups Array of security_groups objects 安全组信息。 server_group_id String 云服务器组ID。 tenancy String 在专属主机上创建弹性云服务器。 dedicated_host_id String 专属主机的ID。 market_type String 云服务器的计费模式,可以选择竞价计费或按需计费。 multi_flavor_priority_policy String 使用伸缩配置创建云主机的时候,多规格使用的优先级策略。 。 表5 disk字段数据结构说明 参数 参数类型 描述 size Integer 磁盘大小,容量单位为GB。 volume_type String 磁盘类型。 disk_type String 系统盘还是数据盘,DATA表示为数据盘,SYS表示为系统盘。 dedicated_storage_id String 磁盘所属的专属存储ID。 data_disk_image_id String 导入数据盘的数据盘镜像ID。 snapshot_id String 磁盘备份的快照ID。 metadata metadata object 创建磁盘的元数据,详情见表6。 iops Integer 云硬盘的iops。当“volume_type”设置为GPSSD2、ESSD2类型的云硬盘时,该参数可以设置。 说明: 了解GPSSD2、ESSD2类型云硬盘的iops,请参见磁盘类型及性能介绍。 仅支持按需计费。 throughput Integer 云硬盘的吞吐量,单位是MiB/s。当“volume_type”设置为GPSSD2类型的云硬盘时,该参数可以设置。 说明: 了解GPSSD2类型云硬盘的吞吐量大小范围,请参见磁盘类型及性能介绍。 仅支持按需计费。 表6 personality字段数据结构说明 参数 参数类型 描述 path String 注入文件路径信息。 content String 注入文件内容,base64格式编码。 表7 public_ip字段数据结构说明 参数 参数类型 描述 eip eip object 云服务器自动分配弹性IP时,创建弹性IP的配置参数。 表8 eip字段数据结构说明 参数 参数类型 描述 ip_type String IP地址类型 bandwidth bandwidth object IP地址带宽参数 表9 bandwidth字段数据结构说明 参数 参数类型 描述 size Integer 带宽(Mbit/s)。 share_type String 带宽的共享类型。 共享类型枚举: PER:独享型。 WHOLE:共享型。 charging_mode String 带宽的计费类型。 bandwidth:按带宽计费。 traffic:按流量计费。 id String 带宽ID,创建WHOLE类型带宽的弹性IP时指定的共享带宽。 表10 metadata字段数据结构说明 参数 参数类型 描述 admin_pass String Windows弹性云服务器Administrator用户的密码。 表11 security_groups字段数据结构说明 参数 参数类型 描述 id String 安全组ID
  • URI GET /autoscaling-api/v1/{project_id}/scaling_configuration/{scaling_configuration_id} 表1 参数说明 参数 是否必选 参数类型 描述 project_id 是 String 项目ID。 scaling_configuration_id 是 String 伸缩配置ID,该ID对应全局唯一配置。可参考查询弹性伸缩配置详情获取。
  • 响应示例 { "limit": 20, "total_number": 2, "start_number": 0, "scaling_configurations": [ { "tenant": "ce061903a53545dcaddb300093b477d2", "scaling_configuration_id": "6afe46f9-7d3d-4046-8748-3b2a1085ad86", "scaling_configuration_name": " config_name_1", "instance_config": { "disk": [ { "size": 40, "volume_type": "SATA", "disk_type": "SYS", "cluster_type" : "DSS", "hw:passthrough": true, "multiattach": false }, { "size": 100, "volume_type": "SATA", "disk_type": "DATA" } ], "personality": null, "instance_name": null, "instance_id": null, "flavorRef": "103", "imageRef": "37ca2b35-6fc7-47ab-93c7-900324809c5c", "key_name": "keypair01", "key_fingerprint" : "SHA256:qlvdUkYgSjKUxcr2uJgJJRMCKMLkJO5BPLooBcgsF8k", "public_ip": null, "user_data": null, "metadata": {}, "security_groups": [{ "id": "6c22a6c0-b5d2-4a84-ac56-51090dcc33be" }], "support_auto_recovery" : null, "disk_prior" : null, "cpu_options" : null, "is_auto_rename" : false, "instance_metadata" : null }, "create_time": "2015-07-23T01:04:07Z" }, { "tenant": "ce061903a53545dcaddb300093b477d2", "scaling_configuration_id": "24a8c5f3-c713-4aba-ac29-c17101009e5d", "scaling_configuration_name": "config_name_2", "instance_config": { "disk": [ { "size": 40, "volume_type": "SATA", "disk_type": "SYS" } ], "personality": null, "instance_name": null, "instance_id": null, "flavorRef": "103", "imageRef": "37ca2b35-6fc7-47ab-93c7-900324809c5c", "key_name": "keypair01", "key_fingerprint" : "SHA256:qlvdUkYgSjKUxcr2uJgJJRMCKMLkJO5BPLooBcgsF8k", "public_ip": null, "user_data": null, "metadata": {}, "security_groups": [{ "id": "6c22a6c0-b5d2-4a84-ac56-51090dcc33be" }], "multi_flavor_priority_policy": "PICK_FIRST" }, "create_time": "2015-07-22T01:08:41Z" } ] }
  • 返回值 正常 200 异常 返回值 说明 400 Bad Request 服务器未能处理请求。 401 Unauthorized 被请求的页面需要用户名和密码。 403 Forbidden 对被请求的页面访问禁止。 404 Not Found 服务器无法找到被请求的页面。 405 Method Not Allowed 请求中指定的方法不被允许。 406 Not Acceptable 服务器生成的响应无法被客户端所接受。 407 Proxy Authentication Required 用户必须首先使用代理服务器进行验证,这样请求才会被处理。 408 Request Timeout 请求超出了服务器的等待时间。 409 Conflict 由于冲突,请求无法被完成。 500 Internal Server Error 请求未完成。服务异常。 501 Not Implemented 请求未完成。服务器不支持所请求的功能。 502 Bad Gateway 请求未完成。服务器从上游服务器收到一个无效的响应。 503 Service Unavailable 请求未完成。系统暂时异常。 504 Gateway Timeout 网关超时。
  • 响应参数 表2 响应参数 参数 参数类型 描述 total_number Integer 总记录数。 start_number Integer 查询的起始行号。 limit Integer 查询记录数。 scaling_configurations Array of scaling_configurations objects 伸缩配置列表。 表3 scaling_configurations字段数据结构说明 参数 参数类型 描述 scaling_configuration_id String 伸缩配置ID,全局唯一。 tenant String 租户ID。 scaling_configuration_name String 伸缩配置名称。 支持模糊匹配。 instance_config instance_config object 实例配置信息。 create_time String 创建伸缩配置时间,遵循UTC时间。 scaling_group_id String 绑定该伸缩配置的伸缩组ID。 表4 instance_config字段数据结构说明 参数 参数类型 描述 flavorRef String 云服务器的规格ID。 imageRef String 镜像ID,同image_id。 disk Array of disk objects 磁盘组信息。 key_name String 登录云服务器的SSH密钥名称。 key_fingerprint String 登录云服务器的SSH密钥指纹。 instance_name String 该参数为预留字段。 说明: 使用已有云服务器规格为模板创建的伸缩配置,查询伸缩配置和列表接口时instance_name为空 instance_id String 该参数为预留字段。 adminPass String 该参数为预留字段。 personality Array of personality objects 注入文件信息。 public_ip public_ip object 云服务器的弹性IP信息。 user_data String cloud-init用户数据,base64格式编码。 metadata metadata object 创建云服务器元数据,详情见表11。 security_groups Array of security_groups objects 安全组信息。 server_group_id String 云服务器组ID。 tenancy String 在专属主机上创建弹性云服务器。 dedicated_host_id String 专属主机的ID。 market_type String 云服务器的计费模式,可以选择竞价计费或按需计费。 multi_flavor_priority_policy String 使用伸缩配置创建云主机的时候,多规格使用的优先级策略。 。 表5 disk字段数据结构说明 参数 参数类型 描述 size Integer 磁盘大小,容量单位为GB。 volume_type String 磁盘类型。 disk_type String 系统盘还是数据盘,DATA表示为数据盘,SYS表示为系统盘。 dedicated_storage_id String 磁盘所属的专属存储ID。 data_disk_image_id String 导入数据盘的数据盘镜像ID。 snapshot_id String 磁盘备份的快照ID。 metadata metadata object 创建磁盘的元数据,详情见表6。 iops Integer 云硬盘的iops。当“volume_type”设置为GPSSD2、ESSD2类型的云硬盘时,该参数可以设置。 说明: 了解GPSSD2、ESSD2类型云硬盘的iops,请参见磁盘类型及性能介绍。 仅支持按需计费。 throughput Integer 云硬盘的吞吐量,单位是MiB/s。当“volume_type”设置为GPSSD2类型的云硬盘时,该参数可以设置。 说明: 了解GPSSD2类型云硬盘的吞吐量大小范围,请参见磁盘类型及性能介绍。 仅支持按需计费。 表6 创建磁盘的metadata字段数据结构说明 参数 参数类型 描述 __system__encrypted String metadata中的表示加密功能的字段,0代表不加密,1代表加密。 该字段不存在时,云硬盘默认为不加密。 __system__cmkid String 用户主密钥ID,是metadata中的表示加密功能的字段,与__system__encrypted配合使用。 说明: 请参考查询密钥列表,通过HTTPS请求获取密钥ID。 表7 personality字段数据结构说明 参数 参数类型 描述 path String 注入文件路径信息。 content String 注入文件内容,base64格式编码。 表8 public_ip字段数据结构说明 参数 参数类型 描述 eip eip object 云服务器自动分配弹性IP时,创建弹性IP的配置参数。 表9 eip字段数据结构说明 参数 参数类型 描述 ip_type String IP地址类型。 bandwidth bandwidth object IP地址带宽参数。 表10 bandwidth字段数据结构说明 参数 参数类型 描述 size Integer 带宽(Mbit/s)。 share_type String 带宽的共享类型。 共享类型枚举: PER:独享型。 WHOLE:共享型。 charging_mode String 带宽的计费类型。 bandwidth:按带宽计费。 traffic:按流量计费。 id String 带宽ID,创建WHOLE类型带宽的弹性IP时指定的共享带宽。 表11 metadata字段数据结构说明 参数 参数类型 描述 admin_pass String Windows弹性云服务器Administrator用户的密码。 表12 security_groups字段数据结构说明 参数 参数类型 描述 id String 安全组ID
  • URI GET /autoscaling-api/v1/{project_id}/scaling_configuration 可以在URI后面用‘?’和‘&’添加不同的查询条件组合。支持参数说明中所有非必选参数过滤,请参考请求示例。 表1 参数说明 参数 是否必选 参数类型 描述 project_id 是 String 项目ID。 scaling_configuration_name 否 String 伸缩配置名称。 支持模糊匹配。 image_id 否 String 镜像ID,同imageRef。 start_number 否 Integer 查询的起始行号,默认为0。最小值为0。 limit 否 Integer 查询的记录条数,默认为20。取值范围为:0~100。
  • 规则 Hudi表必须执行Archive。 对于Hudi的MOR类型和COW类型的表,都需要开启Archive。 Hudi表在写入数据时会自动判断是否需要执行Archive,因为Archive的开关默认打开(hoodie.archive.automatic默认为true)。 Archive操作并不是每次写数据时都会触发,至少需要满足以下两个条件: Hudi表满足hoodie.keep.max.commits设置的阈值。如果是Flink写hudi至少提交的checkpoint要超过这个阈值;如果是Spark写hudi,写Hudi的次数要超过这个阈值。 Hudi表做过Clean,如果没有做过Clean就不会执行Archive(MRS 3.3.1-LTS及以后版本,忽略此项条件)。
  • 建议 MOR表下游采用批量读模式,采用clean的版本数为compaction版本数+1。 MOR表一定要保证Compaction Plan能够被成功执行,Compaction Plan只是记录了Hudi表中哪些Log文件要和哪些Parquet文件合并,所以最重要的地方在于保证Compaction Plan在被执行的时候它需要合并的文件都存在。而Hudi表中只有Clean操作可以清理文件,所以建议Clean的触发阈值(hoodie.cleaner.commits.retained的值)至少要大于Compaction的触发阈值(对于Flink任务来说就是compaction.delta_commits的值)。 MOR表下游采用流式计算,历史版本保留小时级。 如果MOR表的下游是流式计算,例如Flink流读,可以按照业务需要保留小时级的历史版本,这样的话近几个小时之内的增量数据可以通过log文件读出,如果保留时长过短,下游flink作业在重启或者异常中断阻塞的情况下,上游增量数据已经Clean掉了,flink需要从parquet文件读增量数据,性能会有下降;如果保留时间过长,会导致log里面的历史数据冗余存储。 具体可以按照下面的计算公式来保留2个小时的历史版本数据: 版本数设置为3600*2/版本interval时间,版本interval时间来自于flink作业的checkpoint周期,或者上游批量写入的周期。 COW表如果业务没有历史版本数据保留的特殊要求,保留版本数设置为1。 COW表的每个版本都是表的全量数据,保留几个版本就会冗余多少个版本。因此如果业务无历史数据回溯的需求,保留版本数设置为1,也就是保留当前最新版本 clean作业每天至少执行一次,可以2~4小时执行一次。 Hudi的MOR表和COW表都需要保证每天至少1次Clean,MOR表的Clean可以参考2.2.1.6小节和Compaction放在一起异步去执行。COW的Clean可以在写数据时自动判断是否执行。
  • 规则 Hudi表必须执行Clean。 对于Hudi的MOR、COW表,都需要开启Clean。 Hudi表在写入数据时会自动判断是否需要执行Clean,因为Clean的开关默认打开(hoodie.clean.automatic默认为true)。 Clean操作并不是每次写数据时都会触发,至少需要满足两个条件: Hudi表中需要有旧版本的文件。对于COW表来说,只要保证数据被更新过就一定存在旧版本的文件。对于MOR表来说,要保证数据被更新过并且做过Compaction才能有旧版本的文件。 Hudi表满足hoodie.cleaner.commits.retained设置的阈值。如果是Flink写hudi,则至少提交的checkpoint要超过这个阈值;如果是批写Hudi,则批写次数要超过这个阈值。
  • 建议 Spark批处理场景,对写入时延要求不高的场景,采用COW表。 COW表模型中,写入数据存在写放大问题,因此写入速度较慢;但COW具有非常好的读取性能力。而且批量计算对写入时延不是很敏感,因此可以采用COW表。 Hudi表的写任务要开启Hive元数据同步功能。 SparkSQL天然与Hive集成,无需考虑元数据问题。该条建议针对的是通过Spark Datasource API或者Flin写Hudi表的场景,通过这两种方式写Hudi时需要增加向Hive同步元数据的配置项;该配置的目的是将Hudi表的元数据统一托管到Hive元数据服务中,为后续的跨引擎操作数据以及数据管理提供便利。
  • 规则 Hudi表必须设置合理的主键。 Hudi表提供了数据更新和幂等写入能力,该能力要求Hudi表必须设置主键,主键设置不合理会导致数据重复。主键可以为单一主键也可以为复合主键,两种主键类型均要求主键不能有null值和空值,可以参考以下示例设置主键: SparkSQL: // 通过primaryKey指定主键,如果是复合主键需要用逗号分隔 create table hudi_table ( id1 int, id2 int, name string, price double ) using hudi options ( primaryKey = 'id1,id2', preCombineField = 'price' ); SparkDatasource: // 通过hoodie.datasource.write.recordkey.field指定主键 df.write.format("hudi"). option("hoodie.datasource.write.table.type", COPY_ON_WRITE). option("hoodie.datasource.write.precombine.field", "price"). option("hoodie.datasource.write.recordkey.field", "id1,id2"). FlinkSQL: // 通过hoodie.datasource.write.recordkey.field指定主键 create table hudi_table( id1 int, id2 int, name string, price double ) partitioned by (name) with ( 'connector' = 'hudi', 'hoodie.datasource.write.recordkey.field' = 'id1,id2', 'write.precombine.field' = 'price') Hudi表必须配置precombine字段。 在数据同步过程中不可避免会出现数据重复写入、数据乱序问题,例如:异常数据恢复、写入程序异常重启等场景。通过设置合理precombine字段值可以保证数据的准确性,老数据不会覆盖新数据,也就是幂等写入能力。该字段可用选择的类型包括:业务表中更新时间戳、数据库的提交时间戳等。precombine字段不能有null值和空值,可以参考以下示例设置precombine字段: SparkSQL: //通过preCombineField指定precombine字段 create table hudi_table ( id1 int, id2 int, name string, price double ) using hudi options ( primaryKey = 'id1,id2', preCombineField = 'price' ); SparkDatasource: //通过hoodie.datasource.write.precombine.field指定precombine字段 df.write.format("hudi"). option("hoodie.datasource.write.table.type", COPY_ON_WRITE). option("hoodie.datasource.write.precombine.field", "price"). option("hoodie.datasource.write.recordkey.field", "id1,id2"). Flink: //通过write.precombine.field指定precombine字段 create table hudi_table( id1 int, id2 int, name string, price double ) partitioned by (name) with ( 'connector' = 'hudi', 'hoodie.datasource.write.recordkey.field' = 'id1,id2', 'write.precombine.field' = 'price') 流式计算采用MOR表。 流式计算为低时延的实时计算,需要高性能的流式读写能力,在Hudi表中存在的MOR和COW两种模型中,MOR表的流式读写性能相对较好,因此在流式计算场景下采用MOR表模型。关于MOR表在读写性能的对比关系如下: 对比维度 MOR表 COW表 流式写 高 低 流式读 高 低 批量写 高 低 批量读 低 高 实时入湖,表模型采用MOR表。 实时入湖一般的性能要求都在分钟内或者分钟级,结合Hudi两种表模型的对比,因此在实时入湖场景中需要选择MOR表模型。 Hudi表名以及列名采用小写字母。 多引擎读写同一张Hudi表时,为了规避引擎之间大小写的支持不同,统一采用小写字母。
  • 建议 事实表采用日期分区表,维度表采用非分区或者大颗粒度的日期分区 是否采用分区表要根据表的总数据量、增量和使用方式来决定。从表的使用属性看事实表和维度表具有的特点: 事实表:数据总量大,增量大,数据读取多以日期做切分,读取一定时间段的数据。 维度表:总量相对小,增量小,多以更新操作为主,数据读取会是全表读取,或者按照对应业务ID过滤。 基于以上考虑,维度表采用天分区会导致文件数过多,而且是全表读取,会导致所需要的文件读取Task过多,采用大颗粒度的日期分区,例如年分区,可以有效降低分区个数和文件数量;对于增量不是很大的维度表,也可以采用非分区表。如果维度表的总数据量很大或者增量也很大,可以考虑采用某个业务ID进行分区,在大部分数据处理逻辑中针对大维度表,会有一定的业务条件进行过滤来提升处理性能,这类表要结合一定的业务场景来进行优化,无法从单纯的日期分区进行优化。事实表读取方式都会按照时间段切分,近一年、近一个月或者近一天,读取的文件数相对稳定可控,所以事实表优先考虑日期分区表。 分区采用日期字段,分区表粒度,要基于数据更新范围确定,不要过大也不要过小。 分区粒度可以采用年、月、日,分区粒度的目标是减少同时写入的文件桶数,尤其是在有数据量更新,且更新数据有一定时间范围规律的,比如:近一个月的数据更新占比最大,可以按照月份创建分区;近一天内的数据更新占比大,可以按照天进行分区。 采用Bucket索引,写入是通过主键Hash打散的,数据会均匀的写入到分区下每个桶。因为各个分区的数据量是会有波动的,分区下桶的个数设计一般会按照最大分区数据量计算,这样会出现越细粒度的分区,桶的个数会冗余越多。例如: 采用天级分区,平均的日增数据量是3GB,最多一天的日志是8GB,这个会采用Bucket桶数= 8GB/2GB = 4 来创建表;每天的更新数据占比较高,且主要分散到近一个月。这样会导致结果是,每天的数据会写入到全月的Bucket桶中,那就是4*30 = 120个桶。如果采用月分区,分区桶的个数= 3GB * 30 /2GB = 45个桶 ,这样写入的数据桶数减少到了45个桶。在有限的计算资源下,写入的桶数越少,性能越高。
  • 建表示例 create table data_partition(id int, comb int, col0 int,yy int, mm int, dd int) using hudi --指定hudi 数据源 partitioned by(yy,mm,dd) --指定分区, 支持多级分区 location '/opt/log/data_partition' --指定路径,如果不指定建表在hive warehouse里 options( type='mor', --表类型 mor 或者 cow primaryKey='id', --主键,可以是复合主键但是必须全局唯一 preCombineField='comb' --预合并字段,相同主键的数据会按该字段合并,当前不能指定多个字段 )
  • 规则 建表必须指定primaryKey和preCombineField。 Hudi表提供了数据更新的能力和幂等写入的能力,该能力要求数据记录必须设置主键用来识别重复数据和更新操作。不指定主键会导致表丢失数据更新能力,不指定preCombineField会导致主键重复。 参数名称 参数描述 输入值 说明 primaryKey hudi主键 按需 必须指定,可以是复合主键但是必须全局唯一。 preCombineField 预合并键,相同主键的多条数据按该字段进行合并 按需 必须指定,相同主键的数据会按该字段合并,不能指定多个字段。 禁止建表时将hoodie.datasource.hive_sync.enable指定为false。 指定为false将导致新写入的分区无法同步到Hive Metastore中。由于缺失新写入的分区信息,查询引擎读取该时会丢数。 禁止指定Hudi的索引类型为INMEMORY类型。 该索引仅是为了测试使用。生产环境上使用该索引将导致数据重复。
  • Spark表数据维护规范 禁止通过Alter命令修改表关键属性信息:type/primaryKey/preCombineField/hoodie.index.type 错误示例,执行如下语句修改表关键属性: alter table dsrTable set tblproperties('type'='xx'); alter table dsrTable set tblproperties('primaryKey'='xx'); alter table dsrTable set tblproperties('preCombineField'='xx'); alter table dsrTable set tblproperties('hoodie.index.type'='xx'); Hive/Presto等引擎可以直接修改表属性,但是这种修改会导致整个Hudi表出现数据重复,甚至数据损坏;因此禁止修改上述属性。 父主题: Spark读写Hudi开发规范
  • 建议 基于Flink的流式写入的表,在数据量超过2亿条记录,采用Bucket索引,2亿以内可以采用Flink状态索引。 参照Flink状态索引的特点,Hudi表超过一定数据量后,Flink作业状态后端压力很大,需要优化状态后端参数才能维持性能;同时由于Flink冷启动的时候需要遍历全表数据,大数据量也会导致Flink作业启动缓慢。因此基于简化使用的角度,针对大数据量的表,可以通过采用Bucket索引来避免状态后端的复杂调优。 如果Bucket索引+分区表的模式无法平衡Bueckt桶过大的问题,还是可以继续采用Flink状态索引,按照规范去优化对应的配置参数即可。 基于Bucket索引的表,按照单个Bucket 2GB数据量进行设计。 为了规避单个Bucket过大,建议单个Bucket的数据量不要超过2GB(该2GB是指数据内容大小,不是指数据行数也不是parquet的数据文件大小),目的是将对应的桶的Parquet文件大小控制在256MB范围内(平衡读写内存消耗和HDFS存储有效利用),因此可以看出2GB的这个限制只是一个经验值,因为不同的业务数据经过列存压缩后大小是不一样的。 为什么建议是2GB? 2GB的数据存储成列存Parquet文件后,大概的数据文件大小是150MB ~ 256MB左右。不同业务数据会有出入。而HDFS单个数据块一般会是128MB,这样可以有效的利用存储空间。 数据读写占用的内存空间都是原始数据大小(包括空值也是会占用内存的),2GB在大数据计算过程中,处于单task读写可接受范围之内。 如果是单个Bucket的数据量超过了该值范围,可能会有什么影响? 读写任务可能会出现OOM的问题,解决方法就是提升单个task的内存占比。 读写性能下降,因为单个task的处理的数据量变大,导致处理耗时变大。
  • 规则 禁止修改表索引类型。 Hudi表的索引会决定数据存储方式,随意修改索引类型会导致表中已有的存量数据与新增数据之间出现数据重复和数据准确性问题。常见的索引类型如下: 布隆索引:Spark引擎独有索引,采用bloomfiter机制,将布隆索引内容写入到Parquet文件的footer中。 Bucket索引:在写入数据过程中,通过主键进行Hash计算,将数据进行分桶写入;该索引写入速度最快,但是需要合理配置分桶数目;Flink、Spark均支持该索引写入。 状态索引:Flink引擎独有索引,是将行记录的存储位置记录到状态后端的一种索引形式,在作业冷启动过程中会遍历所有数据存储文件生成索引信息。 用Flink状态索引,Flink写入后,不支持Spark继续写入。 Flink在写Hudi的MOR表只会生成log文件,后续通过compaction操作,将log文件转为parquet文件。Spark在更新Hudi表时严重依赖parquet文件是否存在,如果当前Hudi表写的是log文件,采用Spark写入就会导致重复数据的产生。在批量初始化阶段 ,先采用Spark批量写入Hudi表,在用Flink基于Flink状态索引写入不会有问题,原因是Flink冷启动的时候会遍历所有的数据文件生成状态索引。 实时入湖场景中,Spark引擎采用Bucket索引,Flink引擎可以用Bucket索引或者状态索引。 实时入湖都是需要分钟内或者分钟级的高性能入湖,索引的选择会影响到写Hudi表的性能。在性能方面各个索引的区别如下: Bucket索引 优点:写入过程中对主键进行hash分桶写入,性能比较高,不受表的数据量限制。Flink和Spark引擎都支持,Flink和Spark引擎可以实现交叉混写同一张表。 缺点:Bucket个数不能动态调整,数据量波动和整表数据量持续上涨会导致单个Bucket数据量过大出现大数据文件。需要结合分区表来进行平衡改善。 Flink状态索引 优点:主键的索引信息存在状态后端,数据更新只需要点查状态后端即可,速度较快;同时生成的数据文件大小稳定,不会产生小文件、超大文件问题。 缺点:该索引为Flink特有索引。在表的总数据行数达到数亿级别,需要优化状态后端参数来保持写入的性能。使用该索引无法支持Flink和Spark交叉混写。 对于数据总量持续上涨的表,采用Bucket索引时,须使用时间分区,分区键采用数据创建时间。 参照Flink状态索引的特点,Hudi表超过一定数据量后,Flink作业状态后端压力很大,需要优化状态后端参数才能维持性能;同时由于Flink冷启动的时候需要遍历全表数据,大数据量也会导致Flink作业启动缓慢。因此基于简化使用的角度,针对大数据量的表,可以通过采用Bucket索引来避免状态后端的复杂调优。 如果Bucket索引+分区表的模式无法平衡Bueckt桶过大的问题,还是可以继续采用Flink状态索引,按照规范去优化对应的配置参数即可。
  • 规则 有数据持续写入的表,24小时内至少执行一次compaction。 对于MOR表,不管是流式写入还是批量写入,需要保证每天至少完成1次Compaction操作。如果长时间不做compaction,Hudi表的log将会越来越大,这必将会出现以下问题: Hudi表读取很慢,且需要很大的资源。 这是由于读MOR表涉及到log合并,大log合并需要消耗大量的资源并且速度很慢。 长时间进行一次Compaction需要耗费很多资源才能完成,且容易出现OOM。 阻塞Clean,如果没有Compaction操作来产生新版本的Parquet文件,那旧版本的文件就不能被Clean清理,增加存储压力。 CPU与内存比例为1:4~1:8。 Compaction作业是将存量的parquet文件内的数据与新增的log中的数据进行合并,需要消耗较高的内存资源,按照之前的表设计规范以及实际流量的波动结合考虑,建议Compaction作业CPU与内存的比例按照1:4~1:8配置,保证Compaction作业稳定运行。当Compaction出现OOM问题,可以通过调大内存占比解决。 【建议】通过增加并发数提升Compaction性能。
  • 确认表内桶数 Hudi表的桶数设置,关系到表的性能,需要格外引起注意。 以下几点,是设置桶数的关键信息,需要建表前确认。 非分区表 单表数据总条数 = select count(1) from tablename(入湖时需提供); 单条数据大小 = 平均 1KB(华为建议通过select * from tablename limit 100将查询结果粘贴在notepad++中得出100条数据的大小再除以100得到单条平均大小) 单表数据量大小(G) = 单表数据总条数*单表数据大小/1024/1024 非分区表桶数 = MAX(单表数据量大小(G)/2G*2,再向上取整,4) 分区表 最近一个月最大数据量分区数据总条数 = 入湖前咨询产品线 单条数据大小 = 平均 1KB(华为建议通过select * from tablename limit 100将查询结果粘贴在notepad++中得出100条数据的大小再除以100得到单条平均大小) 单分区数据量大小(G) = 最近一个月最大数据量分区数据总条数*单表数据大小/1024/1024 分区表桶数 = MAX(单分区数据量大小(G)/2G,再后向上取整,1) 需要使用的是表的总数据大小,而不是压缩以后的文件大小 桶的设置以偶数最佳,非分区表最小桶数请设置4个,分区表最小桶数请设置1个。
  • 确认建表SQL DataArts支持通过Spark JDBC方式和Spark API方式操作Hudi表: Spark JDBC方式使用公用资源,不用单独起Spark作业,但是不能指定执行SQL所需要的资源以及配置参数,因此建议用来做建表操作或小数据量的查询操作。 Spark API方式执行的SQL独立起Spark作业,有一定的耗时,但是可以通过配置运行程序参数来指定作业所需要的资源等参数,建议批量导入等 作业使用API方式来指定资源运行,防止占用jdbc资源长时间阻塞其他任务。 DataArts使用Spark API方式操作Hudi表,必须要添加参数--conf spark.support.hudi=true,并且通过执行调度来运行作业。
  • 判断使用分区表还是非分区表 根据表的使用场景一般将表分为事实表和维度表: 事实表通常整表数据规模较大,以新增数据为主,更新数据占比小,且更新数据大多落在近一段时间范围内(年或月或天),下游读取该表进行ETL计算时通常会使用时间范围进行裁剪(例如最近一天、一月、一年),这种表通常可以通过数据的创建时间来做分区已保证最佳读写性能。 维度表数据量一般整表数据规模较小,以更新数据为主,新增较少,表数据量比较稳定,且读取时通常需要全量读取做join之类的ETL计算,因此通常使用非分区表性能更好。 分区表的分区键不允许更新,否则会产生重复数据。 例外场景:超大维度表和超小事实表 特殊情况如存在持续大量新增数据的维度表(表数据量在200G以上或日增长量超过60M)或数据量非常小的事实表(表数据量小于10G且未来三至五年增长后也不会超过10G)需要针对具体场景来进行例外处理: 持续大量新增数据的维度表 方法一:预留桶数,如使用非分区表则需通过预估较长一段时间内的数据增量来预先增加桶数,缺点是随着数据的增长,文件依然会持续膨胀; 方法二:大粒度分区(推荐),如果使用分区表则需要根据数据增长情况来计算,例如使用年分区,这种方式相对麻烦些但是多年后表无需重新导入。 方法三:数据老化,按照业务逻辑分析大的维度表是否可以通过数据老化清理无效的维度数据从而降低数据规模。 数据量非常小的事实表 这种可以在预估很长一段时间的数据增长量的前提下使用非分区表预留稍宽裕一些的桶数来提升读写性能。
  • 使用DataArts创建Hudi表 DataArts支持通过Spark JDBC方式和Spark API方式操作Hudi表: Spark JDBC方式使用公用资源,不用单独起Spark作业,但是不能指定执行SQL所需要的资源以及配置参数,因此建议用来做建表操作或小数据量的查询操作。 Spark API方式执行的SQL独立起Spark作业,有一定的耗时,但是可以通过配置运行程序参数来指定作业所需要的资源等参数,建议批量导入等 作业使用API方式来指定资源运行,防止占用jdbc资源长时间阻塞其他任务。 DataArts使用Spark API方式操作Hudi表,必须要添加参数--conf spark.support.hudi=true,并且通过执行调度来运行作业。
  • Spark异步任务执行表compaction参数设置规范 写作业未停止情况下,禁止手动执行run schedule命令生成compaction计划。 错误示例: run schedule on dsrTable 如果还有别的任务在写这张表,执行该操作会导致数据丢失。 执行run compaction命令时,禁止将hoodie.run.compact.only.inline设置成false,该值需要设置成true。 错误示例: set hoodie.run.compact.only.inline=false; run compaction on dsrTable; 如果还有别的任务在写这张表,执行上述操作会导致数据丢失。 正确示例:异步Compaction set hoodie.compact.inline = true; set hoodie.run.compact.only.inline=true; run compaction on dsrTable; 父主题: Spark读写Hudi开发规范
  • Spark写Hudi各种写入模式参数规范说明 类型 说明 开启参数 场景选择 特点 upsert update + insert Hudi默认写入类型,写入具有更新能力。 默认,无需参数开启。 SparkSQL: set hoodie.datasource.write.operation=upsert; DataSource Api: df.write .format("hudi") .options(xxx) .option("hoodie.datasource.write.operation", "upsert") .mode("append") .save("/tmp/tablePath") 默认选择。 优点: 支持小文件合并。 支持更新。 缺点: 写入速度中规中矩。 append 数据无更新直接写入 Spark:Spark侧没有纯append模式可使用bulk insert模式替代。 SparkSQL: set hoodie.datasource.write.operation = bulk_insert; set hoodie.datasource.write.row.writer.enable = true; DataSource Api: df.write .format("hudi") .options(xxx) .option("hoodie.datasource.write.operation", "bulk_insert") .option("hoodie.datasource.write.row.writer.enable", "true") .mode("append") .save("/tmp/tablePath") 追求高吞吐,无数据更新场景。 优点: 写入速度最快。 缺点: 无小文件合并能力。 无更新能力。 需要clustering合并小文件。 delete 删除操作 无需参数,直接使用delete语法即可: delete from tableName where primaryKey='id1'; SQL删除数据数据场景。 和upsert类型一样。 Insert overwrite 覆写分区 无需参数,直接使用insert overwrite语法即可: insert overwrite table tableName partition(dt ='2021-01-04') select * from srcTable; 分区级别重新。 覆写分区。 Insert overwrite table 覆写全表 无需参数,直接使用insert overwrite语法即可: insert overwrite table tableName select * from srcTable; 全部重写。 覆写全表。 Bulk_insert 批量导入 SparkSQL: set hoodie.datasource.write.operation = bulk_insert; set hoodie.datasource.write.row.writer.enable = true; DataSource Api: df.write .format("hudi") .options(xxx) .option("hoodie.datasource.write.operation", "bulk_insert") .option("hoodie.datasource.write.row.writer.enable", "true") .mode("append") .save("/tmp/tablePath") 建议表初始化搬迁的时候使用。 和append模式一样。
  • 操作步骤 以组织管理员或管理账号的身份登录华为云,进入华为云Organizations控制台。 进入策略管理页,单击“标签策略”,进入标签策略页面。 图1 进入标签策略管理页 单击“创建”,进入标签策略创建页面。 图2 单击创建 编辑策略名称。系统会自动生成策略名称,您可根据需要自行修改。但请注意,新创建策略的名称不能与已有策略名称重复。 (可选)输入策略描述。 编辑策略内容,目前支持通过“可视化编辑器”和“JSON”两种方式进行编辑。 可视化编辑器:通过可视化编辑器编辑策略内容,无需了解JSON语法,编辑完成后可自动生成策略。具体步骤如下: 输入标签策略定义的标签的键。 指定标签键的大小写形式。 勾选此项则表示使用标签键的大小写形式进行校验,如不勾选则表示使用标签键的全小写形式,即便标签键有大写也会使用全部小写进行校验。例如标签键为CostCenter,勾选此项后,后续检验规则以CostCenter为准;不勾选此项,则后续校验规则以costcenter为准。 指定标签键的允许值。 勾选此项后单击“添加值”,为标签键指定的一个或多个允许值,表示此标签键仅允许使用此处指定的值,否则为不合规。如不勾选此项或勾选后未添加标签值,则此标签键使用任何值(包括没有值)都将视为合规。 图3 添加标签键的允许值 指定执行标签策略检查的资源类型。 勾选此项后单击“添加资源类型”,在弹窗中阅读并勾选确认标签策略存在的风险说明,然后选择资源类型,单击“确定”。 图4 添加资源类型 单击“添加标签键”,可在策略内容中添加多个标签键用于标签策略检查。 JSON:通过JSON语法编辑策略内容,根据标签策略语法,在JSON编辑框内编写JSON格式的策略内容。编辑时系统会自动校验语法。如不正确,请根据提示进行修正。 图5 使用JSON编辑策略 (可选)为策略添加标签。在标签栏目下,输入标签键和标签值,单击“添加”。 图6 添加标签 单击右下角“保存”后,如跳转到标签策略列表,则标签策略创建成功。
共100000条