【ETCD】【源码阅读】ETCD启动流程源码解读

news2025/1/10 23:42:57

启动流程的图如下:
在这里插入图片描述

1、主函数入口

ETCD 启动的入口在 etcd/server/main.go 文件中。

package main

import (
	"os"

	"go.etcd.io/etcd/server/v3/etcdmain"
)

func main() {
	etcdmain.Main(os.Args)
}

这里调用了 etcdmain.Main(),这是 ETCD 的实际启动逻辑。

2、etcdmain.Main(os.Args)详解

代码源文件:etcd/server/v3/etcdmain.main.go

func Main(args []string) {
	// 1. 检查系统架构支持
	checkSupportArch()

	if len(args) > 1 { // // 2. 检查命令行参数
		cmd := args[1]
		switch cmd {
		case "gateway", "grpc-proxy": // // 3. 判断是否运行网关或 gRPC 代理模式
			if err := rootCmd.Execute(); err != nil {
				fmt.Fprint(os.Stderr, err)
				os.Exit(1)
			}
			return
		}
	}

	startEtcdOrProxyV2(args) // // 4. 启动普通 ETCD 节点或代理节点
}
2.1.checkSupportArch()
  • 功能:检查当前运行的系统架构是否被 ETCD 支持。
  • 目的:确保程序在不支持的架构上不会运行,例如特定 ARM 版本可能不被支持。
2.2. 检查命令行参数:
  • args 是启动时传递的命令行参数,args[0] 通常是可执行文件名,args[1] 是实际命令。
2.3. 启动不同模式:
  • 如果命令为 "gateway""grpc-proxy",表示要运行 ETCD 的网关或 gRPC 代理模式。
  • 执行 rootCmd.Execute(),启动对应的命令逻辑。
  • rootCmd 是 Cobra 框架定义的根命令,包含所有子命令和配置。
2.4. 启动普通节点或代理节点:
  • 如果没有匹配到特殊命令,调用 startEtcdOrProxyV2(args)

  • 功能:根据配置和参数,决定是启动标准 ETCD 节点还是运行代理模式。

    ​ 接下来可以深入分析 startEtcdOrProxyV2 函数,该函数负责实际启动 ETCD 实例或代理模式。它会加载配置、初始化组件,并启动 Raft、MVCC 等核心模块。

3、startEtcdOrProxyV2(args)详解

