MySQL 到 TiDB:vivo 的 Hive Metastore 横向扩展之路

news2025/1/16 5:46:17

以下文章来源于公众号 vivo 互联网技术 ,作者 Wang Zhiwen

导读

本文介绍了 vivo 在大数据元数据服务横向扩展道路上的探索历程,由实际面临的问题出发,对当前主流的横向扩展方案进行了调研及对比测试,通过多方面对比数据择优选择 TiDB 方案。同时分享了整个扩展方案流程、实施遇到的问题及解决方案,对于在大数据元数据性能上面临同样困境的开发者本篇文章具有非常高的参考借鉴价值。

一、背景

大数据元数据服务 Hive Metastore Service(以下简称 HMS),存储着数据仓库中所依赖的所有元数据并提供相应的查询服务,使得计算引擎(Hive、Spark、Presto)能在海量数据中准确访问到需要访问的具体数据,其在离线数仓的稳定构建上扮演着举足轻重的角色。vivo 离线数仓的 Hadoop 集群基于 CDH 5.14.4 版本构建,HMS 的版本选择跟随 CDH 大版本,当前使用版本为 1.1.0-cdh5.14.4。

vivo 在 HMS 底层存储架构未升级前使用的是 MySQL 存储引擎,但随着 vivo 业务发展,数据爆炸式增长,存储的元数据也相应的增长到亿级别(PARTITION_PARAMS:8.1 亿、 PARTITION_KEY_VALS: 3.5 亿 、PARTITIONS: 1.4 亿) ,在如此大量的数据基数下,我们团队经常面临机器资源的性能瓶颈,往往用户多并发的去查询某些大分区表(50w+分区),机器资源的使用率就会被打满,从而导致元数据查询超时,严重时甚至整个 HMS 集群不可用,此时恢复手段只能暂时停服所有 HMS 节点,直到 MySQL 机器负载降下来后在逐步恢复服务。 为此,针对当前 MySQL 方案存在的严重性能瓶颈,HMS 急需一套完善的横向扩展方案来解决当前燃眉之急。

二、横向扩展技术方案选型

为解决 HMS 的性能问题,我们团队对 HMS 横向扩展方案做了大量的调研工作,总体下来业内在 HMS 的横向扩展思路上主要分为对 MySQL 进行拆库扩展或用高性能的分布式引擎替代 MySQL。在第一种思路上做的比较成熟的方案有 http://Hotels.com ( http://hotels.com/ )公司开源的 Waggle Dance,实现了一个跨集群的 Hive Metastore 代理网关,他允许用户同时访问多个集群的数据,这些集群可以部署在不同的平台上,特别是云平台。第二种思路当前主流的做法是用分布式存储引擎 TiDB 替换传统的 MySQL 引擎,在 Hive 社区中有不少公司对 hive 2.x 接入 TiDB 做了大量的测试并应用到生产中( 详情点击 https://cwiki.apache.org/confluence/display/Hive/Using+TiDB+as+the+Hive+Metastore+database )。

2.1 Waggle Dance

Waggle-dance 向用户提供统一的入口,将来自 Metastore 客户端的请求路由到底层对应的 Metastore 服务,同时向用户隐藏了底层的 Metastore 分布,从而在逻辑层面整合了多个 Metastore 的 Hive 库表信息。Waggle-dance 实现了 Metastore 的 Thrift API,客户端无需改动,对用户来说,Waggle-dance 就是一个 Metastore。其整体架构如下:

Waggle Dance 架构

从 Waggle-dance 的架构中最突出的特性是其采用了多个不同的 MySQL 实例分担了原单 MySQL 实例的压力,除此之外其还有如下优势:

  1. 用户侧可以沿用 Metastore 客户端的用法,配置多台 Waggle-dance 的连接,在当前 Waggle-dance 连接服务不可用的时候切换到其他的 Waggle-dance 服务上。
  2. Waggle-dance 只需几秒即可启动,加上其无状态服务的特性,使得 Waggle-dance 具备高效的动态伸缩性,可以在业务高峰期快速上线新的服务节点分散压力,在低峰期下线部分服务节点释放资源。
  3. Waggle-dance 作为一个网关服务,除了路由功能外,还支持后续的定制化开发和差异化部署,平台可根据需要添加诸如鉴权、防火墙过滤等功能。

