11、基于LunarLander登陆器的A2C强化学习(含PYTHON工程)

news2024/11/15 21:24:22

11、基于LunarLander登陆器的A2C强化学习(含PYTHON工程)

LunarLander复现:
07、基于LunarLander登陆器的DQN强化学习案例(含PYTHON工程)

08、基于LunarLander登陆器的DDQN强化学习(含PYTHON工程)

09、基于LunarLander登陆器的Dueling DQN强化学习(含PYTHON工程)

10、基于LunarLander登陆器的Dueling DDQN强化学习(含PYTHON工程)

11、基于LunarLander登陆器的A2C强化学习(含PYTHON工程)

基于TENSORFLOW2.10

0、实践背景

gym的LunarLander是一个用于强化学习的经典环境。在这个环境中,智能体(agent)需要控制一个航天器在月球表面上着陆。航天器的动作包括向上推进、不进行任何操作、向左推进或向右推进。环境的状态包括航天器的位置、速度、方向、是否接触到地面或月球上空等。

智能体的任务是在一定的时间内通过选择正确的动作使航天器安全着陆,并且尽可能地消耗较少的燃料。如果航天器着陆时速度过快或者与地面碰撞,任务就会失败。智能体需要通过不断地尝试和学习来选择最优的动作序列,以完成这个任务。

下面是训练的结果:
在这里插入图片描述

1、Actor-Critic框架的基本概念

Actor:表演者,一般称为pi(policy)网络,根据该网络的输出参数指导物体的具体动作

Critic:批评者,对Agent的动作或者状态进行打分,使得框架能够量化动作的优劣

Reward:奖励R,指的是客观获得的,例如说消灭了敌人或者吃到了金币等等

Return:回报U,可以理解为获得高奖励的可能,越大代表越可能获得高奖励。实际使用的是折扣回报,因为对于很远的奖励我们还需要考虑时间成本。对于一个随机的环境,在t时刻我们无法获得Ut的具体取值,因为我们不知道未来的奖励。
U t = R t + γ ⋅ R t + 1 + γ 2 ⋅ R t + 2 + γ 3 ⋅ R t + 3 + ⋯ U_t=R_t+\gamma\cdot R_{t+1}+\gamma^2\cdot R_{t+2}+\gamma^3\cdot R_{t+3}+\cdots Ut=Rt+γRt+1+γ2Rt+2+γ3Rt+3+

Q(s,a):动作价值函数,其输入为当前状态和要执行的动作,输出为该动作能带来多大的价值,因此,一种贪心的方法是选择能够使Q(s,a)最大动作执行。
Q(s,a)的维度等于动作空间的维度。打个简单的比方,假设我现在有两个动作,向北去捡芝麻,向南去捡西瓜。从最终获得的奖励来看,西瓜是大于芝麻的,但是如果芝麻就在我桌上,但是西瓜在20km以外,那可能我还是选择芝麻得了。那么动作价值函数可能就是(1,0.1)。1是捡芝麻的动作价值,0.1是捡西瓜的动作价值,虽说西瓜好吃,但是太远了,所以其动作价值打分特别低。

Q(s,a)和Ut关系:Q(s,a)是Ut的期望,期望可以理解为求积分,实际上Q是对Ut把所有t之后的时刻(t+1、t+2等等)当作变量求积分得到的。因此Q(s,a)可以直观反应当前状态s下执行各个动作的好坏。
Q π ( s t , a t ) = E [ U t ∣ s t , a t ] Q_\pi(s_t,{a_t})=\mathbb{E}[U_t\mid s_t,{a_t}] Qπ(st,at)=E[Utst,at]

V(s):状态价值函数,是Q函数的期望。因为期望的积分动作消去了动作A,因此状态价值函数V可以用来直观的反应一个状态的好坏。其实际上是Q(s,a)对不同a的加权平均。
例如,自家高低三路被破,依据这个状态我们就知道现在的状态打分不太行。状态打分不行的原因是每个动作都不会带来太高的打分(都要输了)。
V π ( s t ) = E A t [ Q π ( s t , A t ) ∣ s t ] V_{\pi}(s_{t})=\mathbb{E}_{{A_{t}}}[Q_{\pi}(s_{t},{A_{t}})\mid s_{t}] Vπ(st)=EAt[Qπ(st,At)st]

