主頁 > 軟體設計 > 萬字長文決議洗掉Topic流程領導再也不用擔心我排查生產環境問題了(附教學視頻,建議收藏!!!)

萬字長文決議洗掉Topic流程領導再也不用擔心我排查生產環境問題了(附教學視頻,建議收藏!!!)

2021-08-17 08:09:13 軟體設計

在這里插入圖片描述

<iframe id="MML0JRvM-1629033499373" src="https://player.bilibili.com/player.html?aid=504831801" allowfullscreen="true" data-mediaembed="bilibili"></iframe>

【原始碼】Topic洗掉流程分析+常見問題

日常運維問題排查 怎么能夠少了滴滴開源的
滴滴開源LogiKM一站式Kafka監控與管控平臺

文章目錄

    • 洗掉Topic命令
    • 相關配置
    • 原始碼決議
      • 1. 客戶端發起洗掉Topic的請求
      • 2. Controller處理deleteTopics的請求
      • 3. Controller監聽zk變更 執行洗掉Topic流程
        • 3.1 resumeDeletions 執行洗掉方法
        • 3.2 TopicDeletionManager.onPartitionDeletion
      • 4. Brokers 接受StopReplica請求
        • 4.1 日志清理定時執行緒
      • 5.StopReplica 請求成功 執行回呼介面
      • 6. Controller啟動時候 嘗試繼續處理待洗掉的Topic
        • 6.1 獲取需要被洗掉的Topic和暫時不能洗掉的Topic
        • 6.2 topicDeletionManager.init初始化洗掉管理器
        • 6.3 topicDeletionManager.tryTopicDeletion嘗試恢復洗掉
    • 原始碼總結
    • Q&A
      • 什么時候在/admin/delete_topics寫入節點的
      • 什么時候真正執行洗掉Topic磁盤日志
      • 為什么正在重新分配的Topic不能被洗掉
      • 如果在`/admin/delete_topics/`中手動寫入一個節點會不會正常洗掉
      • 如果直接洗掉ZK上的`/brokers/topics/{topicName}`節點會怎樣
      • Controller通知Brokers 執行StopReplica是通知所有的Broker還是只通知跟被洗掉Topic有關聯的Broker?
      • 洗掉程序有Broker不在線 或者執行失敗怎么辦
      • ReplicaStateMachine 副本狀態機
      • 在重新分配的程序中,如果執行洗掉操作會怎么樣

洗掉Topic命令

bin/kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic test

支持正則運算式匹配Topic來進行洗掉,只需要將topic 用雙引號包裹起來
例如: 洗掉以create_topic_byhand_zk為開頭的topic;

bin/kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic “create_topic_byhand_zk.*”
.表示任意匹配除換行符 \n 之外的任何單字符,要匹配 . ,請使用 . ,
·*·:匹配前面的子運算式零次或多次,要匹配 * 字符,請使用 *,
.* : 任意字符

洗掉任意Topic (慎用)

bin/kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic “.*?”

更多的用法請參考正則運算式

相關配置

配置描述默認
file.delete.delay.mstopic洗掉被標記為–delete檔案之后延遲多長時間洗掉正在的Log檔案60000
delete.topic.enable是否能夠洗掉topictrue

原始碼決議

如果覺得閱讀原始碼決議太枯燥,請直接看 原始碼總結及其后面部分

1. 客戶端發起洗掉Topic的請求

在【kafka原始碼】TopicCommand之創建Topic原始碼決議 里面已經分析過了整個請求流程; 所以這里就不再詳細的分析請求的程序了,直接看重點;
在這里插入圖片描述
向Controller發起 deleteTopics請求

2. Controller處理deleteTopics的請求