2.2 TiDB

TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布式数据库产品,具备水平扩容或者缩容、金融级高可用、实时 HTAP、云原生的分布式数据库、兼容 MySQL 5.7 协议和 MySQL 生态等重要特性。在 TiDB 4.x 版本中,其性能及稳定性较与之前版本得到了很大的提升并满足 HMS 的元数据查询性能需求。故我们对 TiDB 也做了相应的调研及测试。结合 HMS 及大数据生态,采用 TiDB 作为元数据存储整体的部署架构如下:

HMS on TiDB 架构

由于 TiDB 本身具有水平扩展能力,扩展后能均分查询压力,该特性就是我们解决 HMS 查询性能瓶颈的大杀器。除此外该架构还有如下优势:

  1. 用户无需任何改动;HMS 侧面没有任何改动,只是其依赖的底层存储发生变化。
  2. 不破坏数据的完整性,无需将数据拆分多个实例来分担压力,对 HMS 来说其就是一个完整、独立的数据库。
  3. 除引入 TiDB 作为存储引擎外,不需要额外的其他服务支撑整个架构的运行。

2.3 TiDB 和 Waggle Dance 对比

前面内容对 Waggle-dance 方案和 TiDB 方案做了简单的介绍及优势总结,以下列举了这两个方案在多个维度的对比:

通过上述多个维度的对比,TiDB 方案在性能表现、水平扩展、运维复杂度及机器成本上都优于 waggle-dance 方案,故我们线上选择了前者进行上线应用。

三、TiDB 上线方案

选择 TiDB 引擎替代原 MySQL 存储引擎,由于 TiDB 与 MySQL 之间不能做双主架构,在切换过程中 HMS 服务须完全停服后并重新启动切换至 TiDB,为保障切换过程顺利及后面若有重大问题发生能及时回滚,在切换前做了如下数据同步架构以保障切换前 MySQL 与 TiDB 数据一致以及切换后仍有 MySQL 兜底。

TiDB & MySQL 上线前后数据同步架构

在上述架构中,切换前唯一可写入的数据源只有源数据库主库,其他所有 TiDB、MySQL 节点都为只读状态,当且仅当所有 HMS 节点停服后,MySQL 源数据库从库及 TiDB 源数据库主库的数据同步最大时间戳与源数据库主库一致时,TiDB 源数据库主库才开放可写入权限,并在修改 HMS 底层存储连接串后逐一拉起 HMS 服务。

在上述架构完成后,即可开始具体的切换流程,切换整体流程如下:

HMS 切换底层存储流程

其中在保障源 MySQL 与 TiDB 数据正常同步前,需要对 TiDB 做以下配置:

● tidb_skip_isolation_level_check 需要配置为 1 ,否则启动 HMS 存在 MetaException 异常。

● tidb_txn_mode 需配置为 pessimistic ,提升事务一致性强度。

● 事务大小限制设置为 3G,可根据自己业务实际情况进行调整。

● 连接限制设置为最大 3000 ,可根据自己业务实际情况进行调整。

此外在开启 sentry 服务状态下,需确认 sentry 元数据中 NOTIFICATION_ID 的值是否落后于 HMS 元数据库中 NOTIFICATION_SEQUENCE 表中的 NEXT_EVENT_ID 值,若落后需将后者替换为前者的值,否则可能会发生建表或创建分区超时异常。

以下为 TiDB 方案在在不同维度上的表现:

  1. 在对 HQL 的兼容性上 TiDB 方案完全兼容线上所有引擎对元数据的查询,不存在语法兼容问题,对 HQL 语法兼容度达 100%
  2. 在性能表现上查询类接口平均耗时优于 MySQL,性能整体提升 15%;建表耗时降低了 80%,且支持更高的并发,TiDB 性能表现不差于 MySQL
  3. 在机器资源使用情况上整体磁盘使用率在 10%以下;在没有热点数据访问的情况下,CPU 平均使用率在 12%;http://CPU.WAIT.IO 平均值在 0.025%以下;集群不存在资源使用瓶颈。
  4. 在可扩展性上 TiDB 支持一键水平扩缩容,且内部实现查询均衡算法,在数据达到均衡的情况下各节点可平摊查询压力。
  5. 在容灾性上 TiDB Binlog 技术可稳定支撑 TiDB 与 MySQL 及 TiDB 之间的数据同步,实现完整的数据备份及可回退选择。
  6. 在服务高可用性上 TiDB 可选择 LVS 或 HaProxy 等服务实现负载均衡及故障转移。

