Spark-环境启动

一、概览

从start-all.sh开始捋,一直捋到Master、Worker的启动并建立通信

二、宏观描述

Master端

1、start-all.sh调用start-master.sh启动Master

2、执行org.apache.spark.deploy.master.Master中main方法

3、通过工厂模式创建RpcEnv子类NettyRpcEnv

        a、创建TransportServer

        b、初始化TransportServer(通过ServerBootstrap去引导Netty并并绑定端口)

        c、Dispatcher将Master作为一个RpcEndpoint注册到RpcEnv中并返回RpcEndpointRef

        d、创建一个端点传递消息的MessageLoop,并将这个MessageLoop和Master绑定

        e、New一个带有待处理消息的收件箱(Inbox)同时也和Master绑定

        f、Inbox中有一个代码块会把OnStart方法添加到消息列表

        g、调用setActive(inbox)将其标记为活动以处理OnStart消息

4、Master中的OnStart的方法被调起

5、处理来自Workers的注册信息RegisterWorker,向Workers发送注册成功信息RegisterWorkerResponse

5、检查并删除超时的Worker

Worker端

1、start-all.sh调用start-workers.sh脚本

2、start-workers.sh去workers文件中查询节点ip或host依次ssh过去启动start-worker.sh脚本

3、各个节点执行org.apache.spark.deploy.worker.Worker中main方法

4、通过工厂模式创建RpcEnv子类NettyRpcEnv

        a、创建TransportServer

        b、初始化TransportServer(通过ServerBootstrap去引导Netty并并绑定端口)

        c、Dispatcher将Master作为一个RpcEndpoint注册到RpcEnv中并返回RpcEndpointRef

        d、创建一个端点传递消息的MessageLoop,并将这个MessageLoop和Master绑定

        e、New一个带有待处理消息的收件箱(Inbox)同时也和Master绑定

        f、Inbox中有一个代码块会把OnStart方法添加到消息列表

        g、调用setActive(inbox)将其标记为活动以处理OnStart消息

5、Worker中的OnStart的方法被调起

6、根据配置看是否启动外部ShuffleService

7、获取资源信息

8、根据Master的URL从RpcEnv中获取MasterEndpointRef

9、向所有的Master(可能会是HA的场景)发送注册信息RegisterWorker

10、接收到来自Master的RegisterWorkerResponse信息

11、向Master发送心跳Heartbeat

三、源码调用绘图

把图下载下来,放大可以看清楚

四、核心源码

脚本部分

1、start-all.sh

#启动所有spark守护进程
#在此节点上启动Master
#在conf/workers中指定的每个节点上启动一个worker# Start Master
"${SPARK_HOME}/sbin"/start-master.sh# Start Workers
"${SPARK_HOME}/sbin"/start-workers.sh

2、start-master.sh

CLASS="org.apache.spark.deploy.master.Master"
#默认端口
SPARK_MASTER_PORT=7077
SPARK_MASTER_WEBUI_PORT=8080
#获取Master节点的域名
$SPARK_MASTER_HOST#启动Master守护进程
"${SPARK_HOME}/sbin"/spark-daemon.sh start $CLASS 1 \--host $SPARK_MASTER_HOST --port $SPARK_MASTER_PORT --webui-port $SPARK_MASTER_WEBUI_PORT \$ORIGINAL_ARGS

3、start-workers.sh

#Master节点默认端口
SPARK_MASTER_PORT=7077
#获取Master节点的域名
$SPARK_MASTER_HOST
#启动所有的worker
"${SPARK_HOME}/sbin/workers.sh" cd "${SPARK_HOME}" \; "${SPARK_HOME}/sbin/start-worker.sh" "spark://$SPARK_MASTER_HOST:$SPARK_MASTER_PORT"

4、start-worker.sh

