浅尝Apache Mesos

文章目录

    • 1. Mesos是什么
    • 2. 共享集群
    • 3. Apache Mesos
      • 3.1 Mesos主节点
      • 3.2 Mesos代理
      • 3.3 Mesos框架
    • 4. 资源管理
      • 4.1 资源提供
      • 4.2 资源角色
      • 4.3 资源预留
      • 4.4 资源权重与配额
    • 5. 实现框架
      • 5.1 框架主类
      • 5.3 实现执行器
    • 6. 小结
    • 参考

1. Mesos是什么

Mesos是什么,Mesos是一个分布式的系统内核。

Mesos的构建原理与Linux内核相同,只是抽象级别不同。Mesos的内核在每台机器上运行并为应用程序(例如Hadoop、Spark、Kafka、ElasticSearch)提供API跨整个数据中心和云环境的资源管理和调度。

Mesos主要有以下特性:

  1. 线性可扩展
    1. 经过业界验证,可以轻松扩展到数万个节点
  2. 高可用性
    1. 使用Zookeeper实现主服务器和代理服务器容错副本,无中断升级
  3. 容器化
    1. 原生支持使用Docker和AppC镜像启动容器
  4. 可插拔隔离
    1. 对CPU、内存、磁盘、端口、GPU和自定义资源隔离模块的一流隔离支持
  5. 两级调度
    1. 支持使用可插入的调度策略在同一集群中运行云原生和遗留应用程序
  6. 接口
    1. 用于开发新的分布式应用程序、操作集群和监控的HTTP API
  7. Web UI
    1. 内置Web UI,用于查看集群状态和容器沙箱导航
  8. 跨平台
    1. 可在Linux、OSX和Windows上运行,与云服务商无关

我们通常会将各种应用程序部署在同一台机器集群上。而Apache Mesos是一个允许此类程序之间共享资源的平台。

2. 共享集群

许多应用程序需要共享集群,总的来说有两种常见的方法:

  1. 对集群静态分区并在每个分区上运行一个应用程序
  2. 为应用程序分配一组机器

上述方法虽然允许应用程序彼此独立运行,但并不能实现较高的资源利用率:比如某个应用程序只运行了一小段时间,之后处于非活动状态,由于我们为该应用程序分配了静态机器或分区,因此在非活动状态期间,存在未使用的资源。

我们可以通过将非活动状态期间的共享资源重新分配给其他应用程序来优化资源利用率,而Apache Mesos则可以帮助应用程序之间的资源动态分配。

3. Apache Mesos

基于我们上面讨论的两种共享集群的方法,应用程序只知道他们正在运行的特定分区或机器的资源,然而Apache Mesos为应用程序提供了集群中所有资源的抽象视图。

Mesos会充当机器与应用程序之间的接口,为应用程序提供集群中所有机器上的可使用资源,它会经常更新此信息从而获取完成状态的应用程序释放的资源。它允许应用程序做出关于哪台机器上执行哪个任务的最佳决定。

为了理解Mesos的工作原理,我们来看下它的架构:

Mesos架构

上图展示了Mesos的主要组件,Mesos由一个管理运行在每个集群节点上的代理守护进程和主守护进程以及在这些代理上运行任务的Mesos框架组成。

主节点通过提供资源实现跨框架的细粒度资源共享(CPU、RAM等)。每个提供的资源包含一个列表<agent ID, resource1: amount1, resource2: amount2, ...>,主节点根据给定的组织策略(例如公平共享和严格优先级)决定向每个框架提供多少资源。为了支持多样化的策略集,主节点才用模块化架构,可通过插件机制来轻松添加新的分配模块。

在Mesos上运行的框架由两个组件组成:

  1. 向主节点注册以获取资源的调度程序
  2. 在代理节点上启动以运行框架任务的执行程序进程

主节点确定向每个框架提供多少资源,而框架的调度程序则选择使用提供资源中的哪些资源。当框架接受提供的资源时,它会将要在这些资源上运行的任务的描述传递给Mesos,反过来,Mesos会在相应的代理上启动任务。

3.1 Mesos主节点

Master是Mesos中的核心组件,用于存储集群中资源的当前状态,此外,它还通过传递有关资源和任务等信息,从而充当代理和应用程序之间的协调器。