以下为上线后 HMS 主要 API 接口调用耗时情况统计:

四、问题及解决方案

4.1 在模拟 TiDB 回滚至 MySQL 过程中出现主键冲突问题

在 TiDB 数据增长 3 倍后,切换回 MySQL 出现主键重复异常,具体日志内容如下:

主键冲突异常日志

产生该问题的主要原因为每个 TiDB 节点在分配主键 ID 时,都申请一段 ID 作为缓存,用完之后再去取下一段,而不是每次分配都向存储节点申请。这意味着,TiDB 的 AUTO_INCREMENT 自增值在单节点上能保证单调递增,但在多个节点下则可能会存在剧烈跳跃。因此,在多节点下,TiDB 的 AUTO_INCREMENT 自增值从全局来看,并非绝对单调递增的,也即并非绝对有序的,从而导致 Metastore 库里的 SEQUENCE_TABLE 表记录的值不是对应表的最大值。

造成主键冲突的主要原因是 SEQUENCE_TABLE 表记录的值不为元数据中实际的最大值,若存在该情况在切换回 MySQL 后就有可能生成已存在的主键导致初见冲突异常,此时只需将 SEQUENCE_TABLE 里的记录值设置当前实际表中的最大值即可。

4.2 PARTITION_KEY_VALS 的索引取舍

在使用 MySQL 引擎中,我们收集了部分慢查询日志,该类查询主要是查询分区表的分区,类似如下 SQL:

#以下查询为查询三级分区表模板,且每级分区都有过来条件
​
SELECT PARTITIONS.PART_ID
FROM PARTITIONS
  INNER JOIN TBLS
  ON PARTITIONS.TBL_ID = TBLS.TBL_ID
    AND TBLS.TBL_NAME = '${TABLE_NAME}'
  INNER JOIN DBS
  ON TBLS.DB_ID = DBS.DB_ID
    AND DBS.NAME = '${DB_NAME}'
  INNER JOIN PARTITION_KEY_VALS FILTER0
  ON FILTER0.PART_ID = PARTITIONS.PART_ID
    AND FILTER0.INTEGER_IDX = ${INDEX1}
  INNER JOIN PARTITION_KEY_VALS FILTER1
  ON FILTER1.PART_ID = PARTITIONS.PART_ID
    AND FILTER1.INTEGER_IDX = ${INDEX2}
  INNER JOIN PARTITION_KEY_VALS FILTER2
  ON FILTER2.PART_ID = PARTITIONS.PART_ID
    AND FILTER2.INTEGER_IDX = ${INDEX3}
WHERE FILTER0.PART_KEY_VAL = '${PART_KEY}'
  AND CASE 
    WHEN FILTER1.PART_KEY_VAL <> '__HIVE_DEFAULT_PARTITION__' THEN CAST(FILTER1.PART_KEY_VAL AS decimal(21, 0))
    ELSE NULL
  END = 10
  AND FILTER2.PART_KEY_VAL = '068';

在测试中通过控制并发重放该类型的 SQL,随着并发的增加,各个 API 的平均耗时也会增长,且重放的 SQL 查询耗时随着并发的增加查询平均耗时达到 100s 以上,虽然 TiDB 及 HMS 在压测期间没有出现任何异常,但显然这种查询效率会让用户很难接受。 DBA 分析该查询没有选择合适的索引导致查询走了全表扫描,建议对 PARTITION_KEY_VALS 的 PARTITION_KEY_VAL 字段添加了额外的索引以加速查询,最终该类型的查询得到了极大的优化,即使加大并发到 100 的情况下平均耗时在 500ms 内,对此我们曾尝试对 PARTITION_KEY_VALS 添加上述索引操作。

