Linux 磁盤與磁盤分區

  Linux 系統中全部的硬件設備都是經過文件的方式來表現和使用的,咱們將這些文件稱爲設備文件,硬盤對應的設備文件通常被稱爲塊設備文件。本文介紹磁盤設備在 Linux 系統中的表示方法以及如何建立磁盤分區。
  
  磁盤分類
  
  比較常見的磁盤類型有服務器中使用的 SCSI 硬盤和消費類市場中的 SATA 硬盤,固然還有當下大熱的各類固態硬盤。
  
  SCSI 硬盤
  
  SCSI 硬盤即採用 SCSI 接口的硬盤。它因爲性能好、穩定性高,所以在服務器上獲得普遍應用。同時其價格也不菲,正因它的價格昂貴,因此在普通PC上不多見到它的蹤影。SCSI 硬盤使用 50 針接口,外觀和普通硬盤接口有些類似(下圖來自互聯網):
  
  SATA 硬盤
  
  SATA(Serial ATA)口的硬盤又叫串口硬盤,Serial ATA 採用串行鏈接方式,串行 ATA 總線使用嵌入式時鐘信號,具有了更強的糾錯能力,與以往相比其最大的區別在於能對傳輸指令(不只僅是數據)進行檢查,若是發現錯誤會自動矯正,這在很大程度上提升了數據傳輸的可靠性。串行接口還具備結構簡單、支持熱插拔的優勢(下圖來自互聯網):
  
  固態硬盤
  
  固態硬盤(Solid State Disk),通常稱之爲 SSD 硬盤,固態硬盤是用固態電子存儲芯片陣列而製成的硬盤,由控制單元和存儲單元(FLASH芯片、DRAM芯片)組成。其主要特色是沒有傳統硬盤的機械結構,讀寫速度很是快(下圖來自互聯網):
  
  磁盤設備在 Linux 下的表示方法
  
  在 Linux 系統中磁盤設備文件的命名規則爲:
  
  主設備號 + 次設備號 + 磁盤分區號
  
  對於目前常見的磁盤,通常表示爲:
  
  sd[a-z]x
  
  主設備號表明設備的類型,相同的主設備號表示同類型的設備。當前常見磁盤的主設備號爲 sd。
  
  次設備號表明同類設備中的序號,用 "a-z" 表示。好比 /dev/sda 表示第一塊磁盤,/dev/sdb 表示第二塊磁盤。
  
  x 表示磁盤分區編號。在每塊磁盤上可能會劃分多個分區,針對每一個分區,Linux 用 /dev/sdbx 表示,這裏的 x 表示第二塊磁盤的第 x 個分區。
  
  以下圖所示:
  
  該系統中一共有四塊磁盤 /dev/sda,/dev/sdb,/dev/sdc 和 /dev/sdd。其中的 /dev/sda 上建立了三個分區,分別是 /dev/sda1,/dev/sda2,/dev/sda5;/dev/sdb 上只有一個分區 /dev/sdb1。而 /dev/sdc 和 /dev/sdd 則還沒有分區(也肯能是隻有一個分區,分區的名稱和磁盤的名稱相同)。
  
  磁盤分區
  
  建立磁盤分區大概有下面幾個目的:
  
  提高數據的安全性(一個分區的數據損壞不會影響其餘分區的數據)
  
  支持安裝多個操做系統
  
  多個小分區對比一個大分區會有性能提高
  
  更好的組織數據
  
  磁盤的分區由主分區、擴展分區和邏輯分區組成。在一塊磁盤上,主分區的最大個數是 4,其中擴展分區也是一個主分區,而且最多隻能有一個擴展分區,但能夠在擴展分區上建立多個邏輯分區。所以主分區(包括擴展分區)的範圍是 1-4,邏輯分區從 5 開始。對於邏輯分區,Linux 規定它們必須創建在擴展分區上,而不是創建在主分區上。
  
  主分區的做用是用來啓動操做系統的,主要存放操做系統的啓動或引導程序,所以建議操做系統的引導程序都放在主分區,好比 Linux 的 /boot 分區,最好放在主分區上:
  
  擴展分區只不過是邏輯分區的 "容器"。實際上只有主分區和邏輯分區是用來進行數據存儲的,於是能夠將數據集中存放在磁盤的邏輯分區中。
  
  咱們能夠經過 fdisk 命令來查看磁盤分區的信息:
  
  $ sudo fdisk -l /dev/sda
  
  輸出中的前幾行是磁盤的基本信息,好比總大小爲 80G,一共有多少個扇區(sector),每一個扇區的大小等等。紅框中的則是咱們比較關注的分區信息:
  
  第一列 Device 顯示了磁盤分區對應的設備文件名。
  
  第二列 Boot 顯示是否爲引導分區,上圖中的 /dev/sda1 就是引導分區。
  
  第三列 Start 表示磁盤分區的起始位置。
  
  第四列 End 表示磁盤分區的結束位置。
  
  第五列 Sectors 表示分區佔用的扇區數目。
  
  第六列 Size 顯示分區的大小。
  
  第七列和第八列顯示的內容相同,分別是數值 ID 及其文字描述。 Id 列顯示了磁盤分區對應的 ID,根據分區的不一樣,分區對應的 ID 號也不相同。Linux 下用 83 表示主分區和邏輯分區,5 表示擴展分區,8e 表示 LVM 分區,82 表示交換分區,7 表示 NTFS 分區。
  
  上圖中的信息代表:/dev/sda1 是一個主分區而且被用做引導分區;/dev/sda2 是擴展分區,其中只有一個邏輯分區,即 /dev/sda5,這點能夠經過兩個分區相同的大小證實。
  
  利用 fdisk 劃分磁盤分區
  
  fdisk 是 Linux 系統中一款功能強大的磁盤分區管理工具,能夠觀察硬盤的使用狀況,也能夠用來管理磁盤分區。本文僅介紹如何使用 fdisk 建立新的磁盤分區。
  
  假設咱們的 Linux 系統中增長了一塊新的磁盤,系統對應的設備名爲 /dev/sdd,下面咱們經過 fdisk 命令對這個磁盤進行分區。
  
  $ sudo fdisk /dev/sdd
  
  輸入命令 n 來建立新分區:
  
  根據上面的提示,咱們選擇 p 來建立主分區,而後提示咱們輸入分區的編號:
  
  主分區的編號爲 1- 4,這裏咱們輸入了 1。接下來是設置分區的大小:
  
  分區的大小是經過設置分區開始處的扇區和結束處的扇區設置的。這裏若是回車兩次會把整個磁盤劃分爲一個分區,也就是整個磁盤的容器都分給了一個分區。這樣一個簡單的分區就差很少完成了,注意此時的分區信息尚未寫入到磁盤中,在這裏還能夠反悔,若是確認執行上面的分區,執行 w 命令就好了:
  
  這時分區操做已經完成了,咱們能夠經過下面的命令查看分區的結果:
  
  NioEventLoop#openSelector()實現了建立selector的功能,默認狀況下,使用SelectorProvider#openSelector()方法建立一個新個selector:
  
  final Selector unwrappedSelector = provider.openSelector();
  
  若是設置環境變量io.netty.noKeySetOptimization=true, 會建立一個selectedKeySet = new SelectedSelectionKeySet(), 而後使用java的反射機制把selector的selectedKeys和publicSelectedKeys替換成selectedKeySet,具體步驟是:
  
  1.獲得selector的真正類型: sun.nio.ch.SelectorImpl
  
  Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
  
  @Override
  
  public Object run() {
  
  try {
  
  return Class.forName(
  
  "sun.nio.ch.SelectorImpl",
  
  false,
  
  PlatformDependent.getSystemClassLoader());
  
  } catch (Throwable cause) {
  
  return cause;
  
  }
  
  }
  
  });
  
  final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
  
  2.替換selector是屬性unwrappedSelector
  
  Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
  
  Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
  
  selectedKeysField.set(unwrappedSelector, selectedKeySet);
  
  publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
  
  之因此會設計一個這樣的優化選項,是由於通常狀況下調用完selector的select或selectNow方法後須要調用Selector#selectedKeys()獲得觸發NIO事件的的SelectableChannel,這樣優化以後,能夠直接從selectedKeySet中獲得已經觸發了NIO事件的SelectableChannel。
  
  在selector上註冊channel感興趣的NIO事件
  
  NioEventLoop提供了unwrappedSelector方法,這個方法返回了它建立好的Selector實例。這樣任何的外部類均可以把任意的SelectableChannel註冊到這selector上。在AbstractNioChannel中, doRegister方法的實現就是使用了這個方法:
  
  selectionKey = javaChannel(www.michenggw.com).register(eventLoop().unwrappedSelector(www.dasheng178.com/), 0, this);
  
  另外,它還提供了一個register方法:
  
  public void register(final SelectableChannel ch, final int interestOps, final NioTask<?> task)
  
  這個方法會把task當成SelectableChannel的附件註冊到selector上:
  
  ch.register(selector, interestOps, task);
  
  實現EventExecutor的run方法,定義NIO事件和Executor任務的處理流程
  
  在NioEventLoop的run方法中實現NIO事件和EventExecutor的任務處理邏輯,這個run方法在io.netty.util.concurrent.SingleThreadEventExecutor中定義。在上一章中,咱們看到了DefaultEventExecutor中是如何實現這個run方法的,這裏咱們將要看到這run方法的另外一個實現。和SingleThreadEventExecutor中的run方法相比,NioEventLoop的run方法不只要及時地執行taskQueue中的任務,還要能及時地處理NIO事件,所以它會同時檢查selector中的NIO事件和和taskQueue隊列,任何一箇中有事件須要處理或有任務須要執行,它不會阻塞線程。同時它也保證了在沒有NIO事件和任務的狀況下線程不會無謂的空轉浪費CUP資源。
  
  run主要實現以下,爲了更清晰的說明它的主要功能,我對原來的代碼進行了一些刪減。
  
  for(;;){
  
  try{
  
  //phase1: 同時檢查NIO事件和任務
  
  switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
  
  case SelectStrategy.CONTINUE:
  
  continue;
  
  case SelectStrategy.SELECT:
  
  select(wakenUp.getAndSet(www.yigouyule2.cn false)); //在taskQueue中沒有任務的時候執行select
  
  }
  
  //phase2: 進入處理NIO事件,執行executor任務
  
  try{
  
  //處理NIO事件
  
  processSelectedKeys();
  
  }finally{
  
  //處理taskQueu中的任務
  
  runAllTasks();
  
  }
  
  }catch(Throwable t){
  
  handleLoopException(t);
  
  $ sudo fdisk -l /dev/sdd
  
  若是嫌上面的執行過程麻煩,能夠用下面的一行命令起到相同的效果:
  
  $ (echo n; echo p; echo 1; echo ; echo ; echo w) | sudo fdisk /dev/sdd
  
  更改分區的類型
  
  上面建立的分區類型默認爲 83(Linux),若是想要一個 8e(Linux LVM)類型的分區該怎麼辦?咱們能夠繼續使用 fdisk 命令修改分區的類型,此次輸入 t 命令來修改分區的類型:
  
  接下來能夠選擇要修改的分區號,咱們只有一個分區,因此默認就是 1。
  
  下面咱們能夠經過 L 命令來查看 fdisk 命令支持的分區類型:
  
  咱們須要建立 LVM,所以咱們使用 LVM 的類型代碼 8e:
  
  最後輸入 w 命令確認變動。再次查看 /dev/sdd 的分區信息,此時分區類型已經變成了 Linux LVM:
  
  總結
  
  分區是使用磁盤的基礎,在分區完成後還須要對分區進行格式化,並把格式化後的文件系統掛載到 Linux 系統以後才能存儲文件。java

相關文章
相關標籤/搜索