func startEtcdOrProxyV2(args []string) {
	// 禁用 gRPC 跟踪,优化性能
	grpc.EnableTracing = false

	// 创建一个新的配置对象
	cfg := newConfig()
	// 保存初始集群配置,方便后续处理
	defaultInitialCluster := cfg.ec.InitialCluster

	// 解析传入的命令行参数,将配置赋值给 cfg
	err := cfg.parse(args[1:])
	// 初始化日志记录器,确保所有输出都写入日志。
	lg := cfg.ec.GetLogger()
	// If we failed to parse the whole configuration, print the error using
	// preferably the resolved logger from the config,
	// but if does not exists, create a new temporary logger.
	if lg == nil {
		var zapError error
		// use this logger
		lg, zapError = logutil.CreateDefaultZapLogger(zap.InfoLevel)
		if zapError != nil {
			fmt.Printf("error creating zap logger %v", zapError)
			os.Exit(1)
		}
	}
	lg.Info("Running: ", zap.Strings("args", args))
	if err != nil {
		lg.Warn("failed to verify flags", zap.Error(err))
		switch {
		case errorspkg.Is(err, embed.ErrUnsetAdvertiseClientURLsFlag):
			lg.Warn("advertise client URLs are not set", zap.Error(err))
		}
		os.Exit(1)
	}

	cfg.ec.SetupGlobalLoggers()

	defer func() {
		logger := cfg.ec.GetLogger()
		if logger != nil {
			logger.Sync()
		}
	}()

	// 解析默认集群地址
	defaultHost, dhErr := (&cfg.ec).UpdateDefaultClusterFromName(defaultInitialCluster)
	if defaultHost != "" {
		lg.Info(
			"detected default host for advertise",
			zap.String("host", defaultHost),
		)
	}
	if dhErr != nil {
		lg.Info("failed to detect default host", zap.Error(dhErr))
	}

	// 设置数据目录 如果未指定数据目录,使用默认目录
	if cfg.ec.Dir == "" {
		cfg.ec.Dir = fmt.Sprintf("%v.etcd", cfg.ec.Name)
		lg.Warn(
			"'data-dir' was empty; using default",
			zap.String("data-dir", cfg.ec.Dir),
		)
	}

	var stopped <-chan struct{}
	var errc <-chan error

	// 判断数据目录类型并启动
	which := identifyDataDirOrDie(cfg.ec.GetLogger(), cfg.ec.Dir)
	if which != dirEmpty {
		lg.Info(
			"server has already been initialized",
			zap.String("data-dir", cfg.ec.Dir),
			zap.String("dir-type", string(which)),
		)
		switch which {
        // 启动etcd
		case dirMember:
			stopped, errc, err = startEtcd(&cfg.ec) // 启动 ETCD 服务
		case dirProxy:
			lg.Panic("v2 http proxy has already been deprecated in 3.6", zap.String("dir-type", string(which)))
		default:
			lg.Panic(
				"unknown directory type",
				zap.String("dir-type", string(which)),
			)
		}
	} else {
		lg.Info(
			"Initialize and start etcd server",
			zap.String("data-dir", cfg.ec.Dir),
			zap.String("dir-type", string(which)),
		)
		stopped, errc, err = startEtcd(&cfg.ec)
	}

	// 处理启动错误
	if err != nil {
	   // ... 省略部分代码
		lg.Fatal("discovery failed", zap.Error(err))
	}

	// 信号处理与退出
	osutil.HandleInterrupts(lg)

	// At this point, the initialization of etcd is done.
	// The listeners are listening on the TCP ports and ready
	// for accepting connections. The etcd instance should be
	// joined with the cluster and ready to serve incoming
	// connections.
	notifySystemd(lg)

	select {
	case lerr := <-errc:
		//2 fatal out on listener errors
		lg.Fatal("listener failed", zap.Error(lerr))
	case <-stopped:
	}

	osutil.Exit(0)
}
3.1. 关键调用

startEtcd(&cfg.ec):这是实际启动 ETCD 服务的函数,负责初始化和启动所有必要组件。

identifyDataDirOrDie():检查数据目录类型,决定是启动服务还是退出。

4、startEtcd(&cfg.ec)详解

// startEtcd runs StartEtcd in addition to hooks needed for standalone etcd.
func startEtcd(cfg *embed.Config) (<-chan struct{}, <-chan error, error) {
	// 是启动 ETCD 服务的核心函数。它负责初始化 ETCD 实例、注册中断信号处理,
	// 并等待服务成功启动或异常停止。
	// 最后,返回相关的停止和错误通道
	e, err := embed.StartEtcd(cfg)

	// 启动失败,立即返回错误
	if err != nil {
		return nil, nil, err
	}
	// 注册中断信号处理
	osutil.RegisterInterruptHandler(e.Close)

	// 等待服务状态
	select {
	case <-e.Server.ReadyNotify(): // wait for e.Server to join the cluster
	case <-e.Server.StopNotify(): // publish aborted from 'ErrStopped'
	}
	return e.Server.StopNotify(), e.Err(), nil
}
4.1 embed.StartEtcd(cfg)

根据传入的配置 cfg,启动一个嵌入式 ETCD 实例。

返回值 eembed.Etcd 实例,封装了 ETCD 服务的所有组件,包括 Raft 节点、存储引擎、gRPC 和 HTTP 接口。

错误处理:如果启动失败,立即返回错误。