但在线上实际的查询中,那些没有产生慢查询的分区查询操作其实都是按天分区的进行一级分区查询的,其 SQL 类似如下:

SELECT "PARTITIONS"."PART_ID"
FROM "PARTITIONS"
  INNER JOIN "TBLS"
  ON "PARTITIONS"."TBL_ID" = "TBLS"."TBL_ID"
    AND "TBLS"."TBL_NAME" = 'tb1'
  INNER JOIN "DBS"
  ON "TBLS"."DB_ID" = "DBS"."DB_ID"
    AND "DBS"."NAME" = 'db1'
  INNER JOIN "PARTITION_KEY_VALS" "FILTER0"
  ON "FILTER0"."PART_ID" = "PARTITIONS"."PART_ID"
    AND "FILTER0"."INTEGER_IDX" = 0
  INNER JOIN "PARTITION_KEY_VALS" "FILTER1"
  ON "FILTER1"."PART_ID" = "PARTITIONS"."PART_ID"
    AND "FILTER1"."INTEGER_IDX" = 1
WHERE "FILTER0"."PART_KEY_VAL" = '2021-12-28'
  AND CASE 
    WHEN "FILTER1"."PART_KEY_VAL" <> '__HIVE_DEFAULT_PARTITION__' THEN CAST("FILTER1"."PART_KEY_VAL" AS decimal(21, 0))
    ELSE NULL
  END = 10;

由于对 PARTITION_KEY_VALS 的 PARTITION_KEY_VAL 字段添加了索引做查询优化,会导致该类查询生成的执行计划中同样会使用 idx_PART_KEY_VAL 索引进行数据扫描,该执行计划如下:

走 idx_PART_KEY_VAL 索引执行计划

添加的 idx_PART_KEY_VAL 索引在该字段的具有相同值的数据较少时,使用该索引能检索较少的数据提升查询效率。在 hive 中的表一级分区基本是按天进行分区的,据统计每天天分区的增量为 26w 左右,如果使用 idx_PART_KEY_VAL 索引,按这个数值计算,查询条件为 day>=2021-12-21 and day<2021-12-26 的查询需要检索将近 160w 条数据,这显然不是一个很好的执行计划。

若执行计划不走 idx_PART_KEY_VAL 索引,TiDB 可通过 dbs、tbls 检索出所有关联 partition 数据,在根据 part_id 和过滤条件扫描 PARTITION_KEY_VALS 数据并返回。此类执行计划扫描的数据量和需要查询的表的分区总量有关,如果该表只有少数的分区,则查询能够迅速响应,但如果查询的表有上百万的分区,则该类执行计划对于该类查询不是最优解。

不走 idx_PART_KEY_VAL 索引执行计划

针对不同执行计划的特性,整理了以下对比点:

在实际生产中元数据基本都是按天分区为主,每天增长大概有 26w 左右,且范围查询的使用场景较多,使用 idx_PART_KEY_VAL 索引查询的执行计划不太适合线上场景,故该索引需不适合添加到线上环境。

4.3 TiDB 内存突增导致宕机问题

在刚上线 TiDB 服务初期,曾数次面临 TiDB 内存溢出的问题,每次出现的时间都随机不确定,出现的时候内存突增几乎在一瞬间,若期间 TiDB 的内存抗住了突增量,突增部分内存释放在很长时间都不会得到释放,最终对 HMS 服务稳定性带来抖动。

TiDB 内存突增情况

通过和 TiDB 开发、DBA 联合分析下,确认 TiDB 内存飙高的原因为用户在使用 Dashboard 功能分析慢查询引起;在分析慢查询过程中,TiDB 需要加载本地所有的 slow-query 日志到内存,如果这些日志过大,则会造成 TiDB 内存突增,此外,如果在分析期间,用户点击了取消按钮,则有可能会造成 TiDB 的内存泄漏。针对该问题制定如下解决方案:

  1. 使用大内存机器替换原小内存机器,避免分析慢查询时内存不够
  2. 调大慢查询阈值为 3s,减少日志产生
  3. 定时 mv 慢查询日志到备份目录