CLASS="org.apache.spark.deploy.worker.Worker"#启动几个Worker实例
$SPARK_WORKER_INSTANCES
#第一个worker的端口号。如果设置,后续的workers将递增此数字。如果未设置,Spark将找到一个有效的端口号,但不能保证模式是可预测的。
$SPARK_WORKER_PORT
#第一个worker的web界面的基本端口。后续的workers将增加这个数字。默认值为8081。
$SPARK_WORKER_WEBUI_PORT
#启动worker
"${SPARK_HOME}/sbin"/spark-daemon.sh start $CLASS $WORKER_NUM \--webui-port "$WEBUI_PORT" $PORT_FLAG $PORT_NUM $MASTER "$@"

scala代码部分

1、Master

//Master 是一个多线程安全的RpcEndpoint
private[deploy] class Master(override val rpcEnv: RpcEnv,address: RpcAddress,webUiPort: Int,val securityMgr: SecurityManager,val conf: SparkConf)extends ThreadSafeRpcEndpoint with Logging with LeaderElectable {private val forwardMessageThread =ThreadUtils.newDaemonSingleThreadScheduledExecutor("master-forward-message-thread")//Master端有所有worker的信息 并且有它们的 Rpc通信地址val workers = new HashSet[WorkerInfo]private val addressToWorker = new HashMap[RpcAddress, WorkerInfo]override def onStart(): Unit = {logInfo("Starting Spark master at " + masterUrl)logInfo(s"Running Spark version ${org.apache.spark.SPARK_VERSION}")webUi = new MasterWebUI(this, webUiPort)webUi.bind()masterWebUiUrl = webUi.webUrl//检测所有Worker的超时任务checkForWorkerTimeOutTask = forwardMessageThread.scheduleAtFixedRate(() => Utils.tryLogNonFatalError { self.send(CheckForWorkerTimeOut) },0, workerTimeoutMs, TimeUnit.MILLISECONDS)}override def onStop(): Unit = {...}//HA下的Leader选举override def electedLeader(): Unit = {self.send(ElectedLeader)}//接收其他 Endpoint 的 send 消息override def receive: PartialFunction[Any, Unit] = {case ElectedLeader => Leader选举case RegisterWorker(...)=> worker 此时会携带它的资源信息 xx核 xx 内存master 会添加这个 worker 并向这个 worker send  RegisterWorkerResponse 消息case RegisterApplication(description, driver) => derver端的应用注册case Heartbeat(workerId, worker) => 接收worker端的心跳case CheckForWorkerTimeOut => 检测worker的心跳......}//接收其他 Endpoint 的 ask 消息override def receiveAndReply(context: RpcCallContext): PartialFunction[Any, Unit] = {case RequestSubmitDriver(description) => 提交 driver case RequestKillDriver(driverId) => 杀掉 drivercase RequestDriverStatus(driverId) => driver 状态case RequestMasterState => master 状态case RequestExecutors(appId, requestedTotal) => 启动 executorscase KillExecutors(appId, executorIds) => 杀掉 executors......}//在workers上启动executors //返回一个数组,其中包含分配给每个worker的核心数。//有两种启动executors 的模式。//第一种方法试图将应用程序的executors 分散到尽可能多的worker进程上, 更适合数据局部性,是默认设置//第二种方法则相反(即在尽可能少的worker进程中启动它们)。//分配给每个executor的核心数量是可配置的。当显式设置此选项时,如果工作进程有足够的内核和内存,则可以在同一worker进程上启动来自同一应用程序的多个executor。否则,//默认情况下,每个executor都会抓取worker上可用的所有内核,在这种情况下,在一次单独的计划迭代中,每个应用程序只能在每个worker上启动一个executor。//请注意,当未设置“spark.executor.cores”时,我们仍然可以在同一个worker上从同一个应用程序启动多个executor。//假设appA和appB都有一个executor在worker1上运行,并且appA.cores>0,则appB完成并释放worker1上的所有内核,因此对于下一个计划迭代,appA启动一个新的executor,抓取worker1上所有空闲的内核,因此我们从运行在worker1的appA中获得多个executor。private def scheduleExecutorsOnWorkers(...){......}//在workers上启动executorsprivate def startExecutorsOnWorkers(): Unit = {.......}//分配worker上的资源给 1个 或多个 executorprivate def allocateWorkerResourceToExecutors(){.......}//在等待的应用程序之间安排当前可用的资源。每当有新应用加入或资源可用性发生变化时,都会调用此方法。private def schedule(): Unit = {.......}......}private[deploy] object Master extends Logging {val SYSTEM_NAME = "sparkMaster"val ENDPOINT_NAME = "Master"def main(argStrings: Array[String]): Unit = {val args = new MasterArguments(argStrings, conf)//启动Master 并返回一个 tuple 3val (rpcEnv, _, _) = startRpcEnvAndEndpoint(args.host, args.port, args.webUiPort, conf)rpcEnv.awaitTermination()}def startRpcEnvAndEndpoint(...){//启动一个RpcEnvval rpcEnv = RpcEnv.create(SYSTEM_NAME, host, port, conf, securityMgr)//将Master Endpoint 注册到 RpcEnv 中val masterEndpoint = rpcEnv.setupEndpoint(ENDPOINT_NAME,new Master(rpcEnv, rpcEnv.address, webUiPort, securityMgr, conf))val portsResponse = masterEndpoint.askSync[BoundPortsResponse](BoundPortsRequest)(rpcEnv, portsResponse.webUIPort, portsResponse.restPort)}}

2、Worker

//Worker 是一个多线程安全的RpcEndpoint
private[deploy] class Worker(...){//Worker 端也有 Master 端的RpcEndpointRefprivate var master: Option[RpcEndpointRef] = Noneprivate var activeMasterUrl: String = ""//该Worker上有哪些 app driver executor val drivers = new HashMap[String, DriverRunner]val executors = new HashMap[String, ExecutorRunner]val appDirectories = new HashMap[String, Seq[String]]override def onStart(): Unit = {//根据配置启动外部ShuffleServicestartExternalShuffleService()//设置资源setupWorkerResources()//向所有Master注册自己registerWithMaster()......}//使用个新的Masterprivate def changeMaster(masterRef: RpcEndpointRef, uiUrl: String,masterAddress: RpcAddress): Unit = {......}//向所有的Master注册private def tryRegisterAllMasters(): Array[JFuture[_]] = {......}//向Master发送注册消息private def sendRegisterMessageToMaster(masterEndpoint: RpcEndpointRef): Unit = {......}//处理Master发送的注册响应private def handleRegisterResponse(msg: RegisterWorkerResponse): Unit = synchronized {msg match {case RegisteredWorker(...) => 注册成功case RegisterWorkerFailed(message) => 注册失败case MasterInStandby => Master 还没准备好}}//处理来自其他 Endpoint 的 send 消息override def receive: PartialFunction[Any, Unit] = synchronized {.......}//处理来自其他 Endpoint 的 ask 消息override def receiveAndReply(context: RpcCallContext): PartialFunction[Any, Unit] = {.......}//向当前主机发送消息。如果尚未在任何主机上成功注册,则消息将被丢弃。private def sendToMaster(message: Any): Unit = {}......}private[deploy] object Worker extends Logging {val SYSTEM_NAME = "sparkWorker"val ENDPOINT_NAME = "Worker"def main(argStrings: Array[String]): Unit = {val args = new WorkerArguments(argStrings, conf)//启动 RpcEnv 并将自己放进去val rpcEnv = startRpcEnvAndEndpoint(args.host, args.port, args.webUiPort, args.cores,args.memory, args.masters, args.workDir, conf = conf,resourceFileOpt = conf.get(SPARK_WORKER_RESOURCE_FILE))......rpcEnv.awaitTermination()}def startRpcEnvAndEndpoint(......){//一个节点可以启动多个worker 默认是1个val systemName = SYSTEM_NAME + workerNumber.map(_.toString).getOrElse("")val rpcEnv = RpcEnv.create(systemName, host, port, conf, securityMgr)val masterAddresses = masterUrls.map(RpcAddress.fromSparkURL)rpcEnv.setupEndpoint(ENDPOINT_NAME, new Worker(rpcEnv, webUiPort, cores, memory,masterAddresses, ENDPOINT_NAME, workDir, conf, securityMgr, resourceFileOpt))rpcEnv}}

3、NettyRpcEnv

//父类是RpcEnv
//RPC环境。[[RpcEndpoint]]需要在[[RpcEnv]]中注册一个名称来接收消息。
//然后[[RpcEnv]]将处理从[[RpcEndpointRef]]或远程节点发送的消息,并将其传递给相应的[[RpcEndpoint]]s。
//对于[[RpcEN]]捕获的未捕获异常,[[Rpcen]]将使用[[RpcCallContext.sendFailure]]将异常发送回发送方,或者在没有此类发送方或“NoterializableException”的情况下记录它们。
//[[RpcEnv]]还提供了一些方法来检索[[RpcEndpointRef]]的给定名称或uri
//它是各种角色通信的基础,是基于Netty的
private[netty] class NettyRpcEnv(...) extends RpcEnv {//分发器private val dispatcher: Dispatcher = new Dispatcher(this, numUsableCores)//基于Netty 其初始化时会通过bootstrap引导启动Netty@volatile private var server: TransportServer = _//[[RpcAddress]]和[[发件箱]]的map。当我们连接到远程[[RpcAddress]]时,我们只需将消息放入其[[Outbox]]即可实现非阻塞的“send”方法。private val outboxes = new ConcurrentHashMap[RpcAddress, Outbox]()//启动这个NettyRpcEnvdef startServer(bindAddress: String, port: Int): Unit = {val bootstraps: java.util.List[TransportServerBootstrap] =if (securityManager.isAuthenticationEnabled()) {java.util.Arrays.asList(new AuthServerBootstrap(transportConf, securityManager))} else {java.util.Collections.emptyList()}//创建一个将尝试绑定到特定主机和端口的Netty服务器server = transportContext.createServer(bindAddress, port, bootstraps)//注册一个RpcEndpointVerifier 用于给远程RpcEndpoint查询是否存在对应的RpcEndpointdispatcher.registerRpcEndpoint(RpcEndpointVerifier.NAME, new RpcEndpointVerifier(this, dispatcher))}//设置一个RpcEndpointoverride def setupEndpoint(name: String, endpoint: RpcEndpoint): RpcEndpointRef = {dispatcher.registerRpcEndpoint(name, endpoint)}//往Outbox中放信息(且指明了收件人)private def postToOutbox(receiver: NettyRpcEndpointRef, message: OutboxMessage): Unit = {......}//向远程 RPC endpoint 发送信息 其实就是放到 Outbox中 private[netty] def send(message: RequestMessage): Unit = {......}//异步发送消息,设置了超时时间,需要等待响应private[netty] def ask[T: ClassTag](message: RequestMessage, timeout: RpcTimeout): Future[T] = {......}......
}//RpcEndpointRef的NettyRpcEnv版本。
//此类的行为因创建位置而异。在“拥有”RpcEndpoint的节点上,它是一个围绕RpcEndpointAddress实例的简单包装器。
//在接收引用序列化版本的其他机器上,行为会发生变化。实例将跟踪发送引用的TransportClient,以便通过客户端连接向端点发送消息,而不需要打开新的连接。
//此引用的RpcAddress可以为空;这意味着ref只能通过客户端连接使用,因为承载端点的进程不监听传入连接。这些引用不应与第三方共享,因为它们将无法向端点发送消息。
private[netty] class NettyRpcEndpointRef(...){.......
}//从发送方发送到接收方的消息。
private[netty] class RequestMessage(...){.......
}//将传入的RPC分派到已注册的端点。
//处理程序跟踪与其通信的所有客户端实例,以便RpcEnv在向客户端端点(即不监听传入连接,而是需要通过客户端Socket联系的端点)发送RPC时知道要使用哪个“TransportClient”实例。
//事件是按每个连接发送的,因此,如果客户端打开多个到RpcEnv的连接,将为该客户端创建多个连接/断开连接事件(尽管具有不同的“RpcAddress”信息)。
private[netty] class NettyRpcHandler(...}.......
}//通过工厂创建NettyRpcEnv
private[rpc] class NettyRpcEnvFactory extends RpcEnvFactory with Logging {def create(config: RpcEnvConfig): RpcEnv = {......}    
}

4、TransportServer

public class TransportServer implements Closeable {//Netty服务端的引导,用于创建ServerChannelprivate final List<TransportServerBootstrap> bootstraps;private ServerBootstrap bootstrap;//构造器public TransportServer(...){...init(hostToBind, portToBind);...}//初始化该TransportServer private void init(String hostToBind, int portToBind) {//IO模式 NIO 、 EPOLL 模式是NIO //如果是Linux操作系统可以在spark-defaults.conf中设置spark.rpc.io.mode = EPOLL 来实现IOMode ioMode = IOMode.valueOf(conf.ioMode());//基于Netty中Reactor模型的启动EventLoopGroup bossGroup = NettyUtils.createEventLoop(ioMode, 1,conf.getModuleName() + "-boss");EventLoopGroup workerGroup =  NettyUtils.createEventLoop(ioMode, conf.serverThreads(),conf.getModuleName() + "-server");bootstrap = new ServerBootstrap().group(bossGroup, workerGroup).channel(NettyUtils.getServerChannelClass(ioMode)).option(ChannelOption.ALLOCATOR, pooledAllocator).option(ChannelOption.SO_REUSEADDR, !SystemUtils.IS_OS_WINDOWS).childOption(ChannelOption.ALLOCATOR, pooledAllocator);//绑定端口启动一个Netty服务端channelFuture = bootstrap.bind(address);}}

5、TransportClient

//客户端,用于获取预先协商的流的连续块。此API旨在实现大量数据的高效传输,这些数据被分解为大小从数百KB到几MB不等的块。
//请注意,虽然此客户端处理从流(即数据平面)中提取块,但流的实际设置是在传输层范围之外完成的。提供方便的方法“sendRPC”来实现客户端和服务器之间的控制平面通信,以执行此设置。
//例如:典型的工作流程是这样的:
//client.sendRPC(new OpenFile("/foo")) --> returns StreamId = 100
//client.fetchChunk(streamId = 100, chunkIndex = 0, callback)
//client.fetchChunk(streamId = 100, chunkIndex = 1, callback)
//......
//client.sendRPC(new CloseStream(100))//使用TransportClientFactory构造TransportClient的实例。单个TransportClient可用于多个流,但任何给定的流都必须限制在单个客户端,以避免乱序响应。
//注意:此类用于向服务器发出请求,而 TransportResponseHandler 负责处理来自服务器的响应。
//并发:线程安全,可以从多个线程调用。
public class TransportClient implements Closeable {//构造的时候给一个 Channel 就可以和Server端进行通信了//给一个TransportResponseHandler  就可以处理来自服务器的响应了public TransportClient(Channel channel, TransportResponseHandler handler) {this.channel = Preconditions.checkNotNull(channel);this.handler = Preconditions.checkNotNull(handler);this.timedOut = false;}public SocketAddress getSocketAddress() {return channel.remoteAddress();}//从远程端请求一个块,来自预先协商的streamId。//块指数从0开始。多次请求同一块是有效的,尽管某些流可能不支持此操作。//多个fetchChunk请求可能同时未完成,并且假设只使用单个TransportClient来获取块,则块保证会按照请求的顺序返回。public void fetchChunk(...){}//请求从远程端以给定的流ID流式传输数据。public void stream(String streamId, StreamCallback callback) {}//向服务器端的RpcHandler发送不透明消息。回调将随服务器的响应或在任何故障时调用。public long sendRpc(ByteBuffer message, RpcResponseCallback callback) {}......}

6、Dispatcher

//消息调度器,负责将RPC消息路由到适当的端点。
private[netty] class Dispatcher(nettyEnv: NettyRpcEnv, numUsableCores: Int) extends Logging {//端点和消息的映射private val endpoints: ConcurrentMap[String, MessageLoop] =new ConcurrentHashMap[String, MessageLoop]//端点和引用的映射private val endpointRefs: ConcurrentMap[RpcEndpoint, RpcEndpointRef] =new ConcurrentHashMap[RpcEndpoint, RpcEndpointRef]private lazy val sharedLoop = new SharedMessageLoop(nettyEnv.conf, this, numUsableCores)//使用名字注册RpcEndpoint 放回对应的引用 //就是在endpoints加一条记录 (name -> RpcEndpoint)def registerRpcEndpoint(name: String, endpoint: RpcEndpoint): NettyRpcEndpointRef = {......}//获取对应的引用def getRpcEndpointRef(endpoint: RpcEndpoint): RpcEndpointRef = endpointRefs.get(endpoint)//向所有已注册的[[RpcEndpoint]]发送消息。这可用于使所有端点都知道网络事件(例如“新增了节点”)。def postToAll(message: InboxMessage): Unit = {......}//向远程端点发送消息def postRemoteMessage(message: RequestMessage, callback: RpcResponseCallback): Unit = {......}//向本地端点发送消息def postLocalMessage(message: RequestMessage, p: Promise[Any]): Unit = {......}//发送一个单向消息def postOneWayMessage(message: RequestMessage): Unit = {}//向特定端点发送消息private def postMessage(){}}

7、MessageLoop

//Dispatcher 用于向端点传递消息的消息循环。
private sealed abstract class MessageLoop(dispatcher: Dispatcher) extends Logging {//待消息循环处理的带有待处理消息的收件箱列表。private val active = new LinkedBlockingQueue[Inbox]()//消息循环任务;应该在消息循环池的所有线程中运行。protected val receiveLoopRunnable = new Runnable() {override def run(): Unit = receiveLoop()}//不停的处理inbox中的信息,private def receiveLoop(): Unit = {while (true) {val inbox = active.take()if (inbox == MessageLoop.PoisonPill) {// Put PoisonPill back so that other threads can see it.setActive(MessageLoop.PoisonPill)return}//处理inbox存储的消息inbox.process(dispatcher)}}}//使用共享线程池为多个RPC端点提供服务的消息循环。
private class DedicatedMessageLoop(...){}

8、Inbox

//一个收件箱,用于存储 RpcEndpoint 的消息,并安全地向其线程发布消息。
private[netty] class Inbox(val endpointName: String, val endpoint: RpcEndpoint)extends Logging {inbox => 给它一个别名,这样我们就可以在闭包中更清楚地使用它。protected val messages = new java.util.LinkedList[InboxMessage]()//OnStart是要处理的第一条消息inbox.synchronized {messages.add(OnStart)}//处理Inbox中的消息def process(dispatcher: Dispatcher): Unit = {message = messages.poll()while (true) {safelyCall(endpoint) {message match {case RpcMessage(_sender, content, context) =>endpoint.receiveAndReplycase OneWayMessage(_sender, content) =>endpoint.receive.applyOrElse[Any, Unit](content, { msg =>case OnStart =>endpoint.onStart() //调用端点的Onstart() Master 、 Worker 的Onstart() 就是这样起来的case OnStop =>dispatcher.removeRpcEndpointRef(endpoint)endpoint.onStop()case RemoteProcessConnected(remoteAddress) =>endpoint.onConnected(remoteAddress)case RemoteProcessDisconnected(remoteAddress) =>endpoint.onDisconnected(remoteAddress)case RemoteProcessConnectionError(cause, remoteAddress) =>endpoint.onNetworkError(cause, remoteAddress)}}}}}

9、OutBox

private[netty] class Outbox(nettyEnv: NettyRpcEnv, val address: RpcAddress) {outbox =>  //给它一个别名,这样我们就可以在闭包中更清楚地使用它。private val messages = new java.util.LinkedList[OutboxMessage]//connectFuture指向连接任务。如果没有连接任务,connectFuture将为空private var connectFuture: java.util.concurrent.Future[Unit] = null//发送消息。如果没有活动连接,请缓存它并启动新连接def send(message: OutboxMessage): Unit = {}//清空消息队列private def drainOutbox(): Unit = {}//异步启动要给连接任务private def launchConnectTask(): Unit = {}}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Vue3】路由Params传参

【Vue3】路由Params传参 背景简介开发环境开发步骤及源码总结 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日…

【Redis】Linux CentOS Redis 的安装—(一)

Redis 一、获取源二、解压编译 一、获取源 //redis-stable是最新稳定版 wget https://download.redis.io/redis-stable.tar.gz二、解压编译 //我指定目录/app tar -xzvf redis-stable.tar.gz -C /appcd /app/redis-stablemake && make install##三 、修改配置启动 …

PyTorch 基础学习(5)- 神经网络

系列文章&#xff1a; PyTorch 基础学习&#xff08;1&#xff09; - 快速入门 PyTorch 基础学习&#xff08;2&#xff09;- 张量 Tensors PyTorch 基础学习&#xff08;3&#xff09; - 张量的数学操作 PyTorch 基础学习&#xff08;4&#xff09;- 张量的类型 PyTorch 基础学…

【阿卡迈防护分析】Vueling航空Akamai破盾实战

文章目录 1. 写在前面2. 风控分析3. 破盾实战 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python…

计算机毕业设计 美妆神域网站 美妆商城系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

springboot生成、响应图片验证码

我们平时经常会碰见图片验证码&#xff0c;那么在springboot中我们该怎么实现呢 我们可以使用一款开源的验证码生成工具EasyCaptcha&#xff0c;其支持多种类型的验证码&#xff0c;例如gif、中文、算术等&#xff0c;并且简单易用&#xff0c;具体内容可参考其官方文档。 效果…

【三维重建】SpotlessSplats:去除瞬态干扰物的三维高斯喷溅(3DGS)

代码&#xff1a;https://spotlesssplats.github.io 论文&#xff1a;https://arxiv.org/pdf/2406.20055 来源&#xff1a;DeepMind&#xff0c;多伦多大学&#xff0c;斯坦福大学&#xff0c;西蒙弗雷泽大学 提示&#xff1a;关注B站【方矩实验室】&#xff0c;查看视频讲解…

11.怎么做好一个动态标签页

效果 步骤 1.在Elementui找一个标签页组件 复制粘贴到代码 2.将他写活 将很多页面需要用的方法和变量写入store editableTabsValue: 2,editableTabs: [{title: 首页,name: index,},],addTab(state, tab) {if (state.editableTabs.findIndex(item > item.title tab.titl…

LVGL系列2--linux + lvglv8 + vscode 移植

LVGL系列 一、LVGL移植 LVGL系列1–AT32移植LVGL_V8具体步骤 LVGL系列2–linux lvglv8 vscode 移植 二、输入设备 LVGL系列3–纯物理(外部)按键&#xff0c;数字键盘控制控件 文章目录 LVGL系列一、LVGL移植二、输入设备 一、新建文件夹并克隆源码官方仓库 7.11.0官方仓库…

【AI/算法类】OPPO 2025届秋招笔试题(B卷)

目录 1. 第一题2. 第二题3. 第三题 ⏰ 时间&#xff1a;2024/08/10 &#x1f504; 输入输出&#xff1a;ACM格式 ⏳ 时长&#xff1a;2h 本试卷还有选择题部分&#xff0c;但这部分比较简单就不再展示。 1. 第一题 小O有一个正整数 x x x&#xff0c;他想知道&#xff0c;第…

抽卡机小程序,开启全新拆卡乐趣

近段时间&#xff0c;盲盒卡牌市场异常火爆&#xff0c;最近爆火的“小马宝莉”系列卡牌就深受消费者的喜爱&#xff0c;受到了广泛关注&#xff0c;同时也推动了卡牌市场的快速发展&#xff01;盲盒卡牌拥有隐藏款卡牌和限量款卡牌&#xff0c;具有非常大的收藏价值&#xff0…

使用Java调用Apache commons-text求解字符串相似性实战

目录 前言 一、字符串距离的几种计算方法 1、Levenshtein 距离 2、Overlap Coefficient计算 3、Q-gram Matching 4、余弦相似性计算 二、基于余弦相似性的基地名称对比 1、加载百科中的基地信息列表 2、设置忽略词列表 3、将数据库地名和Excel进行对比 三、总结 前言…

从力扣中等+困难题+表白HTML测试 -- 文心快码(Baidu Comate)

0 写在前面 官网地址&#xff1a;Baidu Comate Step1 打开文心快码&#xff08;Baidu Comate&#xff09;官网&#xff0c;点击「免费使用」/「下载安装」 Step2 可以根据官网步骤快速唤起VS Code&#xff1b; 也可以直接在VS Code、Visual Studio扩展管理搜索“文心快码”/…

如何用OceanBase实现HBase架构升级

随着数据量的爆炸性增长&#xff0c;特别是半结构化和非结构化数据的涌现&#xff0c;传统关系型数据库如 MySQL 遭遇了前所未有的挑战。这一背景下&#xff0c;为非结构化数据管理而生的 NoSQL 数据库&#xff0c;以及旨在解决海量数据存储难题的分布式技术应运而生&#xff0…

导出word格式的Javadoc(可用于快速生成项目详细设计文档)

导出word格式的Javadoc ​ 最近要编写项目详细设计文档&#xff0c;作为程序员当然想看看有没有能够自动生成的办法&#xff0c;生成详细设计文档&#xff0c;然后再在生成的基础上略做修改就好了&#xff08;偷懒大法~&#xff09;&#xff0c;还真有&#xff0c;特此分享&am…

理解Pytorch中的collate_fn函数

PyTorch中的DataLoader是最常用的类之一&#xff0c;这个类有很多参数&#xff08;14 个&#xff09;&#xff0c;但大多数情况下&#xff0c;你可能只会使用其中的三个&#xff1a;dataset、shuffle 和 batch_size。其中collate_fn是比较少用的函数&#xff0c;这对初学者来说…

Linux线程间通信学习记录(线程同步)

0.线程间通信的方法 &#xff08;1&#xff09;.全局变量&#xff08;要结合同步机制&#xff09; &#xff08;2&#xff09;.信号量 &#xff08;3&#xff09;.P操作 &#xff08;4&#xff09;.V操作 一.线程同步 同步&#xff1a;指的是多个任务按照约定的先后次序相互…

Visual C++ 2010 学习版

这个版本很好用。 在这里放一个链接&#xff0c;做个备份。 这个版本是承前启后的版本&#xff0c;非常的重要。 一、使用VC2010 这个版本创建的解决方案可以在VS2010~VS2022版本中打开&#xff0c;反之也行。 二、使用VC2010 可以编绎VC6.0 ~VC2008的项目。可以使用现成的…

灵办AI助手Chrome插件全面评测:PC Web端的智能办公利器

探索灵办AI助手在Mac OS上的高效表现&#xff0c;支持多款主流浏览器&#xff0c;助你轻松应对办公挑战 文章目录 探索灵办AI助手在Mac OS上的高效表现&#xff0c;支持多款主流浏览器&#xff0c;助你轻松应对办公挑战摘要引言开发环境介绍核心功能评测1. 网页翻译与双语对照 …

Rancher 使用 Minio 备份 Longhorn 数据卷

0. 概述 Longhorn 支持备份到 NFS 或者 S3, 而 MinIO 就是符合 S3 的对象存储服务。通过 docker 部署 minio 服务&#xff0c;然后在 Longhorn UI 中配置备份服务即可。 1. MinIO 部署 1.1 创建备份目录 mkdir -p /home/longhorn-backup/minio/data mkdir -p /home/longhor…