4.2 RegisterInterruptHandler
  • 作用:监听系统中断信号(如 SIGINTSIGTERM),确保在接收到中断信号时,调用 e.Close() 优雅地关闭 ETCD 服务。
  • e.Close:关闭所有资源(网络连接、存储、Raft 等)。

5、embed.StartEtcd(cfg)详解

// StartEtcd launches the etcd server and HTTP handlers for client/server communication.
// The returned Etcd.Server is not guaranteed to have joined the cluster. Wait
// on the Etcd.Server.ReadyNotify() channel to know when it completes and is ready for use.
func StartEtcd(inCfg *Config) (e *Etcd, err error) {

	// 1.配置验证
	if err = inCfg.Validate(); err != nil {
		return nil, err
	}
	serving := false
	// 初始化 ETCD 实例
	e = &Etcd{cfg: *inCfg, stopc: make(chan struct{})}
	cfg := &e.cfg

	// 如果服务未成功启动,则关闭所有资源和监听器
	defer func() {
		if e == nil || err == nil {
			return
		}
		if !serving {
			// errored before starting gRPC server for serveCtx.serversC
			for _, sctx := range e.sctxs {
				close(sctx.serversC)
			}
		}
		e.Close()
		e = nil
	}()

	if !cfg.SocketOpts.Empty() {
		cfg.logger.Info(
			"configuring socket options",
			zap.Bool("reuse-address", cfg.SocketOpts.ReuseAddress),
			zap.Bool("reuse-port", cfg.SocketOpts.ReusePort),
		)
	}
	e.cfg.logger.Info(
		"configuring peer listeners",
		zap.Strings("listen-peer-urls", e.cfg.getListenPeerURLs()),
	)

	// 配置 Peer(节点间通信)监听器
	if e.Peers, err = configurePeerListeners(cfg); err != nil {
		return e, err
	}

	e.cfg.logger.Info(
		"configuring client listeners",
		zap.Strings("listen-client-urls", e.cfg.getListenClientURLs()),
	)

	// 配置 Client(客户端通信)监听器
	if e.sctxs, err = configureClientListeners(cfg); err != nil {
		return e, err
	}

	for _, sctx := range e.sctxs {
		e.Clients = append(e.Clients, sctx.l)
	}

	var (
		urlsmap types.URLsMap
		token   string
	)
	// 初始化集群信息
	memberInitialized := true
	if !isMemberInitialized(cfg) {
		memberInitialized = false
		urlsmap, token, err = cfg.PeerURLsMapAndToken("etcd")
		if err != nil {
			return e, fmt.Errorf("error setting up initial cluster: %w", err)
		}
	}

	// AutoCompactionRetention defaults to "0" if not set.
	if len(cfg.AutoCompactionRetention) == 0 {
		cfg.AutoCompactionRetention = "0"
	}

	// 设置存储和压缩选项
	autoCompactionRetention, err := parseCompactionRetention(cfg.AutoCompactionMode, cfg.AutoCompactionRetention)
	if err != nil {
		return e, err
	}

	backendFreelistType := parseBackendFreelistType(cfg.BackendFreelistType)

	srvcfg := config.ServerConfig{
		Name:                                     cfg.Name,
		ClientURLs:                               cfg.AdvertiseClientUrls,
		PeerURLs:                                 cfg.AdvertisePeerUrls,
		DataDir:                                  cfg.Dir,
		DedicatedWALDir:                          cfg.WalDir,
		SnapshotCount:                            cfg.SnapshotCount,
		SnapshotCatchUpEntries:                   cfg.SnapshotCatchUpEntries,
		MaxSnapFiles:                             cfg.MaxSnapFiles,
		MaxWALFiles:                              cfg.MaxWalFiles,
		InitialPeerURLsMap:                       urlsmap,
		InitialClusterToken:                      token,
		DiscoveryURL:                             cfg.Durl,
		DiscoveryProxy:                           cfg.Dproxy,
		DiscoveryCfg:                             cfg.DiscoveryCfg,
		NewCluster:                               cfg.IsNewCluster(),
		PeerTLSInfo:                              cfg.PeerTLSInfo,
		TickMs:                                   cfg.TickMs,
		ElectionTicks:                            cfg.ElectionTicks(),
		InitialElectionTickAdvance:               cfg.InitialElectionTickAdvance,
		AutoCompactionRetention:                  autoCompactionRetention,
		AutoCompactionMode:                       cfg.AutoCompactionMode,
		QuotaBackendBytes:                        cfg.QuotaBackendBytes,
		BackendBatchLimit:                        cfg.BackendBatchLimit,
		BackendFreelistType:                      backendFreelistType,
		BackendBatchInterval:                     cfg.BackendBatchInterval,
		MaxTxnOps:                                cfg.MaxTxnOps,
		MaxRequestBytes:                          cfg.MaxRequestBytes,
		MaxConcurrentStreams:                     cfg.MaxConcurrentStreams,
		SocketOpts:                               cfg.SocketOpts,
		StrictReconfigCheck:                      cfg.StrictReconfigCheck,
		ClientCertAuthEnabled:                    cfg.ClientTLSInfo.ClientCertAuth,
		AuthToken:                                cfg.AuthToken,
		BcryptCost:                               cfg.BcryptCost,
		TokenTTL:                                 cfg.AuthTokenTTL,
		CORS:                                     cfg.CORS,
		HostWhitelist:                            cfg.HostWhitelist,
		CorruptCheckTime:                         cfg.ExperimentalCorruptCheckTime,
		CompactHashCheckEnabled:                  cfg.ExperimentalCompactHashCheckEnabled,
		CompactHashCheckTime:                     cfg.ExperimentalCompactHashCheckTime,
		PreVote:                                  cfg.PreVote,
		Logger:                                   cfg.logger,
		ForceNewCluster:                          cfg.ForceNewCluster,
		EnableGRPCGateway:                        cfg.EnableGRPCGateway,
		ExperimentalEnableDistributedTracing:     cfg.ExperimentalEnableDistributedTracing,
		UnsafeNoFsync:                            cfg.UnsafeNoFsync,
		EnableLeaseCheckpoint:                    cfg.ExperimentalEnableLeaseCheckpoint,
		LeaseCheckpointPersist:                   cfg.ExperimentalEnableLeaseCheckpointPersist,
		CompactionBatchLimit:                     cfg.ExperimentalCompactionBatchLimit,
		CompactionSleepInterval:                  cfg.ExperimentalCompactionSleepInterval,
		WatchProgressNotifyInterval:              cfg.ExperimentalWatchProgressNotifyInterval,
		DowngradeCheckTime:                       cfg.ExperimentalDowngradeCheckTime,
		WarningApplyDuration:                     cfg.ExperimentalWarningApplyDuration,
		WarningUnaryRequestDuration:              cfg.WarningUnaryRequestDuration,
		ExperimentalMemoryMlock:                  cfg.ExperimentalMemoryMlock,
		ExperimentalTxnModeWriteWithSharedBuffer: cfg.ExperimentalTxnModeWriteWithSharedBuffer,
		ExperimentalBootstrapDefragThresholdMegabytes: cfg.ExperimentalBootstrapDefragThresholdMegabytes,
		ExperimentalMaxLearners:                       cfg.ExperimentalMaxLearners,
		V2Deprecation:                                 cfg.V2DeprecationEffective(),
		ExperimentalLocalAddress:                      cfg.InferLocalAddr(),
		ServerFeatureGate:                             cfg.ServerFeatureGate,
	}

	if srvcfg.ExperimentalEnableDistributedTracing {
		tctx := context.Background()
		tracingExporter, terr := newTracingExporter(tctx, cfg)
		if terr != nil {
			return e, terr
		}
		e.tracingExporterShutdown = func() {
			tracingExporter.Close(tctx)
		}
		srvcfg.ExperimentalTracerOptions = tracingExporter.opts

		e.cfg.logger.Info(
			"distributed tracing setup enabled",
		)
	}

	srvcfg.PeerTLSInfo.LocalAddr = srvcfg.ExperimentalLocalAddress

	print(e.cfg.logger, *cfg, srvcfg, memberInitialized)

	// 创建服务实例
	if e.Server, err = etcdserver.NewServer(srvcfg); err != nil {
		return e, err
	}

	// buffer channel so goroutines on closed connections won't wait forever
	e.errc = make(chan error, len(e.Peers)+len(e.Clients)+2*len(e.sctxs))

	// newly started member ("memberInitialized==false")
	// does not need corruption check
	if memberInitialized && srvcfg.ServerFeatureGate.Enabled(features.InitialCorruptCheck) {
		if err = e.Server.CorruptionChecker().InitialCheck(); err != nil {
			// set "EtcdServer" to nil, so that it does not block on "EtcdServer.Close()"
			// (nothing to close since rafthttp transports have not been started)

			e.cfg.logger.Error("checkInitialHashKV failed", zap.Error(err))
			e.Server.Cleanup()
			e.Server = nil
			return e, err
		}
	}

	// 启动服务
	e.Server.Start()

	e.servePeers()

	e.serveClients()

	// 用于暴露 ETCD 的 监控指标
	if err = e.serveMetrics(); err != nil {
		return e, err
	}

	e.cfg.logger.Info(
		"now serving peer/client/metrics",
		zap.String("local-member-id", e.Server.MemberID().String()),
		zap.Strings("initial-advertise-peer-urls", e.cfg.getAdvertisePeerURLs()),
		zap.Strings("listen-peer-urls", e.cfg.getListenPeerURLs()),
		zap.Strings("advertise-client-urls", e.cfg.getAdvertiseClientURLs()),
		zap.Strings("listen-client-urls", e.cfg.getListenClientURLs()),
		zap.Strings("listen-metrics-urls", e.cfg.getMetricsURLs()),
	)
	serving = true
	return e, nil
}
5.1. 配置验证