4.4 locate 函数查询不走索引导致 TiKV 负异常

在 HMS 中存在部分通过 JDO 的方式去获取分区的查询,该类查询的过滤条件中用 locate 函数过滤 PART_NAME 数据,在 TiDB 中通过函数作用在字段中是不会触发索引查询的,所以在该类查询会加载对应表的所有数据到 TiDB 端计算过滤,TiKV 则需不断扫描全表并传输数据到 TiDB 段,从而导致 TiKV 负载异常。

locate 函数导致全表扫描

然而上述的查询条件可以通过 like 方式去实现,通过使用 like 语法,查询可以成功使用到 PARTITIONS 表的 UNIQUEPARTITION 索引过滤,进而在 TiKV 端进行索引过滤降低负载。

like 语法走索引过滤

通过实现将 locate 函数查询转换为 like 语法查询,有效降低了 TiKV 端的负载情况。在 HMS 端完成变更后,TiKV 的 CPU 使用率降低了将近一倍,由于在 KV 端进行索引过滤,相应的 io 使用率有所上升,但网络传输则有明显的下降,由平均 1G 降低到 200M 左右。

变更前后 TiKV 的负载情况

除 TiKV 负载有明显的降低,TiDB 的整体性能也得到明显的提升,各项操作耗时呈量级降低。以下整理了 TiDB 增删改查的天平均耗时情况:

TiDB P999 天平均耗时统计

4.5 get_all_functions 优化

随着 hive udf 的不断增长,HMS 的 get_all_functions api 平均耗时增长的也越来越久,平均在 40-90s,而该 api 在 hive shell 中首次执行查询操作时会被调用注册所有的 udf,过长的耗时会影响用户对 hive 引擎的使用体验,例如执行简单的 show database 需要等待一分钟甚至更久才能返回结果。

原 get_all_functions api 平均耗时

导致该 api 耗时严重的主要原因是 HMS 通过 JDO 方式获取所有的 Function,在获取所有的 udf 时后台会遍历每条 func 去关联 DBS、FUNC_RU 两个表,获取性能极低。而使用 directSQL 的方式去获取所有 udf 数据,响应耗时都在 1 秒以内完成,性能提升相当明显。以下为 directSQL 的 SQL 实现逻辑:

select FUNCS.FUNC_NAME,
  DBS.NAME,
  FUNCS.CLASS_NAME,
  FUNCS.OWNER_NAME,
  FUNCS.OWNER_TYPE,
  FUNCS.CREATE_TIME,
  FUNCS.FUNC_TYPE,
  FUNC_RU.RESOURCE_URI,
  FUNC_RU.RESOURCE_TYPE
from FUNCS
left join FUNC_RU on FUNCS.FUNC_ID = FUNC_RU.FUNC_ID
left join DBS on FUNCS.DB_ID = DBS.DB_ID

五、总结

我们从 2021 年 7 月份开始对 TiDB 进行调研,在经历数个月的测试于同年 11 月末将 MySQL 引擎切换到 TiDB。由于前期测试主要集中在兼容性和性能测试上,忽略了 TiDB 自身可能潜在的问题,在上线初期经历了数次因慢查询日志将 TiDB 内存打爆的情况,在这特别感谢我们的 DBA 团队、平台运营团队及 TiDB 官方团队帮忙分析、解决问题,得以避免该问题的再次发生;与此同时,由于当前 HMS 使用的版本较低,加上大数据的组件在不断的升级演进,我们也需要去兼容升级带来的变动,如 HDFS 升级到 3.x 后对 EC 文件读取的支持,SPARK 获取分区避免全表扫描改造等;此外由于 TiDB 的 latin 字符集支持中文字符的写入,该特性会导致用户误写入错误的中文分区,对于此类型数据无法通过现有 API 进行删除,还需要在应用层去禁止该类型错误分区写入,避免无用数据累积。