2、Advantage Actor-Critic理论

A2C(Advantage Actor-Critic)在原来的AC框架上进行改进,主要的改进是其Critic网络不再依赖于动作a,更少的变量减少了其拟合的难度。同时在训练时使用了优势函数,降低了Variance,提升了性能。

具体的推导过程参考【王树森】深度强化学习(DRL)的P16。可能有小伙伴非常好奇,为什么A2C的td error和AC算法的不一致,这些都在上面的视频里面给出了计算过程。

训练的流程图如下所示(小写代表的是实际观测到的值):
在这里插入图片描述
为什么pi输出网络往往使用终端为softmax的网络进行拟合?
实际上,pi输出网络往往使用终端为softmax的网络进行拟合,因此其pi网络输出的是概率分布。为什么采用这种方法呢,因为log的形式和交叉熵高度接近,如下就是策略网络的梯度公式:
在这里插入图片描述
这是交叉熵的公式,其中策略网络pi实际上就是概率分布(是不是比较一致嘞),当然Q(s,a)会作为sample_weight体现在其中。-参考softmax loss详解,softmax与交叉熵的关系:
在这里插入图片描述
此外,实际训练时会使用baseline而不会直接使用Q(s,a),也就是下面这个式子
在这里插入图片描述
其中求导乘以后面的那个就是TD error的倒数。

3、Advantage Actor-Critic网络更新流程

在这里插入图片描述


在这里插入图片描述

3、Advantage Actor-Critic关键编程实现

3.1、TD Target的计算

在这里插入图片描述
计算代码如下所示,其中v_value 是使用critic网络预测的下一状态的v,其输入为下一时刻的状态next_state。

    def td_target(self, reward, next_state, done):
        if done:
            return reward
        v_value = self.critic.model(
            np.reshape(next_state, [1, self.state_dim]))
        return np.reshape(reward + self.discount_factor * v_value[0], [1, 1])
3.2、advatnage的计算

advatnage的计算原来是Q-V的形式,但是在A2C算法中Q被近似成了r+gamma*V,也就是所说的TD target:
在这里插入图片描述
advatnage计算代码如下:

    def advatnage(self, td_targets, baselines):
        return td_targets - baselines

baselines基于当前时刻的价值网络self.critic.model(state)

advantage = self.advatnage(
    td_target, self.critic.model(state))
3.3、policy网络的loss计算与梯度下降

policy网络的loss实际上就是在原来的softmax的基础上乘以td error,也就是将td error(advatnage)作为权重。
在这里插入图片描述

    def compute_loss(self, actions, logits, advantages):
        # 输入的logits并不一定是概率分布,因此使用from_logits=True进行额外的归一化
        ce_loss = tf.keras.losses.SparseCategoricalCrossentropy(
            from_logits=True)
        actions = tf.cast(actions, tf.int32)
        policy_loss = ce_loss(
            actions, logits, sample_weight=tf.stop_gradient(advantages))
        return policy_loss

训练代码:

    def train(self, states, actions, advantages):
        with tf.GradientTape() as tape:
            logits = self.model(states, training=True)
            loss = self.compute_loss(
                actions, logits, advantages)
        grads = tape.gradient(loss, self.model.trainable_variables)
        self.opt.apply_gradients(zip(grads, self.model.trainable_variables))
        return loss
3.4、Critic网络的loss计算与梯度下降

上面流程也非常明白,Critic的目的就是让td error为0,所以需要对td error使用均方误差的梯度下降:
在这里插入图片描述

    def compute_loss(self, v_pred, td_targets):
        mse = tf.keras.losses.MeanSquaredError()
        return mse(td_targets, v_pred)

    def train(self, states, td_targets):
        with tf.GradientTape() as tape:
            v_pred = self.model(states, training=True)
            assert v_pred.shape == td_targets.shape
            loss = self.compute_loss(v_pred, tf.stop_gradient(td_targets))
        grads = tape.gradient(loss, self.model.trainable_variables)
        self.opt.apply_gradients(zip(grads, self.model.trainable_variables))
        return loss

4、运行效果展示

agent = Agent('A2C', 4, 8, actor_lr=0.0003, critic_lr=0.0005,
              discount_factor=0.995, batch_size=1)