验证配置是否合法。例如,检查必填项是否缺失

5.2. 初始化 ETCD 实例

创建一个新的 ETCD 实例,并初始化用于控制服务停止的通道 stopc

5.3.延迟清理(defer 块)

在函数退出时,确保资源被正确释放。如果服务未成功启动,则关闭所有资源和监听器。

5.4. 配置网络监听器
配置 Peer(节点间通信)监听器

为节点间通信设置监听器,方便集群内部通过 Raft 协议进行通信。

配置 Client(客户端通信)监听器:

为客户端请求设置监听器,处理外部对 ETCD 的访问。

5.5.初始化集群信息

如果当前节点是新成员,则生成初始集群信息,包括节点 URL 和集群令牌。

5.6.设置存储和压缩选项:

设置数据压缩和存储的保留策略,以控制存储空间占用。

5.7.创建服务实例

基于配置创建 Raft 节点和存储服务。

5.8.启动服务
e.Server.Start()
e.servePeers()
e.serveClients()

启动 Raft 节点,监听节点间和客户端的请求。

5.9 记录启动完成日志并返回结果
  • 记录服务启动成功的信息,包括节点 ID 和监听的 URL。
  • 返回已启动的 ETCD 实例

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

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

相关文章

【RBF SBN READ】hadoop社区基于RBF的SBN READ请求流转