经历了一年多的实际生产环境检验,TiDB 内存整体使用在 10%以内,TiKV CPU 使用平稳,使用峰值均在 30 核内,暂不存在系统瓶颈;HMS 服务的稳定性整体可控,关键 API 性能指标满足业务的实际需求,为业务的增长提供可靠支持。在未来三年内,我们将保持该架构去支撑整个大数据平台组件的稳定运行,期间我们也将持续关注行业内的变动,吸收更多优秀经验应用到我们的生产环境中来,包括但不限于对性能更好的高版本 TiDB 尝试,HMS 的性能优化案例。

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

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

相关文章

10_4阻塞和非阻塞跟poll和等待队列

阻塞和非阻塞 广泛上的区别就是 应用程序如果非阻塞那读取不到数据就应该马上有返回值 阻塞的话就是在应用程序去read数据,但是设备驱动没有数据,就一直卡住,直到有数据再继续往下 补充阻塞知识,应用层大部分都是阻塞 如果要非阻塞 ,应用程序在打开设备节点的时候填写int fd …

文件夹比较工具怎么用 对比两个文件夹找出多余的文件

在日常工作中&#xff0c;经常会接触到大量的文件&#xff0c;长时间堆积&#xff0c;文件夹会越来越多&#xff0c;从而导致文件重复&#xff0c;如果想要找出想要的文件会比较麻烦&#xff0c;那么你知道应该怎么来查找吗&#xff1f;下面就让我们来学习一下文件夹比较工具怎…

【LeetCode刷题-哈希】-- 705.设计哈希集合

705.设计哈希集合 方法&#xff1a;使用链地址法 设哈希表的大小为base&#xff0c;可以设计一个简单的哈希函数&#xff1a;hash(x) x mod base 开辟一个大小为base的数组&#xff0c;数组的每个位置是一个链表&#xff0c;当计算出哈希值后&#xff0c;就插入到对应位置的…