看起来收敛比较快,但是最终结果是不如DQN的,当然我没有仔细去调参。A2C比较为人诟病的就是容易过山车,原来训练不错,突然就跌下去了:
在这里插入图片描述

由于无法使用经验回放训练,其训练速度非常慢:
在这里插入图片描述

5、完整代码(工程在最上方链接)

import base64
from collections import deque

import imageio
import pandas as pd
from matplotlib import pyplot as plt

import wandb
import tensorflow as tf
from keras.layers import Input, Dense
from keras.backend import clear_session
from memory_profiler import profile
import gym
import argparse
import numpy as np


# tf.keras.backend.set_floatx('float64')


class Actor:
    def __init__(self, state_dim, action_dim, actor_lr):
        self.state_dim = state_dim
        self.action_dim = action_dim
        self.model = self.create_model()
        self.opt = tf.keras.optimizers.Adam(actor_lr)

    def create_model(self):
        return tf.keras.Sequential([
            Input((self.state_dim,)),
            Dense(256, activation='relu'),
            Dense(256, activation='relu'),
            Dense(self.action_dim, activation='softmax')
        ])

    def compute_loss(self, actions, logits, advantages):
        # 输入的logits并不一定是概率分布,因此使用from_logits=True进行额外的归一化
        ce_loss = tf.keras.losses.SparseCategoricalCrossentropy(
            from_logits=True)
        actions = tf.cast(actions, tf.int32)
        policy_loss = ce_loss(
            actions, logits, sample_weight=tf.stop_gradient(advantages))
        return policy_loss

    def train(self, states, actions, advantages):
        with tf.GradientTape() as tape:
            logits = self.model(states, training=True)
            loss = self.compute_loss(
                actions, logits, advantages)
        grads = tape.gradient(loss, self.model.trainable_variables)
        self.opt.apply_gradients(zip(grads, self.model.trainable_variables))
        return loss


class Critic:
    def __init__(self, state_dim, critic_lr):
        self.state_dim = state_dim
        self.model = self.create_model()
        self.opt = tf.keras.optimizers.Adam(critic_lr)

    def create_model(self):
        return tf.keras.Sequential([
            Input((self.state_dim,)),
            Dense(256, activation='relu'),
            Dense(256, activation='relu'),
            Dense(1, activation='linear')
        ])

    def compute_loss(self, v_pred, td_targets):
        mse = tf.keras.losses.MeanSquaredError()
        return mse(td_targets, v_pred)

    def train(self, states, td_targets):
        with tf.GradientTape() as tape:
            v_pred = self.model(states, training=True)
            assert v_pred.shape == td_targets.shape
            loss = self.compute_loss(v_pred, tf.stop_gradient(td_targets))
        grads = tape.gradient(loss, self.model.trainable_variables)
        self.opt.apply_gradients(zip(grads, self.model.trainable_variables))
        return loss