由于主服务器发生任何故障都会导致资源和任务状态丢失,因此我们将其部署在高可用性配置中。如上图所示,Mesos部署了主服务器守护进程和一个Master,这些守护进程依靠Zookeeper在发生故障时恢复状态。

3.2 Mesos代理

Mesos集群必须在每台机器上运行代理,这些代理定期向主节点报告其资源,并依次接收应用程序已经安排运行的任务。在计划任务完成或者丢失后,次循环将重复。

3.3 Mesos框架

Mesos允许应用程序实现一个抽象组件,该组件与Master交互以接收集群中的可用资源,并根据这些资源做出调度决策,这些组件成为框架。

Mesos的框架由两个子组件组成:

  • 调度程序:使应用程序能够根据所有代理上的可用资源来调度任务
  • 执行器:在所有代理上运行,并包含该代理上执行任务计划任务所需的所有信息

框架安排任务运行的示例图:

Mesos框架安排任务运行示意

  1. 代理1向主服务器报告其有4个CPU和4GB的可用内存,主服务器随后调度分配策略模块,告知其应该为框架1提供所有可用资源。
  2. 主服务器向框架1发送资源邀约,描述代理1有哪些可用资源
  3. 框架的调度程序向主服务器回复在代理上运行的两个任务的信息,第一个任务使用<2CPU,1GB RAM>,第二个任务使用<1CPU,2GB RAM>
  4. 最后主服务器将任务发送给代理,代理将适当的额资源分配给框架的执行器,执行器则启动这两个任务(图中虚线所示),由于仍然存在1CPU和1GB RAM未分配,因此分配模块现在可以将它提供给框架2.

此外,当任务完成且新资源变为空闲时,此资源提供过程会重复。

Mesos允许应用程序使用各种编程语言实现自定义调度程序和执行程序。按照Mesos-go中的Scheduler接口的定义如下,具体可参考:Mesos Scheduler interface

// Scheduler a type with callback attributes to be provided by frameworks
// schedulers.
//
// Each callback includes a reference to the scheduler driver that was
// used to run this scheduler. The pointer will not change for the
// duration of a scheduler (i.e., from the point you do
// SchedulerDriver.Start() to the point that SchedulerDriver.Stop()
// returns). This is intended for convenience so that a scheduler
// doesn't need to store a reference to the driver itself.
type Scheduler interface {

	Registered(SchedulerDriver, *mesos.FrameworkID, *mesos.MasterInfo)

	Reregistered(SchedulerDriver, *mesos.MasterInfo)

	Disconnected(SchedulerDriver)

	ResourceOffers(SchedulerDriver, []*mesos.Offer)

	OfferRescinded(SchedulerDriver, *mesos.OfferID)

	StatusUpdate(SchedulerDriver, *mesos.TaskStatus)

	FrameworkMessage(SchedulerDriver, *mesos.ExecutorID, *mesos.SlaveID, string)

	SlaveLost(SchedulerDriver, *mesos.SlaveID)

	ExecutorLost(SchedulerDriver, *mesos.ExecutorID, *mesos.SlaveID, int)

	Error(SchedulerDriver, string)
}

从上述接口的定义可以看出,它主要由各种回调方法组成,主要用于与主机通信。

同样,执行器的实现也需要实现Executor接口,具体可参考:Mesos Executor interface

/**
 * Executor callback interface to be implemented by frameworks' executors. Note
 * that only one callback will be invoked at a time, so it is not
 * recommended that you block within a callback because it may cause a
 * deadlock.
 *
 * Each callback includes an instance to the executor driver that was
 * used to run this executor. The driver will not change for the
 * duration of an executor (i.e., from the point you do
 * ExecutorDriver.Start() to the point that ExecutorDriver.Join()
 * returns). This is intended for convenience so that an executor
 * doesn't need to store a pointer to the driver itself.
 */
type Executor interface {

	Registered(ExecutorDriver, *mesosproto.ExecutorInfo, *mesosproto.FrameworkInfo, *mesosproto.SlaveInfo)

	Reregistered(ExecutorDriver, *mesosproto.SlaveInfo)

	Disconnected(ExecutorDriver)

	LaunchTask(ExecutorDriver, *mesosproto.TaskInfo)

	KillTask(ExecutorDriver, *mesosproto.TaskID)

	FrameworkMessage(ExecutorDriver, string)

	Shutdown(ExecutorDriver)

	Error(ExecutorDriver, string)
}