华为OD机试 - 计算疫情扩散时间 - 矩阵(Java 2023 B卷 200分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#…

在CentOS上用yum方式安装MySQL8真实全过程记录(顺利版本)

此文参考我前面的文章《在CentOS上用yum方式安装MySQL8过程记录》&#xff0c;之前比较曲折&#xff0c;现在再安装一台mysql。 因为之前很多坑已经走过&#xff0c;加上这台Linux之前没安装过MYSQL&#xff0c;所以整个过程算是非常顺利。 安装环境&#xff1a;centos7 mysql…

【c++|opencv】一、基础操作---1.图像读取

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 有关c操作opencv记录 1. 正文 1.1 图像读取、显示、保存 // 读取、显示、保存图像#include <opencv2/opencv.hpp> #include <iostream>us…

开发语言工具编程系统化教程入门和初级专辑课程上线

开发语言工具编程系统化教程入门和初级专辑课程上线 学习编程捷径&#xff1a;&#xff08;不论是正在学习编程的大学生&#xff0c;还是IT人士或者是编程爱好者&#xff0c;在学习编程的过程中用正确的学习方法 可以达到事半功倍的效果。对于初学者&#xff0c;可以通过下面…

20M香港服务器性能测试和租用价格,这价格不亏吗?

腾讯云香港轻量应用服务器优惠价格24元一个月&#xff0c;一年288元&#xff0c;以前是30M峰值带宽&#xff0c;现在是20M峰值带宽&#xff0c;阿腾云atengyun.com分享腾讯云香港轻量应用服务器性能测评&#xff0c;包括香港轻量服务器配置价格表、CPU性能和CN2网络延迟测试&am…

IntelliJ IDEA快捷键sout不生效

1.刚下载完idea编辑器时&#xff0c;可能idea里的快捷键打印不生效。这时你打开settings 2.点击settings–>Live Templates–>找到Java这个选项&#xff0c;点击展开 3.找到sout 4.点击全选&#xff0c;保存退出就可以了 5.最后大功告成&#xff01;

​学习一下,什么是预包装食品?​

预包装食品&#xff0c;指预先定量包装或者制作在包装材料和容器中的食品&#xff1b;包括预先定量包装以及预先定量制作在包装材质和容器中并且在一定量限范围内具有统一的质量或体积标识的食品。简单说&#xff0c; 就是指在包装完成后即具有确定的量值&#xff0c;这一确定的…

游戏界面设计:打造吸引人的视觉体验

如何进行游戏界面设计&#xff1f;游戏UI界面设计的前景如何&#xff1f;我相信这是许多UI设计师和想要转向UI设计的设计师非常关心的问题。今天&#xff0c;小将和你谈谈。 首先&#xff0c;游戏界面设计师的前景仍然很好。游戏用户界面是一门研究人机交互的学科&#xff0c;…

【设计模式】第19节:行为型模式之“中介模式”

一、简介 中介模式定义了一个单独的&#xff08;中介&#xff09;对象&#xff0c;来封装一组对象之间的交互。将这组对象之间的交互委派给与中介对象交互&#xff0c;来避免对象之间的直接交互。 中介模式的设计思想跟中间层很像&#xff0c;通过引入中介这个中间层&#xf…

分享个自己写的小程序解包工具

闲聊 前几天在吾爱破解上看到一个小程序逆向的帖子&#xff1a;windows下通杀wx小程序云函数实战 &#xff0c;想着自己也学习一下怎么逆向小程序&#xff0c;一搜 unveilr 仓库没了&#xff0c;看评论好像开始收费了。 我就用aardio写了一个解密和解包工具&#xff0c;这里免…

亚马逊、ebay卖家必读!买家账号关联问题和解决应对方案。

跨境电商卖家最害怕发生的事情之一&#xff0c;就是账号关联了。在多数卖家印象中&#xff0c;平台是不允许一个卖家同时进行多账号操作&#xff0c;一旦被发现就会被强制关停。其实并非如此&#xff0c;平台是允许将不同的亚马逊卖家账号链接在一起&#xff0c;使它们形成一个…

22款奔驰C260L升级原厂360全景影像 高清环绕的视野

360全景影像影像系统提升行车时的便利&#xff0c;不管是新手或是老司机都将是一个不错的配置&#xff0c;无论是在倒车&#xff0c;挪车以及拐弯转角的时候都能及时关注车辆所处的环境状况&#xff0c;避免盲区事故发生&#xff0c;提升行车出入安全性。 360全景影像包含&…

CN考研真题知识点二轮归纳(2)

持续更新&#xff0c;上期目录&#xff1a; CN考研真题知识点二轮归纳&#xff08;1&#xff09;https://blog.csdn.net/jsl123x/article/details/134095044?spm1001.2014.3001.5501 1.DCHP 动态主机配置协议&#xff0c;常用于给主机动态分配IP地址&#xff0c;它提供即插即…

IBM Spectrum LSF Session Scheduler(会话调度程序)提高总体集群利用率和系统性能

IBM Spectrum LSF Session Scheduler 提高总体集群利用率和系统性能 LSF Session Scheduler 使用户能够使用作业级任务调度程序在单个 LSF 作业的分配中运行短期任务的大型集合&#xff0c;该调度程序为作业分配一次资源&#xff0c;并对每个任务复用已分配的资源。 LSF Sessi…

css position属性与js滚动

“视口”就是浏览器窗口中实际显示文档内容的区域&#xff0c;不包含浏览器的“外框”&#xff0c;如菜单、工具条和标签。文档则是指整个网页。 1 css 的position static 正常定位&#xff0c;是元素position属性的默认值&#xff0c;元素遵循常规流。 relative 相对定位&…

什么是 CNN? 卷积神经网络? 怎么用 CNN 进行分类?(3)

参考视频&#xff1a;https://www.youtube.com/watch?vE5Z7FQp7AQQ&listPLuhqtP7jdD8CD6rOWy20INGM44kULvrHu 视频7&#xff1a;CNN 的全局架构 卷积层除了做卷积操作外&#xff0c;还要加上 bias &#xff0c;再经过非线性的函数&#xff0c;这么做的原因是 “scaled p…

SpringCloud 微服务全栈体系(八)

第九章 Docker 二、Docker 的基本操作 1. 镜像操作 1.1 镜像名称 镜像的名称组成&#xff1a; 镜像名称一般分两部分组成&#xff1a;[repository]:[tag]。在没有指定 tag 时&#xff0c;默认是 latest&#xff0c;代表最新版本的镜像 比如&#xff1a;mysql 就是 reposito…