class Agent:
    def __init__(self, model, num_actions, input_dims, actor_lr=0.0005, critic_lr=0.001,
                 discount_factor=0.995, batch_size=4):

        self.action_dim = num_actions
        self.state_dim = input_dims
        self.actor = Actor(self.state_dim, self.action_dim, actor_lr)
        self.critic = Critic(self.state_dim, critic_lr)
        self.model = model
        self.discount_factor = discount_factor
        self.batch_size = batch_size
        self.target_ave_scores = 500
        self.max_num_timesteps = 1000
        self.num_p_av = 100

    def td_target(self, reward, next_state, done):
        if done:
            return reward
        v_value = self.critic.model(
            np.reshape(next_state, [1, self.state_dim]))
        return np.reshape(reward + self.discount_factor * v_value[0], [1, 1])

    def advatnage(self, td_targets, baselines):
        return td_targets - baselines

    def list_to_batch(self, list):
        batch = list[0]
        for elem in list[1:]:
            batch = np.append(batch, elem, axis=0)
        return batch

    # @profile
    def train(self, env, max_episodes=1000, graph=True):
        wandb.init(name='A2C', project="deep-rl-tf2")
        episodes_history, total_point_history, avg_point_history, target_history = [], [], [], []
        for ep in range(max_episodes):
            state_batch = []
            action_batch = []
            td_target_batch = []
            advatnage_batch = []
            episode_reward, done = 0, False

            state, _ = env.reset()
            for t in range(self.max_num_timesteps):
                # self.env.render()
                state = np.reshape(state, [1, self.state_dim])
                probs = self.actor.model(state)
                probs = np.array(probs)
                probs /= probs.sum()

                action = np.random.choice(self.action_dim, p=probs[0])

                next_state, reward, done, _, _ = env.step(action)

                action = np.reshape(action, [1, 1])
                next_state = np.reshape(next_state, [1, self.state_dim])
                reward = np.reshape(reward, [1, 1])

                td_target = self.td_target(reward * 0.01, next_state, done)
                advantage = self.advatnage(
                    td_target, self.critic.model(state))

                # actor_loss = self.actor.train(state, action, advantage)
                # critic_loss = self.critic.train(state, td_target)

                state_batch.append(state)
                action_batch.append(action)
                td_target_batch.append(td_target)
                advatnage_batch.append(advantage)

                if len(state_batch) >= self.batch_size or done:
                    states = self.list_to_batch(state_batch)
                    actions = self.list_to_batch(action_batch)
                    td_targets = self.list_to_batch(td_target_batch)
                    advantages = self.list_to_batch(advatnage_batch)

                    actor_loss = self.actor.train(states, actions, advantages)
                    critic_loss = self.critic.train(states, td_targets)

                    state_batch = []
                    action_batch = []
                    td_target_batch = []
                    advatnage_batch = []

                episode_reward += reward[0][0]
                state = next_state[0]
                if done:
                    break

            episodes_history.append(ep)
            target_history.append(self.target_ave_scores)
            total_point_history.append(episode_reward)
            av_latest_points = np.mean(total_point_history[-self.num_p_av:])
            avg_point_history.append(av_latest_points)

            wandb.log({'target_ave_scores': 300, 'epoch': ep})
            wandb.log({'total_points': episode_reward, 'epoch': ep})
            wandb.log({'av_latest_points': av_latest_points, 'epoch': ep})

            print(
                f"\rEpisode {ep + 1} | Total point average of the last {self.num_p_av} episodes: {av_latest_points:.2f}",
                end="")

            if (ep + 1) % self.num_p_av == 0:
                print(
                    f"\rEpisode {ep + 1} | Total point average of the last {self.num_p_av} episodes: {av_latest_points:.2f}")

            # We will consider that the environment is solved if we get an
            # average of 200 points in the last 100 episodes.
            if av_latest_points >= self.target_ave_scores or ep + 1 == max_episodes:
                print(f"\n\nEnvironment solved in {ep + 1} episodes!")
                self.actor.model.save('saved_networks/' + self.model + '/lunar_lander_model_actor.h5')
                self.critic.model.save('saved_networks/' + self.model + '/lunar_lander_model_critic.h5')
                break

            if graph:
                df = pd.DataFrame({'x': episodes_history, 'Score': total_point_history,
                                   'Average Score': avg_point_history, 'Solved Requirement': target_history})

                plt.plot('x', 'Score', data=df, marker='', color='blue', linewidth=2, label='Score')
                plt.plot('x', 'Average Score', data=df, marker='', color='orange', linewidth=2, linestyle='dashed',
                         label='AverageScore')
                plt.plot('x', 'Solved Requirement', data=df, marker='', color='red', linewidth=2, linestyle='dashed',
                         label='Solved Requirement')
                plt.legend()
                plt.savefig('LunarLander_Train_' + self.model + '.png')

    def test_create_video(self, env, filename, model_name, fps=30):
        self.actor.model = tf.keras.models.load_model(model_name)
        with imageio.get_writer(filename, fps=fps) as video:
            done = False
            state, _ = env.reset()
            frame = env.render()
            video.append_data(frame)
            episode_score = 0
            for t in range(self.max_num_timesteps):
                state = np.reshape(state, [1, self.state_dim])
                probs = self.actor.model(state)
                action = np.argmax(probs.numpy()[0])
                state, reward, done, _, _ = env.step(action)
                episode_score += reward
                frame = env.render()
                video.append_data(frame)
                if done:
                    break
            print(f'episode_score:', episode_score)
            """Embeds an mp4 file in the notebook."""
            video = open(filename, 'rb').read()
            b64 = base64.b64encode(video)
            tag = '''
            <video width="840" height="480" controls>
            <source src="data:video/mp4;base64,{0}" type="video/mp4">
            Your browser does not support the video tag.
            </video>'''.format(b64.decode())
            # return IPython.display.HTML(tag)