读写分离功能的背景及架构 当前联邦生产集群的各个子集群只有Active NameNode在工作,当读写任务变得繁忙的时候,只有一个Active负责处理的话,此时集群的响应和处理能力业务侧感知会明显下降,为此,我们将引入Observer架构,实现读写功能的分离,使得Active只负责写请求,而…

计算机运行时提示错误弹窗“由于找不到 quazip.dll,无法继续执行代码。”是什么原因?“quazip.dll文件缺失”要怎么解决?

计算机运行时错误解析&#xff1a;解决“quazip.dll缺失”问题指南 在软件开发和日常计算机使用中&#xff0c;我们经常会遇到各种运行时错误。今天&#xff0c;我们将深入探讨一个常见的错误提示&#xff1a;“由于找不到quazip.dll&#xff0c;无法继续执行代码。”这一弹窗…

NuHertz/HFSS: 使用矩形、径向和阻抗短截线的平面 LPF 切比雪夫-II 实现

我们今天的主题是使用 NuHertz 和 HFSS 设计 Microstrip Lowpass Chebyshev-Type2 滤波器。切比雪夫 2 型在通带中具有平坦的响应&#xff0c;在阻带中具有波纹。我们将比较 NuHertz 中的不同选项。 低通滤波器由集总 L 和 C 组件制成。这种方法很难用于高频应用程序。高频滤波…