KafkaApis.handle
AdminManager.deleteTopics

  /**
    * Delete topics and wait until the topics have been completely deleted.
    * The callback function will be triggered either when timeout, error or the topics are deleted.
    */
  def deleteTopics(timeout: Int,
                   topics: Set[String],
                   responseCallback: Map[String, Errors] => Unit): Unit = {

    // 1. map over topics calling the asynchronous delete
    val metadata = topics.map { topic =>
        try {
          // zk中寫入資料 標記要被洗掉的topic /admin/delete_topics/Topic名稱
          adminZkClient.deleteTopic(topic)
          DeleteTopicMetadata(topic, Errors.NONE)
        } catch {
          case _: TopicAlreadyMarkedForDeletionException =>
            // swallow the exception, and still track deletion allowing multiple calls to wait for deletion
            DeleteTopicMetadata(topic, Errors.NONE)
          case e: Throwable =>
            error(s"Error processing delete topic request for topic $topic", e)
            DeleteTopicMetadata(topic, Errors.forException(e))
        }
    }

    // 2. 如果客戶端傳過來的timeout<=0或者 寫入zk資料程序例外了 則執行下面的,直接回傳例外
    if (timeout <= 0 || !metadata.exists(_.error == Errors.NONE)) {
      val results = metadata.map { deleteTopicMetadata =>
        // ignore topics that already have errors
        if (deleteTopicMetadata.error == Errors.NONE) {
          (deleteTopicMetadata.topic, Errors.REQUEST_TIMED_OUT)
        } else {
          (deleteTopicMetadata.topic, deleteTopicMetadata.error)
        }
      }.toMap
      responseCallback(results)
    } else {
      // 3. else pass the topics and errors to the delayed operation and set the keys
      val delayedDelete = new DelayedDeleteTopics(timeout, metadata.toSeq, this, responseCallback)
      val delayedDeleteKeys = topics.map(new TopicKey(_)).toSeq
      // try to complete the request immediately, otherwise put it into the purgatory
      topicPurgatory.tryCompleteElseWatch(delayedDelete, delayedDeleteKeys)
    }
  }

  1. zk中寫入資料topic/admin/delete_topics/Topic名稱; 標記要被洗掉的Topic
  2. 如果客戶端傳過來的timeout<=0或者 寫入zk資料程序例外了 則直接回傳例外

3. Controller監聽zk變更 執行洗掉Topic流程

KafkaController.processTopicDeletion

  private def processTopicDeletion(): Unit = {
    if (!isActive) return
    var topicsToBeDeleted = zkClient.getTopicDeletions.toSet
    val nonExistentTopics = topicsToBeDeleted -- controllerContext.allTopics
    if (nonExistentTopics.nonEmpty) {
      warn(s"Ignoring request to delete non-existing topics ${nonExistentTopics.mkString(",")}")
      zkClient.deleteTopicDeletions(nonExistentTopics.toSeq, controllerContext.epochZkVersion)
    }
    topicsToBeDeleted --= nonExistentTopics
    if (config.deleteTopicEnable) {
      if (topicsToBeDeleted.nonEmpty) {
        info(s"Starting topic deletion for topics ${topicsToBeDeleted.mkString(",")}")
        // 標記暫時不可洗掉的Topic
        topicsToBeDeleted.foreach { topic =>
          val partitionReassignmentInProgress =
            controllerContext.partitionsBeingReassigned.map(_.topic).contains(topic)
          if (partitionReassignmentInProgress)
            topicDeletionManager.markTopicIneligibleForDeletion(Set(topic),
              reason = "topic reassignment in progress")
        }
        // add topic to deletion list
        topicDeletionManager.enqueueTopicsForDeletion(topicsToBeDeleted)
      }
    } else {
      // If delete topic is disabled remove entries under zookeeper path : /admin/delete_topics
      info(s"Removing $topicsToBeDeleted since delete topic is disabled")
      zkClient.deleteTopicDeletions(topicsToBeDeleted.toSeq, controllerContext.epochZkVersion)
    }
  }

  1. 如果/admin/delete_topics/下面的節點有不存在的Topic,則清理掉
  2. 如果配置了delete.topic.enable=false不可洗掉Topic的話,則將/admin/delete_topics/下面的節點全部洗掉,然后流程結束
  3. delete.topic.enable=true; 將主題標記為不符合洗掉條件,放到topicsIneligibleForDeletion中; 不符合洗掉條件的是:Topic磁區正在進行磁區重分配
  4. 將Topic添加到洗掉Topic串列topicsToBeDeleted中;
  5. 然后呼叫TopicDeletionManager.resumeDeletions()方法執行洗掉操作