def main():
    myModel = 'A2C'
    env = gym.make('LunarLander-v2', render_mode='rgb_array')
    agent = Agent('A2C', 4, 8, actor_lr=0.0003, critic_lr=0.0005,
                  discount_factor=0.995, batch_size=4)
    # 取消注释以进行训练
    agent.train(env)
    # agent.test_create_video(env, filename='Lunar_Lander_videos/lunar_lander' + myModel + '.mp4',
    #                         model_name='saved_networks/' + myModel + '/lunar_lander_model_actor.h5', fps=30)


if __name__ == "__main__":
    main()

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

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

相关文章

thinkcmf 文件包含 x1.6.0-x2.2.3 已亲自复现

thinkcmf 文件包含 x1.6.0-x2.2.3 CVE-2019-16278 已亲自复现 漏洞名称漏洞描述影响版本 漏洞复现环境搭建漏洞利用 修复建议总结 漏洞名称 漏洞描述 ThinkCMF是一款基于PHPMYSQL开发的中文内容管理框架&#xff0c;底层采用ThinkPHP3.2.3构建。ThinkCMF提出灵活的应用机制&a…

Elasticsearch中复制一个索引数据到新的索引中

问题 我有时候&#xff0c;需要调试一个已经存在的ES索引&#xff0c;需要从已有的索引复制数据到新的索引中去。 解决 这里我借助一个GUI工具&#xff0c;来解决这个问题&#xff0c;底层它是使用Reindex的API实现索引数据复制的。利用Reindex API搞不定这个事情&#xff0…

高德地图_公共交通路径规划API,获取两地点之间的驾车里程和时间

import pandas as pd import requests import jsondef get_dis_tm(origin, destination,city,cityd):url https://restapi.amap.com/v3/direction/transit/integrated?key xxx #这里就是需要去高德开放平台去申请key,请在xxxx位置填写,web服务APIlink {}origin{}&desti…

Laravel的知识点

1.{{ }} 是在 HTML 中内嵌 PHP 的 Blade 语法标识符&#xff0c;表示包含在该区块内的代码都将使用 PHP 来编译运行。 2.两种写法 3.return void 在这段注释中&#xff0c;"return void" 表示该函数或方法没有返回值。这意味着它执行某些操作或任务&#xff0c;但…

基于Java SSM框架实现县小吃门店连锁点餐订餐系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现县小吃门店连锁点餐订餐系统演示 摘要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 沙县小吃点餐系统&#xff0c;主要的模块包括实现管理员&#xff1b;个人中心、用户管…

根据commitID删除某一次提交

1.查看提交历史 git log --prettyoneline2.找到需要删除的那个commit,然后找到上次提交的commitID 比如想要删除下面这一条 我们找到上次提交的commitID 3.执行rebase git rebase -i efa11da0a684977bf8ac047ebb803e2ded2063a4 进入编辑状态显示如下 将需要删除的那个提交前…

基于Elemnet-plus 封装的功能表格,基本囊括element-plus 官网表格的所有使用场景

前言 这是一个多用途的基于element-plus 封装的表格组件&#xff0c;基本上elemnet-plus 官网涉及到的使用场景&#xff0c;都可以&#xff0c;而且使用上来说会简单许多&#xff0c;配置上类似与vxe-table 的使用&#xff0c;下面逐一展示各种场景的使用方式&#xff0c;基本上…

<JavaEE> TCP 的通信机制(三) -- 滑动窗口

目录 TCP的通信机制的核心特性 四、滑动窗口 1&#xff09;什么是滑动窗口&#xff1f; 2&#xff09;滑动窗口的作用是什么&#xff1f; 3&#xff09;批量传输出现丢包如何处理&#xff1f; 1> 接收端ACK丢包 2> 发送端数据包丢包 4&#xff09;适用性 TCP的通…

主动学习如何解决数据标注的难题?主动学习和弱监督学习有何区别?

机器学习的成功与否取决于数据标注的质量和数量。利用主动学习的机器学习技术能加快模型训练的进度和减少数据获取的资金投入。依靠主动学习来得到有价值的数据&#xff0c;以便机器模型从中学习。如果一个模型被具有价值的数据加以训练&#xff0c;它将以较少的人工标注和更短…

