ディスクストレージのストレージ管理を刺激--DiskStore

DiskStore

次の前のここでは、これは、我々は機能クラスDiskStoreディスクストレージを実現分析する、このクラスは比較的簡単です。正式な開始前、私はおそらく背景BlockManagerを分析する必要性を感じ、またはそれは、操作の範囲を動作環境だということ。Blockmanagerは、実行時に、各ノードが実際に(ドライバとエグゼキュータ処理を含む)インスタンスが、このクラスは、両方のドライバ側の変数が作成されているため、放送、またはエグゼキュータ端シャッフルシャッフルは、ブロック、又はタスク実行結果を書き込みます。あまりにもそれぞれということです実際には、各ノード上で実行し、ローカルメモリとディスクを読み書きするBlockmanager内部手続きを意味するコアによって管理されるので、要約は、私が表現したい、BlockManager伝送、またはRDDキャッシュを必要とします工程(ドライバとエグゼキュータ)の例はBlockmanagerにBlockManagerIdクラスによって一意に識別されるBlockmanager例を有し、パッケージが実際の処理のBlockManagerId物理的な場所です。

DiskStore.put

まず、書き込みの最も一般的に使用される方法の一つを見て

def put(blockId: BlockId)(writeFunc: WritableByteChannel => Unit): Unit = {
    // 通过DiskBlockManager对象检查这个blockId对应的文件名的文件是否存在
    if (contains(blockId)) {
      throw new IllegalStateException(s"Block $blockId is already present in the disk store")
    }
    logDebug(s"Attempting to put block $blockId")
    val startTime = System.currentTimeMillis
    // 通过DiskBlockManager获取一个文件用于写入数据
    val file = diskManager.getFile(blockId)
    // 用CountingWritableChannel包装一下,以便于记录写入的字节数
    val out = new CountingWritableChannel(openForWrite(file))
    var threwException: Boolean = true
    try {
      writeFunc(out)
      // 关键步骤,记录到内部的map结构中
      blockSizes.put(blockId, out.getCount)
      threwException = false
    } finally {
      try {
        out.close()
      } catch {
        case ioe: IOException =>
          if (!threwException) {
            threwException = true
            throw ioe
          }
      } finally {
         if (threwException) {
          remove(blockId)
        }
      }
    }
    val finishTime = System.currentTimeMillis
    logDebug("Block %s stored as %s file on disk in %d ms".format(
      file.getName,
      Utils.bytesToString(file.length()),
      finishTime - startTime))
  }

このメソッドは、このような機能が割り当てファイルで、ディスク管理上のディレクトリとファイルを、ディスク上の一定のルールに従って、いくつかのディレクトリとサブディレクトリを作成しますです、何が本当にありません、非常にシンプルですが、より重要なクラスDiskBlockManagerと呼ばれます当社は、これらのディレクトリおよびサブディレクトリに割り当てられたとき、最初の名前を均等にしようとします。

DiskStore.putBytes

このアプローチは、直接putメソッドを呼び出してそれを処理することは容易ではないと言うことです。

  def putBytes(blockId: BlockId, bytes: ChunkedByteBuffer): Unit = {
    put(blockId) { channel =>
      bytes.writeFully(channel)
    }
  }

DiskStore.getBytes

その後、暗号化され、暗号化されていない2種類にてBlockDataオブジェクトにそれをパッケージ化し、最初のDiskBlockManagerにより、対応するファイル名を取得する、のは、この方法を見てみましょう。

  def getBytes(blockId: BlockId): BlockData = {
    val file = diskManager.getFile(blockId.name)
    val blockSize = getSize(blockId)
  
    securityManager.getIOEncryptionKey() match {
      case Some(key) =>
        // Encrypted blocks cannot be memory mapped; return a special object that does decryption
        // and provides InputStream / FileRegion implementations for reading the data.
        new EncryptedBlockData(file, blockSize, conf, key)
  
      case _ =>
        // 看一下DiskBlockData
        new DiskBlockData(minMemoryMapBytes, maxMemoryMapBytes, file, blockSize)
    }
  }

DiskBlockData

ラッパークラスのディスク・ファイルであり、主な機能は、いくつかの便利なインタフェースを提供することを目的とするこのクラスは、データをディスク・ファイルから読み出し、バッファオブジェクトを生成します。
このクラスは、2つの重要な方法toChunkedByteBufferとtoByteBufferを持っている、toByteBufferは言わない、ReadableByteChannel.read(ByteBufferのDST)メソッドを呼び出すと、私たちはtoChunkedByteBufferを見て、ファイルのデータを読み込みます

DiskBlockData.toChunkedByteBuffer

各アプリケーションのメモリブロックサイズが制限maxMemoryMapBytesがあり、複数のブロックに切断する必要があるため、この方法は、時間的に、大量のデータを非常に簡単です

  override def toChunkedByteBuffer(allocator: (Int) => ByteBuffer): ChunkedByteBuffer = {
    // Utils.tryWithResource调用保证在使用完资源后关闭资源
    // 基本等同于java中的try{}finally{}
    Utils.tryWithResource(open()) { channel =>
      var remaining = blockSize
      val chunks = new ListBuffer[ByteBuffer]()
      while (remaining > 0) {
        // 这里取剩余大小和maxMemoryMapBytes的较小值,
        // 也就是说每次申请的内存块大小不超过maxMemoryMapBytes
        val chunkSize = math.min(remaining, maxMemoryMapBytes)
        val chunk = allocator(chunkSize.toInt)
        remaining -= chunkSize
        JavaUtils.readFully(channel, chunk)
        chunk.flip()
        chunks += chunk
      }
      new ChunkedByteBuffer(chunks.toArray)
    }
  }

DiskBlockManager

また、このクラスの前に分析され、主にプロセスを実行して、ディレクトリを管理するために書かれたいくつかの一時ファイルをスパーク管理するために使用されます。

  • まず、(ディレクトリが複数のカンマで区切って指定することができます)ローカルディレクトリを設定するためのパラメータに基づいて作成され、パラメータの優先順位は次のとおりです。あなたが糸上で実行している場合は、ローカルディレクトリの糸パラメータLOCAL_DIRS構成が使用されます。そうでない場合は、環境変数SPARK_LOCAL_DIRSの値を取得します;そうでなければspark.local.dirパラメータ値を取得し、最終ではない構成は、一時ディレクトリとしてパラメータjava.io.tmpdirののJavaシステムの値を使用している場合。

  • 第二に、ディレクトリとの間で分配したファイルに関しては、メソッドのディレクトリ番号のハッシュ値のファイル名が異なるディレクトリに均等に分散ファイルの残りの部分を取るしようとします。

  • 言いたいことがもう一つは、+ rddId +「_ ID RDDキャッシュブロックがRDDBlockId書かれている名前は、ブロックに応じて異なる役割を区別することで、ファイル名の命名は、例えば、そのファイル名のステッチルールは「rdd_」であるということです「+ splitIndex

おすすめ

転載: www.cnblogs.com/zhuge134/p/11007328.html