首页 文章 精选 留言 我的

精选列表

搜索[Harness工程],共10000篇文章
优秀的个人博客,低调大师

百度工程师浅析强化学习

作者 |Jane 导读 本文主要介绍了强化学习(Reinforcement Learning,RL)的基本概念以及什么是RL。强化学习让智能体通过与环境的交互来学习如何做出决策,以获得最大的累积奖励。文章还介绍了策略梯度(Policy Gradient,PG)和近端策略优化(PPO)等强化学习算法。 全文7099字,预计阅读时间18分钟。 01 强化学习(Reinforcement Learning,RL) 1.1 基本概念&什么是RL 强化学习(reinforcement learning,RL)专注于让智能体(agent)通过与环境的交互来学习如何做出决策,以使其在不断变化且不确定的环境中获得最大的累积奖励。 这个过程可以用以下几个要素来描述: 智能体(Agent):智能体是执行动作并与环境进行交互的实体。它可以是一个机器人、一个虚拟角色、一个算法等。 环境(Environment):环境包括智能体所处的所有上下文,包括外部条件、状态变量和其他影响智能体的因素。 动作(Action):智能体可以在环境中执行的操作,这些操作可能会改变环境的状态。 状态(State):状态是描述环境的当前情况的信息。智能体的决策通常依赖于当前状态。 奖励(Reward):在每个时间步,智能体执行一个动作后会获得一个奖励信号,用于指示动作的好坏。目标是最大化累积奖励。 策略(Policy):策略定义了智能体如何根据当前状态选择动作。强化学习的目标之一是找到一个最优策略,使智能体能够获得最大的累积奖励。 价值函数(Value Function):价值函数衡量了在某个状态下执行某个策略能够获得的预期累积奖励。这个函数帮助智能体评估不同状态的重要性。 学习过程:强化学习的核心是智能体通过尝试不同的动作并观察奖励信号来学习适应性策略。它可以使用不同的算法,如Q-learning、Deep Q-Networks(DQN)、Policy Gradient等。 △图1 强化学习过程 其中状态(State)是对整个环境的完整描述,包括了所有对智能体的决策和行动有影响的信息。状态通常用来指导智能体的决策,因为它提供了有关环境当前状态的全部信息。 观测(Observation)则是对状态的一种抽象描述,它可能会忽略或省略一些状态信息。在实际问题中,有时候智能体无法直接观测到完整的状态,而只能获取到一部分信息,即观测。这可能是因为某些信息无法直接测量,或者因为为了简化问题而对状态进行了抽象。 因此,智能体基于它的观测来做出决策,而不是直接使用完整的状态。这就需要智能体具备从观测中学习有关状态的信息的能力,以便更好地进行决策和行动。 下面举一些可应用强化学习的示例: 1、在电子游戏中,摇杆是智能体,主机是环境,显示屏上的游戏画面(像素)是观测,击杀怪物得分则是奖励。 2、在阿法狗围棋对弈中,阿法狗是智能体,人类棋手是环境,棋局是观测,围棋的输赢则是奖励。 在强化学习中,智能体持续与环境进行交互,采取一系列的动作,从而形成一个状态和动作的序列,这个序列被称为轨迹(trajectory): 一个交互序列被称为一个回合(episode),在每个回合中,智能体根据当前状态选择动作,与环境互动,并根据奖励信号进行学习和策略优化,以获得最大化累积奖励。 这里需要注意的是,环境对我们来说是黑盒,是不可控的,它在当前状态下跳转到下一状态是服从一定的分布的,也就是说它是有一定的随机性的,那么它产出的奖励也具有了一定的随机性。我们可控的是actor的policy,即可以通过学习,让policy在面对状态 s 时采取一个能让他获得最大奖励的action。所以实际上我们的目标是最大化期望的累积奖励(expected cumulative reward)。 1.2RL和监督学习的区别 监督学习: 1. 数据独立同分布(i.i.d.):监督学习假设样本是从一个未知分布中独立地采样得到的,数据之间没有时序关联。 2. 标签信息:在监督学习中,每个样本都有正确的标签信息,即模型需要学习从输入到标签的映射关系。 3. 训练目标:监督学习的目标是使模型的预测尽可能地接近真实标签,通常通过最小化预测与真实标签之间的损失函数来实现。 4. 局限性:监督学习在需要大量标记数据、难以获取所有可能状态的标签信息或者数据之间存在时序关联的情况下可能受限。 强化学习: 1. 时序关联数据:强化学习中智能体的观测是时序关联的,当前的决策会影响未来的观测和奖励。 2. 延迟奖励:强化学习中智能体在做出决策后不会立即得到奖励,奖励可能在未来的时间步骤才会出现,这就需要智能体通过试错来学习哪些决策导致了最终的奖励。 3. 探索与学习:强化学习中智能体需要在探索和利用之间找到平衡,以发现能够最大化长期累积奖励的有效策略。 4. 超越人类表现:强化学习的一个优势在于它可以在某些情况下超越人类表现,因为智能体可以自主探索环境并发现人类难以想象的优化策略。 1.3 RL算法类型 按不同类型的智能体方法划分: 1.基于价值的智能体(Value-Based Agents):智能体显式地学习价值函数,然后从学习到的价值函数中隐式地推导出策略,例如Q-learning和Sarsa,这些算法在训练过程中更新状态-动作值函数(Q值),然后根据Q值选择最佳动作。 2.基于策略的智能体(Policy-Based Agents):智能体直接学习策略,即在给定状态下选择每个动作的概率分布。策略梯度(Policy Gradient)方法是一种常见的基于策略的强化学习方法,它通过梯度下降或其他优化算法来更新策略参数,以最大化累积奖励。 3.演员-评论员智能体(Actor-Critic Agents):这是一种综合了前两种方法的智能体。演员(Actor)负责学习策略,而评论员(Critic)负责学习价值函数。演员根据策略选择动作,评论员基于环境的反馈和学习的价值函数提供有关动作的评估。这种结合可以帮助解决价值和策略学习中的某些困难问题,并且在实际应用中表现出很好的性能。 按是否需要对环境建模来划分: 1.Model-Based 方法:需要对环境建模,包括状态转移函数(描述状态之间如何转换)和奖励函数(描述在每个状态下获得的奖励)。一旦模型被建立,智能体可以在模型中进行"心算",即通过模型进行推演,而无需真正地与环境进行交互。这使得智能体可以在模型上进行试错,寻找在真实环境中表现良好的策略。然而,这种方法的关键挑战在于如何准确地建立一个模型,因为环境可能非常复杂且不确定。 2.Model-Free 方法:不需要显式地构建环境模型,而是智能体直接与环境交互,通过尝试和观察来学习策略。这种方法通常需要更多的交互时间和数据,因为智能体需要通过实际的试验来逐步改进策略。Model-free 方法可以分为基于价值和基于策略的方法,前者关注学习状态或状态-动作的价值函数,后者则直接学习策略。 在实际应用中,"model-based"方法可能需要更少的交互次数来找到较优策略,因为它在模型上进行预测和规划。然而,这个模型的建立可能会面临挑战,尤其是在复杂和不确定的环境中。"model-free"方法则更加适用于无法准确建模的情况,但可能需要更多的实际交互来学习策略。选择使用哪种方法通常取决于问题的性质以及可用的数据和计算资源。 02 策略梯度(Policy Gradient,PG) 强化学习的3个核心组成部分:actor(policy、agent)、环境 和 奖励函数。环境和奖励函数不是我们可以控制的,我们能做的是调整Actor的策略,使得它获得最大的奖励。策略一般记作\(\pi\) ,如果使用深度学习来做强化学习,策略就是一个network,其参数记作\(\theta\)。其输入是观测(或states),输出是动作空间的一个概率分布 。(同一个states,同一个env,所采去的action也是可能不同的,所以这里是概率分布,action是具有一定的随机性的)。 △图2 神经网络作为策略 奖励的稀疏性和延迟性? 如果把玩一场游戏看做一个回合(episode),在一个episode里,actor不断与环境进行交互,即在s1时采取了action a1,并获得奖励r1,环境接收a1后跳转到s2,actor看到s2后采取了action a2,并获得奖励r3,...,直至达到某个条件结束游戏。这一个episode里,把环境输出 s 和actor输出 a 以及奖励输出 r 的序列组合起来,就形成了一个轨迹(trajactory): △图3 最大化奖励 计算某个轨迹发生的概率就是: 目标是通过调整actor的参数\(\theta\),最大化整个轨迹中获得的total奖励:\(R(\tau)=\sum_{t=1}^T r^t\) 但是由于采取action的随机性,环境输出states的随机性,得到的reward也是有随机性的,所以在计算中我们需要最大化的不是某个回合的奖励,而是最大化期望奖励。(直观上理解:平均意义上的奖励最大化了,那么某个具体的回合他的奖励也不会小到哪儿去),所以目标就是最大化\(R(\tau)\)的期望值 最大化问题,可以使用梯度上升(gradient ascent)来求解,使用梯度更新公式来更新参数,这就是策略梯度算法。(核心就是采样数据,更新参数,再采样数据,再更新参数。。。) 接下来就是计算\(\bar{R_{\theta}}\)的梯度 再看下\(\bar{R_{\theta}} =\sum_{\tau} R(\tau)p_{\theta}(\tau) = E_{\tau \sim p_{\theta}} [R(\tau)]\) 期望的这个公式的意义:从分布\(p_{\theta}(\tau)\)采样一个轨迹 \(\tau\),计算\(R(\tau)\)的期望值,就是期望奖励(expected reward)。我们要最大化期望奖励。即相当于我们穷举所有的轨迹,每个轨迹对应一个概率。但这个期望无法计算,因为没法穷举所有的轨迹。如何解决呢?=>大数定理:做N次采样,用平均代替期望。 注意, \(p(s_1)\)和\(p(s_{t+1}|s_t,a_t)\)来自环境,由环境决定,\(\theta\)与 无关,因此\(\nabla \log p(s_1)=0\),\(\nabla\sum_{t=1}^{T}\log p(s_{t+1}|s_t,a_t)=0\) 2.1 2个问题 接下来探讨2个问题: 1.如果采取每个action的奖励都是正的,只是有大有小,会出现什么问题? 2.整个episode里每个(s, a)pair都使用了同一个total reward合适吗?这样公平吗?一场游戏输了那里面的每个step的操作都是失败的吗?一场游戏赢了,中间就不会有失误吗? 如何解决这些问题? 解决问题1:增加baseline 如果采取每个action的奖励都是正的,只是有大有小,会出现什么问题? 例如如果所有的 r >= 10,那么r=10就相对来说是『负』的。也就是说在采样中,没有被采样到的动作的概率会被下降,但该动作不一定是不好的动作,因此奖励最好是有正有负的,这可以增加baselinse解决: 通过这种方法,当\(R(\tau)-b>0\)时即总奖励\(R(\tau)>b\),就让\((s,a)\)的概率上升;当\(R(\tau)<b\),即便\(R(\tau)\)是正的,但如果它值很小也是不好的,就让\((s,a)\)的概率下降。 \(b\)可通过对\(\tau\)值取期望来进行设置, 即计算\(\tau\)的平均值,令\(b \approx E[R(\tau)]\)。实践中把训练期间的\(R(\tau)\)的值不断记下来然后计算平均值,用来设置b。 解决问题2:分配合适的分数 1、reward-to-go:未来的总回报 把\(\nabla\log p_{\theta}(a_{t}^n|s_t^n)\)前面的\((R(\tau)-b)\)看作是它的权重,表征了动作a的好坏。这个权重原先是整个轨迹上奖励的总和,现在改成从某个时刻\(t\)开始,一直到游戏结束得到的所有奖励的总和。也就是说计算某个状态-动作对的奖励的时候,不再是把整场游戏得到的奖励全部加起来,而是只计算从这个动作执行以后得到的奖励。直观上也比较容易理解:因为这场游戏在执行这个动作之前发生的事情是与执行这个动作是没有关系的,所以在执行这个动作之前得到的奖励都不能算是这个动作的贡献。我们把执行这个动作以后发生的所有奖励加起来,才是这个动作真正的贡献。 2、discount有折扣的:衰减的回报 进一步,我们在未来的奖励中引入折扣因子。为什么要把未来的奖励做一个折扣呢?因为虽然在某一时刻,执行某一个动作,会影响接下来所有的结果(有可能在某一时刻执行的动作,接下来得到的奖励都是这个动作的功劳),但在一般的情况下,时间拖得越长,该动作的影响力就越小。 折扣因子\(\gamma \in [0,1]\),一般设置为0.9或0.99。其中\(G_t = r_t^n + \gamma r_{t+1}^n + \gamma^2 r_{t+2}^n + \gamma^3 r_{t+3}^n +...+ \gamma^{T_n-t} r_{T_n}^n =r_t^n+\gamma G_{t+1}\) 。从\(G_t\)的展开式可以看到未来的奖励在离t时刻越远时,折扣就越多,这样显然更合理。 2.2 重要性采样 策略梯度算法的缺点: 1.采样效率低:每次当前actor策略与环境交互收集到一批训练资料后,策略一更新,这批数据就不能再使用了,因为actor已经发生了变化,需要重新拿新的actor再次与环境与做交互,拿到新的一批训练资料。而与环境做交互是非常费时间的(相对于在GPU上作训练),整个过程可能大部分时间在做交互收集(采样)数据。 2.迭代步长过长,或步长/学习率难以确定,训练不稳定。 采样效率低的问题,考虑下能不能用另外一个策略\(\pi_{\theta‘}\)和一个actor\(\theta’\)与环境交互,用\(\theta’\)采样到的数据去训练\(\theta\),并且利用这些数据去让\(\theta\)多次执行梯度上升,多次更新参数, 这样就能大幅提升效率。 如何实现这个过程呢? 这个公式可以看做是先从\(q\)里面从采样\(x\),再计算\(f(x) \frac{p(x)}{q(x)}\),再取期望值。所以即便没法从\(p\)里面采样数据,但从\(q\)里面采样数据,我们依然可以通过这种变换来计算从采样\(p\)代入\(x\)以后的期望值。因为是从采样数据,所以我们从采样出来的每一笔数据,都需要乘一个\(\frac{p(x)}{q(x)}\)来修正这两个分布的差异,这个修正银子就叫做重要性权重(importance weight)。 对于用 actor\(\theta\)采样出\(s_t\)与\(a_t\)的状态-动作的对时,我们使用状态-动作对的优势(advantage):\(A_{\theta}(s_t,a_t)\), 来表示累积奖励减去基线这一项,这一项代表的是在状态\(s_t\)采取动作\(a_t\)的好坏(有没有优势)。如果\(A_{\theta}(s_t,a_t)\)是正的,就要增大概率;如果是负的,就要减小概率。 那么回到上面策略梯度的采样效率的问题,就可以考虑,由一个\(p_{\theta’}\)也就是另一个actor(其实就是需要更新的actor的一个副本)去和环境做交互然后收集采样数据,再用这个数据去多次更新\(p_{\theta}\)以提升采样效率。也就是说利用重要性采样,就可以把公式转化为: 上式第3行利用条件概率公式展开,最后去掉\(p_{\theta}(s_t)\)和\(p_{\theta‘}(s_t)\)得到最终的简化的结果。所以根据梯度公式我们可以写出目标函数: 重要性采样解决了采样效率的问题,但也可能会引入新问题。我们再来看下重要性采样的公式:\(E_{x\sim p}[f(x)]=E_{x\sim q}[f(x)\frac{p(x)}{q(x)}]\),虽然它们期望是相等的,但它们的方差如何呢?根据方差计算公式\({Var} [X]=E[X^2]-(E[X])^2\),分别计算出\(f(x)\)和\(f(x)\frac{p(x)}{q(x)}\)的方差: 可以看到2个方差的第一项是不同的,\(\operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]\)的第一项多乘了\(\frac{p(x)}{q(x)}\),如果\(\frac{p(x)}{q(x)}\)差距很大,\(p_{\theta}\left(a_{t} | s_{t}\right)\)的方差就会很大。也就是说如果\(p_{\theta}\left(a_{t} | s_{t}\right)\)与\(p_{\theta'}\left(a_{t} | s_{t}\right)\)相差太大,即这两个分布相差太多,重要性采样的结果就会不好。也就是说通过有限次的采样,如果\(p(x)\)和\(q(x)\)的差距过大,我们是无法保证这个期望的等式在采样数据上一定成立。 怎么避免它们相差太多呢?这就是TRPO和PPO要做的事情。 2.3 TRPO 信任区域策略优化(trust region policy optimization,TRPO)就是对\(\theta\)与\(\theta'\)进行一个约束,让它们的 KL 散度小于: 虽然TRPO解决了分布差距不会很大的问题,但计算有难度(引入约束项,使用拉格朗日的对偶法处理后,采用共轭梯度法进行优化),因此我们一般使用在实现上更容易但性能差不多的PPO。 03 近端策略优化(PPO) 3.1 PPO1(近端策略优化惩罚(PPO-penalty)) **PPO(ProximalPolicyOptimization)**解决TRPO计算量大的问题,不是把约束放在条件里,而是直接放到目标函数里: 其中惩罚项\(\beta \mathrm{KL}\left(\theta, \theta^{k}\right)\)称之为自适应KL散度(adaptive KL divergence),\(\beta\)可以动态调整,其调整策略为: 如果\(KL(\theta,\theta^k)>KL_{max}\),则增加\(\beta\) 如果\(KL(\theta,\theta^k)<KL_{min}\),则减小\(\beta\) 3.2 PPO2(近端策略优化裁剪(PPO-clip)) 如果我们觉得计算 KL 散度很复杂,那么还有一个PPO2算法,PPO2 即近端策略优化裁剪。近端策略优化裁剪的目标函数里面没有 KL 散度,其要最大化的目标函数为 裁剪(clip)函数,裁剪函数是指,在括号里面有3项,如果第一项小于第二项,那就输出\(1-\varepsilon\);第一项如果大于第三项,那就输出\(1+\varepsilon\)。 \(\varepsilon\)是一个超参数,是我们要调整的,可以设置成 0.1 或 0.2 。 为什么这个式子就可以做到\(p_{\theta}\)和\(p_{\theta'}\)差距不会太大呢? 如果\(A>0\),也就是某一个\((a_t,s_t)\)是好的,则我们希望增大这个状态-动作pair的概率。也就是想让\(p_{\theta}(a_t∣s_t)\)越大越好,但它与\(p_{\theta^k}(a_t∣s_t)\)的比值不能超过\(1+\varepsilon\); 如果\(A<0\),也就是某一个\((a_t,s_t)\)是不好的,那则我们希望把\(p_{\theta}(a_t∣s_t)\)减小,当减到比值是\(1-\varepsilon\)的时候停止。 通用这个clip的限制,我们不会让\(p_{\theta}(a_t∣s_t)\)和\(p_{\theta^k}(a_t∣s_t)\)差距太大,并且实现这个其实也很简单,如下: ratios = paddle.exp(cur_batch_log_probs - batch_log_probs.detach()) surr1 = ratios * A_k surr2 = paddle.clip(ratios, 1-self.clip, 1-self.clip) * A_k actor_loss = -paddle.minimum(surr1, surr2) # 负号,把最大化问题转化为最小化问题ratios = paddle.exp(cur_batch_log_probs - batch_log_probs.detach()) surr1 = ratios * A_k surr2 = paddle.clip(ratios, 1-self.clip, 1-self.clip) * A_k actor_loss = -paddle.minimum(surr1, surr2) # 负号,把最大化问题转化为最小化问题 04 总结 ——END—— 参考资料: [1]https://datawhalechina.github.io/easy-rl/#/ [2]https://speech.ee.ntu.edu.tw/~hylee/ml/2020-spring.php 推荐阅读: 浅谈统一权限管理服务的设计与开发 百度APP iOS端包体积50M优化实践(五) HEIC图片和无用类优化实践 百度知道上云与架构演进 百度APP iOS端包体积50M优化实践(四)代码优化 百度App启动性能优化实践篇

优秀的个人博客,低调大师

百度工程师带你了解Module Federation

作者 | 一贫 导读 本文介绍了Module Federation的概念、应用场景,并结合具体的代码示例帮助大家对Module Federation的模块共享,公共依赖加载有个初步的认识,方便后续更深入的学习相关内容,同时也给微前端的探索提供一种新的思路,定会给大家一定的提升和启发。 全文5405字,预计阅读时间14分钟。 01 什么是Module Federation(MF)? 普遍直译为『模块联邦』,我们看看官网是怎么说的? Motivation Multiple separate builds should form a single application. These separate builds should not have dependencies between each other, so they can be developed and deployed individually. This is often known as Micro-Frontends, but is not limited to that. 多个独立的构建可以形成一个应用程序。这些独立的构建不会相互依赖,因此可以单独开发和部署它们。 这通常被称为微前端,但并不仅限于此。 通俗点讲,即MF提供了能在当前应用中远程加载其他服务器上应用的能力。对此,可以引出下面两个概念: host:引用了其他应用的应用 remote:被其他应用所使用的应用 △图片来源于网络 它与我们普遍讨论的基座应用、微应用有所不同,它是去中心化的,相互之间是平等的,每个应用是单独部署在各自的服务器,每个应用都可以引用其他应用,也能被其他应用所引用,即每个应用可以充当host的角色,亦可以作为remote出现。 △图片来源于网络 02 应用场景 微前端:通过shared以及exposes可以将多个应用引入同一应用中进行管理。 资源复用,减少编译体积:可以将多个应用都用到的通用组件单独部署,通过MF的功能在runtime时引入到其他项目中,这样组件代码就不会编译到项目中,同时亦能满足多个项目同时使用的需求,一举两得。 03 如何使用 项目结构如下: module-home:首页,在layout展示一个字符串。 module-layout:布局,只包含一个html模板。 module-lib:暴露工具方法,共享lodash库。 3.1 相关配置参数一览 3.2 各应用的配置 // apps/module-lib/webpack.config.js plugins: [ new ModuleFederationPlugin({ name: 'lib', filename: 'remoteLib.js', library: { type: 'var', name: 'lib' }, exposes: { // 提供工具方法 './utils': './index.js', }, shared: ["lodash"] }) ] // apps/module-home/webpack.config.js plugins: [ new ModuleFederationPlugin({ name: 'home', filename: 'remoteHome.js', library: { type: 'var', name: 'home' }, exposes: { // 提供挂载方法 './mount': './index.js', }, shared: ["lodash"] }) ] // apps/module-layout/webpack.config.js plugins: [ new ModuleFederationPlugin({ name: 'main', filename: 'remoteMain.js', remotes: { 'lib': 'lib@http://localhost:3001/remoteLib.js', 'home': 'home@http://localhost:3003/remoteHome.js', }, shared: ['lodash'] }), new HtmlWebpackPlugin({ template: path.resolve(__dirname, './public/index.html'), inject: 'body' }) ] // apps/module-layout/boot.js import {getUid, setUid} from 'lib/utils' // 使用module-lib中暴露的方法 import {mount} from 'home/mount' // 使用module-home中暴露的挂载方法 import _ from 'lodash'; setUid(); setUid(); console.log(getUid()) console.log(_.get) mount() 如下图所示:在layout中展示了home挂载的节点,控制台也打印了调用lib中方法的log,同时lib分享的lodash也生效了(全程只加载了一个lodash)。 3.3 以remoteLib为例简要分析 // 定义全局变量 var lib; /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "webpack/container/entry/lib": /*!***********************!*\ !*** container entry ***! \***********************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { eval("var moduleMap = {\n\t\"./utils\": () => {\n\t\treturn __webpack_require__.e(\"index_js\").then(() => (() => ((__webpack_require__(/*! ./index.js */ \"./index.js\")))));\n\t}\n};\nvar get = (module, getScope) => {\n\t__webpack_require__.R = getScope;\n\tgetScope = (\n\t\t__webpack_require__.o(moduleMap, module)\n\t\t\t? moduleMap[module]()\n\t\t\t: Promise.resolve().then(() => {\n\t\t\t\tthrow new Error('Module \"' + module + '\" does not exist in container.');\n\t\t\t})\n\t);\n\t__webpack_require__.R = undefined;\n\treturn getScope;\n};\nvar init = (shareScope, initScope) => {\n\tif (!__webpack_require__.S) return;\n\tvar name = \"default\"\n\tvar oldScope = __webpack_require__.S[name];\n\tif(oldScope && oldScope !== shareScope) throw new Error(\"Container initialization failed as it has already been initialized with a different share scope\");\n\t__webpack_require__.S[name] = shareScope;\n\treturn __webpack_require__.I(name, initScope);\n};\n\n// This exports getters to disallow modifications\n__webpack_require__.d(exports, {\n\tget: () => (get),\n\tinit: () => (init)\n});\n\n//# sourceURL=webpack://module-lib/container_entry?"); /***/ }) 1、moduleMap:用来映射expose的模块 2、get方法:导出给host应用,用于获取remote expose的模块 3、init方法:导出给host应用,用于将remote模块注入 get方法中调用了__webpack_require__.e加载chunk /******/ // This file contains only the entry chunk. /******/ // The chunk loading function for additional chunks /******/ __webpack_require__.e = (chunkId) => { /******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { /******/ __webpack_require__.f[key](chunkId, promises); /******/ return promises; /******/ }, [])); /******/ }; __webpack_require__.e调用__webpack_require__.f /******/ __webpack_require__.f.consumes = (chunkId, promises) => { /******/ if(__webpack_require__.o(chunkMapping, chunkId)) { /******/ chunkMapping[chunkId].forEach((id) => { // 如果host已经有则直接使用,否则去remote安装 /******/ if(__webpack_require__.o(installedModules, id)) return promises.push(installedModules[id]); /******/ var onFactory = (factory) => { /******/ installedModules[id] = 0; /******/ __webpack_require__.m[id] = (module) => { /******/ delete __webpack_require__.c[id]; /******/ module.exports = factory(); /******/ } /******/ }; /******/ var onError = (error) => { /******/ delete installedModules[id]; /******/ __webpack_require__.m[id] = (module) => { /******/ delete __webpack_require__.c[id]; /******/ throw error; /******/ } /******/ }; /******/ try { /******/ var promise = moduleToHandlerMapping[id](); /******/ if(promise.then) { /******/ promises.push(installedModules[id] = promise.then(onFactory)['catch'](onError)); /******/ } else onFactory(promise); /******/ } catch(e) { onError(e); } /******/ }); /******/ } /******/ } /******/ })(); host加载自己的bundle main.js,其中使用jsonp加载对应remote提供的remoteLib.js; 在remote中暴露了全局变量,host将remote注入后可以获取对应模块,其中的共享模块使用前会检查自身有没有,如果没有再去加载remote的内容。 04 拓展学习 可以学习开源项目:基于 Webpack 5 Module Federation,优雅且实用的微前端解决方案 https://github.com/yuzhanglong/mf-lite。 ——END—— 参考资料: [1]How to Build a Micro Frontend with Webpack's Module Federation Plugin [2]Webpack 新功能 Module Federation 深入解析 [3]基于 Webpack Module Federation,这可能是一个比较优雅的微前端解决方案 [4]探索 webpack5 新特性 Module federation 在腾讯文档的应用 [5]Module Federation原理剖析 推荐阅读: 巧用Golang泛型,简化代码编写 Go语言DDD实战初级篇 Diffie-Hellman密钥协商算法探究 贴吧低代码高性能规则引擎设计 浅谈权限系统在多利熊业务应用 分布式系统关键路径延迟分析实践

优秀的个人博客,低调大师

假装网络工程师15——IGP综合实验

一、背景介绍 IGP协议的学习即将结束,最后通过一个综合实验最为结尾,实验拓扑如下图所示: 每个路由器的route-id与lo0接口ip地址一致,除基础配置外,还需满足如下约束: RIP需求: 1.R1-R4 运行RIP V2 2.R1仅从R4接收199.172.0.0、199.172.1.0、199.172.2.0、199.172.3.0网段的路由更新 OSPF 进程1需求: 1.所有路由器的router-id均为X.X.X.X(X为路由器编号,如R3为3.3.3.3) 2.运行OSPF的路由器环回口都宣告进ospf且在路由表里看到的环回口网段路由都是24位路由 3.区域0采用区域密文验证,密码为HUAWEI 4.OSPF重分布进入RIP 5.RIP重分布进入OSPF ,OSPF只从RIP接收14.0.0.0/24的路由 OSPF 进程2需求: 1.R4-R5 运行OSPF进程2 2.把OSPF进程2引入进OSPF进程1后要求每一跳metric可变 3.把OSPF进程1引入进OSPF进程2后要求每一跳metric可变 4.要求R4优选R5去往所有网段 5.R4从R5学到的路由条目走2条路径且等价负载均衡 6.RIP-OSPF进程2之间不做重分布 二、基础配置 除了基础的配置,在上图中还包含了一个隐藏条件,ospf1的area 2没有与area 0直接相连,这就需要在R2和R3之间建立一条虚链路,建立的配置如下: [R2]ospf 1 [R2-ospf-1]area 1 [R2-ospf-1-area-0.0.0.1]vlink-peer 3.3.3.3 [R3]ospf 1 [R3-ospf-1]area 1 [R3-ospf-1-area-0.0.0.1]vlink-peer 2.2.2.2 ospf的虚链路无法直接通过display ospf peer brief 查看,只能通过虚链路查看 [R3]display ospf vlink OSPF Process 1 with Router ID 3.3.3.3 Virtual Links Virtual-link Neighbor-id -> 2.2.2.2, Neighbor-State: Full Interface: 23.0.0.3 (Serial2/0/1) Cost: 48 State: P-2-P Type: Virtual Transit Area: 0.0.0.1 Timers: Hello 10 , Dead 40 , Retransmit 5 , Transmit Delay 1 GR State: Normal 此时的基础配置就以完成,接下来进行约束条件的配置 三、约束条件配置 RIP需求: R1-R4 运行RIP V2 [R1]rip [R1-rip-1]version 2 network 14.0.0.0 [R4]rip [R4-rip-1]version 2 network 14.0.0.0 network 4.0.0.0 network 199.172.0.0 network 199.172.1.0 network 199.172.2.0 network 199.172.3.0 network 199.172.4.0 network 199.172.5.0 R1仅从R4接收199.172.0.0、199.172.1.0、199.172.2.0、199.172.3.0网段的路由更新 [R1]rip 1 [R1-rip-1]filter-policy ip-prefix RIP import [R1]ip ip-prefix RIP index 10 permit 199.172.0.0 22 greater-equal 24 less-equal 24 OSPF 进程1需求: 所有路由器的router-id均为X.X.X.X(X为路由器编号,如R3为3.3.3.3) [R1]ospf 1 router-id 1.1.1.1 运行OSPF的路由器环回口都宣告进ospf且在路由表里看到的环回口网段路由都是24位路由 [R1]interface LoopBack 0 [R1-LoopBack0]ospf network-type broadcast 区域0采用区域密文验证,密码为HUAWEI [R1]ospf 1 [R1-ospf-1]area 0 [R1-ospf-1-area-0.0.0.0]authentication-mode md5 1 cipher HUAWEI 在配置区域0认证时需要住的是,虽然R3没有之间跟area0连接,但是R2与R3之间建立了虚链路,相当于把area0的范围扩大了,尽管R3上没有配置area0,但是仍要创造一个area0来用于认证 <R3>display current-configuration configuration ospf [V200R003C00] # ospf 1 area 0.0.0.0 authentication-mode md5 1 cipher %$%$kcn17z")3I-,au"KJu*4^8!%%$%$ area 0.0.0.1 network 3.3.3.3 0.0.0.0 network 23.0.0.3 0.0.0.0 vlink-peer 2.2.2.2 area 0.0.0.2 network 35.0.0.3 0.0.0.0 # return OSPF重分布进入RIP 作为rip域和ospf域的边界路由,引入的动作需要在R1上来进行 [R1]rip 1 [R1-rip-1]import-route ospf 1 RIP重分布进入OSPF ,OSPF只从RIP接收14.0.0.0/24的路由 [R1]ospf 1 [R1-ospf-1]import-route rip 1 route-policy R-2-O [R1]route-policy R-2-O permit node 10 [R1-route-policy]if-match ip-prefix R-2-O [R1]ip ip-prefix R-2-O permit ip ip-prefix R-2-O index 10 permit 14.0.0.0 24 OSPF 进程2需求: R4-R5 运行OSPF进程2(略) 把OSPF进程2引入进OSPF进程1后要求每一跳metric可变(与条件3配置相同,此处略) 把OSPF进程1引入进OSPF进程2后要求每一跳metric可变 由于ospf引入外部路由默认使用type2,即外部路由cost值为1,且不累加内部开销,所以按照要求改为type1,该配置在ospf进程1与ospf进程2的边界路由器R5上操作 [R5]ospf 1 [R5-ospf-1]import-route ospf 2 type 1 要求R4优选R5去往所有网段 路由选路时先比较优先级,rip优先级为100,ospf外部引入优先级为150,所以默认R4去往所有路由是走R1,需要更改rip优先级 [R4]rip 1 [R4-rip-1]preference 151 R4从R5学到的路由条目走2条路径且等价负载均衡 此时R4到任何网段经过R5都有2条链路,且优先级均为150,所以此时比较的是cost开销,由于S2/0/0是串口cost值为48,大于g0/0/0接口的cost值(值为1),所以默认的路由表只会加载g0/0/0所在的45.0.0.0/24网段,所以如果要负载均衡,就需要将s2/0/0接口的cost值改为1,或将g0/0/0接口的cost值改为48 [R4]int g0/0/0 [R4-GigabitEthernet0/0/0]ospf cost 48 RIP-OSPF进程2之间不做重分布(无需操作)

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册