3.1 resumeDeletions 執行洗掉方法

TopicDeletionManager.resumeDeletions()

  private def resumeDeletions(): Unit = {
    val topicsQueuedForDeletion = Set.empty[String] ++ controllerContext.topicsToBeDeleted
    val topicsEligibleForRetry = mutable.Set.empty[String]
    val topicsEligibleForDeletion = mutable.Set.empty[String]

    if (topicsQueuedForDeletion.nonEmpty)
    topicsQueuedForDeletion.foreach { topic =>
      // if all replicas are marked as deleted successfully, then topic deletion is done
      //如果所有副本都被標記為洗掉成功了,然后執行洗掉Topic成功操作; 
      if (controllerContext.areAllReplicasInState(topic, ReplicaDeletionSuccessful)) {
        // clear up all state for this topic from controller cache and zookeeper
        //執行洗掉Topic成功之后的操作; 
        completeDeleteTopic(topic)
        info(s"Deletion of topic $topic successfully completed")
      } else if (!controllerContext.isAnyReplicaInState(topic, ReplicaDeletionStarted)) {
        // if you come here, then no replica is in TopicDeletionStarted and all replicas are not in
        // TopicDeletionSuccessful. That means, that either given topic haven't initiated deletion
        // or there is at least one failed replica (which means topic deletion should be retried).
        if (controllerContext.isAnyReplicaInState(topic, ReplicaDeletionIneligible)) {
          topicsEligibleForRetry += topic
        }
      }

      // Add topic to the eligible set if it is eligible for deletion.
      if (isTopicEligibleForDeletion(topic)) {
        info(s"Deletion of topic $topic (re)started")
        topicsEligibleForDeletion += topic
      }
    }

    // topic deletion retry will be kicked off
    if (topicsEligibleForRetry.nonEmpty) {
      retryDeletionForIneligibleReplicas(topicsEligibleForRetry)
    }

    // topic deletion will be kicked off
    if (topicsEligibleForDeletion.nonEmpty) {
      //洗掉Topic,發送UpdataMetaData請求
      onTopicDeletion(topicsEligibleForDeletion)
    }
  }
}
  1. 重點看看onTopicDeletion方法,標記所有待洗掉磁區;向Brokers發送updateMetadataRequest請求,告知Brokers這個主題正在被洗掉,并將Leader設定為LeaderAndIsrLeaderDuringDelete

    1. 將待洗掉的Topic的所有磁區,執行磁區狀態機的轉換 ;當前狀態–>OfflinePartition->NonExistentPartition ; 這兩個狀態轉換只是在當前Controller記憶體中更新了一下狀態; 關于狀態機請看 【kafka原始碼】Controller中的狀態機TODO…;
    2. client.sendMetadataUpdate(topics.flatMap(controllerContext.partitionsForTopic)) 向待洗掉Topic磁區發送UpdateMetadata請求; 這個時候更新了什么資料呢? 在這里插入圖片描述
      看上面圖片原始碼, 發送UpdateMetadata請求的時候把磁區的Leader= -2; 表示這個磁區正在被洗掉;那么所有正在被洗掉的磁區就被找到了;拿到這些待洗掉磁區之后干嘛呢?
      1. 更新一下限流相關資訊
      2. 呼叫groupCoordinator.handleDeletedPartitions(deletedPartitions): 清除給定的deletedPartitions的組偏移量以及執行偏移量洗掉的函式;就是現在該磁區不能提供服務啦,不能被消費啦

    詳細請看 Kafka的元資料更新UpdateMetadata

    1. 呼叫TopicDeletionManager.onPartitionDeletion介面如下;