4. 资源管理

4.1 资源提供

上面说到代理节点会将其资源信息发布给主服务器,反过来主服务器将这些资源提供给集群中运行的框架,此过程成为资源提供。

资源信息一般由两部分组成:

  1. 资源
    1. 资源用于发布代理机器的硬件信息,例如CPU、内存、磁盘等
  2. 属性

每个代理有五种预定义资源:

  • 中央处理器
  • 图形处理器
  • 内存
  • 磁盘
  • 端口

这些资源的值可以用以下三种类型之一来定义:

  • 标量:用浮点数来表示数值信息,以允许小数值,例如1.5G内存
  • 范围:用于表示标量值的范围,例如端口号范围
  • 集合:用于表示多个文本值

默认情况下,Mesos代理会尝试从机器检测这些资源。但在某些情况下我们可以在代理上配置自定义资源,此类自定义资源的值,也应为上述任何一种类型。

例如,我们可以使用以下这些资源启动我们的代理:

--resources='cpus:24;gpus:2;mem:2048;disk:40960;ports:[21000-24000];bugs(debug_role):{a,b,c}'

上面我们为代理配置了一些预定义资源和一个名为bugs集合类型的自定义资源。

除了资源之外,代理还可以向主服务器发布键值属性,这些属性充当代理的附加元数据,并帮助框架进行调度决策。

一个有用的例子是将带来添加到不同的机架或者区域,然后在同一个机架或者区域上安排各种任务以实现数据本地化

--attributes='rack:abc;zone:sg;os:centos5;level:10;keys:[1000-1500]'

与资源类似,属性的值可以是标量、范围或者文本类型。

4.2 资源角色

现代操作系统许多都支持多用户,同样,Mesos也支持同一个集群中的多个用户,这些用户被称为角色。我们可以将每个决策视为集群中的资源消费者。

由此,Mesos代理可以基于不同的分配策略对不同角色下的资源进行划分,而框架可以在集群内订阅这些角色,从而实现对不同角色下的资源进行细粒度的控制。

例如,假设有一个集群托管应用程序,为组织中不同用户提供服务,因此,通过将资源划分成角色,每个应用程序都可以彼此独立地工作。

此外,框架可以使用这些角色来实现数据局部性。

例如,假设集群中有两个应用程序,分别为生产者和消费者,其中生产者将数据写入持久卷,消费者随后可以读取该卷,我们可以通过生产者共享该卷来优化消费者应用程序。

由于Mesos允许多个应用程序订阅同一角色,我们可以将持久卷与资源角色关联起来,此外,生产者和消费者的框架都将订阅相同的资源角色,因此消费者应用程序现在可以在与生产者应用程序相同的卷上启动数据读取任务。

4.3 资源预留

Mesos如何将集群资源分配给不同的角色,Mesos通过预留来实现资源分配。

预留类型有两种:

  • 静态预留
  • 动态预留

静态预留则是在代理启动时的资源分配:

–resources=“cpus:4;mem:2048;cpus(test_abc):8;mem(test_abc):4096”

与静态预留不同,动态预留允许我们重新调整角色内的资源,Mesos允许框架和集群操作员通过框架消息(作为对资源提供的响应)或者通过HTTP API调用动态更改资源分配。

Mesos将所有不具有任何角色的资源分配给名为(*)的默认角色,Master主服务器向所有框架提供此类资源,无论它们是否订阅了该资源。

4.4 资源权重与配额

Mesos主节点一般使用公平策略来提供资源,它使用加权主导资源公平性来识别缺少资源的角色,然后主服务器向已订阅这些角色的框架提供更多资源。

尽管在应用程序之间公平共享资源是Mesos的一个重要特性,但这并非是必要的。假设一个集群托管着资源占用低的应用程序和资源需求高的应用程序。在样的部署中,我们希望根据应用程序的性质分配资源。

Mesos允许框架通过订阅角色并为该角色添加更高的权重来请求更多资源。因此,如果有两个角色,一个权重为1,另一个为2,则Mesos会为第二个角色分配两倍的公平份额资源。

另外,我们还可以通过HTTP接口调用来配置权重,可参考:Mesos Weights Set by HTTP API

除了确保为具有权重的角色公平分配资源之外,Mesos还确保为角色分配最少的资源。