SpringBoot整合knife4j,以及会遇到的一些bug

这篇文章主要讲解了“Spring Boot集成接口管理工具Knife4j怎么用”&#xff0c;文中的讲解内容简单清晰&#xff0c;易于学习与理解&#xff0c;下面请大家跟着小编的思路慢慢深入&#xff0c;一起来研究和学习“Spring Boot集成接口管理工具Knife4j怎么用”吧&#xff01; 一…

高效的 Java 对象映射库“Orika”

什么是 Orika Orika 是一个高效的 Java 对象映射库&#xff0c;专门用于简化 Java 应用程序中对象之间的转换。它以自动化和优化的方式将一个对象的属性映射到另一个对象&#xff0c;从而减少了手动编写重复代码的需要。Orika 特别适合处理复杂的对象结构以及数据传输对象 &am…

汽车总线协议分析-CAN-FD总线

随着汽车功能的增多&#xff0c;各ECU之间的信息交互也越来越频繁&#xff0c;导致总线负载持续走高&#xff0c;CAN2.0报文只有约40%-50%带宽实际用于数据传输&#xff0c;响应机制易受车内布线的物理特性限制&#xff0c;如广播延迟、导线延迟等&#xff0c;CAN的局限性也逐渐…

【JavaEE】多线程(6)

一、用户态与内核态 【概念】 用户态是指用户程序运行时的状态&#xff0c;在这种状态下&#xff0c;CPU只能执行用户态下的指令&#xff0c;并且只能访问受限的内存空间 内核态是操作系统内核运行时的状态&#xff0c;内核是计算机系统的核心部分&#xff0c;CPU可以执行所有…

故障处理--kuboard无法访问,etcd磁盘空间不足

问题现象&#xff1a; kuboard页面报错 排查过程&#xff1a; 1、查看kuboard是否正常。 2、查看kuboard容器的日志&#xff1a; docker logs -f --tail10 kuboard 大概内容如下&#xff1a; levelerror msg"failed to rotate keys: etcdserver: mvcc: database sp…

unity3d—demo(实现给出图集名字和图片名字生成对应的图片)

目录 实现给出图集名字和图片名字生成对应的图片&#xff1a; 代码示例&#xff1a; dic: 键 是图集名称 值是一个字典 该字典键是图片名称 值是图片&#xff0c;结构如图&#xff1a; 测试代码&#xff1a; 结果&#xff1a; SpriteRenderer 讲解&#xff1a; Resour…

工业异常检测-CVPR2024-新的3D异常数据合成办法和自监督网络IMRNet

论文&#xff1a;https://arxiv.org/pdf/2311.14897v3.pdf 项目&#xff1a;https://github.com/chopper-233/anomaly-shapenet 这篇论文主要关注的是3D异常检测和定位&#xff0c;这是一个在工业质量检查中至关重要的任务。作者们提出了一种新的方法来合成3D异常数据&#x…

WPF编写工业相机镜头选型程序

