-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(routes/meituan): add full text support for meituan tech #18375
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Successfully generated as following: http://localhost:1200/meituan/tech - Success ✔️<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>美团技术团队</title>
<link>https://tech.meituan.com/</link>
<atom:link href="http://localhost:1200/meituan/tech" rel="self" type="application/rss+xml"></atom:link>
<description>美团技术团队最近更新内容。 - Powered by RSSHub</description>
<generator>RSSHub</generator>
<webMaster>[email protected] (RSSHub)</webMaster>
<language>zh-cn</language>
<lastBuildDate>Mon, 17 Feb 2025 04:51:40 GMT</lastBuildDate>
<ttl>5</ttl>
<item>
<title>预测技术在美团弹性伸缩场景的探索与应用</title>
<description><blockquote><p>管理企业大规模服务的弹性伸缩场景中,往往会面临着两个挑战:第一个挑战是精准的负载预测,由于应用实例的启动需要一定预热时间,被动响应式伸缩会在一段时间内影响服务质量;第二个挑战是高效的资源分配,即在保障服务质量的同时控制资源成本。为了解决这些挑战,美团基础技术部与中国人民大学信息学院柴云鹏教授团队展开了“预测技术在弹性伸缩场景的应用”科研合作,相关论文《<a href="https://dl.acm.org/doi/10.1145/3589334.3645330">PASS: Predictive Auto-Scaling System for Large-scale Enterprise Web Applications</a>》在具有国际影响力的会议The Web Conference 2024(CCF-A类会议)上作为Research Full Paper发表。</p></blockquote><h2 id="1-背景">1 背景</h2><p>在管理企业大规模服务弹性伸缩的场景下,Web应用的负载时序数据分析和预测至关重要。然而,由于应用的周期性特征和负载的复杂性,寻找一种能够适应所有应用的预测模型成为了一项挑战。首先,应用的负载数据往往具有周期性,这就需要在进行分析和预测时,需要考虑到这种周期性的影响。其次,由于业务特征的差异,预测算法可能在不同的应用下表现出差异化的效果,不存在“one-size-fits-all”的情况。例如,经测试发现,虽然在线模型的预测效果大多数时候好于离线模型,但在一些规律的突增情况下,在线模型经常存在滞后性的问题。这些问题都需要在对应用负载时序数据分析和预测时,进行深入的研究和探讨。</p><p>除了准确的负载预测,还需要高效的弹性伸缩策略。目前,业界常用的弹性伸缩策略有基于规则的阈值法、基于控制论的目标追踪和排队论。然而,我们发现这些方法并不能有效地保障QoS(Quality of Service,服务质量),尤其是QoS包含对尾延迟的要求时,其背后原因是这些策略的性能模型并不准确。阈值法和目标追踪的性能模型是“当QPS或CPU利用率在给定的范围内时QoS达标”。但这些阈值通常是根据人工经验设置的,并不总是准确。排队论根据统计模型推导在给定的负载和资源下业务的延迟,但它依赖的理论假设(例如用户请求到来的分布)并不总在现实中成立,使其估算的延迟和真实值有偏差。我们在测试中也发现了排队论估算的延迟会略低于真实延迟,因而导致出现服务质量不达标。此外,基于AI的弹性伸缩方法例如强化学习并不一定适用企业的生产环境,因为AI模型缺乏一定的可解释性,且可能会在线上做出有QoS违例风险的行为。</p><h2 id="2-探索分析">2 探索分析</h2><h3 id="2-1-预测实验探索">2.1 预测实验探索</h3><p><strong>发现1</strong>:由于预测算法的固有限制,没有一种单一的算法能够在所有类别的时序数据中都提供最佳的预测效果。多样化的预测算法对于美团丰富的业务流量预测更有效。</p><p>我们对美团的服务流量数据进行周期检测(计算ACF自相关系数),发现92.80%的应用表现出强周期性(相关系数大于0.8),4.55% 显示出弱周期性(相关系数介于0.5~0.8之间),只有2.65%的应用没有表现出明显的周期性(相关系数小于0.5)。因此,对于美团内的大多数服务,可以使用模型可靠地预测QPS流量数据。</p><p>我们使用225个美团真实服务流量数据对业界常用的预测算法进行了测试。实验结果表明,预测效果最好的算法并不是单一的,而是取决于业务流量的具体特征。如图1(a)和(b)所示,我们使用三个代表性服务的流量数据来说明周期因子算法(Seasonal index)和 patchTST模型的预测效果。 在图1(a)中,对于服务1,周期因子算法显著优于patchTST,而在图1(b)中,对于服务2,patchTST却又比周期因子预测效果更好。这一实验说明了最优预测算法的动态多样性,我们需要针对业务流量特征选择最合适的预测算法。</p><p><img src="https://p0.meituan.net/meituantechblog/23c7467785e923d95f3e2cba0fd3ec8897661.png" alt="图1 各种预测算法的准确性和鲁棒性对比" referrerpolicy="no-referrer"></p><p><strong>发现2</strong>:在线预测提供了较高的平均预测准确度,但在“突变特征”表现不佳。 相比之下,离线预测可以捕获“突变特征”,但存在明显的“振幅偏差”问题。</p><p>在线预测模型实时地获取最新的数据输入,输出未来一小段时间(如:15分钟)的预测数据。 离线预测模型无需实时数据输入,直接预测未来较长一段时间(如:1天)的预测数据。 由于缺乏最新实时数据的输入,离线模型往往无法达到和在线模型相同的预测准确性。但在一些有规律的突增时间点,离线模型能够捕捉到突变的周期性特征,从而取得“及时”的预测效果。例如,在周期性“突变特征”的情况下,在线模型可能会表现出预测滞后(图1©中的黑色圆圈突出显示)。 这种滞后效应会持续一段时间,我们称之为“脏区间”。</p><p>相反,离线模型有效地捕获这些信息,从而能够及时进行预测。然而,离线模型存在着“振幅偏差”的问题,即特征的形状被准确地表示,但其绝对值存在差异(见图1(d))。“突变特征”在美团服务中尤其普遍,这是由于美团许多业务都存在午、晚流量高峰。虽然“突变特征”只占实际时间序列数据的一小部分,但这些特征的精确预测对于在生产环境中维持QoS至关重要。</p><h3 id="2-2-伸缩方法分析">2.2 伸缩方法分析</h3><p><strong>发现3</strong>:云平台广泛使用的弹性伸缩方法并不能有效保障QoS,特别是当QoS要求对尾延迟的保障时。 与平均响应时间RT相比,当QoS要求为TP999尾延迟时,表1中几种方法的QoS保障率都显著降低。然而,大多数业务应用都需要关于尾延迟的保障,这使得弹性伸缩方法效率并不高,要么接受QoS违例,要么多冗余资源。</p><p><strong>发现4</strong>:这些弹性伸缩方法的性能模型不够准确。基于阈值的规则和目标跟踪背后的性能模型实际上是“当QPS或CPU利用率在一定范围内时QoS达标”。 而这个范围的参数是根据人工经验确定的。表1的结果证明它并不完全有效。另外,排队论因为过于依赖理论假设而不够准确,导致其估计的RT低于真实值,从而出现QoS违例。</p><p><img src="https://p0.meituan.net/meituantechblog/966b1ed55570bbbf64dbe47c07a55680114485.png" alt="表1 三种常见弹性伸缩方法的QoS保障率和资源成本" referrerpolicy="no-referrer"></p><p>目前云平台的常见弹性伸缩方法有以下几种:</p><ul><li><strong>阈值法</strong>:基于一系列包含阈值的规则来进行弹性伸缩。以CPU资源利用率为例,当资源利用率超过上限阈值时,增加资源,反之,当利用率低于下阈值时,减少资源。阈值参数通常凭经验设置。</li><li><strong>目标追踪</strong>:一种基于反馈的控制论方法,将某个指标(例如CPU资源利用率)维持在特定范围内。当实际资源利用率不在设定范围内时,系统会根据当前状态自动计算需要伸缩的实例数量。例如,假设CPU和流量呈线性相关的前提下,当前10个实例的平均CPU资源利用率为80%,目标值为50%,则实例需要扩容为80%*<sup>10</sup>⁄<sub>50</sub>%=16个实例。</li><li><strong>排队论</strong>:根据排队论模型计算性能指标(例如延迟)并进行相应的伸缩以确保QoS达标。常见的𝑀/𝑀/𝑠模型表示请求到达和处理的时间呈指数分布,共有𝑠服务器并行处理。阿里巴巴的弹性伸缩框架AHPA使用排队论作为性能模型。</li><li><strong>强化学习</strong>:弹性伸缩模块充当代理并与环境交互,在每次执行伸缩操作后接收奖励反馈。它通过反复试验建立状态(当前监控指标)和动作(伸缩多少实例)之间的映射模型。</li></ul><p>大部分云平台使用的弹性伸缩方法都是简单或直接的,比如:阈值法、目标跟踪和排队论。强化学习和其他人工智能相关方法使用较少,因为它们可能会影响在线业务的性能。 我们使用若干具有代表性的后端服务测试了常用弹性伸缩方法的QoS保障率。由于我们的主要目的是验证QoS保障率,因此我们使用了阶梯式增加的工作负载。QoS保障率和资源成本的结果如表1所示。QoS保障率是用QoS保障时长除以总时长计算得出的。资源成本由实例数随时间(分钟)的积分得到。</p><h2 id="3-技术方案">3 技术方案</h2><p>为了解决这些问题,我们提出了 PASS(Predictive Auto-Scaling System),这是一种为企业大规模在线Web应用定制的预测弹性伸缩系统。为了保障预测框架准确性和鲁棒性,我们根据每个应用的特征,动态匹配和校准其适合的预测算法,有效应对了业务负载的多样性。我们进一步建立了基于在线历史日志的性能模型以保障多样化的QoS,可解释的同时不会对在线业务产生负面影响。 除了基于负载预测和性能模型的主动伸缩以外,我们还设计了响应式的兜底策略,以及时应对因不准确的预测或意外事件导致的服务质量违例。在美团广泛的业务应用和真实负载下,相对于表1中其它方法,PASS 表现更优于SOTA,以更少的资源成本实现更高的负载预测准确度和更低的QoS违例。</p><p>PASS的整体架构如图2所示。ELPA(Ensemble Learning-based Prediction Algorithm)实时准确地预测业务负载的QPS时序数据。通过查询基于历史日志构建的性能模型,PASS在不违反QoS的前提下,预测伸缩到业务所需的实例数量。此外,PASS还持续监控QoS指标,如果发现由于预测不准导致的QoS违例,PASS会基于当前真实的延迟校正预测结果,并伸缩到适当数量的实例,以快速消除QoS违例。</p><p><img src="https://p0.meituan.net/meituantechblog/37f87f6fd782585676deb0a9e8e6a96f93213.png" alt="图2 PASS整体架构,图中上半部分的黑线表示离线步骤,下半部分中的红线表示在线过程" referrerpolicy="no-referrer"></p><h3 id="3-1-elpa预测模型">3.1 ELPA预测模型</h3><p>我们提出了ELPA(Ensemble Learning-based Prediction Algorithm)预测算法框架(如图3所示)。对于每一类业务的实时流量,ELPA采用一组相应的在线和离线模型来提供预测服务。我们首先从一系列不同的在线模型中选择一个能够为当前时间序列数据提供最准确预测的模型。然后,为了更好地预测“突变特征”,我们使用一个表现最好的离线预测模型代替在线模型。此外,我们使用振幅调整来改善离线预测时可能出现的“振幅偏差”问题,从而进一步增强预测性能。</p><p><img src="https://p0.meituan.net/meituantechblog/ecfc86400c119460bc189810a47066e4186677.png" alt="图3 预测算法框架" referrerpolicy="no-referrer"></p><p><img src="https://p0.meituan.net/meituantechblog/fb3a35c55b1926c01d4ca5af2a2028d3470282.png" alt="" referrerpolicy="no-referrer"></p><h3 id="3-2-性能模型设计">3.2 性能模型设计</h3><p>我们提出了基于日志的性能模型(Log-based Performance Model)。主要包括:性能模型构建与模型训练校准两部分。</p><p><strong>性能模型构建</strong>:Algorithm1说明了如何基于历史日志(不需要对应用进行画像)构建性能模型。 我们从监控系统获取服务的日志,包括QPS、实例数、QoS指标等信息。 输入的QoS由服务设置,当QoS发生变化时需要重新建立性能模型。我们首先按实例数量聚合输入日志并遍历所有日志(第 1-9 行)。 第4行按照“cap”的粒度(例如最大QPS的千分之一)聚合QPS,以减少数据数量和算法开销。 第5-8行统计QoS违例的发生次数。由于系统故障等因素可能导致某些记录不准确,因此在评估某个QPS的保障率时,我们不仅计算当前的QPS记录,还综合考虑所有较低的QPS记录(第10-19行)。第20行的排序规则是优先考虑大于给定阈值𝛿的QoS保证率,然后按QPS降序排序。𝛿可以根据业务的需求进行调整(默认为0.99),衡量对QoS违例的容忍度。𝛿越接近1,容忍度越低。最后,我们将排序后的第一个QPS指定为当前实例数可以处理的最大流量(第21行)。</p><p><img src="https://p0.meituan.net/meituantechblog/79622676c4c6e5c897adc7aa24e9763d428081.png" alt="" referrerpolicy="no-referrer"></p><p><strong>模型训练校准</strong>:直接根据监控日志构建的性能模型表可能不准确。当应用程序设置的弹性伸缩参数不合理时(例如水平扩容步长较大或资源冗余过多),可能会导致某些实例数没有监控日志,或者数据量极少。这可能会导致最初构建的表中条目丢失或不准确。 为了解决这个问题,我们首先保证原表数据保持非严格单调增长,空的或较低的QPS被之前较高的QPS替换。 然后,对于实例数量增加但QPS不变的部分,我们根据相邻QPS计算斜率并更新它们。 例如,初始化的性能模型映射为{5 : 30, 7 : 20, 8 : 60},使用实例5的QPS替换实例6和7后,则变为{5 : 30,6 : 30,7 : 30,8 : 60}。 然后,根据实例5和8之间的QPS差异,我们更新实例6和7的QPS,得到{5 : 30,6 : 40,7 : 50,8 : 60}。 此外,我们在每天低峰时段使用最新的监控日志定期重建性能模型,以保持准确性。</p><h3 id="3-3-hybrid-auto-scaling方案设计">3.3 Hybrid Auto-scaling方案设计</h3><p>除了预测伸缩,我们还设计了基于排队论的响应式兜底策略,用于处理由于预测不准或热点事件负载突增导致的 QoS 违例。PASS 实时监控应用程序的性能指标。如果检测到QoS违例,PASS将根据 M/M/s排队论模型修改预测的QPS,并重新查询性能模型以快速扩容适当数量的实例。 具体而言,排队论模型如下公式所示:</p><p><img src="https://p0.meituan.net/meituantechblog/8ccc92a88fc1b49d59a4436b3037f48415930.png" alt="" referrerpolicy="no-referrer"></p><p>𝑠表示当前实例的数量,𝑢代表每个实例的瓶颈QPS,𝑝表示延迟的百分比,以及𝑡指的𝑝百分位尾延迟。使用排队理论来估计QPS而不是延迟的原因是,从排队论推导出的延迟往往低于实际值(2.2节中排队论的QoS保障率偏低证明了这一点),因此从实际延迟推导出的QPS将高于实际值。我们基于更高的QPS进行扩容,以快速响应QoS违例并将损失降至最低。并且我们通过实验表明,这部分资源冗余并不会导致大量浪费。</p><h2 id="4-测试结果">4 测试结果</h2><h3 id="4-1-实验环境">4.1 实验环境</h3><p><strong>应用选择</strong>:我们从美团的各个业务线中随机抽取了225个应用,以验证预测模型的准确性。这些应用的历史QPS数据是从美团内部的统一在线监控平台获得的。我们根据数据的预测难度将其分为三个不同的级别。其中,164个服务被定义为简单(具有单一波形模式,并表现出“单峰和多峰”特征),48个服务被定义为中等难度(具有单一波形模式,并表现出“尖峰”或“方形”特征),13个服务被定义为难(混合波形模式,例如“尖峰+方形”)。我们还选择了几个具有代表性的应用进行端到端评估。这些应用是后端服务,提供C端用户基本属性、用户行为查询、搜索和聊天功能。我们记录了在线请求流量,并在离线环境中回放,以恢复真实的在线环境。为了减少时间和资源成本,我们对记录的流量进行了切片,忽略了无法触发弹性伸缩的长期稳定的低峰值负载。</p><p><strong>对比Baseline</strong>:我们比较了各种类型的SOTA预测算法和弹性伸缩方法。预测算法包括:离线算法(周期因子、Prophet)和在线算法(LSTNet、PatchTST和TIDE)。我们评估的在线算法旨在预测从当前时刻开始的第三个时间点的值(时间粒度为5min,也就是预测未来15min),即horizon等于3。这足以满足预测伸缩的要求,因为绝大多数的应用实例能够在15分钟以内完成启动。弹性伸缩方法包括:目标跟踪和AHPA。由于目标跟踪通常可以比具有相同参数的阈值法更快地扩展到目标范围(第2.2节也表明目标跟踪的性能更好),我们没有比较阈值法。其中AHPA是阿里巴巴基于排队论的SOTA预测弹性伸缩方法。</p><h3 id="4-2-预测算法评估">4.2 预测算法评估</h3><p><strong>结论1</strong>:ELPA预测框架结合了在线和离线模型的优势,在绝大多数场景中都取得最好的预测准确度。</p><p><img src="https://p0.meituan.net/meituantechblog/25a1ac0ed1d6dac82b7ef4aea1ff7e5c134871.png" alt="表2 各种预测算法在各种数据集上的准确度总结,分为三个预测难度级别" referrerpolicy="no-referrer"></p><p>(每一行和每一列分别比较所有方法在特定级别的数据集和特定指标上的结果。粗体突出显示每个指标的最佳结果;𝑀𝑒𝑡𝑟𝑖𝑐𝑠_𝑎𝑣𝑔表示当前难度级别数据集的平均预测结果,而𝑊𝑖𝑛𝑛𝑒𝑟显示了按数据集类型评估的方法在准确性方面优于其他方法的比例)</p><p>我们对ELPA以及其他五种广泛使用的预测算法进行了评估。表2显示了各种预测算法的准确度比较。ELPA明显优于单个预测算法,由于其实现了一组优化规则,用于选择最合适的在线/离线组合,并使用振幅校准来预测特定时间段的数据。</p><p><strong>结论2</strong>:离线模型虽然擅长捕捉数据的“突变特征”,但其预测结果和真实值存在显著差异。而在线模型在有效预测这些“突变特征”方面面临挑战。通过两个模型的集成和振幅校准的应用,ELPA框架表现出显著的鲁棒性。</p><p><img src="https://p0.meituan.net/meituantechblog/780407c01d44c01d81d25cb922562ffd97350.png" alt="图4 在线模型、离线模型(包括振幅调整)和 ELPA 的预测实例化展示" referrerpolicy="no-referrer"></p><p>图4提供了ELPA的示例,其中结合了在离线预测模型,并对离线模型进行振幅调整。需要注意的是,“突变特征”可以在各种类型的业务流量中表现出来。由于篇幅限制,我们选择了一个具有代表性的业务负载数据集来突出ELPA的稳健预测能力。图4(a)比较了在线模型(PatchTST)的预测与真实数据。虽然在线模型在大多数情况下显示出很高的预测精度,但在预测“突变特征”时存在显著的滞后问题(黑色圆圈突出显示)。在图4(b)中,蓝色虚线代表离线模型(周期因子)的预测结果,尽管它在大多数情况下和真实值有一定的差距,但及时地预测出了“突变特征”。图4(b)中的红色虚线表示ELPA在离线模型的“突变特征”处的振幅校准结果。最后,图4©展示了ELPA的结果,它集成了在线模型和校准的离线模型,表现出准确的预测效果和预测“突变特征”的能力。</p><h3 id="4-3-端到端效果评估">4.3 端到端效果评估</h3><p>结论3:PASS的性能模型准确有效,在所有测试场景中都实现了最高的QoS保障率(表3)。 与目标跟踪和AHPA相比,平均QoS保障率分别提高了5.54%和7.71%。在多个QoS指标的场景6中表现更为明显,PASS的QoS保障率分别提高了19.21%和22.64%。PASS在所有场景中的平均资源成本也是最低的。 平均资源成本较AHPA降低8.91%,较目标跟踪降低17.02%。在场景4中降低了高达40%和52.76%。只有两个场景中PASS的资源成本略高于AHPA,而在所有其他测试中,PASS的资源成本都是最低的。</p><p><img src="https://p0.meituan.net/meituantechblog/184480305433023042e0acbb550b1c1188155.png" alt="表3 三种auto-scaling方法在不同QoS和测试时长(小时)场景下的端到端性能" referrerpolicy="no-referrer"></p><p>(每个场景中,第一列是QoS保障率,第二列是资源成本(实例数*小时); 粗体突出显示每个指标的最佳结果)</p><p>我们从两个方面来评估弹性伸缩方法的效果。QoS保障率衡量了应用违反QoS的时间长度,其计算方法为QoS得到保证的持续时间与总时间长度的比值。资源成本通过计算实例数量和时间(以小时为单位)的积分得到。 端到端实验结果如表3所示(测试过程详细监控数据见图5和图6,包括QPS系列、实例数以及TP99、TP999时延等QoS指标)。每个测试场景提供了QoS指标、测试时长以及三种方法的QoS保障率和资源成本。</p><p><img src="https://p0.meituan.net/meituantechblog/fd6e868d46f648cf43dd0ed99e67147b126078.png" alt="图5 Scenario1的综合监控数据:QPS系列、实例数和QoS指标" referrerpolicy="no-referrer"></p><p><img src="https://p0.meituan.net/meituantechblog/747c98769d1927b8132a5bab60b7c2a8189270.png" alt="图6 Scenario6的综合监控数据:QPS系列、实例数和QoS指标" referrerpolicy="no-referrer"></p><p>需要注意的是,应用实例启动时并没有进行预热(例如数据库连接初始化、缓存预测等),因此即使实例提前进行了扩容,初始大量的冷查询仍然会导致尾延迟突然增加。如果业务方在其实例启动逻辑中加入预热,我们的QoS保障率将会进一步提高。</p><h2 id="5-经验总结">5 经验总结</h2><ul><li>不同企业的应用场景可能各不相同,场景复杂程度也不一,在实际落地过程中,一些顶会算法不一定适用我们场景,这个时候就需要我们仔细甄别,取长补短,围绕自身场景特点进行算法的创新简化。</li><li>模型并不是越复杂性能越好,要结合预测的特征与场景来选择预测算法。</li><li>除了模型性能外,模型的可落地性也是非常重要的,比如LSTNet支持同时预测多项时间序列,面对大规模服务时能够极大的减少模型落地的开销。</li></ul><h2 id="6-合作方简介">6 合作方简介</h2><p>中国人民大学柴云鹏教授团队致力于云计算、数据库等领域的系统研究和研发,近年团队在系统和数据库等领域的重要会议ASPLOS、SOSP、HPCA、SIGMOD、VLDB、ICDE、WWW等发表多篇高水平论文。在云计算领域,该团队针对资源隔离、资源分配、资源调度等核心问题,提出了一系列方法,可以提升各种复杂场景下的资源利用率,同时保障应用的服务质量,推动云计算技术的进步。团队高度重视科研工作的实用价值,积极推进与科技领域企业合作,针对企业面临的核心挑战,将创新性方法在实际系统中实现,推动研究成果的实际落地与应用,同时助力合作伙伴技术能力提升和商业价值实现。</p></description>
<link>https://tech.meituan.com/2025/02/14/prediction-technology-in-meituan-elastic-scaling.html</link>
<guid isPermaLink="false">https://tech.meituan.com/2025/02/14/prediction-technology-in-meituan-elastic-scaling.html</guid>
<pubDate>Fri, 14 Feb 2025 00:00:00 GMT</pubDate>
<author>美团技术团队</author>
</item>
<item>
<title>美团技术年货 | 600+页电子书,算法、工程、测试、数据、安全系列大合集</title>
<description><p><img src="https://p0.meituan.net/meituantechblog/2b39e0fadbfc2d23762e5be6c359abea783334.png" alt="" referrerpolicy="no-referrer"></p><p>新春将近,一年一度的美团技术年货也如约而至!</p><p>路虽远,行则将至;梦虽遥,追则可及。2024年,是美团技术博客走过的第11个年头,这里没有恢弘的叙事,只是年复年、日复日的默默坚持。截至目前,美团技术团队微信公众号累计发布了600多篇技术文章,感谢大家一路同行,见证我们的成长。</p><p>值蛇年春节到来之际,我们精选过去一年公众号30多篇技术文章和科研论文,整理制作成一本600多页的电子书,作为一份特别的新年礼物,献给每一位热爱技术的你。</p><p><img src="https://p0.meituan.net/meituantechblog/46a9990011b1af1679be6b780ce0c90e747914.png" alt="" referrerpolicy="no-referrer"></p><p>这本电子书内容覆盖算法、工程、测试、安全、数据等多个技术领域,希望能为你的工作和学习带来一些启发与帮助。也欢迎您将这份电子书分享给更多志同道合、积极向上的同事和朋友,一起携手共进,砥砺前行。</p><p>在新的一年里,愿大家乘风破浪,勇往直前,历尽千帆,梦想终将实现!</p><h2 id="如何获取">如何获取?</h2><p><img src="https://p0.meituan.net/meituantechblog/0f95586a87d5a2161fea060b87f4419c389208.jpg" alt="" referrerpolicy="no-referrer"></p><p>关注美团技术团队微信公众号,在菜单栏对话框回复关键词:2024年货。即可获取下载链接。</p><p>温馨提醒:</p><ul><li>美团技术年货合集大小约为80M,下载需要一定的时间;</li><li>打开电子书目录后,可直接点击感兴趣的标题进行阅读;</li><li>部分文章中的动态图片无法在电子书中进行完全的展示,大家可以移步美团技术团队官方博客 <a href="https://tech.meituan.com/">tech.meituan.com</a> ,或在美团技术团队公众号历史文章中进行阅读,感谢理解。</li></ul><h2 id="往期年货下载">往期年货下载</h2><p>在「美团技术团队」微信公众号对话框中回复关键字:【2023年货】、【2022年货】、【2021年货】、【2020年货】、【2019年货】、【2018年货】、【2017年货】,即可获取往期年货下载链接。</p><p>| 本文系美团技术团队出品,著作权归属美团。欢迎出于分享和交流等非商业目的转载或使用本文内容,敬请注明“内容转载自美团技术团队”。本文未经许可,不得进行商业性转载或者使用。任何商用行为,请发送邮件至[email protected]申请授权。</p></description>
<link>https://tech.meituan.com/2025/01/16/2024-spring-festival-present.html</link>
<guid isPermaLink="false">https://tech.meituan.com/2025/01/16/2024-spring-festival-present.html</guid>
<pubDate>Thu, 16 Jan 2025 00:00:00 GMT</pubDate>
<author>美团技术团队</author>
</item>
<item>
<title>鸿蒙应用签名实操及机制探究</title>
<description><h2 id="1-背景">1. 背景</h2><p>华为鸿蒙单框架操作系统HarmonyOS NEXT已于2024年10月23日正式发布Release版。HarmonyOS NEXT仅支持鸿蒙原生应用,不再兼容安卓。本文对鸿蒙公开资料进行了深入分析和解读,梳理了鸿蒙单框架应用的签名机制,拆解每一步的实操过程和背后的实现原理,并对源码分析整理签名的校验机制。从中管中窥豹,探究鸿蒙系统的安全设计思路,希望能给从事鸿蒙研发的同学提供一些借鉴。</p><p>成文过程中特别参考OpenHarmony 5.0.0-Release版的文档和源码,详见<a href="https://gitee.com/openharmony/docs/blob/OpenHarmony-5.0.0-Release/zh-cn/release-notes/OpenHarmony-v5.0.0-release.md">openharmony</a>。</p><h2 id="2-签名机制">2. 签名机制</h2><p>签名相关的代码在<a href="https://gitee.com/openharmony/developtools_hapsigner/tree/OpenHarmony-v5.0.0-Release/">developtools_hapsigner</a>仓库里,签名流程梳理如下:</p><p><img src="https://p0.meituan.net/meituantechblog/ff3bff190a0dd7ab8adab552c0b168a5182681.png" alt="" referrerpolicy="no-referrer"></p><p>签名步骤可按如下分组:</p><ol><li>生成开发者签名证书,包括①、②、③。</li><li>生成Profile文件,包括④、⑤。</li><li>生成签名的App,包括⑥、⑦。</li></ol><h3 id="2-1-生成开发者签名证书">2.1 生成开发者签名证书</h3><p><strong>① 生成开发者公私钥</strong></p><p>通过华为的DevEco-Studio工具可以直接生成包含开发者公私钥的p12文件(详见<a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-signing-V5#section462703710326">具体操作步骤</a>。)</p><p><img src="https://p0.meituan.net/meituantechblog/39ceff06aa892e8b390931cd7e0c2b42149083.png" alt="" referrerpolicy="no-referrer"></p><p>笔者示例生成的p12文件(保存为my.p12)是标准的PKCS#12格式(定义在<a href="https://datatracker.ietf.org/doc/html/rfc7292">RFC 7292</a>),用来存储一组或多组公钥证书(里面包含公钥)和其对应的私钥(用localKeyID字段进行匹配公私钥的匹配),使用ASN.1来定义其数据结构,并采用DER编码规则将这些结构编码为二进制形式。</p><p>可以通过openssl命令解析其结构,或者直接查看公钥证书和私钥信息:</p><pre><code>openssl asn1parse -in my.p12 -inform DER //解码DER和解析ASN.1
openssl pkcs12 -info -in my.p12 //查看公钥证书和私钥信息
</code></pre><p>笔者用于示例生成的p12文件里包含的公钥证书如下:</p><pre><code>-----BEGIN CERTIFICATE-----
MIIBqTCCAU+gAwIBAgIIKG2ih6j2GSswCgYIKoZIzj0EAwIwSTEJMAcGA1UEBhMA
MQkwBwYDVQQIEwAxCTAHBgNVBAcTADEJMAcGA1UEChMAMQkwBwYDVQQLEwAxEDAO
BgNVBAMTB3Rlc3RzY3IwHhcNMjQwOTIzMTI1NjM3WhcNNDkwOTE3MTI1NjM3WjBJ
MQkwBwYDVQQGEwAxCTAHBgNVBAgTADEJMAcGA1UEBxMAMQkwBwYDVQQKEwAxCTAH
BgNVBAsTADEQMA4GA1UEAxMHdGVzdHNjcjBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABD28s78rF8+X1JWgkQcfHB2Gy20MCT51Oue6eG5ZbPsUKlZrPx0aRX0einL2
E5WsE3st0zI4yvj0KzhdEwksCWCjITAfMB0GA1UdDgQWBBRtCEWMjEr+bnXoAqSC
fjmk1btJQDAKBggqhkjOPQQDAgNIADBFAiAAiMtQXgCMUxrKtaPKvGqllswi1FRU
h1brCAbJ1t81FgIhAMXbzmeJlA7/zxZDULLRW0rCY6CU3KMDHr8N38EmuDug
-----END CERTIFICATE-----
</code></pre><p>公钥证书的表示是遵循Privacy Enhanced Mail(PEM)协议(定义在<a href="https://datatracker.ietf.org/doc/html/rfc7468">RFC 7468</a>)的文本文件,其格式如下:</p><p><img src="https://p0.meituan.net/meituantechblog/4a90e7be57a8255b5922cc634926f72a52454.png" alt="" referrerpolicy="no-referrer"></p><p>PEM 文件的label用于指示文件的内容类型。以下是一些常见的 PEM header和footer(后面会陆续见到):</p><p><img src="https://p0.meituan.net/meituantechblog/875082d625dabf269d4b36658138fe24134936.png" alt="" referrerpolicy="no-referrer"></p><p>解析具体公钥证书信息可以采用如下命令(将公钥证书以文本的形式保存为my.pem文件):</p><pre><code>openssl x509 -in my.pem -text -noout
</code></pre><p>解析得到如下输出(重要部分加了注释):</p><pre><code>Certificate:
Data:
Version: 3 (0x2) //证书的版本号
Serial Number: 2913163237517564203 (0x286da287a8f6192b) //证书的序列号,用于唯一标识证书
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = , ST = , L = , O = , OU = , CN = testscr //证书颁发者的信息
Validity
Not Before: Sep 23 12:56:37 2024 GMT //证书的开始有效期
Not After : Sep 17 12:56:37 2049 GMT //证书的结束有效期
Subject: C = , ST = , L = , O = , OU = , CN = testscr //证书持有者的信息
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey //公钥算法,这里是椭圆曲线
Public-Key: (256 bit) //公钥的位数,这里是256
pub:// 证书持有者的公钥值,以十六进制表示
04:3d:bc:b3:bf:2b:17:cf:97:d4:95:a0:91:07:1f:
1c:1d:86:cb:6d:0c:09:3e:75:3a:e7:ba:78:6e:59:
6c:fb:14:2a:56:6b:3f:1d:1a:45:7d:1e:8a:72:f6:
13:95:ac:13:7b:2d:d3:32:38:ca:f8:f4:2b:38:5d:
13:09:2c:09:60
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Subject Key Identifier: //证书持有者的标识
6D:08:45:8C:8C:4A:FE:6E:75:E8:02:A4:82:7E:39:A4:D5:BB:49:40
Signature Algorithm: ecdsa-with-SHA256
Signature Value: //证书的数字签名值
30:45:02:20:00:88:cb:50:5e:00:8c:53:1a:ca:b5:a3:ca:bc:
6a:a5:96:cc:22:d4:54:54:87:56:eb:08:06:c9:d6:df:35:16:
02:21:00:c5:db:ce:67:89:94:0e:ff:cf:16:43:50:b2:d1:5b:
4a:c2:63:a0:94:dc:a3:03:1e:bf:0d:df:c1:26:b8:3b:a0
</code></pre><p>公钥信息(包括公钥算法、公钥位数、公钥值等)属于结构化数据并且较长,不利于识别和比较,所以需要用一个简短的字符串来标识公钥唯一性。常用做法是使用公钥指纹(Public Key Pin,也叫公钥Pin),计算方式是对DER编码的公钥进行SHA-256计算并进行Base64编码。</p><p>这里需要注意的是,在X509扩展字段里包括了Subject Key Identifier(SKID)字段,也是证书持有者的标识。那标识公钥的唯一性为什么不直接使用证书里自带的SKID,还要自己算一遍呢,根据<a href="https://tech.meituan.com/2025/01/06/hihu.com/org/mei-tuan-dian-ping-ji-shu-tuan-dui/activities">RFC 3280-4.2.1.2</a>章节中对SKID的定义:</p><blockquote><p>For CA certificates, subject key identifiers SHOULD be derived from the public key or a method that generates unique values.</p><p>Two common methods for generating key identifiers from the public key are:</p><p>(1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the value of the BIT STRING subjectPublicKey (excluding the tag, length, and number of unused bits).</p><p>(2) The keyIdentifier is composed of a four bit type field with the value 0100 followed by the least significant 60 bits of the SHA-1 hash of the value of the BIT STRING subjectPublicKey (excluding the tag, length, and number of unused bit string bits).</p></blockquote><p>SKID的计算可以通过公钥得到,但计算方式并不唯一,也可以通过任意的算法得到,只要保证唯一性就可以了。定义里推荐了两种基于SHA-1的算法,openssl采用的算法(详见<a href="https://github.com/openssl/openssl/blob/master/crypto/x509/v3_skid.c">v3_skid.c的ossl_x509_pubkey_hash</a>函数)是对DER编码的公钥进行SHA-1计算。</p><p>如果采用SKID来进行公钥的唯一性校验,那么攻击者可以伪造一个证书,里面的SKID和你的一样(SHA-1碰撞,或者直接照抄一下也行),这样的证书也是合法的,就可以轻易绕过对公钥的校验。所以SKID一般只用于在证书链中寻找父子关系,并不用于公钥的唯一性标识。另外,还有Authority Key Identifier(AKID)字段用于标识证书的颁发者。当验证一个证书链时,验证程序会检查每个证书的AKID和上一个证书的SKID是否匹配,确保它们形成一个连续的信任链。</p><p>使用如下命令可以从PEM协议的公钥证书中提取PEM协议的公钥:</p><pre><code>openssl x509 -in my.pem -pubkey -noout
</code></pre><p>输出如下:</p><pre><code>-----BEGIN PUBLIC KEY----- //公钥标头
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE95zFs5cFHauzIYEuuw3g2R75a1ir
qEW0JWP9qAKkyVCizN0nnzcn/Fo5oeSZR1iPUnJvjlnpNvZL9BcQbLqa7g==
-----END PUBLIC KEY-----
</code></pre><p>使用如下命令可以继续转换成DER编码并计算SHA-256和Base64编码:</p><pre><code>openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
</code></pre><p>所以结合使用如下命令可以直接从符合PEM协议的公钥证书文件中得到对应的公钥指纹:</p><pre><code>openssl x509 -in my.pem -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
</code></pre><p>最终笔者示例的公钥证书计算得到的公钥指纹为:</p><pre><code>fzyRjPvTPElBAj0VlYlVA74M3RMtUh5ljKbOYf1NDA0=
</code></pre><p><strong>② 生成证书签名请求</strong></p><p>同样通过DevEco-Studio可以直接生成证书签名请求Certificate Signing Request(CSR)文件(详见<a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-signing-V5#section462703710326">具体操作步骤</a>)。得到的CSR内容示例如下:</p><pre><code>-----BEGIN NEW CERTIFICATE REQUEST----- //CSR标头
MIIBMzCB2wIBADBJMQkwBwYDVQQGEwAxCTAHBgNVBAgTADEJMAcGA1UEBxMAMQkw
BwYDVQQKEwAxCTAHBgNVBAsTADEQMA4GA1UEAxMHdGVzdHNjcjBZMBMGByqGSM49
AgEGCCqGSM49AwEHA0IABD28s78rF8+X1JWgkQcfHB2Gy20MCT51Oue6eG5ZbPsU
KlZrPx0aRX0einL2E5WsE3st0zI4yvj0KzhdEwksCWCgMDAuBgkqhkiG9w0BCQ4x
ITAfMB0GA1UdDgQWBBRtCEWMjEr+bnXoAqSCfjmk1btJQDAKBggqhkjOPQQDAgNH
ADBEAiAlzkRf0AHKh59/deFGo/4JHQRSbw6P+Q7qsiiMMWHT7wIgGugWrCm7tFLh
mRjEEyJNOpen9kfhyOanSRrwtBlEFc0=
-----END NEW CERTIFICATE REQUEST-----
</code></pre><p>生成的CSR文件是标准的PKCS#10格式(定义在<a href="https://datatracker.ietf.org/doc/html/rfc2986">RFC 2986</a>),用于向证书颁发机构(CA)请求签发数字证书的文件,包含申请者的公钥和一些身份信息,这些信息将包含在颁发的证书中。可以看到CSR文件也是遵循PEM协议的,可以如下命令解析CSR文件的内容(保存为my.csr文件):</p><pre><code>openssl req -text -noout -verify -in my.csr
</code></pre><p>输出示例(重要部分加了注释):</p><pre><code>Certificate request self-signature verify OK //表明CSR的自签名已成功验证
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = , ST = , L = , O = , OU = , CN = testscr //证书申请者的信息
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub: //证书申请者的公钥值,和上面my.pem里的公钥值相同
04:3d:bc:b3:bf:2b:17:cf:97:d4:95:a0:91:07:1f:
1c:1d:86:cb:6d:0c:09:3e:75:3a:e7:ba:78:6e:59:
6c:fb:14:2a:56:6b:3f:1d:1a:45:7d:1e:8a:72:f6:
13:95:ac:13:7b:2d:d3:32:38:ca:f8:f4:2b:38:5d:
13:09:2c:09:60
ASN1 OID: prime256v1
NIST CURVE: P-256
Attributes:
Requested Extensions:
X509v3 Subject Key Identifier: //证书申请者的标识
6D:08:45:8C:8C:4A:FE:6E:75:E8:02:A4:82:7E:39:A4:D5:BB:49:40
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:44:02:20:25:ce:44:5f:d0:01:ca:87:9f:7f:75:e1:46:a3:
fe:09:1d:04:52:6f:0e:8f:f9:0e:ea:b2:28:8c:31:61:d3:ef:
02:20:1a:e8:16:ac:29:bb:b4:52:e1:99:18:c4:13:22:4d:3a:
97:a7:f6:47:e1:c8:e6:a7:49:1a:f0:b4:19:44:15:cd
</code></pre><p>注意到其中证书申请者的公钥值和上面p12文件中的公钥值是一样的,说明CSR中包含了我们的公钥信息。使用如下命令也可以直接从CSR文件中得到公钥指纹:</p><pre><code>openssl req -in my.csr -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
</code></pre><p>示例生成的CSR计算得到的公钥指纹为:</p><pre><code>fzyRjPvTPElBAj0VlYlVA74M3RMtUh5ljKbOYf1NDA0=
</code></pre><p>和通过公钥证书计算得到的公钥指纹相同。</p><p><strong>③ 生成开发者签名叶子证书</strong></p><p>证书的作用可以抽象概括为:</p><blockquote><p>颁发者(Issuer)说:持有者(Subject)的公钥是某某某。</p></blockquote><p>证书一般分为三级:根证书(Root Certificate)、中间证书(Intermediate Certificate)、叶子证书(Leaf Certificate)。</p><ul><li>叶子证书由中间证书颁发(即叶子证书的Issuer+AKID和中间证书的Subject+SKID相同)</li><li>中间证书由根证书颁发(即中间证书的Issuer+AKID和根证书的Subject+SKID相同)</li><li>根证书由自己颁发(也就是自签名,根证书的Issuer和Subject相同)</li></ul><p><img src="https://p0.meituan.net/meituantechblog/f84d81562441e05423584a1a9ef00f3286955.png" alt="" referrerpolicy="no-referrer"></p><p>我们需要的是用于给我们App签名的开发者签名叶子证书,这需要华为的开发者签名中间证书来帮我们颁发。叶子证书分为调试证书和发布证书,我们以发布证书为例(详见具体<a href="https://developer.huawei.com/consumer/cn/doc/app/agc-help-add-releasecert-0000001946273961">操作步骤</a>):</p><p><img src="https://p0.meituan.net/meituantechblog/abad5af520a234c6c0504606541e3e90229818.png" alt="" referrerpolicy="no-referrer"></p><p>需要上传我们的CSR文件,得到的证书文件内容示例如下:</p><pre><code>-----BEGIN CERTIFICATE-----
MIICGjCCAaGgAwIBAgIIShhpn519jNAwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE
AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjAzMDQzOVoXDTQ5MDMx
NjAzMDQzOVowUzELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEeMBwGA1UEAwwVSHVhd2VpIENCRyBSb290IENBIEcyMHYw
EAYHKoZIzj0CAQYFK4EEACIDYgAEWidkGnDSOw3/HE2y2GHl+fpWBIa5S+IlnNrs
GUvwC1I2QWvtqCHWmwFlFK95zKXiM8s9yV3VVXh7ivN8ZJO3SC5N1TCrvB2lpHMB
wcz4DA0kgHCMm/wDec6kOHx1xvCRo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
AQH/BAUwAwEB/zAdBgNVHQ4EFgQUo45a9Vq8cYwqaiVyfkiS4pLcIAAwCgYIKoZI
zj0EAwMDZwAwZAIwMypeB7P0IbY7c6gpWcClhRznOJFj8uavrNu2PIoz9KIqr3jn
BlBHJs0myI7ntYpEAjBbm8eDMZY5zq5iMZUC6H7UzYSix4Uy1YlsLVV738PtKP9h
FTjgDHctXJlC5L7+ZDY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDATCCAoigAwIBAgIIXmuDXbWpOB8wCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE
AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDcwOTAyMDQyNFoXDTMwMDcw
NzAyMDQyNFowYjELMAkGA1UEBgwCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEtMCsGA1UEAwwkSHVhd2VpIENCRyBEZXZlbG9wZXIgUmVs
YXRpb25zIENBIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE65LdoIZh1hlpZ2gP
bJ6gPhHsvYSRe22KETgdqeVeYnrbRHI9wsPT6RGYS+pU4mPl6wxzgDMqN6SY/BoZ
luhkE1PzaHoPoNIWIq0O33hpyKyyYwAacIUEjYurkw1E9r9no4IBGDCCARQwHwYD
VR0jBBgwFoAUo45a9Vq8cYwqaiVyfkiS4pLcIAAwHQYDVR0OBBYEFNtek7Ij6NDk
/nF6Zumkc0dbf/NeMEYGA1UdIAQ/MD0wOwYEVR0gADAzMDEGCCsGAQUFBwIBFiVo
dHRwOi8vY3BraS1jYXdlYi5odWF3ZWkuY29tL2Nwa2kvY3BzMBIGA1UdEwEB/wQI
MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMGYGA1UdHwRfMF0wW6BZoFeGVWh0dHA6
Ly9jcGtpLWNhd2ViLmh1YXdlaS5jb20vY3BraS9zZXJ2bGV0L2NybEZpbGVEb3du
LmNybD9jZXJ0eXBlPTEwJi9yb290X2cyX2NybC5jcmwwCgYIKoZIzj0EAwMDZwAw
ZAIwWO1X5q2MdfpR1Q237GpUHGbL1C13rGyFg2p3AYo44FpZ2/A9ss0wOHKM4KDl
ZPqdAjBLkf8NPZy7KVog98+iCTLq35DJ2ZVxkCxknA9YhiHVyXf4HPm4JlT7rW7o
Q+FzM3c=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICujCCAkGgAwIBAgIOY8ui/vvwxqFf+kFokYUwCgYIKoZIzj0EAwMwYjELMAkG
A1UEBgwCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEt
MCsGA1UEAwwkSHVhd2VpIENCRyBEZXZlbG9wZXIgUmVsYXRpb25zIENBIEcyMB4X
DTI0MDkyMzEyNTgwNFoXDTI3MDkyMzEyNTgwNFowazELMAkGA1UEBhMCQ04xDzAN
BgNVBAoMBuW8oOaZqDEcMBoGA1UECwwTMTI4OTY3Njc4NjA2NTQ5NDk3NzEtMCsG
A1UEAwwk5byg5pmoKDEyODk2NzY3ODYwNjU0OTQ5NzcpXCxSZWxlYXNlMFkwEwYH
KoZIzj0CAQYIKoZIzj0DAQcDQgAEPbyzvysXz5fUlaCRBx8cHYbLbQwJPnU657p4
blls+xQqVms/HRpFfR6KcvYTlawTey3TMjjK+PQrOF0TCSwJYKOB0TCBzjAMBgNV
HRMBAf8EAjAAMFkGA1UdHwRSMFAwTqBMoEqGSGh0dHA6Ly9oNWhvc3RpbmctZHJj
bi5kYmFua2Nkbi5jbi9jY2g1L2NybC9oZHJjYWcyL0h1YXdlaUNCR0hEUkcyY3Js
LmNybDAfBgNVHSMEGDAWgBTbXpOyI+jQ5P5xembppHNHW3/zXjAdBgNVHQ4EFgQU
bQhFjIxK/m516AKkgn45pNW7SUAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
CCsGAQUFBwMDMAoGCCqGSM49BAMDA2cAMGQCMFzNlsafNs7ad5xelZOzCebdRofE
VaQZJW0o5QAdTX0t9Ij1o/zUm0bXIf8ZZTJLYgIwKuuZu+LeLCLZJFEM7tYKDhIK
TegCiesP1THuMgiZhZYOYl1kIZBPVrEB8O1wtxEm
-----END CERTIFICATE-----
</code></pre><p>可以看到叶子证书文件里也包括了中间证书和根证书,分别解析证书信息如下:</p><p>根证书:</p><pre><code>Certificate:
Data:
Version: 3 (0x2)
Serial Number: 5339133492510690512 (0x4a18699f9d7d8cd0)
Signature Algorithm: ecdsa-with-SHA384
Issuer: C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
Validity
Not Before: Mar 16 03:04:39 2020 GMT
Not After : Mar 16 03:04:39 2049 GMT
Subject: C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
04:5a:27:64:1a:70:d2:3b:0d:ff:1c:4d:b2:d8:61:
e5:f9:fa:56:04:86:b9:4b:e2:25:9c:da:ec:19:4b:
f0:0b:52:36:41:6b:ed:a8:21:d6:9b:01:65:14:af:
79:cc:a5:e2:33:cb:3d:c9:5d:d5:55:78:7b:8a:f3:
7c:64:93:b7:48:2e:4d:d5:30:ab:bc:1d:a5:a4:73:
01:c1:cc:f8:0c:0d:24:80:70:8c:9b:fc:03:79:ce:
a4:38:7c:75:c6:f0:91
ASN1 OID: secp384r1
NIST CURVE: P-384
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
A3:8E:5A:F5:5A:BC:71:8C:2A:6A:25:72:7E:48:92:E2:92:DC:20:00
Signature Algorithm: ecdsa-with-SHA384
Signature Value:
30:64:02:30:33:2a:5e:07:b3:f4:21:b6:3b:73:a8:29:59:c0:
a5:85:1c:e7:38:91:63:f2:e6:af:ac:db:b6:3c:8a:33:f4:a2:
2a:af:78:e7:06:50:47:26:cd:26:c8:8e:e7:b5:8a:44:02:30:
5b:9b:c7:83:31:96:39:ce:ae:62:31:95:02:e8:7e:d4:cd:84:
a2:c7:85:32:d5:89:6c:2d:55:7b:df:c3:ed:28:ff:61:15:38:
e0:0c:77:2d:5c:99:42:e4:be:fe:64:36
</code></pre><p>中间证书:</p><pre><code>Certificate:
Data:
Version: 3 (0x2)
Serial Number: 6803676100576229407 (0x5e6b835db5a9381f)
Signature Algorithm: ecdsa-with-SHA384
Issuer: C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
Validity
Not Before: Jul 9 02:04:24 2020 GMT
Not After : Jul 7 02:04:24 2030 GMT
Subject: C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Developer Relations CA G2
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
04:eb:92:dd:a0:86:61:d6:19:69:67:68:0f:6c:9e:
a0:3e:11:ec:bd:84:91:7b:6d:8a:11:38:1d:a9:e5:
5e:62:7a:db:44:72:3d:c2:c3:d3:e9:11:98:4b:ea:
54:e2:63:e5:eb:0c:73:80:33:2a:37:a4:98:fc:1a:
19:96:e8:64:13:53:f3:68:7a:0f:a0:d2:16:22:ad:
0e:df:78:69:c8:ac:b2:63:00:1a:70:85:04:8d:8b:
ab:93:0d:44:f6:bf:67
ASN1 OID: secp384r1
NIST CURVE: P-384
X509v3 extensions:
X509v3 Authority Key Identifier:
A3:8E:5A:F5:5A:BC:71:8C:2A:6A:25:72:7E:48:92:E2:92:DC:20:00
X509v3 Subject Key Identifier:
DB:5E:93:B2:23:E8:D0:E4:FE:71:7A:66:E9:A4:73:47:5B:7F:F3:5E
X509v3 Certificate Policies:
Policy: X509v3 Any Policy
CPS: http://cpki-caweb.huawei.com/cpki/cps
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 CRL Distribution Points:
Full Name:
URI:http://cpki-caweb.huawei.com/cpki/servlet/crlFileDown.crl?certype=10&amp;/root_g2_crl.crl
Signature Algorithm: ecdsa-with-SHA384
Signature Value:
30:64:02:30:58:ed:57:e6:ad:8c:75:fa:51:d5:0d:b7:ec:6a:
54:1c:66:cb:d4:2d:77:ac:6c:85:83:6a:77:01:8a:38:e0:5a:
59:db:f0:3d:b2:cd:30:38:72:8c:e0:a0:e5:64:fa:9d:02:30:
4b:91:ff:0d:3d:9c:bb:29:5a:20:f7:cf:a2:09:32:ea:df:90:
c9:d9:95:71:90:2c:64:9c:0f:58:86:21:d5:c9:77:f8:1c:f9:
b8:26:54:fb:ad:6e:e8:43:e1:73:33:77
</code></pre><p>叶子证书:</p><pre><code>Certificate:
Data:
Version: 3 (0x2)
Serial Number:
63:cb:a2:fe:fb:f0:c6:a1:5f:fa:41:68:91:85
Signature Algorithm: ecdsa-with-SHA384
Issuer: C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Developer Relations CA G2
Validity
Not Before: Sep 23 12:58:04 2024 GMT
Not After : Sep 23 12:58:04 2027 GMT
Subject: C = CN, O = \E5\BC\A0\E6\99\A8, OU = 1289676786065494977, CN = "\E5\BC\A0\E6\99\A8(1289676786065494977)\\,Release"
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:3d:bc:b3:bf:2b:17:cf:97:d4:95:a0:91:07:1f:
1c:1d:86:cb:6d:0c:09:3e:75:3a:e7:ba:78:6e:59:
6c:fb:14:2a:56:6b:3f:1d:1a:45:7d:1e:8a:72:f6:
13:95:ac:13:7b:2d:d3:32:38:ca:f8:f4:2b:38:5d:
13:09:2c:09:60
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 CRL Distribution Points:
Full Name:
URI:http://h5hosting-drcn.dbankcdn.cn/cch5/crl/hdrcag2/HuaweiCBGHDRG2crl.crl
X509v3 Authority Key Identifier:
DB:5E:93:B2:23:E8:D0:E4:FE:71:7A:66:E9:A4:73:47:5B:7F:F3:5E
X509v3 Subject Key Identifier:
6D:08:45:8C:8C:4A:FE:6E:75:E8:02:A4:82:7E:39:A4:D5:BB:49:40
X509v3 Key Usage: critical
Digital Signature
X509v3 Extended Key Usage:
Code Signing
Signature Algorithm: ecdsa-with-SHA384
Signature Value:
30:64:02:30:5c:cd:96:c6:9f:36:ce:da:77:9c:5e:95:93:b3:
09:e6:dd:46:87:c4:55:a4:19:25:6d:28:e5:00:1d:4d:7d:2d:
f4:88:f5:a3:fc:d4:9b:46:d7:21:ff:19:65:32:4b:62:02:30:
2a:eb:99:bb:e2:de:2c:22:d9:24:51:0c:ee:d6:0a:0e:12:0a:
4d:e8:02:89:eb:0f:d5:31:ee:32:08:99:85:96:0e:62:5d:64:
21:90:4f:56:b1:01:f0:ed:70:b7:11:26
</code></pre><p>注意到,颁发下来的叶子证书里Subject和我们申请时所使用的CSR里的Subject不同,叶子证书里是:</p><blockquote><p>Subject: C = CN, O = \E5\BC\A0\E6\99\A8, OU = 1289676786065494977, CN = “\E5\BC\A0\E6\99\A8(1289676786065494977)\,Release”</p></blockquote><p>CSR里是:</p><blockquote><p>Subject: C = , ST = , L = , O = , OU = , CN = testscr</p></blockquote><p>说明华为在颁发叶子证书的时候,并没有使用我们CSR里的Subject,而是根据我们在开发者平台网站上登陆的账号信息,对Subject进行了填充。其中OU字段跟账号信息有关(类似iOS的Team ID,但在华为开发者网站上没有找到直接查看的地方)。叶子证书里的公钥信息还是和CSR保持一致,计算得到的公钥指纹也一样。</p><p>另外,华为目前给叶子证书的有效期是3年,3年以后需要续期成新证书。当然,如果续期新证书的时候使用的CSR不变,那么新证书的公钥指纹也依然会保持不变。</p><h3 id="2-2-生成profile文件">2.2 生成Profile文件</h3><p><strong>④ 登记App信息</strong></p><p>这里主要是在华为开发者平台上登记一下App的各项信息,跟着<a href="https://developer.huawei.com/consumer/cn/doc/app/agc-help-harmonyos-releaseapp-0000001914554900">操作步骤</a>来即可:</p><p><img src="https://p0.meituan.net/meituantechblog/9ee43a7228353151f524b9e3487eb817212315.png" alt="" referrerpolicy="no-referrer"></p><p>需要注意的是,包名填写的时候,平台会在线检查一下是否和已经存在的包名有重复(包括其他人申请的包名)。申请成功以后,会分配一个唯一的APP ID:</p><p><img src="https://p0.meituan.net/meituantechblog/bc9c333f2aa419ccedae155d2099144b124038.png" alt="" referrerpolicy="no-referrer"></p><p>这个APP ID用来在网站上标识APP的唯一性。后面文章中会出现类似的名称,为了消除歧义,相似的字段用括号内容区分,这里称为APP ID(网站)。</p><p><strong>⑤ 生成Profile文件</strong></p><p>Profile文件是描述App的包名、签名、申请的权限列表、安装包类型、可安装设备等信息的文件(类似iOS的Provisioning Profile),签名后保存为Cryptographic Message Syntax格式(CMS,扩展的PKCS#7/格式,CMS定义在<a href="https://datatracker.ietf.org/doc/html/rfc5652">RFC 5652</a>,PKCS#7定义在<a href="https://datatracker.ietf.org/doc/html/rfc2315">RFC 2315</a>。)</p><p>跟着<a href="https://developer.huawei.com/consumer/cn/doc/app/agc-help-add-releaseprofile-0000001914714796">操作步骤</a>,选择之前的APP ID(网站)和证书,可以得到对应的Profile文件:</p><p><img src="https://p0.meituan.net/meituantechblog/575ea26ba13ea156416477c136e924f6141731.png" alt="" referrerpolicy="no-referrer"></p><p>Profile也分为发布和调试两种,发布只能选择发布证书,调试只能选择调试证书。这里继续以发布类型为例,生成的Profile文件(保存为my.p7b)被华为签名后, 通过如下命令可以查看里面的所有信息:</p><pre><code>openssl pkcs7 -in my.p7b -print -inform DER
</code></pre><p>主要包括配置信息和签名信息两部分,也可以通过如下命令分别查看配置信息和签名信息:</p><pre><code>openssl smime -verify -in my.p7b -inform DER -noverify //查看配置信息
openssl pkcs7 -in my.p7b -print_certs -inform DER //查看证书信息
</code></pre><p>得到的示例配置信息如下(*为手动打码):</p><pre><code>{
"version-name": "2.0.0",
"version-code": 2,
"app-distribution-type": "app_gallery",
"uuid": "234e1d73-****-****-****-f81e2598d0ff",
"validity": {
"not-before": 1727096284,
"not-after": 1821704284
},
"type": "release",
"bundle-info": {
"developer-id": "300**********7916",
"distribution-certificate": "-----BEGIN CERTIFICATE-----\nMIICujCCAkGgAwIBAgIOY8ui/vvwxqFf+kFokYUwCgYIKoZIzj0EAwMwYjELMAkG\nA1UEBgwCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEt\nMCsGA1UEAwwkSHVhd2VpIENCRyBEZXZlbG9wZXIgUmVsYXRpb25zIENBIEcyMB4X\nDTI0MDkyMzEyNTgwNFoXDTI3MDkyMzEyNTgwNFowazELMAkGA1UEBhMCQ04xDzAN\nBgNVBAoMBuW8oOaZqDEcMBoGA1UECwwTMTI4OTY3Njc4NjA2NTQ5NDk3NzEtMCsG\nA1UEAwwk5byg5pmoKDEyODk2NzY3ODYwNjU0OTQ5NzcpXCxSZWxlYXNlMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAEPbyzvysXz5fUlaCRBx8cHYbLbQwJPnU657p4\nblls+xQqVms/HRpFfR6KcvYTlawTey3TMjjK+PQrOF0TCSwJYKOB0TCBzjAMBgNV\nHRMBAf8EAjAAMFkGA1UdHwRSMFAwTqBMoEqGSGh0dHA6Ly9oNWhvc3RpbmctZHJj\nbi5kYmFua2Nkbi5jbi9jY2g1L2NybC9oZHJjYWcyL0h1YXdlaUNCR0hEUkcyY3Js\nLmNybDAfBgNVHSMEGDAWgBTbXpOyI+jQ5P5xembppHNHW3/zXjAdBgNVHQ4EFgQU\nbQhFjIxK/m516AKkgn45pNW7SUAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG\nCCsGAQUFBwMDMAoGCCqGSM49BAMDA2cAMGQCMFzNlsafNs7ad5xelZOzCebdRofE\nVaQZJW0o5QAdTX0t9Ij1o/zUm0bXIf8ZZTJLYgIwKuuZu+LeLCLZJFEM7tYKDhIK\nTegCiesP1THuMgiZhZYOYl1kIZBPVrEB8O1wtxEm\n-----END CERTIFICATE-----\n",
"bundle-name": "com.***.test",
"apl": "normal",
"app-feature": "hos_normal_app",
"app-identifier": "576************2509"
},
"baseapp-info": {},
"permissions": {},
"acls": {},
"issuer": "app_gallery"
}
</code></pre><p>具体每个字段的含义可以参考<a href="https://gitee.com/openharmony/docs/blob/OpenHarmony-v5.0.0-Release/zh-cn/application-dev/security/app-provision-structure.md">官方文档</a>和<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/provision/provision_verify.cpp">源码中的定义</a>,其中重点字段解析如下:</p><p><img src="https://p0.meituan.net/meituantechblog/9ec3fb6ceb8499af8b70cb9ed6c58853311182.png" alt="" referrerpolicy="no-referrer"></p><p>得到的示例证书内容如下:</p><pre><code>subject=C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
issuer=C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
-----BEGIN CERTIFICATE-----
MIICGjCCAaGgAwIBAgIIShhpn519jNAwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE
AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjAzMDQzOVoXDTQ5MDMx
NjAzMDQzOVowUzELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEeMBwGA1UEAwwVSHVhd2VpIENCRyBSb290IENBIEcyMHYw
EAYHKoZIzj0CAQYFK4EEACIDYgAEWidkGnDSOw3/HE2y2GHl+fpWBIa5S+IlnNrs
GUvwC1I2QWvtqCHWmwFlFK95zKXiM8s9yV3VVXh7ivN8ZJO3SC5N1TCrvB2lpHMB
wcz4DA0kgHCMm/wDec6kOHx1xvCRo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
AQH/BAUwAwEB/zAdBgNVHQ4EFgQUo45a9Vq8cYwqaiVyfkiS4pLcIAAwCgYIKoZI
zj0EAwMDZwAwZAIwMypeB7P0IbY7c6gpWcClhRznOJFj8uavrNu2PIoz9KIqr3jn
BlBHJs0myI7ntYpEAjBbm8eDMZY5zq5iMZUC6H7UzYSix4Uy1YlsLVV738PtKP9h
FTjgDHctXJlC5L7+ZDY=
-----END CERTIFICATE-----
subject=C = CN, O = Huawei, OU = HOS AppGallery, CN = HOS Profile Management
issuer=C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Software Signing Service CA
-----BEGIN CERTIFICATE-----
MIIC7TCCAnOgAwIBAgIIV5nKqt2oGmwwCgYIKoZIzj0EAwMwZDELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEvMC0GA1UE
AwwmSHVhd2VpIENCRyBTb2Z0d2FyZSBTaWduaW5nIFNlcnZpY2UgQ0EwHhcNMjMw
NDI0MDYyNjMxWhcNMjgwNDI0MDYyNjMxWjBYMQswCQYDVQQGDAJDTjEPMA0GA1UE
CgwGSHVhd2VpMRcwFQYDVQQLDA5IT1MgQXBwR2FsbGVyeTEfMB0GA1UEAwwWSE9T
IFByb2ZpbGUgTWFuYWdlbWVudDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDdY
3RoPqb6WD8UpXJiavZLN48iamektKUKZHFl9xwr1Siu77z3lI86cREa3Flw50uKc
xkMNKM4FWBRMd3CDhI+jggEZMIIBFTAfBgNVHSMEGDAWgBT69fe+IFZdXdTabfEU
FTwdCduyNDAdBgNVHQ4EFgQU0a99kztpYeCetotz0YIduJ2I2VcwRgYDVR0gBD8w
PTA7BgRVHSAAMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly9wa2kuY29uc3VtZXIuaHVh
d2VpLmNvbS9jYS9jcHMwDgYDVR0PAQH/BAQDAgeAMEwGA1UdHwRFMEMwQaA/oD2G
O2h0dHA6Ly9wa2kuY29uc3VtZXIuaHVhd2VpLmNvbS9jYS9jcmwvc29mdF9zaWdu
X3Nydl9jcmwuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBgGDCsGAQQBj1sCgngB
AwQIMAYCAQEKAQEwCgYIKoZIzj0EAwMDaAAwZQIwRYOlQ6Qq2SF8LHQ78xpNYh47
zMemerx5oG4F6Uq/3ARPfowvdrEu5Ss+njPMG0FFAjEA0s7YhO7Ktm60mkuHuxQS
46fqIHh/PAPJ2ozg1yDSD771bAGn7mDeGjaAFXEtKzU5
-----END CERTIFICATE-----
subject=C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Software Signing Service CA
issuer=C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
-----BEGIN CERTIFICATE-----
MIIDADCCAoegAwIBAgIIJGDixWQS3MkwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE
AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjEyMzIzOVoXDTQwMDMx
NjEyMzIzOVowZDELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEvMC0GA1UEAwwmSHVhd2VpIENCRyBTb2Z0d2FyZSBTaWdu
aW5nIFNlcnZpY2UgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASsEz7cwYkzFh9b
xIwKfXx5qHGjl5WITy0teGnNWqv+jYCceeixHqErvK7YRn2hVPIqhRqKWeANHZUK
G0qxi+NIpmSmQS8/63CLz1QAcxfv2Xl3/V82dF0v9lm16ehMsN+jggEVMIIBETAf
BgNVHSMEGDAWgBSjjlr1WrxxjCpqJXJ+SJLiktwgADAdBgNVHQ4EFgQU+vX3viBW
XV3U2m3xFBU8HQnbsjQwDwYDVR0TAQH/BAUwAwEB/zBGBgNVHSAEPzA9MDsGBFUd
IAAwMzAxBggrBgEFBQcCARYlaHR0cDovL2Nwa2ktY2F3ZWIuaHVhd2VpLmNvbS9j
cGtpL2NwczAOBgNVHQ8BAf8EBAMCAQYwZgYDVR0fBF8wXTBboFmgV4ZVaHR0cDov
L2Nwa2ktY2F3ZWIuaHVhd2VpLmNvbS9jcGtpL3NlcnZsZXQvY3JsRmlsZURvd24u
Y3JsP2NlcnR5cGU9MTAmL3Jvb3RfZzJfY3JsLmNybDAKBggqhkjOPQQDAwNnADBk
AjBrAQQxUlNgqhYkcEm5eksnPxDkPJSY/qNd2BDgbvEydiLwPSvB7Z9lipxz8ikZ
EeUCMGppWcaV//SIG1y5tEwthLwWeEaF613vUILWQLir8+CA3RZGsRBqtE8xSqfz
yafLYQ==
-----END CERTIFICATE-----
</code></pre><p>这里依然是完整的三级证书链,注意,根证书和之前申请到的开发者签名证书的根证书一样,但中间证书和叶子证书均不一样,比较如下(红色底色表示内容相同):</p><p><img src="https://p0.meituan.net/meituantechblog/83ab59e0e7296e818531e3ca03010f13173401.png" alt="" referrerpolicy="no-referrer"></p><h3 id="2-3-生成签名的app">2.3 生成签名的App</h3><p><strong>⑥ 得到签名的App包</strong></p><p>将生成的Profile文件、叶子证书文件等配置到项目的signingConfigs里,使用华为的IDE可以直接得到签名后的App包:</p><p><img src="https://p0.meituan.net/meituantechblog/e305f605163fc00e1ba613f4ed6ea230147135.png" alt="" referrerpolicy="no-referrer"></p><p>或者<a href="https://gitee.com/openharmony/developtools_hapsigner#%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E">参考命令</a>手动给未签名的App包进行签名。</p><p>得到的签名的App包只是用于提供给华为商店进行审核和后续的拆包,并不能直接安装到手机上运行。App包实际上就是标准的ZIP格式,可以修改后缀为.zip进行解压:</p><p><img src="https://p0.meituan.net/meituantechblog/8283faf0944d27fe295b9ff2286828a021855.png" alt="" referrerpolicy="no-referrer"></p><p>可以看到里面包括了.hap包和描述App一些信息的pack.info文件。</p><p>那么对App包进行签名的内容以及Profile文件在哪里呢?根据对源码里<a href="https://gitee.com/openharmony/developtools_hapsigner/blob/OpenHarmony-v5.0.0-Release/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/VerifyHap.java">VerifyHap.java类的verifyHap</a>函数进行分析,发现鸿蒙上的签名机制类似Android V3,签名信息和Profile文件存储在自定义的HapSigningBlock区,放到了ZIP格式Central Directory区的前面,其结构如下:</p><p><img src="https://p0.meituan.net/meituantechblog/575288d443290509f33b9961fc456897119046.png" alt="" referrerpolicy="no-referrer"></p><p>HapSigningBlock区的魔数(转成string也就是<hap sign="" block="">):</hap></p><pre><code> /**
* The value of lower 8 bytes of magic word
*/
public static final long HAP_SIG_BLOCK_MAGIC_LO_V3 = 0x676973207061683cL;
/**
* The value of higher 8 bytes of magic word
*/
public static final long HAP_SIG_BLOCK_MAGIC_HI_V3 = 0x3e6b636f6c62206eL;
/**
* Size of hap signature block header
*/
public static final int HAP_SIG_BLOCK_HEADER_SIZE = 32;
</code></pre><p>通过hex工具直接打开App包也可以在Central Directory区前面找到:</p><p><img src="https://p0.meituan.net/meituantechblog/fb9e6953eba868a5f42bc5bb0d8b2c0b87714.png" alt="" referrerpolicy="no-referrer"></p><p>其中SignatureSchemeBlock区存放了CMS格式的Hap包签名信息,而Profile文件就存储在SigningBlock区,Type是0x20000002:</p><pre><code> /**
* ID of profile block
*/
public static final int HAP_PROFILE_BLOCK_ID = 0x20000002;
</code></pre><p>通过如下<a href="https://gitee.com/openharmony/developtools_hapsigner/tree/OpenHarmony-v5.0.0-Release/dist">hap-sign-tool.jar</a>的命令可以导出存储在App包或Hap包里的签名证书和Profile文件:</p><pre><code>java -jar hap-sign-tool.jar verify-app -inFile my-signed.app -outCertChain my-signed.cer -outProfile my-signed.p7b
</code></pre><p><strong>⑦ 签名校验、拆包、重签名</strong></p><p>提供给华为应用市场审核的App包在经过签名校验,确认是开发者的应用以及应用的完整性以后,华为会取出App包SigningBlock区的Profile文件,解压出Hap包,把Profile文件或Profile文件内的配置(下一章节展开描述区别)重新放到Hap包的SigningBlock区里,并用Hap的签名叶子证书对Hap包进行重新签名,签名方式和给App包签名一样。最终真正<strong>通过应用市场下发到手机上的是经过重签名的Hap包(类似iOS的双层签名机制)</strong>。解析出签名证书如下:</p><pre><code>CN=HOS AppGallery Application Release, OU=HOS AppGallery, O=Huawei, C=CN
-----BEGIN CERTIFICATE-----
MIIC+TCCAn+gAwIBAgIIWXsBFAJOQzIwCgYIKoZIzj0EAwMwZDELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEvMC0GA1UE
AwwmSHVhd2VpIENCRyBTb2Z0d2FyZSBTaWduaW5nIFNlcnZpY2UgQ0EwHhcNMjMw
NDI0MDYyMjA1WhcNMjgwNDI0MDYyMjA1WjBkMQswCQYDVQQGDAJDTjEPMA0GA1UE
CgwGSHVhd2VpMRcwFQYDVQQLDA5IT1MgQXBwR2FsbGVyeTErMCkGA1UEAwwiSE9T
IEFwcEdhbGxlcnkgQXBwbGljYXRpb24gUmVsZWFzZTBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABIokjn9tVRpgEC6b1AR9chiiejUGBiF83Lzm1giyZX9XKVzTPkHq
RRuML+zhRtT1JESEMOUggPyJbe9+rt3k9CijggEZMIIBFTAfBgNVHSMEGDAWgBT6
9fe+IFZdXdTabfEUFTwdCduyNDAdBgNVHQ4EFgQUFzRtDLYZ7zX/idRsHYmJZ734
vwgwRgYDVR0gBD8wPTA7BgRVHSAAMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly9wa2ku
Y29uc3VtZXIuaHVhd2VpLmNvbS9jYS9jcHMwDgYDVR0PAQH/BAQDAgeAMEwGA1Ud
HwRFMEMwQaA/oD2GO2h0dHA6Ly9wa2kuY29uc3VtZXIuaHVhd2VpLmNvbS9jYS9j
cmwvc29mdF9zaWduX3Nydl9jcmwuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBgG
DCsGAQQBj1sCgngBAwQIMAYCAQEKAQAwCgYIKoZIzj0EAwMDaAAwZQIxAJofyGQW
4ZVDW64qTeiVQVn5w7iRhejP6YFqYX9h/5mNXKMQ8ZuQCFT7EaqhVblWlQIwWIPB
xC+YhPz6JmDMSZDynZINnXi0T3k9UvbcCybbd2k2PWHYvYqQdKAuYGcNc2Ho
-----END CERTIFICATE-----
CN=Huawei CBG Software Signing Service CA, OU=Huawei CBG, O=Huawei, C=CN
-----BEGIN CERTIFICATE-----
MIIDADCCAoegAwIBAgIIJGDixWQS3MkwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE
AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjEyMzIzOVoXDTQwMDMx
NjEyMzIzOVowZDELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEvMC0GA1UEAwwmSHVhd2VpIENCRyBTb2Z0d2FyZSBTaWdu
aW5nIFNlcnZpY2UgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASsEz7cwYkzFh9b
xIwKfXx5qHGjl5WITy0teGnNWqv+jYCceeixHqErvK7YRn2hVPIqhRqKWeANHZUK
G0qxi+NIpmSmQS8/63CLz1QAcxfv2Xl3/V82dF0v9lm16ehMsN+jggEVMIIBETAf
BgNVHSMEGDAWgBSjjlr1WrxxjCpqJXJ+SJLiktwgADAdBgNVHQ4EFgQU+vX3viBW
XV3U2m3xFBU8HQnbsjQwDwYDVR0TAQH/BAUwAwEB/zBGBgNVHSAEPzA9MDsGBFUd
IAAwMzAxBggrBgEFBQcCARYlaHR0cDovL2Nwa2ktY2F3ZWIuaHVhd2VpLmNvbS9j
cGtpL2NwczAOBgNVHQ8BAf8EBAMCAQYwZgYDVR0fBF8wXTBboFmgV4ZVaHR0cDov
L2Nwa2ktY2F3ZWIuaHVhd2VpLmNvbS9jcGtpL3NlcnZsZXQvY3JsRmlsZURvd24u
Y3JsP2NlcnR5cGU9MTAmL3Jvb3RfZzJfY3JsLmNybDAKBggqhkjOPQQDAwNnADBk
AjBrAQQxUlNgqhYkcEm5eksnPxDkPJSY/qNd2BDgbvEydiLwPSvB7Z9lipxz8ikZ
EeUCMGppWcaV//SIG1y5tEwthLwWeEaF613vUILWQLir8+CA3RZGsRBqtE8xSqfz
yafLYQ==
-----END CERTIFICATE-----
</code></pre><p>注意这里给<strong>Hap的签名证书和我们之前申请的开发者签名证书不一样</strong>,Hap签名证书和对应的私钥都是华为的,跟我们的应用没有关系,而且签名证书链里不包含根证书的信息。</p><p>这里再和之前的证书对比一下(红色和黄色底色表示内容分别相同):</p><p><img src="https://p0.meituan.net/meituantechblog/2745ee0de317a237680ed567848101fa267287.png" alt="" referrerpolicy="no-referrer"></p><p>三者的根证书都一样,Profile签名证书和Hap签名证书的中间证书一样,三者的叶子证书均不一样。</p><p>另外,如果在上架应用市场的时候,勾选了加密:</p><p><img src="https://p0.meituan.net/meituantechblog/b23b24b27260692d1e25976a07f16fca188561.png" alt="" referrerpolicy="no-referrer"></p><p>根据《<a href="https://developer.huawei.com/consumer/cn/doc/guidebook/harmonyecoappsecurity-guidebook-0000001808819033">鸿蒙生态应用安全技术白皮书</a>》描述,只是对Hap包里的代码做加密,然后重新签名,所以证书和Profile文件的解析均不受影响。</p><h2 id="3-校验机制">3. 校验机制</h2><p>签名相关的代码在<a href="https://gitee.com/openharmony/security_appverify/tree/OpenHarmony-v5.0.0-Release/">security_appverify</a>仓库里,签名校验流程梳理如下(图上所有判断条件在失败情况下均会导致签名校验失败,为了直观不画出此流程):</p><p><img src="https://p0.meituan.net/meituantechblog/9a02c110d00d5ae9596c3966ec8ca11c377687.png" alt="" referrerpolicy="no-referrer"></p><p>签名校验步骤可以分成三组,分别是:</p><ol><li>SignatureSchemeBlock区校验。</li><li>Profile校验和解析。</li><li>Hap包完整性校验。</li></ol><h3 id="3-1-signatureschemeblock区校验">3.1 SignatureSchemeBlock区校验</h3><p>校验Hap包时首先在ZIP的Central Directory区前32个字节寻找是否有HapSigningBlock区的Header,找到以后定位到SignatureSchemeBlock区,解析其CMS格式,并校验SignatureSchemeBlock区证书链的完整性。证书链完整性校验流程如下:</p><p><img src="https://p0.meituan.net/meituantechblog/2fad2d1c6eea7aa33fbfdcfc0f9bcfdb42777.png" alt="" referrerpolicy="no-referrer"></p><p>校验叶子证书时,需要按证书指定算法重新计算证书的hash,并使用上一级证书(中间证书)的公钥对叶子证书里的证书签名进行解密,与重新计算的hash比对是否相同,相同则认为证书可信。中间证书继续通过根证书的公钥校验自己的证书签名。根证书用自己的公钥校验自己。</p><p>上一章说到,SignatureSchemeBlock区的证书链不包括根证书,所以这一步需要使用到根证书其实是内置在鸿蒙系统里的,存放地址是:</p><pre><code>/system/etc/security/trusted_root_ca.json
</code></pre><p>具体内容如下:</p><pre><code>{
"C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Root CA G2":"-----BEGIN CERTIFICATE-----\nMIICGjCCAaGgAwIBAgIIShhpn519jNAwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC\nQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE\nAwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjAzMDQzOVoXDTQ5MDMx\nNjAzMDQzOVowUzELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE\nCwwKSHVhd2VpIENCRzEeMBwGA1UEAwwVSHVhd2VpIENCRyBSb290IENBIEcyMHYw\nEAYHKoZIzj0CAQYFK4EEACIDYgAEWidkGnDSOw3/HE2y2GHl+fpWBIa5S+IlnNrs\nGUvwC1I2QWvtqCHWmwFlFK95zKXiM8s9yV3VVXh7ivN8ZJO3SC5N1TCrvB2lpHMB\nwcz4DA0kgHCMm/wDec6kOHx1xvCRo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T\nAQH/BAUwAwEB/zAdBgNVHQ4EFgQUo45a9Vq8cYwqaiVyfkiS4pLcIAAwCgYIKoZI\nzj0EAwMDZwAwZAIwMypeB7P0IbY7c6gpWcClhRznOJFj8uavrNu2PIoz9KIqr3jn\nBlBHJs0myI7ntYpEAjBbm8eDMZY5zq5iMZUC6H7UzYSix4Uy1YlsLVV738PtKP9h\nFTjgDHctXJlC5L7+ZDY=\n-----END CERTIFICATE-----\n"
}
</code></pre><p>可以看到这个根证书就是上一章解析出来的根证书,所以这里可以校验通过。</p><p>在确认证书链可信以后,根据叶子证书的Subject判断Hap包的安装来源,具体代码在<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/init/trusted_source_manager.cpp">trusted_source_manager.cpp的MatchTrustedSource函数里</a>,也就是和内置的Hap签名证书列表进行比较,看匹配到哪一个。内置的Hap签名证书列表存放地址是:</p><pre><code>/system/etc/security/trusted_apps_sources.json
</code></pre><p>具体内容如下:</p><pre><code>{
"version": "1.0.1",
"release-time":"2021-06-03 10:06:00",
"trust-app-source":[
{
"name":"huawei app gallery",
"app-signing-cert":"C=CN, O=Huawei, OU=HOS AppGallery, CN=HOS AppGallery Application Release",
"profile-signing-certificate":"C=CN, O=Huawei, OU=HOS AppGallery, CN=HOS Profile Management",
"profile-debug-signing-certificate":"C=CN, O=Huawei, OU=HOS AppGallery, CN=HOS Profile Management Debug",
"issuer-ca":"C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Software Signing Service CA",
"root-ca": "C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Root CA G2",
"max-certs-path":3,
"critialcal-cert-extension":["keyusage","huawei-signing-capability"]
},
{
"name":"huawei system apps",
"app-signing-cert":"C=CN, O=Huawei CBG, OU=HOS Development Team, CN=HOS Application Provision Release",
"profile-signing-certificate":"C=CN, O=Huawei CBG, OU=HOS Development Team, CN=HOS Application Provision Profile Release",
"profile-debug-signing-certificate":"C=CN, O=Huawei CBG, OU=HOS Development Team, CN=HOS Application Provision Profile Release_Debug",
"issuer-ca":"C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Software Signing Service CA",
"root-ca": "C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Root CA G2",
"max-certs-path":3,
"critialcal-cert-extension":["keyusage","huawei-signing-capability"]
},
{
"name":"third_party app preload",
"app-signing-cert":"C=CN, O=Huawei, OU=HOS Open Platform, CN=HOS Preload Service",
"profile-signing-certificate":"",
"profile-debug-signing-certificate":"",
"issuer-ca":"C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Software Signing Service CA",
"root-ca": "C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Root CA G2",
"max-certs-path":3,
"critialcal-cert-extension":["keyusage","huawei-signing-capability"]
}
]
}
</code></pre><p>这里有Huawei App Gallery(应用市场)、Huawei System Apps(系统应用)、Third_party App Preload(三方预装)三组。每一组包括对应的Hap签名证书Subject、Profile签名证书Subject等信息。</p><p>我们走应用市场分发的Hap包会匹配到Huawei App Gallery这个证书。</p><h3 id="3-2-profile解析和校验">3.2 Profile解析和校验</h3><p>接下来在SigningBlock区寻找Profile,这里注意到<strong>不同Hap包签名方式会影响Profile的存储格式</strong>。对于走应用市场分发的Hap包,Profile是直接把其配置以字符串的格式保存,而对于其他情况,则是用CMS的格式保存。那么应用市场分发的Hap包也就不需要Profile的文件签名校验了。</p><p>对于其他情况,首先会使用Profile里保存的叶子证书公钥校验Profile的文件签名,然后会校验叶子证书Subject是否和匹配的同组内Profile签名证书Subject相同。</p><p>校验通过后解析Profile里的配置信息,根据type不同走不同的校验逻辑:</p><ul><li>发布,会校验是否为允许的安装来源,根据<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/verify/hap_verify_v2.cpp">hap_verify_v2.cpp的IsAppDistributedTypeAllowInstall函数</a>,允许的来源包括企业签名、MDM、众包测试等分发场景。</li><li>调试,会校验待安装的设备UDID是否在Profile的device-ids列表中。</li></ul><p>都校验通过后,再继续看Profile文件签名证书和Hap的签名正式是否相同,并继续对Profile配置的字段规则合法性进行检测。走完这一步,就可以认为Profile是可信的。</p><p>随后会生成App ID(公钥)和Fingerprint两个新的字段和验证结果一并返回。其中APP ID(公钥)是根据Profile配置里开发者签名证书公钥生成的(详见<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/verify/hap_verify_v2.cpp">GenerateAppId函数</a>),fingerprint是根据Profile配置里开发者签名证书直接计算整个证书的指纹(注意不是上一章的公钥指纹,详见<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/verify/hap_verify_v2.cpp">GenerateFingerprint</a>函数)。至此完成Profile的解析和校验。</p><p>另外,在鸿蒙<a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-bundlemanager-bundleinfo-V5#signatureinfo">SignatureInfo API</a>中,会返回三个参数:</p><p><img src="https://p0.meituan.net/meituantechblog/1908765069afdf87f4c353952de39790212422.png" alt="" referrerpolicy="no-referrer"></p><p>其中API返回的appId为了消除歧义,这里称为APP ID(接口)。</p><p>根据包管理子系统<a href="https://gitee.com/openharmony/bundlemanager_bundle_framework/blob/OpenHarmony-v5.0.0-Release/services/bundlemgr/src/bundle_install_checker.cpp">bundle_install_checker.cpp的ParseHapFiles函数</a>、<a href="https://gitee.com/openharmony/bundlemanager_bundle_framework/blob/OpenHarmony-v5.0.0-Release/services/bundlemgr/include/inner_bundle_info.h">inner_bundle_info.h的SetProvisionId函数</a>和<a href="https://gitee.com/openharmony/bundlemanager_bundle_framework/pulls/52/files">这个PR</a>来看:</p><pre><code>// bundle_install_checker.cpp
newInfo.SetProvisionId(provisionInfo.appId);
// inner_bundle_info.h
void SetProvisionId(const std::string &amp;provisionId)
{
baseBundleInfo_-&gt;appId = baseBundleInfo_-&gt;name + Constants::FILE_UNDERLINE + provisionId;
}
</code></pre><p>APP ID(接口)的值实际上是APP ID(公钥)加上了{bundleName}_的前缀。</p><h3 id="3-3-hap包完整性校验">3.3 Hap包完整性校验</h3><p>这一步的过程和Hap包签名类似,将ZIP包中数据和HapSigningBlock区里非SignatureSchemeBlock的部分拼接,重新计算hash,与使用Hap签名叶子证书公钥解密SignatureSchemeBlock区签名后的hash比较,相同则认为Hap包未被篡改。具体可以参考<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/util/hap_signing_block_utils.cpp">hap_signing_block_utils.cpp的VerifyHapIntegrity函数</a>,这里就不展开了。</p><h2 id="总结">总结</h2><p>从鸿蒙单框架应用的签名和校验机制的种种细节中可以看出,HarmonyOS NEXT的安全设计非常务实,融合了Android和iOS双端的特性,有借鉴Android成熟的部分(签名格式),但更多的是参考了iOS的设计思路(双层签名机制),甚至更加严格。期待HarmonyOS NEXT给我们带来一个新的未来。</p><p>特别感谢华为同学对本文的大力支持。</p></description>
<link>https://tech.meituan.com/2025/01/06/openharmony.html</link>
<guid isPermaLink="false">https://tech.meituan.com/2025/01/06/openharmony.html</guid>
<pubDate>Mon, 06 Jan 2025 00:00:00 GMT</pubDate>
<author>美团技术团队</author>
</item>
<item>
<title>2024 | 美团技术团队热门技术文章汇总</title>
<description><p>岁月的车轮滚滚向前,我们即将挥别充满回忆的2024,迈入崭新的、充满希望的2025。在此,衷心感谢伙伴们过去一年的陪伴与支持。</p><p><img src="https://p0.meituan.net/meituantechblog/b976fc16e0fb9e5060b6049585dabcad249415.jpg" alt="" referrerpolicy="no-referrer"></p><p>今天,我们整理了2024年美团技术团队最为热门的10篇技术文章,这些文章覆盖了基础理论、数据存储、因果推断、搜索推荐、智能测试、知识图谱、领域驱动设计等多个技术领域,期望这些精选内容能为大家带来一些启发或帮助。愿大家在新的一年里,持续深耕技术沃土,稳步前行,不断攀登新的高峰。</p><h2 id="01-基本功-一文讲清多线程和多线程同步">01&nbsp;基本功 | 一文讲清多线程和多线程同步</h2><p><img src="https://p0.meituan.net/meituantechblog/46c434af68b098f65491bb9cc64a176f383178.jpg" alt="" referrerpolicy="no-referrer"></p><p>多线程编程是现代软件开发中的一项关键技术,在多线程编程中,开发者可以将复杂的任务分解为多个独立的线程,使其并行执行,从而充分利用多核处理器的优势。然而,多线程编程也带来了挑战,例如线程同步、死锁和竞态条件等问题。本篇文章将深入探讨多线程编程的基本概念(原子操作、CAS、Lock-free、内存屏障、伪共享、乱序执行等)、常见模式和最佳实践。通过具体的代码示例,希望能够帮助大家掌握多线程编程的核心技术,并在实际开发中应用这些知识,提升软件的性能和稳定性。(<a href="https://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&amp;mid=2651778446&amp;idx=1&amp;sn=44306b644777a4d939730e7774071541&amp;scene=21#wechat_redirect">阅读全文</a>)</p><h2 id="02-ddd在大众点评交易系统演进中的应用">02&nbsp;DDD在大众点评交易系统演进中的应用</h2><p><img src="https://p0.meituan.net/meituantechblog/0365d5c51db9c02682794df240eb7eb7626207.jpg" alt="" referrerpolicy="no-referrer"></p><p>本文整理自美团技术沙龙第73期《基于领域驱动设计(DDD)的架构演进和实践》(<a href="https://www.bilibili.com/video/BV1nt4y1J7hH/?spm_id_from=333.999.0.0&amp;vd_source=aea2a93491bea0d72f7e5b8a79085d70">B站视频</a>),主要介绍了DDD的核心概念、常见的设计思路,并结合DDD介绍大众点评交易系统的演进过程,最后做了一些总结和思考。(<a href="https://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&amp;mid=2651777662&amp;idx=1&amp;sn=22ba8694d0a0d1da7c47b0a6a1367fab&amp;scene=21#wechat_redirect">阅读全文</a>)</p><h2 id="03-美团大规模kv存储挑战与架构实践">03&nbsp;美团大规模KV存储挑战与架构实践</h2><p><img src="https://p0.meituan.net/meituantechblog/01f2c4d5e7f9df82909c160a655a2295822233.jpg" alt="" referrerpolicy="no-referrer"></p><p>KV 存储作为美团一项重要的在线存储服务,承载了在线服务每天万亿级的请求量,并且保持着 99.995% 的服务可用性。文章主要分为四个部分:第一部分介绍了美团 KV 存储发展历程;第二部分分享了内存 KV Squirrel 挑战和架构实践;第三部分阐述了持久化 KV Cellar 挑战和架构实践;最后一部分介绍了未来的发展规划。(<a hre |
TonyRL
reviewed
Feb 17, 2025
Successfully generated as following: http://localhost:1200/meituan/tech - Success ✔️<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>美团技术团队</title>
<link>https://tech.meituan.com/</link>
<atom:link href="http://localhost:1200/meituan/tech" rel="self" type="application/rss+xml"></atom:link>
<description>美团技术团队最近更新内容。 - Powered by RSSHub</description>
<generator>RSSHub</generator>
<webMaster>[email protected] (RSSHub)</webMaster>
<language>zh-cn</language>
<lastBuildDate>Tue, 18 Feb 2025 02:16:30 GMT</lastBuildDate>
<ttl>5</ttl>
<item>
<title>预测技术在美团弹性伸缩场景的探索与应用</title>
<description><blockquote><p>管理企业大规模服务的弹性伸缩场景中,往往会面临着两个挑战:第一个挑战是精准的负载预测,由于应用实例的启动需要一定预热时间,被动响应式伸缩会在一段时间内影响服务质量;第二个挑战是高效的资源分配,即在保障服务质量的同时控制资源成本。为了解决这些挑战,美团基础技术部与中国人民大学信息学院柴云鹏教授团队展开了“预测技术在弹性伸缩场景的应用”科研合作,相关论文《<a href="https://dl.acm.org/doi/10.1145/3589334.3645330">PASS: Predictive Auto-Scaling System for Large-scale Enterprise Web Applications</a>》在具有国际影响力的会议The Web Conference 2024(CCF-A类会议)上作为Research Full Paper发表。</p></blockquote><h2 id="1-背景">1 背景</h2><p>在管理企业大规模服务弹性伸缩的场景下,Web应用的负载时序数据分析和预测至关重要。然而,由于应用的周期性特征和负载的复杂性,寻找一种能够适应所有应用的预测模型成为了一项挑战。首先,应用的负载数据往往具有周期性,这就需要在进行分析和预测时,需要考虑到这种周期性的影响。其次,由于业务特征的差异,预测算法可能在不同的应用下表现出差异化的效果,不存在“one-size-fits-all”的情况。例如,经测试发现,虽然在线模型的预测效果大多数时候好于离线模型,但在一些规律的突增情况下,在线模型经常存在滞后性的问题。这些问题都需要在对应用负载时序数据分析和预测时,进行深入的研究和探讨。</p><p>除了准确的负载预测,还需要高效的弹性伸缩策略。目前,业界常用的弹性伸缩策略有基于规则的阈值法、基于控制论的目标追踪和排队论。然而,我们发现这些方法并不能有效地保障QoS(Quality of Service,服务质量),尤其是QoS包含对尾延迟的要求时,其背后原因是这些策略的性能模型并不准确。阈值法和目标追踪的性能模型是“当QPS或CPU利用率在给定的范围内时QoS达标”。但这些阈值通常是根据人工经验设置的,并不总是准确。排队论根据统计模型推导在给定的负载和资源下业务的延迟,但它依赖的理论假设(例如用户请求到来的分布)并不总在现实中成立,使其估算的延迟和真实值有偏差。我们在测试中也发现了排队论估算的延迟会略低于真实延迟,因而导致出现服务质量不达标。此外,基于AI的弹性伸缩方法例如强化学习并不一定适用企业的生产环境,因为AI模型缺乏一定的可解释性,且可能会在线上做出有QoS违例风险的行为。</p><h2 id="2-探索分析">2 探索分析</h2><h3 id="2-1-预测实验探索">2.1 预测实验探索</h3><p><strong>发现1</strong>:由于预测算法的固有限制,没有一种单一的算法能够在所有类别的时序数据中都提供最佳的预测效果。多样化的预测算法对于美团丰富的业务流量预测更有效。</p><p>我们对美团的服务流量数据进行周期检测(计算ACF自相关系数),发现92.80%的应用表现出强周期性(相关系数大于0.8),4.55% 显示出弱周期性(相关系数介于0.5~0.8之间),只有2.65%的应用没有表现出明显的周期性(相关系数小于0.5)。因此,对于美团内的大多数服务,可以使用模型可靠地预测QPS流量数据。</p><p>我们使用225个美团真实服务流量数据对业界常用的预测算法进行了测试。实验结果表明,预测效果最好的算法并不是单一的,而是取决于业务流量的具体特征。如图1(a)和(b)所示,我们使用三个代表性服务的流量数据来说明周期因子算法(Seasonal index)和 patchTST模型的预测效果。 在图1(a)中,对于服务1,周期因子算法显著优于patchTST,而在图1(b)中,对于服务2,patchTST却又比周期因子预测效果更好。这一实验说明了最优预测算法的动态多样性,我们需要针对业务流量特征选择最合适的预测算法。</p><p><img src="https://p0.meituan.net/meituantechblog/23c7467785e923d95f3e2cba0fd3ec8897661.png" alt="图1 各种预测算法的准确性和鲁棒性对比" referrerpolicy="no-referrer"></p><p><strong>发现2</strong>:在线预测提供了较高的平均预测准确度,但在“突变特征”表现不佳。 相比之下,离线预测可以捕获“突变特征”,但存在明显的“振幅偏差”问题。</p><p>在线预测模型实时地获取最新的数据输入,输出未来一小段时间(如:15分钟)的预测数据。 离线预测模型无需实时数据输入,直接预测未来较长一段时间(如:1天)的预测数据。 由于缺乏最新实时数据的输入,离线模型往往无法达到和在线模型相同的预测准确性。但在一些有规律的突增时间点,离线模型能够捕捉到突变的周期性特征,从而取得“及时”的预测效果。例如,在周期性“突变特征”的情况下,在线模型可能会表现出预测滞后(图1©中的黑色圆圈突出显示)。 这种滞后效应会持续一段时间,我们称之为“脏区间”。</p><p>相反,离线模型有效地捕获这些信息,从而能够及时进行预测。然而,离线模型存在着“振幅偏差”的问题,即特征的形状被准确地表示,但其绝对值存在差异(见图1(d))。“突变特征”在美团服务中尤其普遍,这是由于美团许多业务都存在午、晚流量高峰。虽然“突变特征”只占实际时间序列数据的一小部分,但这些特征的精确预测对于在生产环境中维持QoS至关重要。</p><h3 id="2-2-伸缩方法分析">2.2 伸缩方法分析</h3><p><strong>发现3</strong>:云平台广泛使用的弹性伸缩方法并不能有效保障QoS,特别是当QoS要求对尾延迟的保障时。 与平均响应时间RT相比,当QoS要求为TP999尾延迟时,表1中几种方法的QoS保障率都显著降低。然而,大多数业务应用都需要关于尾延迟的保障,这使得弹性伸缩方法效率并不高,要么接受QoS违例,要么多冗余资源。</p><p><strong>发现4</strong>:这些弹性伸缩方法的性能模型不够准确。基于阈值的规则和目标跟踪背后的性能模型实际上是“当QPS或CPU利用率在一定范围内时QoS达标”。 而这个范围的参数是根据人工经验确定的。表1的结果证明它并不完全有效。另外,排队论因为过于依赖理论假设而不够准确,导致其估计的RT低于真实值,从而出现QoS违例。</p><p><img src="https://p0.meituan.net/meituantechblog/966b1ed55570bbbf64dbe47c07a55680114485.png" alt="表1 三种常见弹性伸缩方法的QoS保障率和资源成本" referrerpolicy="no-referrer"></p><p>目前云平台的常见弹性伸缩方法有以下几种:</p><ul><li><strong>阈值法</strong>:基于一系列包含阈值的规则来进行弹性伸缩。以CPU资源利用率为例,当资源利用率超过上限阈值时,增加资源,反之,当利用率低于下阈值时,减少资源。阈值参数通常凭经验设置。</li><li><strong>目标追踪</strong>:一种基于反馈的控制论方法,将某个指标(例如CPU资源利用率)维持在特定范围内。当实际资源利用率不在设定范围内时,系统会根据当前状态自动计算需要伸缩的实例数量。例如,假设CPU和流量呈线性相关的前提下,当前10个实例的平均CPU资源利用率为80%,目标值为50%,则实例需要扩容为80%*<sup>10</sup>⁄<sub>50</sub>%=16个实例。</li><li><strong>排队论</strong>:根据排队论模型计算性能指标(例如延迟)并进行相应的伸缩以确保QoS达标。常见的𝑀/𝑀/𝑠模型表示请求到达和处理的时间呈指数分布,共有𝑠服务器并行处理。阿里巴巴的弹性伸缩框架AHPA使用排队论作为性能模型。</li><li><strong>强化学习</strong>:弹性伸缩模块充当代理并与环境交互,在每次执行伸缩操作后接收奖励反馈。它通过反复试验建立状态(当前监控指标)和动作(伸缩多少实例)之间的映射模型。</li></ul><p>大部分云平台使用的弹性伸缩方法都是简单或直接的,比如:阈值法、目标跟踪和排队论。强化学习和其他人工智能相关方法使用较少,因为它们可能会影响在线业务的性能。 我们使用若干具有代表性的后端服务测试了常用弹性伸缩方法的QoS保障率。由于我们的主要目的是验证QoS保障率,因此我们使用了阶梯式增加的工作负载。QoS保障率和资源成本的结果如表1所示。QoS保障率是用QoS保障时长除以总时长计算得出的。资源成本由实例数随时间(分钟)的积分得到。</p><h2 id="3-技术方案">3 技术方案</h2><p>为了解决这些问题,我们提出了 PASS(Predictive Auto-Scaling System),这是一种为企业大规模在线Web应用定制的预测弹性伸缩系统。为了保障预测框架准确性和鲁棒性,我们根据每个应用的特征,动态匹配和校准其适合的预测算法,有效应对了业务负载的多样性。我们进一步建立了基于在线历史日志的性能模型以保障多样化的QoS,可解释的同时不会对在线业务产生负面影响。 除了基于负载预测和性能模型的主动伸缩以外,我们还设计了响应式的兜底策略,以及时应对因不准确的预测或意外事件导致的服务质量违例。在美团广泛的业务应用和真实负载下,相对于表1中其它方法,PASS 表现更优于SOTA,以更少的资源成本实现更高的负载预测准确度和更低的QoS违例。</p><p>PASS的整体架构如图2所示。ELPA(Ensemble Learning-based Prediction Algorithm)实时准确地预测业务负载的QPS时序数据。通过查询基于历史日志构建的性能模型,PASS在不违反QoS的前提下,预测伸缩到业务所需的实例数量。此外,PASS还持续监控QoS指标,如果发现由于预测不准导致的QoS违例,PASS会基于当前真实的延迟校正预测结果,并伸缩到适当数量的实例,以快速消除QoS违例。</p><p><img src="https://p0.meituan.net/meituantechblog/37f87f6fd782585676deb0a9e8e6a96f93213.png" alt="图2 PASS整体架构,图中上半部分的黑线表示离线步骤,下半部分中的红线表示在线过程" referrerpolicy="no-referrer"></p><h3 id="3-1-elpa预测模型">3.1 ELPA预测模型</h3><p>我们提出了ELPA(Ensemble Learning-based Prediction Algorithm)预测算法框架(如图3所示)。对于每一类业务的实时流量,ELPA采用一组相应的在线和离线模型来提供预测服务。我们首先从一系列不同的在线模型中选择一个能够为当前时间序列数据提供最准确预测的模型。然后,为了更好地预测“突变特征”,我们使用一个表现最好的离线预测模型代替在线模型。此外,我们使用振幅调整来改善离线预测时可能出现的“振幅偏差”问题,从而进一步增强预测性能。</p><p><img src="https://p0.meituan.net/meituantechblog/ecfc86400c119460bc189810a47066e4186677.png" alt="图3 预测算法框架" referrerpolicy="no-referrer"></p><p><img src="https://p0.meituan.net/meituantechblog/fb3a35c55b1926c01d4ca5af2a2028d3470282.png" alt="" referrerpolicy="no-referrer"></p><h3 id="3-2-性能模型设计">3.2 性能模型设计</h3><p>我们提出了基于日志的性能模型(Log-based Performance Model)。主要包括:性能模型构建与模型训练校准两部分。</p><p><strong>性能模型构建</strong>:Algorithm1说明了如何基于历史日志(不需要对应用进行画像)构建性能模型。 我们从监控系统获取服务的日志,包括QPS、实例数、QoS指标等信息。 输入的QoS由服务设置,当QoS发生变化时需要重新建立性能模型。我们首先按实例数量聚合输入日志并遍历所有日志(第 1-9 行)。 第4行按照“cap”的粒度(例如最大QPS的千分之一)聚合QPS,以减少数据数量和算法开销。 第5-8行统计QoS违例的发生次数。由于系统故障等因素可能导致某些记录不准确,因此在评估某个QPS的保障率时,我们不仅计算当前的QPS记录,还综合考虑所有较低的QPS记录(第10-19行)。第20行的排序规则是优先考虑大于给定阈值𝛿的QoS保证率,然后按QPS降序排序。𝛿可以根据业务的需求进行调整(默认为0.99),衡量对QoS违例的容忍度。𝛿越接近1,容忍度越低。最后,我们将排序后的第一个QPS指定为当前实例数可以处理的最大流量(第21行)。</p><p><img src="https://p0.meituan.net/meituantechblog/79622676c4c6e5c897adc7aa24e9763d428081.png" alt="" referrerpolicy="no-referrer"></p><p><strong>模型训练校准</strong>:直接根据监控日志构建的性能模型表可能不准确。当应用程序设置的弹性伸缩参数不合理时(例如水平扩容步长较大或资源冗余过多),可能会导致某些实例数没有监控日志,或者数据量极少。这可能会导致最初构建的表中条目丢失或不准确。 为了解决这个问题,我们首先保证原表数据保持非严格单调增长,空的或较低的QPS被之前较高的QPS替换。 然后,对于实例数量增加但QPS不变的部分,我们根据相邻QPS计算斜率并更新它们。 例如,初始化的性能模型映射为{5 : 30, 7 : 20, 8 : 60},使用实例5的QPS替换实例6和7后,则变为{5 : 30,6 : 30,7 : 30,8 : 60}。 然后,根据实例5和8之间的QPS差异,我们更新实例6和7的QPS,得到{5 : 30,6 : 40,7 : 50,8 : 60}。 此外,我们在每天低峰时段使用最新的监控日志定期重建性能模型,以保持准确性。</p><h3 id="3-3-hybrid-auto-scaling方案设计">3.3 Hybrid Auto-scaling方案设计</h3><p>除了预测伸缩,我们还设计了基于排队论的响应式兜底策略,用于处理由于预测不准或热点事件负载突增导致的 QoS 违例。PASS 实时监控应用程序的性能指标。如果检测到QoS违例,PASS将根据 M/M/s排队论模型修改预测的QPS,并重新查询性能模型以快速扩容适当数量的实例。 具体而言,排队论模型如下公式所示:</p><p><img src="https://p0.meituan.net/meituantechblog/8ccc92a88fc1b49d59a4436b3037f48415930.png" alt="" referrerpolicy="no-referrer"></p><p>𝑠表示当前实例的数量,𝑢代表每个实例的瓶颈QPS,𝑝表示延迟的百分比,以及𝑡指的𝑝百分位尾延迟。使用排队理论来估计QPS而不是延迟的原因是,从排队论推导出的延迟往往低于实际值(2.2节中排队论的QoS保障率偏低证明了这一点),因此从实际延迟推导出的QPS将高于实际值。我们基于更高的QPS进行扩容,以快速响应QoS违例并将损失降至最低。并且我们通过实验表明,这部分资源冗余并不会导致大量浪费。</p><h2 id="4-测试结果">4 测试结果</h2><h3 id="4-1-实验环境">4.1 实验环境</h3><p><strong>应用选择</strong>:我们从美团的各个业务线中随机抽取了225个应用,以验证预测模型的准确性。这些应用的历史QPS数据是从美团内部的统一在线监控平台获得的。我们根据数据的预测难度将其分为三个不同的级别。其中,164个服务被定义为简单(具有单一波形模式,并表现出“单峰和多峰”特征),48个服务被定义为中等难度(具有单一波形模式,并表现出“尖峰”或“方形”特征),13个服务被定义为难(混合波形模式,例如“尖峰+方形”)。我们还选择了几个具有代表性的应用进行端到端评估。这些应用是后端服务,提供C端用户基本属性、用户行为查询、搜索和聊天功能。我们记录了在线请求流量,并在离线环境中回放,以恢复真实的在线环境。为了减少时间和资源成本,我们对记录的流量进行了切片,忽略了无法触发弹性伸缩的长期稳定的低峰值负载。</p><p><strong>对比Baseline</strong>:我们比较了各种类型的SOTA预测算法和弹性伸缩方法。预测算法包括:离线算法(周期因子、Prophet)和在线算法(LSTNet、PatchTST和TIDE)。我们评估的在线算法旨在预测从当前时刻开始的第三个时间点的值(时间粒度为5min,也就是预测未来15min),即horizon等于3。这足以满足预测伸缩的要求,因为绝大多数的应用实例能够在15分钟以内完成启动。弹性伸缩方法包括:目标跟踪和AHPA。由于目标跟踪通常可以比具有相同参数的阈值法更快地扩展到目标范围(第2.2节也表明目标跟踪的性能更好),我们没有比较阈值法。其中AHPA是阿里巴巴基于排队论的SOTA预测弹性伸缩方法。</p><h3 id="4-2-预测算法评估">4.2 预测算法评估</h3><p><strong>结论1</strong>:ELPA预测框架结合了在线和离线模型的优势,在绝大多数场景中都取得最好的预测准确度。</p><p><img src="https://p0.meituan.net/meituantechblog/25a1ac0ed1d6dac82b7ef4aea1ff7e5c134871.png" alt="表2 各种预测算法在各种数据集上的准确度总结,分为三个预测难度级别" referrerpolicy="no-referrer"></p><p>(每一行和每一列分别比较所有方法在特定级别的数据集和特定指标上的结果。粗体突出显示每个指标的最佳结果;𝑀𝑒𝑡𝑟𝑖𝑐𝑠_𝑎𝑣𝑔表示当前难度级别数据集的平均预测结果,而𝑊𝑖𝑛𝑛𝑒𝑟显示了按数据集类型评估的方法在准确性方面优于其他方法的比例)</p><p>我们对ELPA以及其他五种广泛使用的预测算法进行了评估。表2显示了各种预测算法的准确度比较。ELPA明显优于单个预测算法,由于其实现了一组优化规则,用于选择最合适的在线/离线组合,并使用振幅校准来预测特定时间段的数据。</p><p><strong>结论2</strong>:离线模型虽然擅长捕捉数据的“突变特征”,但其预测结果和真实值存在显著差异。而在线模型在有效预测这些“突变特征”方面面临挑战。通过两个模型的集成和振幅校准的应用,ELPA框架表现出显著的鲁棒性。</p><p><img src="https://p0.meituan.net/meituantechblog/780407c01d44c01d81d25cb922562ffd97350.png" alt="图4 在线模型、离线模型(包括振幅调整)和 ELPA 的预测实例化展示" referrerpolicy="no-referrer"></p><p>图4提供了ELPA的示例,其中结合了在离线预测模型,并对离线模型进行振幅调整。需要注意的是,“突变特征”可以在各种类型的业务流量中表现出来。由于篇幅限制,我们选择了一个具有代表性的业务负载数据集来突出ELPA的稳健预测能力。图4(a)比较了在线模型(PatchTST)的预测与真实数据。虽然在线模型在大多数情况下显示出很高的预测精度,但在预测“突变特征”时存在显著的滞后问题(黑色圆圈突出显示)。在图4(b)中,蓝色虚线代表离线模型(周期因子)的预测结果,尽管它在大多数情况下和真实值有一定的差距,但及时地预测出了“突变特征”。图4(b)中的红色虚线表示ELPA在离线模型的“突变特征”处的振幅校准结果。最后,图4©展示了ELPA的结果,它集成了在线模型和校准的离线模型,表现出准确的预测效果和预测“突变特征”的能力。</p><h3 id="4-3-端到端效果评估">4.3 端到端效果评估</h3><p>结论3:PASS的性能模型准确有效,在所有测试场景中都实现了最高的QoS保障率(表3)。 与目标跟踪和AHPA相比,平均QoS保障率分别提高了5.54%和7.71%。在多个QoS指标的场景6中表现更为明显,PASS的QoS保障率分别提高了19.21%和22.64%。PASS在所有场景中的平均资源成本也是最低的。 平均资源成本较AHPA降低8.91%,较目标跟踪降低17.02%。在场景4中降低了高达40%和52.76%。只有两个场景中PASS的资源成本略高于AHPA,而在所有其他测试中,PASS的资源成本都是最低的。</p><p><img src="https://p0.meituan.net/meituantechblog/184480305433023042e0acbb550b1c1188155.png" alt="表3 三种auto-scaling方法在不同QoS和测试时长(小时)场景下的端到端性能" referrerpolicy="no-referrer"></p><p>(每个场景中,第一列是QoS保障率,第二列是资源成本(实例数*小时); 粗体突出显示每个指标的最佳结果)</p><p>我们从两个方面来评估弹性伸缩方法的效果。QoS保障率衡量了应用违反QoS的时间长度,其计算方法为QoS得到保证的持续时间与总时间长度的比值。资源成本通过计算实例数量和时间(以小时为单位)的积分得到。 端到端实验结果如表3所示(测试过程详细监控数据见图5和图6,包括QPS系列、实例数以及TP99、TP999时延等QoS指标)。每个测试场景提供了QoS指标、测试时长以及三种方法的QoS保障率和资源成本。</p><p><img src="https://p0.meituan.net/meituantechblog/fd6e868d46f648cf43dd0ed99e67147b126078.png" alt="图5 Scenario1的综合监控数据:QPS系列、实例数和QoS指标" referrerpolicy="no-referrer"></p><p><img src="https://p0.meituan.net/meituantechblog/747c98769d1927b8132a5bab60b7c2a8189270.png" alt="图6 Scenario6的综合监控数据:QPS系列、实例数和QoS指标" referrerpolicy="no-referrer"></p><p>需要注意的是,应用实例启动时并没有进行预热(例如数据库连接初始化、缓存预测等),因此即使实例提前进行了扩容,初始大量的冷查询仍然会导致尾延迟突然增加。如果业务方在其实例启动逻辑中加入预热,我们的QoS保障率将会进一步提高。</p><h2 id="5-经验总结">5 经验总结</h2><ul><li>不同企业的应用场景可能各不相同,场景复杂程度也不一,在实际落地过程中,一些顶会算法不一定适用我们场景,这个时候就需要我们仔细甄别,取长补短,围绕自身场景特点进行算法的创新简化。</li><li>模型并不是越复杂性能越好,要结合预测的特征与场景来选择预测算法。</li><li>除了模型性能外,模型的可落地性也是非常重要的,比如LSTNet支持同时预测多项时间序列,面对大规模服务时能够极大的减少模型落地的开销。</li></ul><h2 id="6-合作方简介">6 合作方简介</h2><p>中国人民大学柴云鹏教授团队致力于云计算、数据库等领域的系统研究和研发,近年团队在系统和数据库等领域的重要会议ASPLOS、SOSP、HPCA、SIGMOD、VLDB、ICDE、WWW等发表多篇高水平论文。在云计算领域,该团队针对资源隔离、资源分配、资源调度等核心问题,提出了一系列方法,可以提升各种复杂场景下的资源利用率,同时保障应用的服务质量,推动云计算技术的进步。团队高度重视科研工作的实用价值,积极推进与科技领域企业合作,针对企业面临的核心挑战,将创新性方法在实际系统中实现,推动研究成果的实际落地与应用,同时助力合作伙伴技术能力提升和商业价值实现。</p></description>
<link>https://tech.meituan.com/2025/02/14/prediction-technology-in-meituan-elastic-scaling.html</link>
<guid isPermaLink="false">https://tech.meituan.com/2025/02/14/prediction-technology-in-meituan-elastic-scaling.html</guid>
<pubDate>Fri, 14 Feb 2025 00:00:00 GMT</pubDate>
<author>美团技术团队</author>
</item>
<item>
<title>美团技术年货 | 600+页电子书,算法、工程、测试、数据、安全系列大合集</title>
<description><p><img src="https://p0.meituan.net/meituantechblog/2b39e0fadbfc2d23762e5be6c359abea783334.png" alt="" referrerpolicy="no-referrer"></p><p>新春将近,一年一度的美团技术年货也如约而至!</p><p>路虽远,行则将至;梦虽遥,追则可及。2024年,是美团技术博客走过的第11个年头,这里没有恢弘的叙事,只是年复年、日复日的默默坚持。截至目前,美团技术团队微信公众号累计发布了600多篇技术文章,感谢大家一路同行,见证我们的成长。</p><p>值蛇年春节到来之际,我们精选过去一年公众号30多篇技术文章和科研论文,整理制作成一本600多页的电子书,作为一份特别的新年礼物,献给每一位热爱技术的你。</p><p><img src="https://p0.meituan.net/meituantechblog/46a9990011b1af1679be6b780ce0c90e747914.png" alt="" referrerpolicy="no-referrer"></p><p>这本电子书内容覆盖算法、工程、测试、安全、数据等多个技术领域,希望能为你的工作和学习带来一些启发与帮助。也欢迎您将这份电子书分享给更多志同道合、积极向上的同事和朋友,一起携手共进,砥砺前行。</p><p>在新的一年里,愿大家乘风破浪,勇往直前,历尽千帆,梦想终将实现!</p><h2 id="如何获取">如何获取?</h2><p><img src="https://p0.meituan.net/meituantechblog/0f95586a87d5a2161fea060b87f4419c389208.jpg" alt="" referrerpolicy="no-referrer"></p><p>关注美团技术团队微信公众号,在菜单栏对话框回复关键词:2024年货。即可获取下载链接。</p><p>温馨提醒:</p><ul><li>美团技术年货合集大小约为80M,下载需要一定的时间;</li><li>打开电子书目录后,可直接点击感兴趣的标题进行阅读;</li><li>部分文章中的动态图片无法在电子书中进行完全的展示,大家可以移步美团技术团队官方博客 <a href="https://tech.meituan.com/">tech.meituan.com</a> ,或在美团技术团队公众号历史文章中进行阅读,感谢理解。</li></ul><h2 id="往期年货下载">往期年货下载</h2><p>在「美团技术团队」微信公众号对话框中回复关键字:【2023年货】、【2022年货】、【2021年货】、【2020年货】、【2019年货】、【2018年货】、【2017年货】,即可获取往期年货下载链接。</p><p>| 本文系美团技术团队出品,著作权归属美团。欢迎出于分享和交流等非商业目的转载或使用本文内容,敬请注明“内容转载自美团技术团队”。本文未经许可,不得进行商业性转载或者使用。任何商用行为,请发送邮件至[email protected]申请授权。</p></description>
<link>https://tech.meituan.com/2025/01/16/2024-spring-festival-present.html</link>
<guid isPermaLink="false">https://tech.meituan.com/2025/01/16/2024-spring-festival-present.html</guid>
<pubDate>Thu, 16 Jan 2025 00:00:00 GMT</pubDate>
<author>美团技术团队</author>
</item>
<item>
<title>鸿蒙应用签名实操及机制探究</title>
<description><h2 id="1-背景">1. 背景</h2><p>华为鸿蒙单框架操作系统HarmonyOS NEXT已于2024年10月23日正式发布Release版。HarmonyOS NEXT仅支持鸿蒙原生应用,不再兼容安卓。本文对鸿蒙公开资料进行了深入分析和解读,梳理了鸿蒙单框架应用的签名机制,拆解每一步的实操过程和背后的实现原理,并对源码分析整理签名的校验机制。从中管中窥豹,探究鸿蒙系统的安全设计思路,希望能给从事鸿蒙研发的同学提供一些借鉴。</p><p>成文过程中特别参考OpenHarmony 5.0.0-Release版的文档和源码,详见<a href="https://gitee.com/openharmony/docs/blob/OpenHarmony-5.0.0-Release/zh-cn/release-notes/OpenHarmony-v5.0.0-release.md">openharmony</a>。</p><h2 id="2-签名机制">2. 签名机制</h2><p>签名相关的代码在<a href="https://gitee.com/openharmony/developtools_hapsigner/tree/OpenHarmony-v5.0.0-Release/">developtools_hapsigner</a>仓库里,签名流程梳理如下:</p><p><img src="https://p0.meituan.net/meituantechblog/ff3bff190a0dd7ab8adab552c0b168a5182681.png" alt="" referrerpolicy="no-referrer"></p><p>签名步骤可按如下分组:</p><ol><li>生成开发者签名证书,包括①、②、③。</li><li>生成Profile文件,包括④、⑤。</li><li>生成签名的App,包括⑥、⑦。</li></ol><h3 id="2-1-生成开发者签名证书">2.1 生成开发者签名证书</h3><p><strong>① 生成开发者公私钥</strong></p><p>通过华为的DevEco-Studio工具可以直接生成包含开发者公私钥的p12文件(详见<a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-signing-V5#section462703710326">具体操作步骤</a>。)</p><p><img src="https://p0.meituan.net/meituantechblog/39ceff06aa892e8b390931cd7e0c2b42149083.png" alt="" referrerpolicy="no-referrer"></p><p>笔者示例生成的p12文件(保存为my.p12)是标准的PKCS#12格式(定义在<a href="https://datatracker.ietf.org/doc/html/rfc7292">RFC 7292</a>),用来存储一组或多组公钥证书(里面包含公钥)和其对应的私钥(用localKeyID字段进行匹配公私钥的匹配),使用ASN.1来定义其数据结构,并采用DER编码规则将这些结构编码为二进制形式。</p><p>可以通过openssl命令解析其结构,或者直接查看公钥证书和私钥信息:</p><pre><code>openssl asn1parse -in my.p12 -inform DER //解码DER和解析ASN.1
openssl pkcs12 -info -in my.p12 //查看公钥证书和私钥信息
</code></pre><p>笔者用于示例生成的p12文件里包含的公钥证书如下:</p><pre><code>-----BEGIN CERTIFICATE-----
MIIBqTCCAU+gAwIBAgIIKG2ih6j2GSswCgYIKoZIzj0EAwIwSTEJMAcGA1UEBhMA
MQkwBwYDVQQIEwAxCTAHBgNVBAcTADEJMAcGA1UEChMAMQkwBwYDVQQLEwAxEDAO
BgNVBAMTB3Rlc3RzY3IwHhcNMjQwOTIzMTI1NjM3WhcNNDkwOTE3MTI1NjM3WjBJ
MQkwBwYDVQQGEwAxCTAHBgNVBAgTADEJMAcGA1UEBxMAMQkwBwYDVQQKEwAxCTAH
BgNVBAsTADEQMA4GA1UEAxMHdGVzdHNjcjBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABD28s78rF8+X1JWgkQcfHB2Gy20MCT51Oue6eG5ZbPsUKlZrPx0aRX0einL2
E5WsE3st0zI4yvj0KzhdEwksCWCjITAfMB0GA1UdDgQWBBRtCEWMjEr+bnXoAqSC
fjmk1btJQDAKBggqhkjOPQQDAgNIADBFAiAAiMtQXgCMUxrKtaPKvGqllswi1FRU
h1brCAbJ1t81FgIhAMXbzmeJlA7/zxZDULLRW0rCY6CU3KMDHr8N38EmuDug
-----END CERTIFICATE-----
</code></pre><p>公钥证书的表示是遵循Privacy Enhanced Mail(PEM)协议(定义在<a href="https://datatracker.ietf.org/doc/html/rfc7468">RFC 7468</a>)的文本文件,其格式如下:</p><p><img src="https://p0.meituan.net/meituantechblog/4a90e7be57a8255b5922cc634926f72a52454.png" alt="" referrerpolicy="no-referrer"></p><p>PEM 文件的label用于指示文件的内容类型。以下是一些常见的 PEM header和footer(后面会陆续见到):</p><p><img src="https://p0.meituan.net/meituantechblog/875082d625dabf269d4b36658138fe24134936.png" alt="" referrerpolicy="no-referrer"></p><p>解析具体公钥证书信息可以采用如下命令(将公钥证书以文本的形式保存为my.pem文件):</p><pre><code>openssl x509 -in my.pem -text -noout
</code></pre><p>解析得到如下输出(重要部分加了注释):</p><pre><code>Certificate:
Data:
Version: 3 (0x2) //证书的版本号
Serial Number: 2913163237517564203 (0x286da287a8f6192b) //证书的序列号,用于唯一标识证书
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = , ST = , L = , O = , OU = , CN = testscr //证书颁发者的信息
Validity
Not Before: Sep 23 12:56:37 2024 GMT //证书的开始有效期
Not After : Sep 17 12:56:37 2049 GMT //证书的结束有效期
Subject: C = , ST = , L = , O = , OU = , CN = testscr //证书持有者的信息
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey //公钥算法,这里是椭圆曲线
Public-Key: (256 bit) //公钥的位数,这里是256
pub:// 证书持有者的公钥值,以十六进制表示
04:3d:bc:b3:bf:2b:17:cf:97:d4:95:a0:91:07:1f:
1c:1d:86:cb:6d:0c:09:3e:75:3a:e7:ba:78:6e:59:
6c:fb:14:2a:56:6b:3f:1d:1a:45:7d:1e:8a:72:f6:
13:95:ac:13:7b:2d:d3:32:38:ca:f8:f4:2b:38:5d:
13:09:2c:09:60
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Subject Key Identifier: //证书持有者的标识
6D:08:45:8C:8C:4A:FE:6E:75:E8:02:A4:82:7E:39:A4:D5:BB:49:40
Signature Algorithm: ecdsa-with-SHA256
Signature Value: //证书的数字签名值
30:45:02:20:00:88:cb:50:5e:00:8c:53:1a:ca:b5:a3:ca:bc:
6a:a5:96:cc:22:d4:54:54:87:56:eb:08:06:c9:d6:df:35:16:
02:21:00:c5:db:ce:67:89:94:0e:ff:cf:16:43:50:b2:d1:5b:
4a:c2:63:a0:94:dc:a3:03:1e:bf:0d:df:c1:26:b8:3b:a0
</code></pre><p>公钥信息(包括公钥算法、公钥位数、公钥值等)属于结构化数据并且较长,不利于识别和比较,所以需要用一个简短的字符串来标识公钥唯一性。常用做法是使用公钥指纹(Public Key Pin,也叫公钥Pin),计算方式是对DER编码的公钥进行SHA-256计算并进行Base64编码。</p><p>这里需要注意的是,在X509扩展字段里包括了Subject Key Identifier(SKID)字段,也是证书持有者的标识。那标识公钥的唯一性为什么不直接使用证书里自带的SKID,还要自己算一遍呢,根据<a href="https://tech.meituan.com/2025/01/06/hihu.com/org/mei-tuan-dian-ping-ji-shu-tuan-dui/activities">RFC 3280-4.2.1.2</a>章节中对SKID的定义:</p><blockquote><p>For CA certificates, subject key identifiers SHOULD be derived from the public key or a method that generates unique values.</p><p>Two common methods for generating key identifiers from the public key are:</p><p>(1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the value of the BIT STRING subjectPublicKey (excluding the tag, length, and number of unused bits).</p><p>(2) The keyIdentifier is composed of a four bit type field with the value 0100 followed by the least significant 60 bits of the SHA-1 hash of the value of the BIT STRING subjectPublicKey (excluding the tag, length, and number of unused bit string bits).</p></blockquote><p>SKID的计算可以通过公钥得到,但计算方式并不唯一,也可以通过任意的算法得到,只要保证唯一性就可以了。定义里推荐了两种基于SHA-1的算法,openssl采用的算法(详见<a href="https://github.com/openssl/openssl/blob/master/crypto/x509/v3_skid.c">v3_skid.c的ossl_x509_pubkey_hash</a>函数)是对DER编码的公钥进行SHA-1计算。</p><p>如果采用SKID来进行公钥的唯一性校验,那么攻击者可以伪造一个证书,里面的SKID和你的一样(SHA-1碰撞,或者直接照抄一下也行),这样的证书也是合法的,就可以轻易绕过对公钥的校验。所以SKID一般只用于在证书链中寻找父子关系,并不用于公钥的唯一性标识。另外,还有Authority Key Identifier(AKID)字段用于标识证书的颁发者。当验证一个证书链时,验证程序会检查每个证书的AKID和上一个证书的SKID是否匹配,确保它们形成一个连续的信任链。</p><p>使用如下命令可以从PEM协议的公钥证书中提取PEM协议的公钥:</p><pre><code>openssl x509 -in my.pem -pubkey -noout
</code></pre><p>输出如下:</p><pre><code>-----BEGIN PUBLIC KEY----- //公钥标头
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE95zFs5cFHauzIYEuuw3g2R75a1ir
qEW0JWP9qAKkyVCizN0nnzcn/Fo5oeSZR1iPUnJvjlnpNvZL9BcQbLqa7g==
-----END PUBLIC KEY-----
</code></pre><p>使用如下命令可以继续转换成DER编码并计算SHA-256和Base64编码:</p><pre><code>openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
</code></pre><p>所以结合使用如下命令可以直接从符合PEM协议的公钥证书文件中得到对应的公钥指纹:</p><pre><code>openssl x509 -in my.pem -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
</code></pre><p>最终笔者示例的公钥证书计算得到的公钥指纹为:</p><pre><code>fzyRjPvTPElBAj0VlYlVA74M3RMtUh5ljKbOYf1NDA0=
</code></pre><p><strong>② 生成证书签名请求</strong></p><p>同样通过DevEco-Studio可以直接生成证书签名请求Certificate Signing Request(CSR)文件(详见<a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-signing-V5#section462703710326">具体操作步骤</a>)。得到的CSR内容示例如下:</p><pre><code>-----BEGIN NEW CERTIFICATE REQUEST----- //CSR标头
MIIBMzCB2wIBADBJMQkwBwYDVQQGEwAxCTAHBgNVBAgTADEJMAcGA1UEBxMAMQkw
BwYDVQQKEwAxCTAHBgNVBAsTADEQMA4GA1UEAxMHdGVzdHNjcjBZMBMGByqGSM49
AgEGCCqGSM49AwEHA0IABD28s78rF8+X1JWgkQcfHB2Gy20MCT51Oue6eG5ZbPsU
KlZrPx0aRX0einL2E5WsE3st0zI4yvj0KzhdEwksCWCgMDAuBgkqhkiG9w0BCQ4x
ITAfMB0GA1UdDgQWBBRtCEWMjEr+bnXoAqSCfjmk1btJQDAKBggqhkjOPQQDAgNH
ADBEAiAlzkRf0AHKh59/deFGo/4JHQRSbw6P+Q7qsiiMMWHT7wIgGugWrCm7tFLh
mRjEEyJNOpen9kfhyOanSRrwtBlEFc0=
-----END NEW CERTIFICATE REQUEST-----
</code></pre><p>生成的CSR文件是标准的PKCS#10格式(定义在<a href="https://datatracker.ietf.org/doc/html/rfc2986">RFC 2986</a>),用于向证书颁发机构(CA)请求签发数字证书的文件,包含申请者的公钥和一些身份信息,这些信息将包含在颁发的证书中。可以看到CSR文件也是遵循PEM协议的,可以如下命令解析CSR文件的内容(保存为my.csr文件):</p><pre><code>openssl req -text -noout -verify -in my.csr
</code></pre><p>输出示例(重要部分加了注释):</p><pre><code>Certificate request self-signature verify OK //表明CSR的自签名已成功验证
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = , ST = , L = , O = , OU = , CN = testscr //证书申请者的信息
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub: //证书申请者的公钥值,和上面my.pem里的公钥值相同
04:3d:bc:b3:bf:2b:17:cf:97:d4:95:a0:91:07:1f:
1c:1d:86:cb:6d:0c:09:3e:75:3a:e7:ba:78:6e:59:
6c:fb:14:2a:56:6b:3f:1d:1a:45:7d:1e:8a:72:f6:
13:95:ac:13:7b:2d:d3:32:38:ca:f8:f4:2b:38:5d:
13:09:2c:09:60
ASN1 OID: prime256v1
NIST CURVE: P-256
Attributes:
Requested Extensions:
X509v3 Subject Key Identifier: //证书申请者的标识
6D:08:45:8C:8C:4A:FE:6E:75:E8:02:A4:82:7E:39:A4:D5:BB:49:40
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:44:02:20:25:ce:44:5f:d0:01:ca:87:9f:7f:75:e1:46:a3:
fe:09:1d:04:52:6f:0e:8f:f9:0e:ea:b2:28:8c:31:61:d3:ef:
02:20:1a:e8:16:ac:29:bb:b4:52:e1:99:18:c4:13:22:4d:3a:
97:a7:f6:47:e1:c8:e6:a7:49:1a:f0:b4:19:44:15:cd
</code></pre><p>注意到其中证书申请者的公钥值和上面p12文件中的公钥值是一样的,说明CSR中包含了我们的公钥信息。使用如下命令也可以直接从CSR文件中得到公钥指纹:</p><pre><code>openssl req -in my.csr -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
</code></pre><p>示例生成的CSR计算得到的公钥指纹为:</p><pre><code>fzyRjPvTPElBAj0VlYlVA74M3RMtUh5ljKbOYf1NDA0=
</code></pre><p>和通过公钥证书计算得到的公钥指纹相同。</p><p><strong>③ 生成开发者签名叶子证书</strong></p><p>证书的作用可以抽象概括为:</p><blockquote><p>颁发者(Issuer)说:持有者(Subject)的公钥是某某某。</p></blockquote><p>证书一般分为三级:根证书(Root Certificate)、中间证书(Intermediate Certificate)、叶子证书(Leaf Certificate)。</p><ul><li>叶子证书由中间证书颁发(即叶子证书的Issuer+AKID和中间证书的Subject+SKID相同)</li><li>中间证书由根证书颁发(即中间证书的Issuer+AKID和根证书的Subject+SKID相同)</li><li>根证书由自己颁发(也就是自签名,根证书的Issuer和Subject相同)</li></ul><p><img src="https://p0.meituan.net/meituantechblog/f84d81562441e05423584a1a9ef00f3286955.png" alt="" referrerpolicy="no-referrer"></p><p>我们需要的是用于给我们App签名的开发者签名叶子证书,这需要华为的开发者签名中间证书来帮我们颁发。叶子证书分为调试证书和发布证书,我们以发布证书为例(详见具体<a href="https://developer.huawei.com/consumer/cn/doc/app/agc-help-add-releasecert-0000001946273961">操作步骤</a>):</p><p><img src="https://p0.meituan.net/meituantechblog/abad5af520a234c6c0504606541e3e90229818.png" alt="" referrerpolicy="no-referrer"></p><p>需要上传我们的CSR文件,得到的证书文件内容示例如下:</p><pre><code>-----BEGIN CERTIFICATE-----
MIICGjCCAaGgAwIBAgIIShhpn519jNAwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE
AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjAzMDQzOVoXDTQ5MDMx
NjAzMDQzOVowUzELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEeMBwGA1UEAwwVSHVhd2VpIENCRyBSb290IENBIEcyMHYw
EAYHKoZIzj0CAQYFK4EEACIDYgAEWidkGnDSOw3/HE2y2GHl+fpWBIa5S+IlnNrs
GUvwC1I2QWvtqCHWmwFlFK95zKXiM8s9yV3VVXh7ivN8ZJO3SC5N1TCrvB2lpHMB
wcz4DA0kgHCMm/wDec6kOHx1xvCRo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
AQH/BAUwAwEB/zAdBgNVHQ4EFgQUo45a9Vq8cYwqaiVyfkiS4pLcIAAwCgYIKoZI
zj0EAwMDZwAwZAIwMypeB7P0IbY7c6gpWcClhRznOJFj8uavrNu2PIoz9KIqr3jn
BlBHJs0myI7ntYpEAjBbm8eDMZY5zq5iMZUC6H7UzYSix4Uy1YlsLVV738PtKP9h
FTjgDHctXJlC5L7+ZDY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDATCCAoigAwIBAgIIXmuDXbWpOB8wCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE
AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDcwOTAyMDQyNFoXDTMwMDcw
NzAyMDQyNFowYjELMAkGA1UEBgwCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEtMCsGA1UEAwwkSHVhd2VpIENCRyBEZXZlbG9wZXIgUmVs
YXRpb25zIENBIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE65LdoIZh1hlpZ2gP
bJ6gPhHsvYSRe22KETgdqeVeYnrbRHI9wsPT6RGYS+pU4mPl6wxzgDMqN6SY/BoZ
luhkE1PzaHoPoNIWIq0O33hpyKyyYwAacIUEjYurkw1E9r9no4IBGDCCARQwHwYD
VR0jBBgwFoAUo45a9Vq8cYwqaiVyfkiS4pLcIAAwHQYDVR0OBBYEFNtek7Ij6NDk
/nF6Zumkc0dbf/NeMEYGA1UdIAQ/MD0wOwYEVR0gADAzMDEGCCsGAQUFBwIBFiVo
dHRwOi8vY3BraS1jYXdlYi5odWF3ZWkuY29tL2Nwa2kvY3BzMBIGA1UdEwEB/wQI
MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMGYGA1UdHwRfMF0wW6BZoFeGVWh0dHA6
Ly9jcGtpLWNhd2ViLmh1YXdlaS5jb20vY3BraS9zZXJ2bGV0L2NybEZpbGVEb3du
LmNybD9jZXJ0eXBlPTEwJi9yb290X2cyX2NybC5jcmwwCgYIKoZIzj0EAwMDZwAw
ZAIwWO1X5q2MdfpR1Q237GpUHGbL1C13rGyFg2p3AYo44FpZ2/A9ss0wOHKM4KDl
ZPqdAjBLkf8NPZy7KVog98+iCTLq35DJ2ZVxkCxknA9YhiHVyXf4HPm4JlT7rW7o
Q+FzM3c=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICujCCAkGgAwIBAgIOY8ui/vvwxqFf+kFokYUwCgYIKoZIzj0EAwMwYjELMAkG
A1UEBgwCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEt
MCsGA1UEAwwkSHVhd2VpIENCRyBEZXZlbG9wZXIgUmVsYXRpb25zIENBIEcyMB4X
DTI0MDkyMzEyNTgwNFoXDTI3MDkyMzEyNTgwNFowazELMAkGA1UEBhMCQ04xDzAN
BgNVBAoMBuW8oOaZqDEcMBoGA1UECwwTMTI4OTY3Njc4NjA2NTQ5NDk3NzEtMCsG
A1UEAwwk5byg5pmoKDEyODk2NzY3ODYwNjU0OTQ5NzcpXCxSZWxlYXNlMFkwEwYH
KoZIzj0CAQYIKoZIzj0DAQcDQgAEPbyzvysXz5fUlaCRBx8cHYbLbQwJPnU657p4
blls+xQqVms/HRpFfR6KcvYTlawTey3TMjjK+PQrOF0TCSwJYKOB0TCBzjAMBgNV
HRMBAf8EAjAAMFkGA1UdHwRSMFAwTqBMoEqGSGh0dHA6Ly9oNWhvc3RpbmctZHJj
bi5kYmFua2Nkbi5jbi9jY2g1L2NybC9oZHJjYWcyL0h1YXdlaUNCR0hEUkcyY3Js
LmNybDAfBgNVHSMEGDAWgBTbXpOyI+jQ5P5xembppHNHW3/zXjAdBgNVHQ4EFgQU
bQhFjIxK/m516AKkgn45pNW7SUAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
CCsGAQUFBwMDMAoGCCqGSM49BAMDA2cAMGQCMFzNlsafNs7ad5xelZOzCebdRofE
VaQZJW0o5QAdTX0t9Ij1o/zUm0bXIf8ZZTJLYgIwKuuZu+LeLCLZJFEM7tYKDhIK
TegCiesP1THuMgiZhZYOYl1kIZBPVrEB8O1wtxEm
-----END CERTIFICATE-----
</code></pre><p>可以看到叶子证书文件里也包括了中间证书和根证书,分别解析证书信息如下:</p><p>根证书:</p><pre><code>Certificate:
Data:
Version: 3 (0x2)
Serial Number: 5339133492510690512 (0x4a18699f9d7d8cd0)
Signature Algorithm: ecdsa-with-SHA384
Issuer: C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
Validity
Not Before: Mar 16 03:04:39 2020 GMT
Not After : Mar 16 03:04:39 2049 GMT
Subject: C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
04:5a:27:64:1a:70:d2:3b:0d:ff:1c:4d:b2:d8:61:
e5:f9:fa:56:04:86:b9:4b:e2:25:9c:da:ec:19:4b:
f0:0b:52:36:41:6b:ed:a8:21:d6:9b:01:65:14:af:
79:cc:a5:e2:33:cb:3d:c9:5d:d5:55:78:7b:8a:f3:
7c:64:93:b7:48:2e:4d:d5:30:ab:bc:1d:a5:a4:73:
01:c1:cc:f8:0c:0d:24:80:70:8c:9b:fc:03:79:ce:
a4:38:7c:75:c6:f0:91
ASN1 OID: secp384r1
NIST CURVE: P-384
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
A3:8E:5A:F5:5A:BC:71:8C:2A:6A:25:72:7E:48:92:E2:92:DC:20:00
Signature Algorithm: ecdsa-with-SHA384
Signature Value:
30:64:02:30:33:2a:5e:07:b3:f4:21:b6:3b:73:a8:29:59:c0:
a5:85:1c:e7:38:91:63:f2:e6:af:ac:db:b6:3c:8a:33:f4:a2:
2a:af:78:e7:06:50:47:26:cd:26:c8:8e:e7:b5:8a:44:02:30:
5b:9b:c7:83:31:96:39:ce:ae:62:31:95:02:e8:7e:d4:cd:84:
a2:c7:85:32:d5:89:6c:2d:55:7b:df:c3:ed:28:ff:61:15:38:
e0:0c:77:2d:5c:99:42:e4:be:fe:64:36
</code></pre><p>中间证书:</p><pre><code>Certificate:
Data:
Version: 3 (0x2)
Serial Number: 6803676100576229407 (0x5e6b835db5a9381f)
Signature Algorithm: ecdsa-with-SHA384
Issuer: C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
Validity
Not Before: Jul 9 02:04:24 2020 GMT
Not After : Jul 7 02:04:24 2030 GMT
Subject: C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Developer Relations CA G2
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
04:eb:92:dd:a0:86:61:d6:19:69:67:68:0f:6c:9e:
a0:3e:11:ec:bd:84:91:7b:6d:8a:11:38:1d:a9:e5:
5e:62:7a:db:44:72:3d:c2:c3:d3:e9:11:98:4b:ea:
54:e2:63:e5:eb:0c:73:80:33:2a:37:a4:98:fc:1a:
19:96:e8:64:13:53:f3:68:7a:0f:a0:d2:16:22:ad:
0e:df:78:69:c8:ac:b2:63:00:1a:70:85:04:8d:8b:
ab:93:0d:44:f6:bf:67
ASN1 OID: secp384r1
NIST CURVE: P-384
X509v3 extensions:
X509v3 Authority Key Identifier:
A3:8E:5A:F5:5A:BC:71:8C:2A:6A:25:72:7E:48:92:E2:92:DC:20:00
X509v3 Subject Key Identifier:
DB:5E:93:B2:23:E8:D0:E4:FE:71:7A:66:E9:A4:73:47:5B:7F:F3:5E
X509v3 Certificate Policies:
Policy: X509v3 Any Policy
CPS: http://cpki-caweb.huawei.com/cpki/cps
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 CRL Distribution Points:
Full Name:
URI:http://cpki-caweb.huawei.com/cpki/servlet/crlFileDown.crl?certype=10&amp;/root_g2_crl.crl
Signature Algorithm: ecdsa-with-SHA384
Signature Value:
30:64:02:30:58:ed:57:e6:ad:8c:75:fa:51:d5:0d:b7:ec:6a:
54:1c:66:cb:d4:2d:77:ac:6c:85:83:6a:77:01:8a:38:e0:5a:
59:db:f0:3d:b2:cd:30:38:72:8c:e0:a0:e5:64:fa:9d:02:30:
4b:91:ff:0d:3d:9c:bb:29:5a:20:f7:cf:a2:09:32:ea:df:90:
c9:d9:95:71:90:2c:64:9c:0f:58:86:21:d5:c9:77:f8:1c:f9:
b8:26:54:fb:ad:6e:e8:43:e1:73:33:77
</code></pre><p>叶子证书:</p><pre><code>Certificate:
Data:
Version: 3 (0x2)
Serial Number:
63:cb:a2:fe:fb:f0:c6:a1:5f:fa:41:68:91:85
Signature Algorithm: ecdsa-with-SHA384
Issuer: C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Developer Relations CA G2
Validity
Not Before: Sep 23 12:58:04 2024 GMT
Not After : Sep 23 12:58:04 2027 GMT
Subject: C = CN, O = \E5\BC\A0\E6\99\A8, OU = 1289676786065494977, CN = "\E5\BC\A0\E6\99\A8(1289676786065494977)\\,Release"
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:3d:bc:b3:bf:2b:17:cf:97:d4:95:a0:91:07:1f:
1c:1d:86:cb:6d:0c:09:3e:75:3a:e7:ba:78:6e:59:
6c:fb:14:2a:56:6b:3f:1d:1a:45:7d:1e:8a:72:f6:
13:95:ac:13:7b:2d:d3:32:38:ca:f8:f4:2b:38:5d:
13:09:2c:09:60
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 CRL Distribution Points:
Full Name:
URI:http://h5hosting-drcn.dbankcdn.cn/cch5/crl/hdrcag2/HuaweiCBGHDRG2crl.crl
X509v3 Authority Key Identifier:
DB:5E:93:B2:23:E8:D0:E4:FE:71:7A:66:E9:A4:73:47:5B:7F:F3:5E
X509v3 Subject Key Identifier:
6D:08:45:8C:8C:4A:FE:6E:75:E8:02:A4:82:7E:39:A4:D5:BB:49:40
X509v3 Key Usage: critical
Digital Signature
X509v3 Extended Key Usage:
Code Signing
Signature Algorithm: ecdsa-with-SHA384
Signature Value:
30:64:02:30:5c:cd:96:c6:9f:36:ce:da:77:9c:5e:95:93:b3:
09:e6:dd:46:87:c4:55:a4:19:25:6d:28:e5:00:1d:4d:7d:2d:
f4:88:f5:a3:fc:d4:9b:46:d7:21:ff:19:65:32:4b:62:02:30:
2a:eb:99:bb:e2:de:2c:22:d9:24:51:0c:ee:d6:0a:0e:12:0a:
4d:e8:02:89:eb:0f:d5:31:ee:32:08:99:85:96:0e:62:5d:64:
21:90:4f:56:b1:01:f0:ed:70:b7:11:26
</code></pre><p>注意到,颁发下来的叶子证书里Subject和我们申请时所使用的CSR里的Subject不同,叶子证书里是:</p><blockquote><p>Subject: C = CN, O = \E5\BC\A0\E6\99\A8, OU = 1289676786065494977, CN = “\E5\BC\A0\E6\99\A8(1289676786065494977)\,Release”</p></blockquote><p>CSR里是:</p><blockquote><p>Subject: C = , ST = , L = , O = , OU = , CN = testscr</p></blockquote><p>说明华为在颁发叶子证书的时候,并没有使用我们CSR里的Subject,而是根据我们在开发者平台网站上登陆的账号信息,对Subject进行了填充。其中OU字段跟账号信息有关(类似iOS的Team ID,但在华为开发者网站上没有找到直接查看的地方)。叶子证书里的公钥信息还是和CSR保持一致,计算得到的公钥指纹也一样。</p><p>另外,华为目前给叶子证书的有效期是3年,3年以后需要续期成新证书。当然,如果续期新证书的时候使用的CSR不变,那么新证书的公钥指纹也依然会保持不变。</p><h3 id="2-2-生成profile文件">2.2 生成Profile文件</h3><p><strong>④ 登记App信息</strong></p><p>这里主要是在华为开发者平台上登记一下App的各项信息,跟着<a href="https://developer.huawei.com/consumer/cn/doc/app/agc-help-harmonyos-releaseapp-0000001914554900">操作步骤</a>来即可:</p><p><img src="https://p0.meituan.net/meituantechblog/9ee43a7228353151f524b9e3487eb817212315.png" alt="" referrerpolicy="no-referrer"></p><p>需要注意的是,包名填写的时候,平台会在线检查一下是否和已经存在的包名有重复(包括其他人申请的包名)。申请成功以后,会分配一个唯一的APP ID:</p><p><img src="https://p0.meituan.net/meituantechblog/bc9c333f2aa419ccedae155d2099144b124038.png" alt="" referrerpolicy="no-referrer"></p><p>这个APP ID用来在网站上标识APP的唯一性。后面文章中会出现类似的名称,为了消除歧义,相似的字段用括号内容区分,这里称为APP ID(网站)。</p><p><strong>⑤ 生成Profile文件</strong></p><p>Profile文件是描述App的包名、签名、申请的权限列表、安装包类型、可安装设备等信息的文件(类似iOS的Provisioning Profile),签名后保存为Cryptographic Message Syntax格式(CMS,扩展的PKCS#7/格式,CMS定义在<a href="https://datatracker.ietf.org/doc/html/rfc5652">RFC 5652</a>,PKCS#7定义在<a href="https://datatracker.ietf.org/doc/html/rfc2315">RFC 2315</a>。)</p><p>跟着<a href="https://developer.huawei.com/consumer/cn/doc/app/agc-help-add-releaseprofile-0000001914714796">操作步骤</a>,选择之前的APP ID(网站)和证书,可以得到对应的Profile文件:</p><p><img src="https://p0.meituan.net/meituantechblog/575ea26ba13ea156416477c136e924f6141731.png" alt="" referrerpolicy="no-referrer"></p><p>Profile也分为发布和调试两种,发布只能选择发布证书,调试只能选择调试证书。这里继续以发布类型为例,生成的Profile文件(保存为my.p7b)被华为签名后, 通过如下命令可以查看里面的所有信息:</p><pre><code>openssl pkcs7 -in my.p7b -print -inform DER
</code></pre><p>主要包括配置信息和签名信息两部分,也可以通过如下命令分别查看配置信息和签名信息:</p><pre><code>openssl smime -verify -in my.p7b -inform DER -noverify //查看配置信息
openssl pkcs7 -in my.p7b -print_certs -inform DER //查看证书信息
</code></pre><p>得到的示例配置信息如下(*为手动打码):</p><pre><code>{
"version-name": "2.0.0",
"version-code": 2,
"app-distribution-type": "app_gallery",
"uuid": "234e1d73-****-****-****-f81e2598d0ff",
"validity": {
"not-before": 1727096284,
"not-after": 1821704284
},
"type": "release",
"bundle-info": {
"developer-id": "300**********7916",
"distribution-certificate": "-----BEGIN CERTIFICATE-----\nMIICujCCAkGgAwIBAgIOY8ui/vvwxqFf+kFokYUwCgYIKoZIzj0EAwMwYjELMAkG\nA1UEBgwCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEt\nMCsGA1UEAwwkSHVhd2VpIENCRyBEZXZlbG9wZXIgUmVsYXRpb25zIENBIEcyMB4X\nDTI0MDkyMzEyNTgwNFoXDTI3MDkyMzEyNTgwNFowazELMAkGA1UEBhMCQ04xDzAN\nBgNVBAoMBuW8oOaZqDEcMBoGA1UECwwTMTI4OTY3Njc4NjA2NTQ5NDk3NzEtMCsG\nA1UEAwwk5byg5pmoKDEyODk2NzY3ODYwNjU0OTQ5NzcpXCxSZWxlYXNlMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAEPbyzvysXz5fUlaCRBx8cHYbLbQwJPnU657p4\nblls+xQqVms/HRpFfR6KcvYTlawTey3TMjjK+PQrOF0TCSwJYKOB0TCBzjAMBgNV\nHRMBAf8EAjAAMFkGA1UdHwRSMFAwTqBMoEqGSGh0dHA6Ly9oNWhvc3RpbmctZHJj\nbi5kYmFua2Nkbi5jbi9jY2g1L2NybC9oZHJjYWcyL0h1YXdlaUNCR0hEUkcyY3Js\nLmNybDAfBgNVHSMEGDAWgBTbXpOyI+jQ5P5xembppHNHW3/zXjAdBgNVHQ4EFgQU\nbQhFjIxK/m516AKkgn45pNW7SUAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG\nCCsGAQUFBwMDMAoGCCqGSM49BAMDA2cAMGQCMFzNlsafNs7ad5xelZOzCebdRofE\nVaQZJW0o5QAdTX0t9Ij1o/zUm0bXIf8ZZTJLYgIwKuuZu+LeLCLZJFEM7tYKDhIK\nTegCiesP1THuMgiZhZYOYl1kIZBPVrEB8O1wtxEm\n-----END CERTIFICATE-----\n",
"bundle-name": "com.***.test",
"apl": "normal",
"app-feature": "hos_normal_app",
"app-identifier": "576************2509"
},
"baseapp-info": {},
"permissions": {},
"acls": {},
"issuer": "app_gallery"
}
</code></pre><p>具体每个字段的含义可以参考<a href="https://gitee.com/openharmony/docs/blob/OpenHarmony-v5.0.0-Release/zh-cn/application-dev/security/app-provision-structure.md">官方文档</a>和<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/provision/provision_verify.cpp">源码中的定义</a>,其中重点字段解析如下:</p><p><img src="https://p0.meituan.net/meituantechblog/9ec3fb6ceb8499af8b70cb9ed6c58853311182.png" alt="" referrerpolicy="no-referrer"></p><p>得到的示例证书内容如下:</p><pre><code>subject=C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
issuer=C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
-----BEGIN CERTIFICATE-----
MIICGjCCAaGgAwIBAgIIShhpn519jNAwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE
AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjAzMDQzOVoXDTQ5MDMx
NjAzMDQzOVowUzELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEeMBwGA1UEAwwVSHVhd2VpIENCRyBSb290IENBIEcyMHYw
EAYHKoZIzj0CAQYFK4EEACIDYgAEWidkGnDSOw3/HE2y2GHl+fpWBIa5S+IlnNrs
GUvwC1I2QWvtqCHWmwFlFK95zKXiM8s9yV3VVXh7ivN8ZJO3SC5N1TCrvB2lpHMB
wcz4DA0kgHCMm/wDec6kOHx1xvCRo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
AQH/BAUwAwEB/zAdBgNVHQ4EFgQUo45a9Vq8cYwqaiVyfkiS4pLcIAAwCgYIKoZI
zj0EAwMDZwAwZAIwMypeB7P0IbY7c6gpWcClhRznOJFj8uavrNu2PIoz9KIqr3jn
BlBHJs0myI7ntYpEAjBbm8eDMZY5zq5iMZUC6H7UzYSix4Uy1YlsLVV738PtKP9h
FTjgDHctXJlC5L7+ZDY=
-----END CERTIFICATE-----
subject=C = CN, O = Huawei, OU = HOS AppGallery, CN = HOS Profile Management
issuer=C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Software Signing Service CA
-----BEGIN CERTIFICATE-----
MIIC7TCCAnOgAwIBAgIIV5nKqt2oGmwwCgYIKoZIzj0EAwMwZDELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEvMC0GA1UE
AwwmSHVhd2VpIENCRyBTb2Z0d2FyZSBTaWduaW5nIFNlcnZpY2UgQ0EwHhcNMjMw
NDI0MDYyNjMxWhcNMjgwNDI0MDYyNjMxWjBYMQswCQYDVQQGDAJDTjEPMA0GA1UE
CgwGSHVhd2VpMRcwFQYDVQQLDA5IT1MgQXBwR2FsbGVyeTEfMB0GA1UEAwwWSE9T
IFByb2ZpbGUgTWFuYWdlbWVudDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDdY
3RoPqb6WD8UpXJiavZLN48iamektKUKZHFl9xwr1Siu77z3lI86cREa3Flw50uKc
xkMNKM4FWBRMd3CDhI+jggEZMIIBFTAfBgNVHSMEGDAWgBT69fe+IFZdXdTabfEU
FTwdCduyNDAdBgNVHQ4EFgQU0a99kztpYeCetotz0YIduJ2I2VcwRgYDVR0gBD8w
PTA7BgRVHSAAMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly9wa2kuY29uc3VtZXIuaHVh
d2VpLmNvbS9jYS9jcHMwDgYDVR0PAQH/BAQDAgeAMEwGA1UdHwRFMEMwQaA/oD2G
O2h0dHA6Ly9wa2kuY29uc3VtZXIuaHVhd2VpLmNvbS9jYS9jcmwvc29mdF9zaWdu
X3Nydl9jcmwuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBgGDCsGAQQBj1sCgngB
AwQIMAYCAQEKAQEwCgYIKoZIzj0EAwMDaAAwZQIwRYOlQ6Qq2SF8LHQ78xpNYh47
zMemerx5oG4F6Uq/3ARPfowvdrEu5Ss+njPMG0FFAjEA0s7YhO7Ktm60mkuHuxQS
46fqIHh/PAPJ2ozg1yDSD771bAGn7mDeGjaAFXEtKzU5
-----END CERTIFICATE-----
subject=C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Software Signing Service CA
issuer=C = CN, O = Huawei, OU = Huawei CBG, CN = Huawei CBG Root CA G2
-----BEGIN CERTIFICATE-----
MIIDADCCAoegAwIBAgIIJGDixWQS3MkwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE
AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjEyMzIzOVoXDTQwMDMx
NjEyMzIzOVowZDELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEvMC0GA1UEAwwmSHVhd2VpIENCRyBTb2Z0d2FyZSBTaWdu
aW5nIFNlcnZpY2UgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASsEz7cwYkzFh9b
xIwKfXx5qHGjl5WITy0teGnNWqv+jYCceeixHqErvK7YRn2hVPIqhRqKWeANHZUK
G0qxi+NIpmSmQS8/63CLz1QAcxfv2Xl3/V82dF0v9lm16ehMsN+jggEVMIIBETAf
BgNVHSMEGDAWgBSjjlr1WrxxjCpqJXJ+SJLiktwgADAdBgNVHQ4EFgQU+vX3viBW
XV3U2m3xFBU8HQnbsjQwDwYDVR0TAQH/BAUwAwEB/zBGBgNVHSAEPzA9MDsGBFUd
IAAwMzAxBggrBgEFBQcCARYlaHR0cDovL2Nwa2ktY2F3ZWIuaHVhd2VpLmNvbS9j
cGtpL2NwczAOBgNVHQ8BAf8EBAMCAQYwZgYDVR0fBF8wXTBboFmgV4ZVaHR0cDov
L2Nwa2ktY2F3ZWIuaHVhd2VpLmNvbS9jcGtpL3NlcnZsZXQvY3JsRmlsZURvd24u
Y3JsP2NlcnR5cGU9MTAmL3Jvb3RfZzJfY3JsLmNybDAKBggqhkjOPQQDAwNnADBk
AjBrAQQxUlNgqhYkcEm5eksnPxDkPJSY/qNd2BDgbvEydiLwPSvB7Z9lipxz8ikZ
EeUCMGppWcaV//SIG1y5tEwthLwWeEaF613vUILWQLir8+CA3RZGsRBqtE8xSqfz
yafLYQ==
-----END CERTIFICATE-----
</code></pre><p>这里依然是完整的三级证书链,注意,根证书和之前申请到的开发者签名证书的根证书一样,但中间证书和叶子证书均不一样,比较如下(红色底色表示内容相同):</p><p><img src="https://p0.meituan.net/meituantechblog/83ab59e0e7296e818531e3ca03010f13173401.png" alt="" referrerpolicy="no-referrer"></p><h3 id="2-3-生成签名的app">2.3 生成签名的App</h3><p><strong>⑥ 得到签名的App包</strong></p><p>将生成的Profile文件、叶子证书文件等配置到项目的signingConfigs里,使用华为的IDE可以直接得到签名后的App包:</p><p><img src="https://p0.meituan.net/meituantechblog/e305f605163fc00e1ba613f4ed6ea230147135.png" alt="" referrerpolicy="no-referrer"></p><p>或者<a href="https://gitee.com/openharmony/developtools_hapsigner#%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E">参考命令</a>手动给未签名的App包进行签名。</p><p>得到的签名的App包只是用于提供给华为商店进行审核和后续的拆包,并不能直接安装到手机上运行。App包实际上就是标准的ZIP格式,可以修改后缀为.zip进行解压:</p><p><img src="https://p0.meituan.net/meituantechblog/8283faf0944d27fe295b9ff2286828a021855.png" alt="" referrerpolicy="no-referrer"></p><p>可以看到里面包括了.hap包和描述App一些信息的pack.info文件。</p><p>那么对App包进行签名的内容以及Profile文件在哪里呢?根据对源码里<a href="https://gitee.com/openharmony/developtools_hapsigner/blob/OpenHarmony-v5.0.0-Release/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/VerifyHap.java">VerifyHap.java类的verifyHap</a>函数进行分析,发现鸿蒙上的签名机制类似Android V3,签名信息和Profile文件存储在自定义的HapSigningBlock区,放到了ZIP格式Central Directory区的前面,其结构如下:</p><p><img src="https://p0.meituan.net/meituantechblog/575288d443290509f33b9961fc456897119046.png" alt="" referrerpolicy="no-referrer"></p><p>HapSigningBlock区的魔数(转成string也就是<hap sign="" block="">):</hap></p><pre><code> /**
* The value of lower 8 bytes of magic word
*/
public static final long HAP_SIG_BLOCK_MAGIC_LO_V3 = 0x676973207061683cL;
/**
* The value of higher 8 bytes of magic word
*/
public static final long HAP_SIG_BLOCK_MAGIC_HI_V3 = 0x3e6b636f6c62206eL;
/**
* Size of hap signature block header
*/
public static final int HAP_SIG_BLOCK_HEADER_SIZE = 32;
</code></pre><p>通过hex工具直接打开App包也可以在Central Directory区前面找到:</p><p><img src="https://p0.meituan.net/meituantechblog/fb9e6953eba868a5f42bc5bb0d8b2c0b87714.png" alt="" referrerpolicy="no-referrer"></p><p>其中SignatureSchemeBlock区存放了CMS格式的Hap包签名信息,而Profile文件就存储在SigningBlock区,Type是0x20000002:</p><pre><code> /**
* ID of profile block
*/
public static final int HAP_PROFILE_BLOCK_ID = 0x20000002;
</code></pre><p>通过如下<a href="https://gitee.com/openharmony/developtools_hapsigner/tree/OpenHarmony-v5.0.0-Release/dist">hap-sign-tool.jar</a>的命令可以导出存储在App包或Hap包里的签名证书和Profile文件:</p><pre><code>java -jar hap-sign-tool.jar verify-app -inFile my-signed.app -outCertChain my-signed.cer -outProfile my-signed.p7b
</code></pre><p><strong>⑦ 签名校验、拆包、重签名</strong></p><p>提供给华为应用市场审核的App包在经过签名校验,确认是开发者的应用以及应用的完整性以后,华为会取出App包SigningBlock区的Profile文件,解压出Hap包,把Profile文件或Profile文件内的配置(下一章节展开描述区别)重新放到Hap包的SigningBlock区里,并用Hap的签名叶子证书对Hap包进行重新签名,签名方式和给App包签名一样。最终真正<strong>通过应用市场下发到手机上的是经过重签名的Hap包(类似iOS的双层签名机制)</strong>。解析出签名证书如下:</p><pre><code>CN=HOS AppGallery Application Release, OU=HOS AppGallery, O=Huawei, C=CN
-----BEGIN CERTIFICATE-----
MIIC+TCCAn+gAwIBAgIIWXsBFAJOQzIwCgYIKoZIzj0EAwMwZDELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEvMC0GA1UE
AwwmSHVhd2VpIENCRyBTb2Z0d2FyZSBTaWduaW5nIFNlcnZpY2UgQ0EwHhcNMjMw
NDI0MDYyMjA1WhcNMjgwNDI0MDYyMjA1WjBkMQswCQYDVQQGDAJDTjEPMA0GA1UE
CgwGSHVhd2VpMRcwFQYDVQQLDA5IT1MgQXBwR2FsbGVyeTErMCkGA1UEAwwiSE9T
IEFwcEdhbGxlcnkgQXBwbGljYXRpb24gUmVsZWFzZTBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABIokjn9tVRpgEC6b1AR9chiiejUGBiF83Lzm1giyZX9XKVzTPkHq
RRuML+zhRtT1JESEMOUggPyJbe9+rt3k9CijggEZMIIBFTAfBgNVHSMEGDAWgBT6
9fe+IFZdXdTabfEUFTwdCduyNDAdBgNVHQ4EFgQUFzRtDLYZ7zX/idRsHYmJZ734
vwgwRgYDVR0gBD8wPTA7BgRVHSAAMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly9wa2ku
Y29uc3VtZXIuaHVhd2VpLmNvbS9jYS9jcHMwDgYDVR0PAQH/BAQDAgeAMEwGA1Ud
HwRFMEMwQaA/oD2GO2h0dHA6Ly9wa2kuY29uc3VtZXIuaHVhd2VpLmNvbS9jYS9j
cmwvc29mdF9zaWduX3Nydl9jcmwuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBgG
DCsGAQQBj1sCgngBAwQIMAYCAQEKAQAwCgYIKoZIzj0EAwMDaAAwZQIxAJofyGQW
4ZVDW64qTeiVQVn5w7iRhejP6YFqYX9h/5mNXKMQ8ZuQCFT7EaqhVblWlQIwWIPB
xC+YhPz6JmDMSZDynZINnXi0T3k9UvbcCybbd2k2PWHYvYqQdKAuYGcNc2Ho
-----END CERTIFICATE-----
CN=Huawei CBG Software Signing Service CA, OU=Huawei CBG, O=Huawei, C=CN
-----BEGIN CERTIFICATE-----
MIIDADCCAoegAwIBAgIIJGDixWQS3MkwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC
Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE
AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjEyMzIzOVoXDTQwMDMx
NjEyMzIzOVowZDELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEvMC0GA1UEAwwmSHVhd2VpIENCRyBTb2Z0d2FyZSBTaWdu
aW5nIFNlcnZpY2UgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASsEz7cwYkzFh9b
xIwKfXx5qHGjl5WITy0teGnNWqv+jYCceeixHqErvK7YRn2hVPIqhRqKWeANHZUK
G0qxi+NIpmSmQS8/63CLz1QAcxfv2Xl3/V82dF0v9lm16ehMsN+jggEVMIIBETAf
BgNVHSMEGDAWgBSjjlr1WrxxjCpqJXJ+SJLiktwgADAdBgNVHQ4EFgQU+vX3viBW
XV3U2m3xFBU8HQnbsjQwDwYDVR0TAQH/BAUwAwEB/zBGBgNVHSAEPzA9MDsGBFUd
IAAwMzAxBggrBgEFBQcCARYlaHR0cDovL2Nwa2ktY2F3ZWIuaHVhd2VpLmNvbS9j
cGtpL2NwczAOBgNVHQ8BAf8EBAMCAQYwZgYDVR0fBF8wXTBboFmgV4ZVaHR0cDov
L2Nwa2ktY2F3ZWIuaHVhd2VpLmNvbS9jcGtpL3NlcnZsZXQvY3JsRmlsZURvd24u
Y3JsP2NlcnR5cGU9MTAmL3Jvb3RfZzJfY3JsLmNybDAKBggqhkjOPQQDAwNnADBk
AjBrAQQxUlNgqhYkcEm5eksnPxDkPJSY/qNd2BDgbvEydiLwPSvB7Z9lipxz8ikZ
EeUCMGppWcaV//SIG1y5tEwthLwWeEaF613vUILWQLir8+CA3RZGsRBqtE8xSqfz
yafLYQ==
-----END CERTIFICATE-----
</code></pre><p>注意这里给<strong>Hap的签名证书和我们之前申请的开发者签名证书不一样</strong>,Hap签名证书和对应的私钥都是华为的,跟我们的应用没有关系,而且签名证书链里不包含根证书的信息。</p><p>这里再和之前的证书对比一下(红色和黄色底色表示内容分别相同):</p><p><img src="https://p0.meituan.net/meituantechblog/2745ee0de317a237680ed567848101fa267287.png" alt="" referrerpolicy="no-referrer"></p><p>三者的根证书都一样,Profile签名证书和Hap签名证书的中间证书一样,三者的叶子证书均不一样。</p><p>另外,如果在上架应用市场的时候,勾选了加密:</p><p><img src="https://p0.meituan.net/meituantechblog/b23b24b27260692d1e25976a07f16fca188561.png" alt="" referrerpolicy="no-referrer"></p><p>根据《<a href="https://developer.huawei.com/consumer/cn/doc/guidebook/harmonyecoappsecurity-guidebook-0000001808819033">鸿蒙生态应用安全技术白皮书</a>》描述,只是对Hap包里的代码做加密,然后重新签名,所以证书和Profile文件的解析均不受影响。</p><h2 id="3-校验机制">3. 校验机制</h2><p>签名相关的代码在<a href="https://gitee.com/openharmony/security_appverify/tree/OpenHarmony-v5.0.0-Release/">security_appverify</a>仓库里,签名校验流程梳理如下(图上所有判断条件在失败情况下均会导致签名校验失败,为了直观不画出此流程):</p><p><img src="https://p0.meituan.net/meituantechblog/9a02c110d00d5ae9596c3966ec8ca11c377687.png" alt="" referrerpolicy="no-referrer"></p><p>签名校验步骤可以分成三组,分别是:</p><ol><li>SignatureSchemeBlock区校验。</li><li>Profile校验和解析。</li><li>Hap包完整性校验。</li></ol><h3 id="3-1-signatureschemeblock区校验">3.1 SignatureSchemeBlock区校验</h3><p>校验Hap包时首先在ZIP的Central Directory区前32个字节寻找是否有HapSigningBlock区的Header,找到以后定位到SignatureSchemeBlock区,解析其CMS格式,并校验SignatureSchemeBlock区证书链的完整性。证书链完整性校验流程如下:</p><p><img src="https://p0.meituan.net/meituantechblog/2fad2d1c6eea7aa33fbfdcfc0f9bcfdb42777.png" alt="" referrerpolicy="no-referrer"></p><p>校验叶子证书时,需要按证书指定算法重新计算证书的hash,并使用上一级证书(中间证书)的公钥对叶子证书里的证书签名进行解密,与重新计算的hash比对是否相同,相同则认为证书可信。中间证书继续通过根证书的公钥校验自己的证书签名。根证书用自己的公钥校验自己。</p><p>上一章说到,SignatureSchemeBlock区的证书链不包括根证书,所以这一步需要使用到根证书其实是内置在鸿蒙系统里的,存放地址是:</p><pre><code>/system/etc/security/trusted_root_ca.json
</code></pre><p>具体内容如下:</p><pre><code>{
"C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Root CA G2":"-----BEGIN CERTIFICATE-----\nMIICGjCCAaGgAwIBAgIIShhpn519jNAwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC\nQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE\nAwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjAzMDQzOVoXDTQ5MDMx\nNjAzMDQzOVowUzELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE\nCwwKSHVhd2VpIENCRzEeMBwGA1UEAwwVSHVhd2VpIENCRyBSb290IENBIEcyMHYw\nEAYHKoZIzj0CAQYFK4EEACIDYgAEWidkGnDSOw3/HE2y2GHl+fpWBIa5S+IlnNrs\nGUvwC1I2QWvtqCHWmwFlFK95zKXiM8s9yV3VVXh7ivN8ZJO3SC5N1TCrvB2lpHMB\nwcz4DA0kgHCMm/wDec6kOHx1xvCRo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T\nAQH/BAUwAwEB/zAdBgNVHQ4EFgQUo45a9Vq8cYwqaiVyfkiS4pLcIAAwCgYIKoZI\nzj0EAwMDZwAwZAIwMypeB7P0IbY7c6gpWcClhRznOJFj8uavrNu2PIoz9KIqr3jn\nBlBHJs0myI7ntYpEAjBbm8eDMZY5zq5iMZUC6H7UzYSix4Uy1YlsLVV738PtKP9h\nFTjgDHctXJlC5L7+ZDY=\n-----END CERTIFICATE-----\n"
}
</code></pre><p>可以看到这个根证书就是上一章解析出来的根证书,所以这里可以校验通过。</p><p>在确认证书链可信以后,根据叶子证书的Subject判断Hap包的安装来源,具体代码在<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/init/trusted_source_manager.cpp">trusted_source_manager.cpp的MatchTrustedSource函数里</a>,也就是和内置的Hap签名证书列表进行比较,看匹配到哪一个。内置的Hap签名证书列表存放地址是:</p><pre><code>/system/etc/security/trusted_apps_sources.json
</code></pre><p>具体内容如下:</p><pre><code>{
"version": "1.0.1",
"release-time":"2021-06-03 10:06:00",
"trust-app-source":[
{
"name":"huawei app gallery",
"app-signing-cert":"C=CN, O=Huawei, OU=HOS AppGallery, CN=HOS AppGallery Application Release",
"profile-signing-certificate":"C=CN, O=Huawei, OU=HOS AppGallery, CN=HOS Profile Management",
"profile-debug-signing-certificate":"C=CN, O=Huawei, OU=HOS AppGallery, CN=HOS Profile Management Debug",
"issuer-ca":"C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Software Signing Service CA",
"root-ca": "C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Root CA G2",
"max-certs-path":3,
"critialcal-cert-extension":["keyusage","huawei-signing-capability"]
},
{
"name":"huawei system apps",
"app-signing-cert":"C=CN, O=Huawei CBG, OU=HOS Development Team, CN=HOS Application Provision Release",
"profile-signing-certificate":"C=CN, O=Huawei CBG, OU=HOS Development Team, CN=HOS Application Provision Profile Release",
"profile-debug-signing-certificate":"C=CN, O=Huawei CBG, OU=HOS Development Team, CN=HOS Application Provision Profile Release_Debug",
"issuer-ca":"C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Software Signing Service CA",
"root-ca": "C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Root CA G2",
"max-certs-path":3,
"critialcal-cert-extension":["keyusage","huawei-signing-capability"]
},
{
"name":"third_party app preload",
"app-signing-cert":"C=CN, O=Huawei, OU=HOS Open Platform, CN=HOS Preload Service",
"profile-signing-certificate":"",
"profile-debug-signing-certificate":"",
"issuer-ca":"C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Software Signing Service CA",
"root-ca": "C=CN, O=Huawei, OU=Huawei CBG, CN=Huawei CBG Root CA G2",
"max-certs-path":3,
"critialcal-cert-extension":["keyusage","huawei-signing-capability"]
}
]
}
</code></pre><p>这里有Huawei App Gallery(应用市场)、Huawei System Apps(系统应用)、Third_party App Preload(三方预装)三组。每一组包括对应的Hap签名证书Subject、Profile签名证书Subject等信息。</p><p>我们走应用市场分发的Hap包会匹配到Huawei App Gallery这个证书。</p><h3 id="3-2-profile解析和校验">3.2 Profile解析和校验</h3><p>接下来在SigningBlock区寻找Profile,这里注意到<strong>不同Hap包签名方式会影响Profile的存储格式</strong>。对于走应用市场分发的Hap包,Profile是直接把其配置以字符串的格式保存,而对于其他情况,则是用CMS的格式保存。那么应用市场分发的Hap包也就不需要Profile的文件签名校验了。</p><p>对于其他情况,首先会使用Profile里保存的叶子证书公钥校验Profile的文件签名,然后会校验叶子证书Subject是否和匹配的同组内Profile签名证书Subject相同。</p><p>校验通过后解析Profile里的配置信息,根据type不同走不同的校验逻辑:</p><ul><li>发布,会校验是否为允许的安装来源,根据<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/verify/hap_verify_v2.cpp">hap_verify_v2.cpp的IsAppDistributedTypeAllowInstall函数</a>,允许的来源包括企业签名、MDM、众包测试等分发场景。</li><li>调试,会校验待安装的设备UDID是否在Profile的device-ids列表中。</li></ul><p>都校验通过后,再继续看Profile文件签名证书和Hap的签名正式是否相同,并继续对Profile配置的字段规则合法性进行检测。走完这一步,就可以认为Profile是可信的。</p><p>随后会生成App ID(公钥)和Fingerprint两个新的字段和验证结果一并返回。其中APP ID(公钥)是根据Profile配置里开发者签名证书公钥生成的(详见<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/verify/hap_verify_v2.cpp">GenerateAppId函数</a>),fingerprint是根据Profile配置里开发者签名证书直接计算整个证书的指纹(注意不是上一章的公钥指纹,详见<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/verify/hap_verify_v2.cpp">GenerateFingerprint</a>函数)。至此完成Profile的解析和校验。</p><p>另外,在鸿蒙<a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-bundlemanager-bundleinfo-V5#signatureinfo">SignatureInfo API</a>中,会返回三个参数:</p><p><img src="https://p0.meituan.net/meituantechblog/1908765069afdf87f4c353952de39790212422.png" alt="" referrerpolicy="no-referrer"></p><p>其中API返回的appId为了消除歧义,这里称为APP ID(接口)。</p><p>根据包管理子系统<a href="https://gitee.com/openharmony/bundlemanager_bundle_framework/blob/OpenHarmony-v5.0.0-Release/services/bundlemgr/src/bundle_install_checker.cpp">bundle_install_checker.cpp的ParseHapFiles函数</a>、<a href="https://gitee.com/openharmony/bundlemanager_bundle_framework/blob/OpenHarmony-v5.0.0-Release/services/bundlemgr/include/inner_bundle_info.h">inner_bundle_info.h的SetProvisionId函数</a>和<a href="https://gitee.com/openharmony/bundlemanager_bundle_framework/pulls/52/files">这个PR</a>来看:</p><pre><code>// bundle_install_checker.cpp
newInfo.SetProvisionId(provisionInfo.appId);
// inner_bundle_info.h
void SetProvisionId(const std::string &amp;provisionId)
{
baseBundleInfo_-&gt;appId = baseBundleInfo_-&gt;name + Constants::FILE_UNDERLINE + provisionId;
}
</code></pre><p>APP ID(接口)的值实际上是APP ID(公钥)加上了{bundleName}_的前缀。</p><h3 id="3-3-hap包完整性校验">3.3 Hap包完整性校验</h3><p>这一步的过程和Hap包签名类似,将ZIP包中数据和HapSigningBlock区里非SignatureSchemeBlock的部分拼接,重新计算hash,与使用Hap签名叶子证书公钥解密SignatureSchemeBlock区签名后的hash比较,相同则认为Hap包未被篡改。具体可以参考<a href="https://gitee.com/openharmony/security_appverify/blob/OpenHarmony-v5.0.0-Release/interfaces/innerkits/appverify/src/util/hap_signing_block_utils.cpp">hap_signing_block_utils.cpp的VerifyHapIntegrity函数</a>,这里就不展开了。</p><h2 id="总结">总结</h2><p>从鸿蒙单框架应用的签名和校验机制的种种细节中可以看出,HarmonyOS NEXT的安全设计非常务实,融合了Android和iOS双端的特性,有借鉴Android成熟的部分(签名格式),但更多的是参考了iOS的设计思路(双层签名机制),甚至更加严格。期待HarmonyOS NEXT给我们带来一个新的未来。</p><p>特别感谢华为同学对本文的大力支持。</p></description>
<link>https://tech.meituan.com/2025/01/06/openharmony.html</link>
<guid isPermaLink="false">https://tech.meituan.com/2025/01/06/openharmony.html</guid>
<pubDate>Mon, 06 Jan 2025 00:00:00 GMT</pubDate>
<author>美团技术团队</author>
</item>
<item>
<title>2024 | 美团技术团队热门技术文章汇总</title>
<description><p>岁月的车轮滚滚向前,我们即将挥别充满回忆的2024,迈入崭新的、充满希望的2025。在此,衷心感谢伙伴们过去一年的陪伴与支持。</p><p><img src="https://p0.meituan.net/meituantechblog/b976fc16e0fb9e5060b6049585dabcad249415.jpg" alt="" referrerpolicy="no-referrer"></p><p>今天,我们整理了2024年美团技术团队最为热门的10篇技术文章,这些文章覆盖了基础理论、数据存储、因果推断、搜索推荐、智能测试、知识图谱、领域驱动设计等多个技术领域,期望这些精选内容能为大家带来一些启发或帮助。愿大家在新的一年里,持续深耕技术沃土,稳步前行,不断攀登新的高峰。</p><h2 id="01-基本功-一文讲清多线程和多线程同步">01&nbsp;基本功 | 一文讲清多线程和多线程同步</h2><p><img src="https://p0.meituan.net/meituantechblog/46c434af68b098f65491bb9cc64a176f383178.jpg" alt="" referrerpolicy="no-referrer"></p><p>多线程编程是现代软件开发中的一项关键技术,在多线程编程中,开发者可以将复杂的任务分解为多个独立的线程,使其并行执行,从而充分利用多核处理器的优势。然而,多线程编程也带来了挑战,例如线程同步、死锁和竞态条件等问题。本篇文章将深入探讨多线程编程的基本概念(原子操作、CAS、Lock-free、内存屏障、伪共享、乱序执行等)、常见模式和最佳实践。通过具体的代码示例,希望能够帮助大家掌握多线程编程的核心技术,并在实际开发中应用这些知识,提升软件的性能和稳定性。(<a href="https://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&amp;mid=2651778446&amp;idx=1&amp;sn=44306b644777a4d939730e7774071541&amp;scene=21#wechat_redirect">阅读全文</a>)</p><h2 id="02-ddd在大众点评交易系统演进中的应用">02&nbsp;DDD在大众点评交易系统演进中的应用</h2><p><img src="https://p0.meituan.net/meituantechblog/0365d5c51db9c02682794df240eb7eb7626207.jpg" alt="" referrerpolicy="no-referrer"></p><p>本文整理自美团技术沙龙第73期《基于领域驱动设计(DDD)的架构演进和实践》(<a href="https://www.bilibili.com/video/BV1nt4y1J7hH/?spm_id_from=333.999.0.0&amp;vd_source=aea2a93491bea0d72f7e5b8a79085d70">B站视频</a>),主要介绍了DDD的核心概念、常见的设计思路,并结合DDD介绍大众点评交易系统的演进过程,最后做了一些总结和思考。(<a href="https://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&amp;mid=2651777662&amp;idx=1&amp;sn=22ba8694d0a0d1da7c47b0a6a1367fab&amp;scene=21#wechat_redirect">阅读全文</a>)</p><h2 id="03-美团大规模kv存储挑战与架构实践">03&nbsp;美团大规模KV存储挑战与架构实践</h2><p><img src="https://p0.meituan.net/meituantechblog/01f2c4d5e7f9df82909c160a655a2295822233.jpg" alt="" referrerpolicy="no-referrer"></p><p>KV 存储作为美团一项重要的在线存储服务,承载了在线服务每天万亿级的请求量,并且保持着 99.995% 的服务可用性。文章主要分为四个部分:第一部分介绍了美团 KV 存储发展历程;第二部分分享了内存 KV Squirrel 挑战和架构实践;第三部分阐述了持久化 KV Cellar 挑战和架构实践;最后一部分介绍了未来的发展规划。(<a hre |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Involved Issue / 该 PR 相关 Issue
Close #
Example for the Proposed Route(s) / 路由地址示例
New RSS Route Checklist / 新 RSS 路由检查表
Puppeteer
Note / 说明