Mesos允许我们为资源角色添加配额,配额可以指定角色保证接收到的最小资源量。

5. 实现框架

Mesos允许应用程序选择任意语言提供框架实现,即实现Scheduler和Executor的接口从而实现框架。

5.1 框架主类

在实现调度程序和执行程序之前,需要先实现框架的入口点:

  • 向master注册
  • 向代理执行器提供运行时信息
  • 启动调度程序

下面程序来自Mesos官方提供的示例,具体可参考:Mesos Framework Python test examples

import os
import sys
import time

import mesos.interface
from mesos.interface import mesos_pb2
from mesos.scheduler import MesosSchedulerDriver

TOTAL_TASKS = 5

TASK_CPUS = 1
TASK_MEM = 128

class TestScheduler(mesos.interface.Scheduler):
    def __init__(self, implicitAcknowledgements, executor, framework):
        self.implicitAcknowledgements = implicitAcknowledgements
        self.executor = executor
        self.framework = framework
        self.taskData = {}
        self.tasksLaunched = 0
        self.tasksFinished = 0
        self.messagesSent = 0
        self.messagesReceived = 0
		# 注册
    def registered(self, driver, frameworkId, masterInfo):
        print "Registered with framework ID %s" % frameworkId.value
        self.framework.id.CopyFrom(frameworkId)
        driver.updateFramework(framework, [])

    def resourceOffers(self, driver, offers):# 资源申请
        for offer in offers:
            tasks = []
            offerCpus = 0
            offerMem = 0
            for resource in offer.resources:
                if resource.name == "cpus":
                    offerCpus += resource.scalar.value
                elif resource.name == "mem":
                    offerMem += resource.scalar.value

            print "Received offer %s with cpus: %s and mem: %s" \
                  % (offer.id.value, offerCpus, offerMem)

            remainingCpus = offerCpus
            remainingMem = offerMem

            while self.tasksLaunched < TOTAL_TASKS and \
                  remainingCpus >= TASK_CPUS and \
                  remainingMem >= TASK_MEM:
                tid = self.tasksLaunched
                self.tasksLaunched += 1

                print "Launching task %d using offer %s" \
                      % (tid, offer.id.value)

                task = mesos_pb2.TaskInfo()
                task.task_id.value = str(tid)
                task.slave_id.value = offer.slave_id.value
                task.name = "task %d" % tid
                task.executor.MergeFrom(self.executor)

                cpus = task.resources.add()
                cpus.name = "cpus"
                cpus.type = mesos_pb2.Value.SCALAR
                cpus.scalar.value = TASK_CPUS # CPU资源

                mem = task.resources.add()
                mem.name = "mem"
                mem.type = mesos_pb2.Value.SCALAR
                mem.scalar.value = TASK_MEM # 内存资源

                tasks.append(task)
                self.taskData[task.task_id.value] = (
                    offer.slave_id, task.executor.executor_id)

                remainingCpus -= TASK_CPUS
                remainingMem -= TASK_MEM

            operation = mesos_pb2.Offer.Operation()
            operation.type = mesos_pb2.Offer.Operation.LAUNCH
            operation.launch.task_infos.extend(tasks)

            driver.acceptOffers([offer.id], [operation])

    def statusUpdate(self, driver, update):# 状态更新
        print "Task %s is in state %s" % \
            (update.task_id.value, mesos_pb2.TaskState.Name(update.state))

        # Ensure the binary data came through.
        if update.data != "data with a \0 byte":
            print "The update data did not match!"
            print "  Expected: 'data with a \\x00 byte'"
            print "  Actual:  ", repr(str(update.data))
            sys.exit(1)

        if update.state == mesos_pb2.TASK_FINISHED:
            self.tasksFinished += 1
            if self.tasksFinished == TOTAL_TASKS:
                print "All tasks done, waiting for final framework message"

            slave_id, executor_id = self.taskData[update.task_id.value]

            self.messagesSent += 1
            driver.sendFrameworkMessage(
                executor_id,
                slave_id,
                'data with a \0 byte')

        if update.state == mesos_pb2.TASK_LOST or \
           update.state == mesos_pb2.TASK_KILLED or \
           update.state == mesos_pb2.TASK_FAILED:
            print "Aborting because task %s is in unexpected state %s with message '%s'" \
                % (update.task_id.value, mesos_pb2.TaskState.Name(update.state), update.message)
            driver.abort()

        # Explicitly acknowledge the update if implicit acknowledgements
        # are not being used.
        if not self.implicitAcknowledgements:
            driver.acknowledgeStatusUpdate(update)
		# 框架消息处理
    def frameworkMessage(self, driver, executorId, slaveId, message):
        self.messagesReceived += 1

        # The message bounced back as expected.
        if message != "data with a \0 byte":
            print "The returned message data did not match!"
            print "  Expected: 'data with a \\x00 byte'"
            print "  Actual:  ", repr(str(message))
            sys.exit(1)
        print "Received message:", repr(str(message))

        if self.messagesReceived == TOTAL_TASKS:
            if self.messagesReceived != self.messagesSent:
                print "Sent", self.messagesSent,
                print "but received", self.messagesReceived
                sys.exit(1)
            print "All tasks done, and all messages received, exiting"
            driver.stop()

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print "Usage: %s master" % sys.argv[0]
        sys.exit(1)

    executor = mesos_pb2.ExecutorInfo()
    executor.executor_id.value = "default"
    executor.command.value = os.path.abspath("./test-executor")
    executor.name = "Test Executor (Python)"
    executor.source = "python_test"

    framework = mesos_pb2.FrameworkInfo()
    framework.user = "" # Have Mesos fill in the current user.
    framework.name = "Test Framework (Python)"
    framework.checkpoint = True
    framework.role = "*"

    implicitAcknowledgements = 1
    if os.getenv("MESOS_EXPLICIT_ACKNOWLEDGEMENTS"):
        print "Enabling explicit status update acknowledgements"
        implicitAcknowledgements = 0

    if os.getenv("MESOS_EXAMPLE_AUTHENTICATE"):
        print "Enabling authentication for the framework"

        if not os.getenv("MESOS_EXAMPLE_PRINCIPAL"):
            print "Expecting authentication principal in the environment"
            sys.exit(1);

        credential = mesos_pb2.Credential()
        credential.principal = os.getenv("MESOS_EXAMPLE_PRINCIPAL")

        if os.getenv("MESOS_EXAMPLE_SECRET"):
            credential.secret = os.getenv("MESOS_EXAMPLE_SECRET")

        framework.principal = os.getenv("MESOS_EXAMPLE_PRINCIPAL")

    else:
        framework.principal = "test-framework-python"
        credential = None

    # Subscribe with all roles suppressed to test updateFramework() method
    driver = MesosSchedulerDriver(
        TestScheduler(implicitAcknowledgements, executor, framework),
        framework,
        sys.argv[1],
        implicitAcknowledgements,
        credential,
        [framework.role])

    status = 0 if driver.run() == mesos_pb2.DRIVER_STOPPED else 1

    # Ensure that the driver process terminates.
    driver.stop();

    sys.exit(status)