安防视频监控系统EasyCVR实现H.265视频在3秒内起播的注意事项

可视化云监控平台/安防视频监控系统EasyCVR视频综合管理平台&#xff0c;采用了开放式的网络结构&#xff0c;可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;同时…

ZETA落地合肥、宜城南方水泥,纵行科技携手中才邦业助力水泥企业数智化管理

近日&#xff0c;合肥南方水泥、宜城南方水泥落地ZETA预测性维护方案&#xff0c;通过在水泥厂内搭建ZETA网络&#xff0c;并在B类及C类主辅机设备上安装ZETA系列端智能传感器&#xff0c;进行数据采集和监测设备运行状态、以及早期故障警报和诊断&#xff0c;实现水泥生产设备…

PHP的Laravel加一个小页面出现问题(whereRaw的用法)

1.权限更新问题 因为是已经有样例了所以html和php页面很快写出来了 然后就是页面写完了路由不知道在哪写&#xff0c;后来想起来之前有要开权限来着&#xff0c;试了一下&#xff0c;还是不行&#xff0c;不过方向是对了 这是加的路由&#xff0c;不过需要在更新一下权限 这…

零基础刷代码随想录【Day1】|| 二分查找,移除元素

我的个人主页&#xff1a;☆光之梦☆的博客_CSDN博客-C语言基础语法&#xff08;超详细&#xff09;领域博主 欢迎各位 &#x1f44d;点赞 ⭐收藏 &#x1f4dd;评论 我的专栏&#xff1a;C语言基础语法&#xff08;超详细&#xff09;_☆光之梦☆的博客-CSDN博客&#xff08;这…

Ubuntu安装K8S(1.28版本,基于containrd)

原文网址&#xff1a;Ubuntu安装K8S(1.28版本&#xff0c;基于containrd&#xff09;-CSDN博客 简介 本文介绍Ubuntu安装K8S的方法。 官网文档&#xff1a;这里 1.安装K8S 1.让apt支持SSL传输 sudo apt-get update sudo apt-get -y install apt-transport-https ca-certi…

【算法与数据结构】860、LeetCode柠檬水找零

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题的思路比较简单&#xff0c;首先要保存收到的零钱&#xff0c;其次计算找零&#xff0c;最后分解找…

git的常用命令以及在可视化工具中的使用方法

一.引言 想当初在刚进公司的时候&#xff0c;对于git的使用非常不熟悉&#xff0c;特别是分支的概念&#xff0c;导致开发效率变低&#xff0c;故通过此文章&#xff0c;总结git的使用经验 二.Git 常用命令详解 2.1 git clone [url]: 克隆远程仓库到本地 刚开始时&#xff0c…

Anaconda 环境中安装OpenCV (cv2)

1、使用Anaconda 的对应环境&#xff0c;查看环境中的Python版本号 (1)使用Anaconda 查看存在的环境&#xff1a;conda info --env (2)激活环境&#xff1a;conda activate XXX 2、根据版本号&#xff0c;下载对应的 python-opencv 包 &#xff08;1&#xff09;选择国内源的…

K8S网络类型

k8s的网络类型 k8s的通信模式 1 pod内部之间容器与容器之间的通信&#xff0c;在同一个pod中容器是共享资源和网络&#xff0c;使用同一个网络命名空间&#xff0c;可以直接通信 2 同一个node节点之内&#xff0c;不同pod之间的通信&#xff0c;每个pod都有一个全局的真实ip地…

RabbitMQ 报错:Failed to declare queue(s):[QD, QA, QB]

实在没想到会犯这种低级错误。 回顾整理一下吧&#xff1a; 原因&#xff1a;SpringBoot主配置类默认只会扫描自己所在的包及其子包下面的组件。其他位置的配置不会被扫描。 如果非要使用其他位置&#xff0c;就需要在启动类上面指定新的扫描位置。注意新的扫描位置会覆盖默…

深入浅出:分布式、CAP 和 BASE 理论(荣耀典藏版)

大家好&#xff0c;我是月夜枫&#xff0c;一个漂泊江湖多年的 985 非科班程序员&#xff0c;曾混迹于国企、互联网大厂和创业公司的后台开发攻城狮。 在计算机科学领域&#xff0c;分布式系统是一门极具挑战性的研究方向&#xff0c;也是互联网应用中必不可少的优化实践&…