3.2 TopicDeletionManager.onPartitionDeletion

  1. 將所有Dead replicas 副本直接移動到ReplicaDeletionIneligible狀態,如果某些副本已死,也將相應的主題標記為不適合洗掉,因為它無論如何都不會成功完成
  2. 副本狀態轉換成OfflineReplica; 這個時候會對該Topic的所有副本所在Broker發起StopReplicaRequest 請求;(引數deletePartitions = false,表示還不執行洗掉操作); 以便他們停止向Leader發送fetch請求; 關于狀態機請看 【kafka原始碼】Controller中的狀態機TODO…;
  3. 副本狀態轉換成 ReplicaDeletionStarted狀態,這個時候會對該Topic的所有副本所在Broker發起StopReplicaRequest 請求;(引數deletePartitions = true,表示執行洗掉操作),這將發送帶有 deletePartition=true 的 StopReplicaRequest ,并將洗掉相應磁區的所有副本中的所有持久資料

4. Brokers 接受StopReplica請求

最終呼叫的是介面
ReplicaManager.stopReplica ==> LogManager.asyncDelete

將給定主題磁區“logdir”的目錄重命名為“logdir.uuid.delete”,并將其添加到洗掉佇列中
例如 :
在這里插入圖片描述

def asyncDelete(topicPartition: TopicPartition, isFuture: Boolean = false): Log = {
    val removedLog: Log = logCreationOrDeletionLock synchronized {
      //將待洗掉的partition在 Logs中洗掉掉
      if (isFuture)
        futureLogs.remove(topicPartition)
      else
        currentLogs.remove(topicPartition)
    }
    if (removedLog != null) {
      //我們需要等到要洗掉的日志上沒有更多的清理任務,然后才能真正洗掉它,
      if (cleaner != null && !isFuture) {
        cleaner.abortCleaning(topicPartition)
        cleaner.updateCheckpoints(removedLog.dir.getParentFile)
      }
      //重命名topic副本檔案夾 命名規則 topic-uuid-delete
      removedLog.renameDir(Log.logDeleteDirName(topicPartition))
      checkpointRecoveryOffsetsAndCleanSnapshot(removedLog.dir.getParentFile, ArrayBuffer.empty)
      checkpointLogStartOffsetsInDir(removedLog.dir.getParentFile)
      //將Log添加到待洗掉Log佇列中,等待洗掉
      addLogToBeDeleted(removedLog)

    } else if (offlineLogDirs.nonEmpty) {
      throw new KafkaStorageException(s"Failed to delete log for ${if (isFuture) "future" else ""} $topicPartition because it may be in one of the offline directories ${offlineLogDirs.mkString(",")}")
    }
    removedLog
  }

4.1 日志清理定時執行緒

上面我們知道最終是將待洗掉的Log添加到了logsToBeDeleted這個佇列中; 這個佇列就是待洗掉Log佇列,有一個執行緒 kafka-delete-logs專門來處理的;我們來看看這個執行緒怎么作業的

LogManager.startup 啟動的時候 ,啟動了一個定時執行緒

   scheduler.schedule("kafka-delete-logs", // will be rescheduled after each delete logs with a dynamic period
                         deleteLogs _,
                         delay = InitialTaskDelayMs,
                         unit = TimeUnit.MILLISECONDS)

洗掉日志的執行緒

  /**
   *  Delete logs marked for deletion. Delete all logs for which `currentDefaultConfig.fileDeleteDelayMs`
   *  has elapsed after the delete was scheduled. Logs for which this interval has not yet elapsed will be
   *  considered for deletion in the next iteration of `deleteLogs`. The next iteration will be executed
   *  after the remaining time for the first log that is not deleted. If there are no more `logsToBeDeleted`,
   *  `deleteLogs` will be executed after `currentDefaultConfig.fileDeleteDelayMs`.
   * 洗掉標記為洗掉的日志檔案;
   * file.delete.delay.ms 檔案延遲洗掉時間 默認60000毫秒
   * 
   */
  private def deleteLogs(): Unit = {
    var nextDelayMs = 0L
    try {
      def nextDeleteDelayMs: Long = {
        if (!logsToBeDeleted.isEmpty) {
          val (_, scheduleTimeMs) = logsToBeDeleted.peek()
          scheduleTimeMs + currentDefaultConfig.fileDeleteDelayMs - time.milliseconds()
        } else
          currentDefaultConfig.fileDeleteDelayMs
      }

      while ({nextDelayMs = nextDeleteDelayMs; nextDelayMs <= 0}) {
        val (removedLog, _) = logsToBeDeleted.take()
        if (removedLog != null) {
          try {
            //立即徹底洗掉此日志目錄和檔案系統中的所有內容
            removedLog.delete()
            info(s"Deleted log for partition ${removedLog.topicPartition} in ${removedLog.dir.getAbsolutePath}.")
          } catch {
            case e: KafkaStorageException =>
              error(s"Exception while deleting $removedLog in dir ${removedLog.dir.getParent}.", e)
          }
        }
      }
    } catch {
      case e: Throwable =>
        error(s"Exception in kafka-delete-logs thread.", e)
    } finally {
      try {
        scheduler.schedule("kafka-delete-logs",
          deleteLogs _,
          delay = nextDelayMs,
          unit = TimeUnit.MILLISECONDS)
      } catch {
        case e: Throwable =>
          if (scheduler.isStarted) {
            // No errors should occur unless scheduler has been shutdown
            error(s"Failed to schedule next delete in kafka-delete-logs thread", e)
          }
      }
    }
  }