调度程序可能会由于缺乏资源而无法再代理上启动任务,则会被拒绝,就是上面的DRIVER_STOPPED。

5.3 实现执行器

框架的执行器组件负责在Mesos代理上执行应用程序服务。

import sys
import threading
import time

import mesos.interface
from mesos.interface import mesos_pb2
from mesos.executor import MesosExecutorDriver

class MyExecutor(mesos.interface.Executor):
    def launchTask(self, driver, task):
        # Create a thread to run the task. Tasks should always be run in new
        # threads or processes, rather than inside launchTask itself.
        def run_task():
            print "Running task %s" % task.task_id.value
            update = mesos_pb2.TaskStatus()
            update.task_id.value = task.task_id.value
            update.state = mesos_pb2.TASK_RUNNING
            update.data = 'data with a \0 byte'
            driver.sendStatusUpdate(update)

            # This is where one would perform the requested task.

            print "Sending status update..."
            update = mesos_pb2.TaskStatus()
            update.task_id.value = task.task_id.value
            update.state = mesos_pb2.TASK_FINISHED
            update.data = 'data with a \0 byte'
            driver.sendStatusUpdate(update)
            print "Sent status update"

        thread = threading.Thread(target=run_task)
        thread.start()

    def frameworkMessage(self, driver, message):
        # Send it back to the scheduler.
        driver.sendFrameworkMessage(message)

if __name__ == "__main__":
    print "Starting executor"
    driver = MesosExecutorDriver(MyExecutor())
    sys.exit(0 if driver.run() == mesos_pb2.DRIVER_STOPPED else 1)