该程序满足面阵和线阵的要求。 前端代码 <Window x:Class"相机镜头选型.MainWindow" Loaded"Window_Loaded"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml…

springai结合ollama

目录 ollama 介绍 使用 下载&#xff1a; 安装&#xff1a; 点击这个玩意next就行了。 运行 spring ai使用ollama调用本地部署的大模型 加依赖 配置yml 写代码 ollama 介绍 官网&#xff1a;Ollama Ollama是一个用于部署和运行各种开源大模型的工具&#xff1b; …

Linux 统信UOS 设置程序“桌面快捷方式”与“开机自启动”

最近在统信uos系统 arm64架构上进行QT程序的开发&#xff0c;基本开发完毕后&#xff0c;开始着手准备程序的开机自启动模块&#xff0c;因为一般来说&#xff0c;程序在客户现场使用都是需要开机自启的。 然后在百度海淘&#xff0c;很少有这类相关的博客介绍&#xff0c;有一…

WiFi受限不再愁,电脑无网络快速修复指南

有时在试图连接WiFi时&#xff0c;会发现网络连接受限&#xff0c;或无法正常访问互联网。这种情况不仅影响了工作效率&#xff0c;还可能错过重要的信息。那么&#xff0c;究竟是什么原因导致了电脑WiFi连接受限呢&#xff1f;又该如何解决这一问题呢&#xff1f;小A今天就来教…

java注解(一):什么是注解?什么是元注解?如何自定义注解?注解的原理是什么?

目录 1、什么是注解&#xff1f; 2、什么是元注解 1、Target() 2、Retention() 3、Documented 4、Inherited 3、如何自定义注解以解使用 4、注解的原理 本篇文章主要是介绍注解的概念、原理&#xff0c;以及通过代码演示4种元注解、如何自定义注解。通过反编译的形式进…

【Docker】Linux与Windows系统安装Docker+Docker上简单安装MySQL

一、Windows安装Docker 由于我在许多平台搜索Windows下安装Docker的方法&#xff0c;都提到了Win10家庭版无法直接安装Docker。个人电脑就是Win10家庭版&#xff0c;本着实践出真知的想法&#xff0c;个人在本机Win10家庭版实验结果为需要采用下述传统手动安装的办法&#xff…

阿里云整理(二)

阿里云整理 1. 访问网站2. 专业名词2.1 域名2.2 域名备案2.3 云解析DNS2.4 CDN2.5 WAF 1. 访问网站 用户使用浏览器访问网站大体分为几个过程&#xff1a; 用户在浏览器输入域名URL&#xff0c;例如www.baidu.com。 不过&#xff0c;浏览器并不知道为该域名提供服务的服务器具…

Robust Depth Enhancement via Polarization Prompt Fusion Tuning

paper&#xff1a;论文地址 code&#xff1a;github项目地址 今天给大家分享一篇2024CVPR上的文章&#xff0c;文章是用偏振做提示学习&#xff0c;做深度估计的。模型架构图如下 这篇博客不是讲这篇论文的内容&#xff0c;感兴趣的自己去看paper&#xff0c;主要是分享环境&…

Oceanbase离线集群部署

准备工作 两台服务器 服务器的配置参照官网要求来 服务器名配置服务器IPoceanbase116g8h192.168.10.239oceanbase216g8h192.168.10.239 这里选oceanbase1作为 obd机器 oceanbase安装包 选择社区版本的时候自己系统的安装包 ntp时间同步rpm包 联网机器下载所需的软件包 …

Ajax:回忆与节点

一点回忆 面对我的Ajax学习&#xff0c;实现前后端交互&#xff0c;最开始我采用的使用网络寻找intellij IDEA Ultimate破解方法&#xff0c;然后最终成功&#xff0c;然后按照相关教程配置java ee项目&#xff0c;然后中间又去配置了Tomcat服务器&#xff0c;然后又去学习了一…