file.delete.delay.ms 決定延遲多久洗掉

5.StopReplica 請求成功 執行回呼介面

Topic洗掉完成, 清理相關資訊
觸發這個介面的地方是: 每個Broker執行洗掉StopReplica成功之后,都會執行一個回呼函式;TopicDeletionStopReplicaResponseReceived ; 當然呼叫方是Controller,回呼到的也就是Controller;

傳入回呼函式的地方
在這里插入圖片描述

執行回呼函式 KafkaController.processTopicDeletionStopReplicaResponseReceived

  1. 如果回呼有例外,洗掉失敗則將副本狀態轉換成==》ReplicaDeletionIneligible,并且重新執行resumeDeletions方法;

  2. 如果回呼正常,則變更狀態 ReplicaDeletionStarted==》ReplicaDeletionSuccessful;并且重新執行resumeDeletions方法;

  3. resumeDeletions方法會判斷所有副本是否均被洗掉,如果全部洗掉了就會執行下面的completeDeleteTopic代碼;否則會繼續洗掉未被成功洗掉的副本

      private def completeDeleteTopic(topic: String): Unit = {
        // deregister partition change listener on the deleted topic. This is to prevent the partition change listener
        // firing before the new topic listener when a deleted topic gets auto created
        client.mutePartitionModifications(topic)
        val replicasForDeletedTopic = controllerContext.replicasInState(topic, ReplicaDeletionSuccessful)
        // controller will remove this replica from the state machine as well as its partition assignment cache
        replicaStateMachine.handleStateChanges(replicasForDeletedTopic.toSeq, NonExistentReplica)
        controllerContext.topicsToBeDeleted -= topic
        controllerContext.topicsWithDeletionStarted -= topic
        client.deleteTopic(topic, controllerContext.epochZkVersion)
        controllerContext.removeTopic(topic)
      }
    
    1. 清理記憶體中相關資訊
    2. 取消注冊被洗掉Topic的相關節點監聽器;節點是/brokers/topics/Topic名稱
    3. 洗掉zk中的資料包括;/brokers/topics/Topic名稱/config/topics/Topic名稱/admin/delete_topics/Topic名稱

6. Controller啟動時候 嘗試繼續處理待洗掉的Topic