执行器的代码比较简单,主要是定义了task执行的逻辑以及对应将数据发回调度器的逻辑。

6. 小结

因为在工作中看到有对应的Mesos字眼,虽然自己不会去直接接触这个东西(大多都是通过包装好的组件间接使用),但了解一下运行原理对自己理解一些组件会有一些帮助。

主要是学习了一下Mesos的基本原理和统一集群中运行的应用程序之间的资源共享,以及Mesos是如何通过集群资源(CPU和内存等)帮助应用程序实现资源最大利用。

里面还有涉及到关于Mesos的资源的公平分配策略以及订阅角色的应用程序之间的资源动态分配,Mesos允许应用程序根据集群中的Mesos代理提供的资源做出调度决策,同时Mesos提供了大量HTTP API可用于接口调用进行资源的权重和配额修改。

另外关于Mesos的具体实践还需要继续学习,这次只是在虚拟机大致跑了一下测试用例,并没有采用手动编写程序的方式来进行具体实践。

参考

  • Mesos Architecture
  • mesos-go
  • Apache Mesos

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

8、Redis 的线程模型、I/O 模型和多线程

Redis 的线程模型、I/O 模型和多线程 1. Redis 的线程模型 Redis 以其高效的单线程模型著称&#xff0c;从设计之初&#xff0c;Redis 就选择了单线程模式&#xff0c;这在很大程度上简化了其内部实现和维护。单线程模式避免了多线程编程中常见的竞争条件和锁机制问题&#x…

【WebRTC实现点对点视频通话】

介绍 WebRTC (Web Real-Time Communications) 是一个实时通讯技术&#xff0c;也是实时音视频技术的标准和框架。简单来说WebRTC是一个集大成的实时音视频技术集&#xff0c;包含了各种客户端api、音视频编/解码lib、流媒体传输协议、回声消除、安全传输等。对于开发者来说可以…

【云原生】Prometheus监控Docker指标并接入Grafana

目录 一、前言 二、docker监控概述 2.1 docker常用监控指标 2.2 docker常用监控工具 三、CAdvisor概述 3.1 CAdvisor是什么 3.2 CAdvisor功能特点 3.3 CAdvisor使用场景 四、CAdvisor对接Prometheus与Grafana 4.1 环境准备 4.2 docker部署CAdvisor 4.2.2 docker部署…

汉诺塔与青蛙跳台阶

1.汉诺塔 根据汉诺塔 - 维基百科 介绍 1.1 背景 最早发明这个问题的人是法国数学家爱德华卢卡斯。 传说越南河内某间寺院有三根银棒&#xff0c;上串 64 个金盘。寺院里的僧侣依照一个古老的预言&#xff0c;以上述规则移动这些盘子&#xff1b;预言说当这些盘子移动完毕&am…

Java项目:基于SSM框架实现的共享客栈管理系统分前后台【ssm+B/S架构+源码+数据库+毕业论文】

一、项目简介 本项目是一套基于SSM框架实现的共享客栈管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能…

网页生成二维码、在线演示

https://andi.cn/page/621504.html

go语言day11 错误 defer(),panic(),recover()

错误&#xff1a; 创建错误 1&#xff09;fmt包下提供的方法 fmt.Errorf(" 格式化字符串信息 " &#xff0c; 空接口类型对象 ) 2&#xff09;errors包下提供的方法 errors.New(" 字符串信息 ") 创建自定义错误 需要实现error接口&#xff0c;而error接口…

【JAVA多线程】线程池概论

目录 1.概述 2.ThreadPoolExector 2.1.参数 2.2.新任务提交流程 2.3.拒绝策略 2.4.代码示例 1.概述 线程池的核心&#xff1a; 线程池的实现原理是个标准的生产消费者模型&#xff0c;调用方不停向线程池中写数据&#xff0c;线程池中的线程组不停从队列中取任务。 实现…

“未来已来·智能共融”高峰论坛在京成功举办

在人工智能技术的澎湃浪潮中,其与传统产业的深度融合正逐步成为驱动区域经济增长的新引擎。2024年7月4号,一场以“未来已来智能共融——探索人类智能与人工智能共生共进的新路径”为主题的高峰论坛在北京电子科技职业学院图书馆圆满落幕,为北京经济技术开发区(简称“北京经开区…

时间处理的未来:Java 8全新日期与时间API完全解析

文章目录 一、改进背景二、本地日期时间三、时区日期时间四、格式化 一、改进背景 Java 8针对时间处理进行了全面的改进&#xff0c;重新设计了所有日期时间、日历及时区相关的 API。并把它们都统一放置在 java.time 包和子包下。 Java5的不足之处&#xff1a; 非线程安全&…

JAVA 课设 满汉楼餐厅点餐系统

一、代码详解 1.总体结构展示 2.总体代码 2.1 libs文件 链接&#xff1a;https://pan.baidu.com/s/1nH-I7gIlsqyMpXDDCFRuOA 提取码&#xff1a;3404 2.2 配置的德鲁连接池 #keyvalue driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/mhl?rewriteBa…

SAP_MM模块-特殊业务场景下的系统实现方案

一、业务背景 目前公司有一种电商业务&#xff0c;卖的是备品配件&#xff0c;是公司先跟供应商采购&#xff0c;然后再销售给客户&#xff0c;系统账就是按照正常业务来流转&#xff0c;公司进行采购订单入库&#xff0c;然后销售订单出库。 不过这种备品配件&#xff0c;实…

Android使用http加载自建服务器静态网页

最终效果如下图&#xff0c;成功加载了电脑端的静态网页内容&#xff0c;这是一个xml文件。 电脑端搭建http服务器 使用“Apache Http Server”&#xff0c;下载地址是&#xff1a;https://httpd.apache.org/download.cgi。具体操作步骤&#xff0c;参考&#xff1a;Apache …

卫星IoT产品发展前景

卫星IoT产品发展前景 一、概述 卫星IoT产品是指利用卫星通信技术实现物联网设备互联互通的解决方案。随着卫星互联网技术的快速发展&#xff0c;卫星IoT产品正逐渐成为解决偏远地区、海洋、航空等场景下物联网连接问题的重要手段。 二、性能特点 广泛覆盖&#xff1a; 卫星…

ssrf结合redis未授权getshell

目录 漏洞介绍 SSRF Redis未授权 利用原理 环境搭建 利用过程 rockylinux cron计划任务反弹shell 写公钥免密登录 ubuntu 写公钥免密登录 漏洞介绍 SSRF SSRF&#xff08;server side request forgrey&#xff09;服务端请求伪造&#xff0c;因后端未过滤用户输入&…

SpringBoot实现多数据源切换

1. 概述 仓库地址&#xff1a;https://gitee.com/aopmin/multi-datasource-demo 随着项目规模的扩大和业务需求的复杂化&#xff0c;单一数据源已经不能满足实际开发中的需求。在许多情况下&#xff0c;我们需要同时操作多个数据库&#xff0c;或者需要将不同类型的数据存储在不…

陶建辉当选 GDOS 全球数据库及开源峰会荣誉顾问

近日&#xff0c;第二十三届 GOPS 全球运维大会暨 XOps 技术创新峰会在北京正式召开。本次会议重点议题方向包括开源数据库落地思考、金融数据库自主可控、云原生时代下数据库、数据库智能运维、数据库安全与隐私、开源数据库与治理。大会深入探讨这些方向&#xff0c;促进了数…

Matplotlib 学习

知识点 1.plot()&#xff1a;用于绘制线图和 散点图scatter() 函数&#xff1a;plot() 函数可以接受许多可选参数&#xff0c;用于控制图形的外观&#xff0c;例如&#xff1a;颜色: colorblue 控制线条的颜色。线型: linestyle-- 控制线条的样式&#xff0c;例如虚线。标记…

前端vue后端java使用easyexcel框架下载表格xls数据工具类

一 使用alibaba开源的 easyexcel框架&#xff0c;后台只需一个工具类即可实现下载 后端下载实现 依赖 pom.xml <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependen…

昇思25天学习打卡营第12天|FCN图像语义分割

文章目录 昇思MindSpore应用实践基于MindSpore的FCN图像语义分割1、FCN 图像分割简介2、构建 FCN 模型3、数据预处理4、模型训练自定义评价指标 Metrics 5、模型推理结果 Reference 昇思MindSpore应用实践 本系列文章主要用于记录昇思25天学习打卡营的学习心得。 基于MindSpo…