我們之前分析Controller上線的時候有看到
KafkaController.onControllerFailover
以下省略部分代碼

 private def onControllerFailover(): Unit = {
    // 獲取哪些Topic需要被洗掉,哪些暫時還不能洗掉
     val (topicsToBeDeleted, topicsIneligibleForDeletion) = fetchTopicDeletionsInProgress()

    info("Initializing topic deletion manager")
    //Topic洗掉管理器初始化
    topicDeletionManager.init(topicsToBeDeleted, topicsIneligibleForDeletion)

    //Topic洗掉管理器 嘗試開始洗掉Topi
    topicDeletionManager.tryTopicDeletion()

6.1 獲取需要被洗掉的Topic和暫時不能洗掉的Topic

fetchTopicDeletionsInProgress

  1. topicsToBeDeleted所有需要被洗掉的Topic從zk中/admin/delete_topics 獲取
  2. topicsIneligibleForDeletion有一部分Topic還暫時不能被洗掉:
    ①. Topic任意磁區正在進行副本重分配
    ②. Topic任意磁區副本存在不在線的情況(只有topic有一個副本所在的Broker例外就不能能洗掉)
  3. 將得到的資料存在在controllerContext記憶體中

6.2 topicDeletionManager.init初始化洗掉管理器

  1. 如果服務器配置delete.topic.enable=false不允許洗掉topic的話,則洗掉/admin/delete_topics 中的節點; 這個節點下面的資料是標記topic需要被洗掉的意思;

6.3 topicDeletionManager.tryTopicDeletion嘗試恢復洗掉

這里又回到了上面分析過的resumeDeletions啦;恢復洗掉操作

  def tryTopicDeletion(): Unit = {
    if (isDeleteTopicEnabled) {
      resumeDeletions()
    }
  }

原始碼總結

整個Topic洗掉, 請看下圖
在這里插入圖片描述

幾個注意點:

  1. Controller 也是Broker
  2. Controller發起洗掉請求的時候,只是跟相關聯的Broker發起洗掉請求;
  3. Broker不在線或者洗掉失敗,Controller會持續進行洗掉操作; 或者Broker上線之后繼續進行洗掉操作

Q&A

列舉在此主題下比較常見的問題; 如果讀者有其他問題可以在評論區評論, 博主會不定期更新

什么時候在/admin/delete_topics寫入節點的

客戶端發起洗掉操作deleteTopics的時候,Controller回應deleteTopics請求, 這個時候Controller就將待洗掉Topic寫入了zk的/admin/delete_topics/Topic名稱節點中了;

什么時候真正執行洗掉Topic磁盤日志

Controller監聽到zk節點/admin/delete_topics之后,向所有存活的Broker發送洗掉Topic的請求; Broker收到請求之后將待洗掉副本標記為–delete后綴; 然后會有專門日志清理現場來進行真正的洗掉操作; 延遲多久洗掉是靠file.delete.delay.ms來決定的;默認是60000毫秒 = 一分鐘

為什么正在重新分配的Topic不能被洗掉

正在重新分配的Topic,你都不知道它具體會落在哪個地方,所以肯定也就不知道啥時候洗掉啊;
等分配完畢之后,就會繼續洗掉流程

如果在/admin/delete_topics/中手動寫入一個節點會不會正常洗掉

如果寫入的節點,并不是一個真實存在的Topic;則將會直接被洗掉
當然要注意如果配置了delete.topic.enable=false不可洗掉Topic的話,則將/admin/delete_topics/下面的節點全部洗掉,然后流程結束
如果寫入的節點是一個真實存在的Topic; 則將會執行洗掉Topic的流程; 本質上跟用Kafka客戶端執行洗掉Topic操作沒有什么不同

如果直接洗掉ZK上的/brokers/topics/{topicName}節點會怎樣

TODO…

Controller通知Brokers 執行StopReplica是通知所有的Broker還是只通知跟被洗掉Topic有關聯的Broker?

只是通知跟被洗掉Topic有關聯的Broker;
請看下圖原始碼,可以看到所有需要被StopReplica的副本都是被過濾了一遍,獲取它們所在的BrokerId; 最后呼叫的時候也是sendRequest(brokerId, stopReplicaRequest) ;根據獲取到的BrokerId發起的請求
在這里插入圖片描述

洗掉程序有Broker不在線 或者執行失敗怎么辦

Controller會繼續洗掉操作;或者等Broker上線然后繼續洗掉操作; 反正就是一定會保證所有的磁區都被洗掉(被標記了–delete)之后才會把zk上的資料清理掉;

ReplicaStateMachine 副本狀態機

請看 【kafka原始碼】Controller中的狀態機TODO

在重新分配的程序中,如果執行洗掉操作會怎么樣

洗掉操作會等待,等待重新分配完成之后,繼續進行洗掉操作
在這里插入圖片描述

Finally: 本文閱讀原始碼為 Kafka-2.5

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/294267.html

標籤:其他

上一篇:計算機組成原理期末復習必備知識點大全——第五章(輸入輸出系統)

下一篇:CSS學習筆記(二)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more