Linux上配置使用iSCSI詳細說明

来源:https://www.cnblogs.com/f-ck-need-u/archive/2018/05/21/9067906.html
-Advertisement-
Play Games

本文詳細介紹iSCSI相關的內容,以及在Linux上如何實現iSCSI。 第1章 iSCSI簡介 1.1 scsi和iscsi 傳統的SCSI技術是存儲設備最基本的標準協議,但通常需要設備互相靠近並用SCSI匯流排連接,因此受到物理環境的限制。 iSCSI(Internet Small Compute ...


本文詳細介紹iSCSI相關的內容,以及在Linux上如何實現iSCSI。

第1章 iSCSI簡介

1.1 scsi和iscsi

傳統的SCSI技術是存儲設備最基本的標準協議,但通常需要設備互相靠近並用SCSI匯流排連接,因此受到物理環境的限制。

iSCSI(Internet Small Computer System Interface),顧名思義,iSCSI是網路上的SCSI,也就是通過網路連接的SCSI。它是由IBM公司研究開發用於實現在IP網路上運行SCSI協議的存儲技術,能夠讓SCSI介面與乙太網技術相結合,使用iSCSI協議基於乙太網傳送SCSI命令與數據,剋服了SCSI需要直接連接存儲設備的局限性,使得可以跨越不同的伺服器共用存儲設備,並可以做到不停機狀態下擴展存儲容量。

iSCSI實現的是IP SAN,數據傳輸基於乙太網。

1.2 iSCSI數據封裝

initiator向target發起scsi命令後,在數據報文從裡向外逐層封裝SCSI協議報文、iSCSI協議報文、tcp頭、ip頭。

封裝是需要消耗CPU資源的,如果完全以軟體方式來實現iscsi,那麼所有的封裝過程都由操作系統來完成。在很繁忙的伺服器上,這樣的資源消耗可能不太能接受,但好在它是完全免費的,對於不是非常繁忙的伺服器採用它可以節省一大筆資金。

除了軟體方式實現,還有硬體方式的initiator(TOE卡和HBA卡),通過硬體方式實現iSCSI。由於它們有控制晶元,可以幫助或者完全替代操作系統對協議報文的封裝。

  • TOE卡,操作系統首先封裝SCSI和iSCSI協議報文,而TCP/IP頭則交由TOE內的晶元來封裝,這樣就能減少一部分系統資源消耗。
  • HBA卡,操作系統只需封裝SCSI,剩餘的iSCSI協議報文還有TCP/IP頭由HBA晶元負責封裝。

顯然,HBA卡實現iSCSI是最好的方案,但是它要花錢,還不便宜。

第2章 配置使用iSCSI

2.1 部署iscsi前的說明和需求描述

1.說明

  • (1).iscsi在target端是工作在套接字上的,監聽埠預設是3260,且使用的是tcp連接。因為要保證數據安全性,使用udp可能會導致丟包。
  • (2).iscsi對客戶端有身份認證的需要,有兩種認證方式:基於IP認證,基於CHAP認證(雙方都進行驗證,即雙向認證)。

2.需求描述

找一臺伺服器A作為iscsi的target,將其中的一塊磁碟或分區/dev/sdb當作要共用的存儲設備共用出去。再找兩台伺服器B和C當作iscsi initiator連接到target的共用存儲上。

大致拓撲圖如下:

請確保伺服器A上已經關閉了防火牆或者允許了3260埠。

下圖描述了使用iSCSI的大致過程,後文內容雖然因為介紹各種用法而顯得比較雜,但根據這張圖的流程,閱讀時很容易搞清楚相關內容。

2.2 安裝target

在伺服器A上:

yum -y install scsi-target-utils

查看該工具包生成了哪些文件。

rpm -ql scsi-target-utils
/etc/rc.d/init.d/tgtd   #
/etc/sysconfig/tgtd
/etc/tgt/targets.conf   #
/usr/sbin/tgt-admin     #
/usr/sbin/tgt-setup-lun
/usr/sbin/tgtadm        #
/usr/sbin/tgtd
/usr/sbin/tgtimg
/usr/share/doc/scsi-target-utils-1.0.24
/usr/share/doc/scsi-target-utils-1.0.24/README
/usr/share/doc/scsi-target-utils-1.0.24/README.iscsi
/usr/share/doc/scsi-target-utils-1.0.24/README.iser
/usr/share/doc/scsi-target-utils-1.0.24/README.lu_configuration
/usr/share/doc/scsi-target-utils-1.0.24/README.mmc
/usr/share/man/man5/targets.conf.5.gz
/usr/share/man/man8/tgt-admin.8.gz
/usr/share/man/man8/tgt-setup-lun.8.gz
/usr/share/man/man8/tgtadm.8.gz

其中/usr/sbin/tgtadm/usr/sbin/tgt-admin的都是管理和配置target的工具,它們作用是一樣的,只不過tgtadm是命令行下的工具,而tgt-admin是根據配置文件/etc/tgt/targets.conf調用tgtadm來實現。另外/etc/init.d/tgtd是服務啟動腳本。

這個時候已經可以啟動target服務了。

service tgtd start
netstat -tnlp | grep 3260
tcp     0    0 0.0.0.0:3260    0.0.0.0:*   LISTEN    2074/tgtd
tcp     0    0 :::3260         :::*        LISTEN    2074/tgtd

加入開機自啟動。

chkconfig tgtd on

2.2.1 tgtadm命令用法說明

tgtadm是一個高度模式化的命令,他們的模式很相近。有三個模式:target、logicalunit、account。指定模式時使用--mode選項。再使用--op來指定對應模式下的選項。另外,使用-lld指定driver,有兩種driver:iscsi和iser,基本都會使用iscsi。

tgtadm --help
  --lld <driver> --mode target --op new --tid <id> --targetname <name>
                        add a new target with <id> and <name>. <id> 
                        must not be zero.
  --lld <driver> --mode target --op delete [--force] --tid <id>
                        delete the specific target with <id>.
                        With force option, the specific target is 
                        deleted even if there is an activity.
  --lld <driver> --mode target --op show
                        show all the targets.
  --lld <driver> --mode target --op show --tid <id>
                        show the specific target's parameters.
  --lld <driver> --mode target --op update --tid <id> --name <param> --value <value>
                        change the target parameters of the specific
                        target with <id>.
  --lld <driver> --mode target --op bind --tid <id> --initiator-address <address>
  --lld <driver> --mode target --op bind --tid <id> --initiator-name <name>
                        enable the target to accept the specific initiators.
  --lld <driver> --mode target --op unbind --tid <id> --initiator-address <address>
  --lld <driver> --mode target --op unbind --tid <id> --initiator-name <name>
                        disable the specific permitted initiators.
  --lld <driver> --mode logicalunit --op new --tid <id> --lun <lun> \
                        --backing-store <path> --bstype <type> --bsoflags <options>
                        add a new logical unit with <lun> to the specific
                        target with <id>. The logical unit is offered
                        to the initiators. <path> must be block device files
                        (including LVM and RAID devices) or regular files. 
                        bstype option is optional.
                        bsoflags supported options are sync and direct
                        (sync:direct for both).
  --lld <driver> --mode logicalunit --op delete --tid <id> --lun <lun>
                        delete the specific logical unit with <lun> 
                        that the target with <id> has.
  --lld <driver> --mode account --op new --user <name> --password <pass>
                        add a new account with <name> and <pass>.
  --lld <driver> --mode account --op delete --user <name>
                        delete the specific account having <name>.
  --lld <driver> --mode account --op bind --tid <id> --user <name> [--outgoing]
                        add the specific account having <name> to 
                        the specific target with <id>.
                        <user> could be <IncomingUser> or <OutgoingUser>.
                        If you use --outgoing option, the account will be
                        added as an outgoing account.
  --lld <driver> --mode account --op unbind --tid <id> --user <name>
                        delete the specific account having <name> from 
                        specific target.
  --control-port <port> use control port <port>

看上去很複雜。不過可以將上面的語法拋去driver部分,target、logicalunit和account這3種模式下的操作方式簡化後如下:

這樣就簡單的多了。

上表中的選項都是長格式的,但他們都有對應的短格式選項。

target和logicalunit兩個模式隨後就會有示例,而account是和CHAP認證有關的,將在後文和配置文件放在一塊解釋。

2.2.2 target的命名方式

iqn.YYYY-mm.<reversed domain name>[:identifier]
  • iqn是iscsi qualified name的縮寫,就像fqdn一樣。
  • YYYY-mm描述的是此target是何年何月創建的,如2016-06。
  • <reversed domain name>是功能變數名稱的反寫,起到了唯一性的作用,如longshuai.com寫為com.longshuai。
  • identifier是可選的,是為了知道此target相關信息而設的描述性選項,如指明此target用到了哪些硬碟。

示例:

iqn.2016-06.com.longshuai:test.disk1

2.2.3 創建一個target

需要說明的是,下麵的實驗全是使用命令行工具tgtadm來實現的。但是修改配置文件然後使用tgt-admin也是一樣可以的,且target數量多的時候,更建議使用配置為文件載入的方式。最重要的一點是,使用命令行方式創建的target及lu等是臨時生效的,在target服務重啟後就失效了,再手動建立它們是一件相當麻煩的事情。

如下,分別使用了長格式選項和短格式選項分別創建和顯示target。註意:創建target時,tid不能是0,因為0是被系統保留的。

tgtadm --lld iscsi --mode target --op new --tid 1 --targetname iqn.2017-03.com.longshuai:test.disk1
tgtadm -L iscsi -m target -o show

以上是第一個target的信息。從信息中可以看到:

  • 創建完第一個target後自動就創建了一個LUN為0的logicalunit(以後簡稱lu),這是固定給每個target都使用的LUN。
  • 此lu的類型是controller。
  • "backing store type"為null,即此lu沒有向下擴展邏輯設備,因為它是lun控制器。也就是說這個LUN是保留作為lu控制器用的。
  • "I_T nexus information"記錄的是initiator與此target的聯結關係,nexus的意思就是聯結、關聯,在後文介紹initiator的時候會展示此處信息。

現在向此target添加一個lu,使用的是新插入的磁碟/dev/sdc(全新,未進行分區)。當然,使用新建立的分區或者已經格式化後的分區做實驗也可以。

tgtadm -L iscsi -m logicalunit -o new -t 1 -l 1 -b /dev/sdc

然後再來查看target的信息。

tgtadm -L iscsi -m target -o show

從LUN 1信息中可以看出,lu type已經是disk而非controller,且顯示了此lu的容量大小是42950M。另外還顯示了使用的邏輯設備是/dev/sdc,且是可讀可寫的(rdwr)。

但到目前為止,該target都沒有定義共用給誰,這從target信息的最後兩行Account/ACL information中可以看出。

現在將此target綁定一個共用IP,即說明此IP可以連接該target。這是iSCSI的一種認證方式:IP認證。除此之外,還有基於account的CHAP認證,詳細內容見後文。IP認證的作用是允許Initiator發現該target,並允許做進一步的基account的CHAP認證。

tgtadm -L iscsi -m target -o bind -t 1 -I 192.168.100.0/24
tgtadm -L iscsi -m target -o show

再添加一個10G分區/dev/sdb1為邏輯存儲單元,lun=2。

tgtadm -L iscsi -m logicalunit -o new -t 1 -l 2 -b /dev/sdb1
tgtadm -L iscsi -m target -o show

由於該lu是在target id=1下的,所以192.168.100.0這個網段的機器也能訪問此設備。也就是說,共用出去的是target級別而不是lu級別的。

然後在iscsi的"客戶端"initiator安裝iscsi-initiator-utils看看是否能看見這兩個設備。如果想急著看結果,請跳到安裝initiator的章節中。

2.2.4 tgt-admin和配置文件targets.conf

tgt-admin是讀取配置文件的選項然後調用tgtadm來執行的工具。它的選項很多可以簡化tgtadm命令的書寫,畢竟tgtadm的選項太長太多餘了,除此之外也有一些其他的作用用於更細緻的配(tgtadm配置的太粗糙了)。用法如下:

tgt的配置文件為/etc/tgt/targets.conf,該配置文件的格式很容易讀懂,能實現的target和lun的配置方式多種多樣。它的配製方法在後文會和iscsi initiator的配置文件/etc/iscsi/iscsid.conf放在一起介紹。

下麵就使用tgt-admin為當前的target生成對應的配置文件來稍作分析。

首先列出當前target的信息。

bash> tgt-admin -s
Target 1: iqn.2017-03.com.longshuai:test.disk1
    System information:
        Driver: iscsi
        State: ready
    I_T nexus information:
    LUN information:
        LUN: 0
            Type: controller
            SCSI ID: IET     00010000
            SCSI SN: beaf10
            Size: 0 MB, Block size: 1
            Online: Yes
            Removable media: No
            Prevent removal: No
            Readonly: No
            Backing store type: null
            Backing store path: None
            Backing store flags: 
        LUN: 1
            Type: disk
            SCSI ID: IET     00010001
            SCSI SN: beaf11
            Size: 10742 MB, Block size: 512
            Online: Yes
            Removable media: No
            Prevent removal: No
            Readonly: No
            Backing store type: rdwr
            Backing store path: /dev/sdb1
            Backing store flags: 
        LUN: 2
            Type: disk
            SCSI ID: IET     00010002
            SCSI SN: beaf12
            Size: 42950 MB, Block size: 512
            Online: Yes
            Removable media: No
            Prevent removal: No
            Readonly: No
            Backing store type: rdwr
            Backing store path: /dev/sdc
            Backing store flags:  
    Account information:
    ACL information:
        192.168.100.0/24

使用--dump選項輸出為配置文件的格式,並將其重定向到/tmp/tgt.conf中。

bash> tgt-admin --dump | tee /tmp/tgt.conf
default-driver iscsi

<target iqn.2017-03.com.longshuai:test.disk1>
        backing-store /dev/sdb1
        backing-store /dev/sdc
        initiator-address 192.168.100.0/24
</target>

由此可以看出,全局使用的driver是iscsi,名稱為iqn.2017-03.com.longshuai:test.disk1的target有兩個backing-store,即邏輯設備,分別是/dev/sdb1和/dev/sdc。但是要註意,這樣導出的配置文件指定的LUN號碼可能會在tgt-admin讀取並執行的時候更換位置,但這並不會有任何影響。

現在將已有的target全部刪除,再去查看信息就已經沒有了。

tgt-admin --delete ALL
tgt-admin -s

再從剛纔生成的配置文件中讀取並啟動。然後查看信息,發現已經有了target。

tgt-admin -e -c /tmp/tgt.conf
tgt-admin -s

關於tgt-admin其他選項也都很簡單,都是從字面意思就能看出來用法的。所以就不多說明瞭。

另外需要說明的是在tgt的配置文件/etc/tgt/targets.conf中有一行:

#include /etc/tgt/temp/*.conf

將此行註釋後,以後可以導出配置文件到/etc/tgt/temp目錄下並以.conf作為尾碼,重啟tgtd服務即可重新載入,而不需要在手動載入了。不過有個問題,使用dump出來的配置文件會有default-driver指令行,而這一行在主配置文件中也有,且他們是不能出現多次的,否則將會報錯,所以需要將主配置文件中的default-driver指令註釋掉。

2.3 安裝initiator

安裝Initiator的機器成為iscsi的發起者,initiator本身的意思就是"發起者",在這裡即iscsi的"客戶端"程式的意思。

此處先在B伺服器(192.168.100.5)上安裝iscsi-initiator-utils。另一臺C伺服器後面再做測試。

yum -y install iscsi-initiator-utils

2.3.1 相關文件和目錄說明

下麵是此安裝包生成的一些重要文件和目錄(只列出了必要的部分)。

rpm –ql iscsi-initiator-utils

其中:

  • /etc/iscsi/iscsid.conf:是iscsi發起者的配置文件。
  • /etc/rc.d/init.d/{iscsi,iscsid}:服務啟動腳本,只需要啟動iscsi即可,因為它會自動調用iscsid腳本。
  • /sbin/iscsi-iname:為initiator命名的工具。就像target有自己獨特的iqn名稱,initiator也有獨特的名稱標識自己。
  • /sbin/iscsiadm:initiator的管理工具,在initiator上的絕大部分的命令都是通過它來執行的。
  • /var/lib/iscsi/ifaces:指定使用哪個網卡介面和target通信。
  • /var/lib/iscssi/nodes:該目錄中保存了發現的target,分別是以target_name命名的目錄,在target_name目錄下又保存了以"target_ip,port"(如192.168.100.151,3260)的配置文件,這個配置文件是本initiator向對應的target 發起連接時的參數,這些參數繼承於/etc/iscsi/iscsid.conf
  • /var/lib/iscsi/send_targets:該目錄中也存儲了一個或多個以"target_IP,port"命名的目錄,記錄的是discovery的歷史記錄,對於discovery成功的則在對應的目錄會有文件,否則是空目錄。

其中IP,port的記錄方式稱為protal,是入口、入門的意思。

需要註意的是,建議不要把iscsi和iscsid設置為開機自啟動,因為開機時如果它找不到target的時候會一直卡在那裡等待。可以將其放在rc.local文件中來啟動。

chkconfig iscsi off
chkconfig iscsid off
echo "service iscsi start" >>/etc/rc.d/rc.local

2.3.2 iscsi-iname命令

和target一樣,initiator也需要一個獨特的名稱來標識自己讓target識別。initiator在連接target的時候,會讀取/etc/iscsi/initiatorname.iscsi中的內容作為自己的iname。

初始狀態的iname如下:

bash> cat /etc/iscsi/initiatorname.iscsi   
InitiatorName=iqn.1994-05.com.redhat:ceb390801983

其中尾碼"ceb390801983"是一個隨機串。

也可以為iname生成一個別名,只需在此文件中另起一行寫入以下內容:

InitiatorAlias=INAME_ALIAS

如:

InitiatorAlias=client.longshuai.com

若要自指定iname,可以手動修改該文件。也可以使用iscsi-iname工具來生成iname並保存到該文件。

bash> iscsi-iname
iqn.1994-05.com.redhat:5a804fa64f8e
bash> iscsi-iname
iqn.1994-05.com.redhat:ca4eb16bbddd

可以看出iscsi-iname生成的iname首碼都是一樣的,修改的只是尾碼部分的隨機串。如果要指定首碼,則使用-p選項。

bash> iscsi-iname -p iqn.2017-03.com.longshuai
iqn.2017-03.com.longshuai:adb6a5ec885c

所以,通過iscsi-iname向/etc/iscsi/initiatorname.iscsi中寫入一個iname。

echo Initiatorname=`iscsi-iname -p iqn.2017-03.com.longshuai` >/etc/iscsi/initiatorname.iscsi

然後重啟下iscsi服務。

service iscsi restart

2.3.3 iscsiadm命令

iscsiadm也是一個模式化的命令,使用-m指定mode。mode有:discovery、node、session、iface。一般就用前兩個mode。

  • discovery:發現某伺服器是否有target輸出,以及輸出了哪些target。發現target後會生成target資料庫discoverydb。
  • node:管理跟某target的關聯關係。在discovery發現了target後,是否要跟target建立關係,是否要刪除已有的關係或者解除已有的關係等。刪除關聯關係不僅會解除關聯,還會刪除發現target後生成的discoverydb。
  • session:會話管理。
  • iface:介面管理。

2.3.4 發現target(discovery)

即使用discovery模式。

iscsiadm -m discovery [ -d debug_level ] [ -t type -p ip:port -I ifaceN [ -p ip:port ]

-d:輸出調試信息,級別從0-8。出現錯誤的時候用來判斷錯誤來源是很有用處的,可以使用級別2。
-I:指定發現target時通信介面。
-t type:有三種type(sendtargets,SLP,iSNS),一般只會用到sendtargets,可以簡寫為st。
-p IP:PORT:指定要發現target的IP和埠,不指定埠時使用預設的3260。

現在可以進行discovery了。這裡發起兩次,第一次是正確的,第二次是錯誤的(該IP上沒有target或主機未啟動)。

bash> iscsiadm -m discovery -t st -p 192.168.100.151:3260
192.168.100.151:3260,1 iqn.2017-03.com.longshuai:test.disk1

bash> iscsiadm -m discovery -t st -p 192.168.100.152:3260
iscsiadm: cannot make connection to 192.168.100.152: No route to host
iscsiadm: cannot make connection to 192.168.100.152: No route to host
iscsiadm: cannot make connection to 192.168.100.152: No route to host
iscsiadm: cannot make connection to 192.168.100.152: No route to host
iscsiadm: cannot make connection to 192.168.100.152: No route to host
iscsiadm: cannot make connection to 192.168.100.152: No route to host
iscsiadm: connection login retries (reopen_max) 5 exceeded
iscsiadm: Could not perform SendTargets discovery: encountered connection failure

如果出現以上錯誤,檢查下是不是防火牆阻擋了,是不是IP地址寫錯了。

在發現了target後,在/var/lib/iscsi中的nodes和send_targets目錄中就有了文件。

tree /var/lib/iscsi/

可以看到,對於discovery失敗的在send_targets目錄中也會記錄,只不過是空目錄。在nodes目錄和正確discovery到的send_targets子目錄中都有幾個配置文件,都是些參數信息。而且可以看到,send_targets中的目錄是nodes目錄的軟鏈接。

如果想重新發現已存在的target時,可以清空nodes目錄中對應的項,然後再discovery。

使用service iscsi status可以查看到相關信息項。

2.3.5 關聯和解除關聯target(node)

關聯target的作用是initiator和target建立session,建立session後,initiator上就可以查看、訪問、操作target上的scsi設備。

有兩種關聯方法,一是關聯所有,一是指定單個target進行關聯。

iscsiadm -m node [-d debug_level] [-L all,manual,automatic] [-U all,manual,automatic]
iscsiadm -m node [-d debug_level] [[-T targetname -p ip:port -I ifaceN] [-l | -u ]] [-o operation]

-d:指定debug級別,有0-8個級別。
-L和-U:分別是登錄和登出target,可以指定ALL表示所有發現的target,或者manual指定。
-l和-u:分別是登錄和登出某一個target。
-T:用於-l或-u時指定要登錄和登出的targetname。
-o:對discoverydb做某些操作,可用的操作有new/delete/update/show,一般只會用到delete和show。

例如,使用單個的關聯方式關聯target。其中target_name可以通過命令iscsiadm -m node查看。

bash> iscsiadm -m node
192.168.100.151:3260,1 iqn.2017-03.com.longshuai:test.disk1

bash> iscsiadm -m node -T iqn.2017-03.com.longshuai:test.disk1 -p 192.168.100.151:3260 -l
Logging in to [iface: default, target: iqn.2017-03.com.longshuai:test.disk1, portal: 192.168.100.151,3260] (multiple)
Login to [iface: default, target: iqn.2017-03.com.longshuai:test.disk1, portal: 192.168.100.151,3260] successful.

實際上,在執行discovery的時候很可能就已經自動執行了關聯,所以再次關聯很可能什麼消息也看不到。如果是這樣的話,需要先退出session,再進行關聯。當然也可能是直接顯示successful,這樣就說明原來discovery的時候是沒有主動關聯的。

iscsiadm -m node -T iqn.2017-03.com.longshuai:test.disk1 -p 192.168.100.151:3260 -u

此時fdisk -l看看是否已經多出了兩塊硬碟出來。

bash> fdisk -l

Disk /dev/sda: 21.5 GB, 21474836480 bytes
255 heads, 63 sectors/track, 2610 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x0005ff67

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          32      256000   83  Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2              32        2356    18666496   83  Linux
/dev/sda3            2356        2611     2048000   82  Linux swap / Solaris

Disk /dev/sdb: 10.7 GB, 10742183424 bytes
64 heads, 32 sectors/track, 10244 cylinders
Units = cylinders of 2048 * 512 = 1048576 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000


Disk /dev/sdc: 42.9 GB, 42949672960 bytes
64 heads, 32 sectors/track, 40960 cylinders
Units = cylinders of 2048 * 512 = 1048576 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

現在就可以對這兩塊邏輯盤進行分區格式化(創建文件系統),並投入使用。

此時先看下target端的target信息。

tgt-admin -s | less

其中I_T nexus表示initiator到target的關聯信息,nexus的值是該initiator關聯到target的次數。多個initiator會顯示多個I_T nexus信息。這裡可以看到只有一個I_T nexus,說明只有一個initiator進行了關聯。

2.3.6 iSCSI的數據不安全性(不同步性)

現在在initiator上將/dev/sdb進行格式化,並向其中寫入一個文件。

parted /dev/sdb mklabel gpt
parted /dev/sdb mkpart /dev/sdb1 ext4 1 10G
mkfs.ext4 /dev/sdb1
parted /dev/sdb print
mount /dev/sdb1 /mnt/
echo "haha" > /mnt/test.txt

然後配置伺服器C(192.168.100.6),讓其作為另一臺initiator。

bash> yum -y install iscsi-initiator-utils
bash> iscsiadm -m discovery -t st -p 192.168.100.151:3260
bash> iscsiadm -m node -T iqn.2017-03.com.longshuai:test.disk1 -p 192.168.100.151:3260 -l
bash> fdisk -l
bash> mount /dev/sdb1 /mnt

bash> ls /mnt
lost+found  test.txt

不出所料,C伺服器也能掛載/dev/sdb1,且在B伺服器寫入的test.txt文件也已經同步過來了。

再看看此時target的target信息。

bash> tgt-admin -s
Target 1: iqn.2017-03.com.longshuai:test.disk1
    System information:
        Driver: iscsi
        State: ready
    I_T nexus information:
        I_T nexus: 1
            Initiator: iqn.2017-03.com.longshuai:b01d684ad13f
            Connection: 0
                IP Address: 192.168.100.5
        I_T nexus: 2
            Initiator: iqn.1994-05.com.redhat:42b7f829d2ec
            Connection: 0
                IP Address: 192.168.100.6

現在在C伺服器上,向/dev/sdb1掛載的目錄/mnt下寫入一個文件,看看是否會同步到B伺服器上。

echo "hehe" >/mnt/test1.txt

在192.168.100.5上執行:

ls /mnt/
lost+found  test.txt

echo "heihei" >/mnt/test3.txt

顯然,test1.txt並沒有同步到B伺服器上。同理,此時B中再寫入文件也不會同步到C上。

那麼在C上卸載/mnt,然後再次掛載會有什麼情況呢?

umount /mnt
mount /dev/sdb1 /mnt

ls /mnt
lost+found  test3.txt  test.txt

沒看錯,test1.txt確實沒了。這就是使用iscsi出現的問題,多個主機同時使用邏輯存儲,數據會衝突並且不能及時同步而導致數據丟失。

所以,iscsi一定要配合集群文件系統或者分散式文件系統來使用以防止上述問題。

2.3.7 initiator開機一直處於等待狀態

該問題在前文描述過。

出現這個問題是因為initiator端設置了iscsi或iscsid開機自啟動,正好又無法和target聯繫,如通信出現故障、target處於關機狀態、target中的tgtd服務未啟動、target上的target_id和target_name等配置改變了。

總而言之,開機自啟動的時候無法正常關聯/var/lib/iscsi目錄下記錄的target就會出現此問題。

解決辦法也是建議的辦法是把iscsi和iscsid的開機自啟動關閉掉,然後把啟動他們的命令放到rc.local中。

如果已經遇到了無法正常開機的情況,那麼可以多等待些時間,或者修改target端讓target端能夠和initiator匹配上。如target端本來是關機狀態,將其開機即可。

第3章 target和initiator的配置文件

3.1 initiator的配置文件

一般而言,對於initiator的配置文件/etc/iscsi/iscsid.conf,裡面預設設置了重啟服務就自動對已發現過的target進行關聯,所以重啟iscsi服務的時候會自動進行關聯

如果不使用CHAP,則基本可以無視這個配置文件。使用CHAP認證的時候配置下麵CHAP相關的段落就夠了,其他的配置段落可以不用理會。關於CHAP認證,稍後就介紹。

# *************
# CHAP Settings
# *************

####以下是initiator authentication相關
# To enable CHAP authentication set node.session.auth.authmethod to CHAP. The default is None.
#node.session.auth.authmethod = CHAP

# To set a CHAP username and password for initiator authentication by the target(s):
#node.session.auth.username = username
#node.session.auth.password = password

####以下是target authentication相關
# To set a CHAP username and password for target(s) authentication by the initiator:
#node.session.auth.username_in = username_in
#node.session.auth.password_in = password_in

####以下是discovery認證相關,iscsi-initiator-utils似乎不支持這個認證,所以以下項不能開啟和設置
# To enable CHAP authentication for a discovery session to the target
# set discovery.sendtargets.auth.authmethod to CHAP. The default is None.
#discovery.sendtargets.auth.authmethod = CHAP

# To set a discovery session CHAP username and password for the initiator authentication by the target(s):
#discovery.sendtargets.auth.username = username
#discovery.sendtargets.auth.password = password

# To set a discovery session CHAP username and password for target(s) authentication by the initiator:
#discovery.sendtargets.auth.username_in = username_in
#discovery.sendtargets.auth.password_in = password_in

所以,如果只要實現單向認證,則開啟以下三項即可。

node.session.auth.authmethod = CHAP
node.session.auth.username = username
node.session.auth.password = password

如果要實現雙向認證,則需要開啟以下5項。

node.session.auth.authmethod = CHAP
node.session.auth.username = username
node.session.auth.password = password
node.session.auth.username_in = username_in
node.session.auth.password_in = password_in

且需要註意的是,如果是單向認證,則後兩項必須不能開,開了就會進行雙向認證。

雖然iscsi-initiator-utils支持discovery認證,但是由於scsi-target-utils不支持discovery認證,所以在認證關聯target之前必須先進行discovery,也就是說在target端的訪問控制列表ACL項中必須要定義允許initiator進行discovery。

3.2 target配置文件的配置方法

target端使用tgtadm命令配置的結果都是工作在內核中的,重啟tgt服務或重啟系統時,記憶體中的內容都會丟失。所以要永久讓配置生效需要寫入到配置文件中去。

target的配置文件預設是/etc/tgt/targets.conf,但是可以在/etc/tgt/temp/目錄(預設不存在)下建立多個以".conf"為尾碼的配置文件,然後啟用主配置文件中的include指令即可。

以下給出兩個配置的例子,這個配置文件很通俗易懂。

#include /etc/tgt/temp/*.conf
default-driver iscsi

<target iqn.2017-03.com.longshuai:test.disk1>
        backing-store /dev/sdb1
        backing-store /dev/sdc
        incominguser <incoming_username> <PASSWORD>
        outgoinguser <outgoing_username> <PASSWORD> 
        initiator-address 192.168.100.0/24
</target>

這樣的配置,backing-store的順序決定了lun號碼的順序,上面的配置中/dev/sdb1會是Lun1,/dev/sdc會是lun2。

若想要為每個邏輯設備指定想要指定的lun號碼,需要將每個backing-store封裝在target中並獨立指定lun號碼。

#include /etc/tgt/temp/*.conf
default-driver iscsi

<target iqn.2017-03.com.longshuai:test.disk1>
        <backing-store /dev/sdb1>
              lun 5
        </backing-store>
        <backing-store /dev/sdc>
              lun 6
        </backing-store>
        incominguser <incoming_username> <PASSWORD>
        outgoinguser <outgoing_username> <PASSWORD> 
        initiator-address 192.168.100.0/24
</target>

3.3 重啟tgtd服務不載入配置文件的問題

如果在正常狀態下有initiator關聯了target設備,此時重啟tgtd服務很可能會導致配置文件中的配置不生效,這是為了保護initiator仍然可以隨時關聯target而不丟失數據和狀態設立的機制。但不得不說,這個特性真的很讓人煩惱,配置不生效,難道非得再使用tgtadm來重新生成到內核嗎?

問題如下描述。

當前的target狀態如下:

bash> tgt-admin -s             
Target 1: iqn.2017-03.com.longshuai:test1.disk1
    System information:
        Driver: iscsi
        State: ready
    I_T nexus information:
    LUN information:
        LUN: 0
            Type: controller
            SCSI ID: IET     00010000
            SCSI SN: beaf10
     ……省略部分結果……  
        LUN: 1
            Type: disk
            SCSI ID: IET     00010001
            SCSI SN: beaf11
     ……省略部分結果…… 
        LUN: 2
            Type: disk
            SCSI ID: IET     00010002
            SCSI SN: beaf12
            Size: 42950 MB, Block size: 512
     ……省略部分結果…… 
    Account information:
    ACL information:
        192.168.100.0/24

配置文件中啟用的項如下。這和上面的狀態是一樣的。

<target iqn.2017-03.com.longshuai:test1.disk1>
        backing-store /dev/sdb1
        backing-store /dev/sdc
        initiator-address 192.168.100.0/24
</target>

此時在initiator上關聯此target,然後登出。這裡無論登不登出對target的影響都是一樣的。

iscsiadm -m discovery -t st -p 192.168.100.151:3260
iscsiadm -m node -T iqn.2017-03.com.longshuai:test1.disk1 -p 192.168.100.151:3260 -l
iscsiadm -m node -T iqn.2017-03.com.longshuai:test1.disk1 -p 192.168.100.151:3260 -u

再重啟target上的tgtd服務,然後查看狀態。

service tgtd restart
Stopping SCSI target daemon:                               [  OK  ]
Starting SCSI target daemon:                               [  OK  ]

tgt-admin -s
Target 1: iqn.2017-03.com.longshuai:test1.disk1
    System information:
        Driver: iscsi
        State: ready
    I_T nexus information:
    LUN information:
        LUN: 0
            Type: controller
            SCSI ID: IET     00010000
            SCSI SN: beaf10
            Size: 0 MB, Block size: 1
            Online: Yes
            Removable media: No
            Prevent removal: No
            Readonly: No
            Backing store type: null
            Backing store path: None
            Backing store flags: 
    Account information:
    ACL information:
        192.168.100.0/24

結果lun1和lun2沒了。無論再怎麼重啟結果都是一樣,哪怕是手動使用tgt-admin -e -c指定配置文件執行結果也一樣。

好在/etc/init.d/tgtd提供了不少的選項。

/etc/init.d/tgtd --help
Usage: /etc/init.d/tgtd {start|stop|status|restart|condrestart|try-restart|reload|force-stop|force-restart|force-reload}

它們的意思無須多述。

經過測試,上述問題只有使用force-reload選項能解決,其他所有選項都無效,包括force-restart和reload。

service tgtd force-reload

或者重啟系統也能解決,但是誰沒事會重啟系統呢?

第4章 account模式和CHAP認證

4.1 CHAP認證

基於IP的認證比較粗糙,不過多數時候已經夠用了。但對於安全性要求高的環境來說,使用CHAP認證更好一些。

CHAP(Challenge-Handshake Authentication Protocol),稱為挑戰式握手認證協議,它是雙向認證,當然也支持單向認證。

對於iscsi而言,在CHAP認證的機制上有兩種方式:initiator authenticationtarget authentication

  1. initiator authentication認證
     
    在initiator嘗試連接到一個target的時候,initator需要提供一個用戶名和密碼給target被target進行認證。也就是說initiator需要被target認證,它向target端提供的賬號和密碼是target端指定的。
     
    這個賬號和密碼對於target來說是流入的賬號和密碼,用incoming表示。所以後面稱呼這個賬號和密碼為incoming賬號和incoming密碼。再次說明,incoming賬號是initiator端提供給target端,被target端認證的賬號。
     
  2. target authentication認證
     
    在initiator嘗試連接到一個target的時候,target有時也需要被initiator認證,以確保該target是合法而非偽裝的target,這就要求target提供一個用戶名和密碼給initiator被initiator進行認證。
     
    target向initiator提供的賬號和密碼對於target而言是流出的,所以稱之為outgoing。所以outgoing使用的賬號和密碼在後文稱為outgoing賬號和outgoing密碼。而對於initiator而言是incoming的,所以在initiator配置文件中稱為in。也就是說outgoing賬號是target端提供給initiator端,被initiator認證的賬號,但儘管如此,這個賬號和密碼還是在target端創建和綁定的。

綜上,不管是什麼認證,賬號和密碼都是target端創建和綁定。

以上兩種認證方式是有層次順序的。一般來說,有認證需求的時候都是伺服器驗證客戶端是否有許可權,iscsi也一樣。

initiator authentication可以單獨存在,它可以在沒有target authentication的情況下應用,這時候的CHAP認證就是單向認證(target認證initiator的合法性)。

target authentication只有在initiator authentication的基礎上才能進行。也就是說target認證和initiator認證必須同時存在才可以。即initiator和target需要相互認證實現雙向CHAP認證。

4.2 tgtadm命令的account模式用法

以下是tgtadm --help關於account的結果,但是用法給的並不全面。

--lld <driver> --mode account --op new --user <name> --password <pass>
--lld <driver> --mode account --op delete --user <name>
--lld <driver> --mode account --op bind --tid <id> --user <name> [--outgoing]
--lld <driver> --mode account --op unbind --tid <id> --user <name>

以下是個人發現的較為全面的用法,為了偷懶,所以使用短選項格式來表示。其中

# 新建一個用戶
-L <driver> -m account -o new --u <name> --p <pass>

# 刪除一個用戶
-L <driver> -m account -o delete --u <name>

# 查看用戶列表
-L <driver> -m account -o show

# 綁定用戶到target上,outgoing的意義在後文會說明
-L <driver> -m account -o bind -t <tid> -u <name> [--outgoing]

# 從target上解綁用戶
-L <driver> -m account -o unbind -t <tid> -u <name> [--outgoing]

4.3 實現CHAP單向認證

  1. 首先確保target的ACL是允許initiator進行discovery的。

    bash> tgt-admin -s | sed -n '/Account/,$p'
    Account information:
    ACL information:
        192.168.100.0/24
  2. 在target端創建initiator authentication所需的賬號和密碼並綁定到target_ID上。這個賬號是用來對initiator進行單向認證的,所以對於target而言是incoming賬號。

    tgtadm -L iscsi -m account -o new --user incoming_malong --password incoming_123456 
    tgtadm -L iscsi -m account -o bind -t 1 --user incoming_malong

    查看下綁定情況。

    tgt-admin -s | sed -n '/Account/,$p'
    Account information:
        incoming_malong
    ACL information:
        192.168.100.0/24
    由於tgtg的工作在內核當中的,所以配置好後無需重啟服務,這些賬號相關的就可以生效。
  3. 在initiator端修改配置文件/etc/iscsi/iscsid.conf,設置以下幾項,這裡故意沒啟用密碼認證部分,是為了看到認證失敗的結果。。(這裡使用的是伺服器B,即192.168.100.5這台機器,伺服器C即192.168.100.6在後面綁定多個賬號的時候拿來做測試用)

    vim /etc/iscsi/iscsid.conf
    node.session.auth.authmethod = CHAP
    node.session.auth.username = incoming_malong
    #node.session.auth.password = incoming_123456
  4. 在initiator發現,然後關聯。

    bash> iscsiadm -m discovery -t st -p 192.168.100.151:3260
    192.168.100.151:3260,1 iqn.2017-03.com.longshuai:test.disk1  
       
    bash> iscsiadm -m node -T iqn.2017-03.com.longshuai:test.disk1 -p 192.168.100.151:3260 -l
    Logging in to [iface: default, target: iqn.2017-03.com.longshuai:test.disk1, portal: 192.168.100.151,3260] (multiple)
    iscsiadm: Could not login to [iface: default, target: iqn.2017-03.com.longshuai:test.disk1, portal: 192.168.100.151,3260].
    iscsiadm: initiator reported error (24 - iSCSI login failed due to authorization failure)
    iscsiadm: Could not log into all portals

因為認證所需的密碼沒設置,所以認證失敗了。設置為正確的賬號和密碼再進行發現、關聯認證。

bash> vim /etc/iscsi/iscsid.conf
node.session.auth.authmethod = CHAP
node.session.auth.username = incoming_malong
node.session.auth.password = incoming_123456

bash> iscsiadm -m discovery -t st -p 192.168.100.151:3260
192.168.100.151:3260,1 iqn.2017-03.com.longshuai:test.disk1

bash> iscsiadm -m node -T iqn.2017-03.com.longshuai:test.disk1 -p 192.168.100.151:3260 -l
Logging in to [iface: default, target: iqn.2017-03.com.longshuai:test.disk1, portal: 192.168.100.151,3260] (multiple)
Login to [iface: default, target: iqn.2017-03.com.longshuai:test.disk1, portal: 192.168.100.151,3260] successful.

4.4 實現CHAP雙向認證

要雙向認證,那麼target端需要創建一個outgoing賬號和密碼,並綁定到target上。註意下麵的--outgoing選項,表示是從target流出的賬號,即表示該target要被initiator認證。

tgtadm -L iscsi -m account -o new --user outgoing_malong --password outgoing_123456
tgtadm -L iscsi -m account -o bind -t 1 --user outgoing_malong --outgoing

查看下target上的賬號信息。在信息中,outgoing的賬號後面使用括弧對此進行了標識。

tgt-admin -s | sed -n '/Account/,$p'
    Account information:
        incoming_malong
        outgoing_malong (outgoing)
    ACL information:
        192.168.100.0/24

然後在initiator端配置CHAP雙向認證。同樣,此處先配置一個錯誤的情況以作比較。

vim /etc/iscsi/iscsid.conf
node.session.auth.authmethod = CHAP
node.session.auth.username = incoming_malong
node.session.auth.password = incoming_123456
node.session.auth.username_in = outgoing_malong
#node.session.auth.password_in = outgoing_123456

重新進行發現和關聯。不過首先要登出已經登錄的target。

iscsiadm -m node -Tiqn.2017-03.com.longshuai:test.disk1 -p 192.168.100.151:3260 -u

iscsiadm -m discovery -t st -p 192.168.100.151:3260
192.168.100.151:3260,1 iqn.2017-03.com.longshuai:test.disk1

iscsiadm -m node -Tiqn.2017-03.com.longshuai:test.disk1 -p 192.168.100.151:3260 -l
Logging in to [iface: default, target: iqn.2017-03.com.longshuai:test.disk1, portal: 192.168.100.151,3260] (multiple)
iscsiadm: Could not login to [iface: default, target: iqn.2017-03.com.longshuai:test.disk1, portal: 192.168.100.151,3260].
iscsiadm: initiator reported error (19 - encountered non-retryable iSCSI login failure)
iscsiadm: Could not log into all portals

它提示遇到不可重試的iscsi登錄錯誤,因為target無法被initiator認證,initiator認為這個target是非法的target。

配置為正確的密碼然後再進行發現、關聯。

vim /etc/iscsi/iscsid.conf
node.session.auth.authmethod = CHAP
node.session.auth.username = incoming_malong
node.session.auth.password = incoming_123456
node.session.auth.username_in = outgoing_malong
node.session.auth.password_in = outgoing_123456

iscsiadm -m discovery -t st -p 192.168.100.151:3260
iscsiadm -m node -Tiqn.2017-03.com.longshuai:test.disk1 -p 192.168.100.151:3260 -l

4.5 綁定多個outgoing賬號

tgtadm -L iscsi -m account -o new --user outgoing_user1 --password outgoing_passwd1

tgtadm -L iscsi -m account -o bind -t 1 --user outgoing_user1 --outgoing
tgtadm: this target already has an outgoing account

綁定的時候提示已經有一個outgoing賬號,說明一個target的outgoing賬號只能有一個。也就是說,某一個target被認證的時候是1對多的關係。

但是incoming賬號並非如此。

4.6 綁定多個incoming賬號

tgtadm -L iscsi -m account -o new --user incoming_user1 --password incoming_passwd1
tgtadm -L iscsi -m account -o new --user incoming_user2 --password incoming_passwd2 
tgtadm -L iscsi -m account -o bind -t 1 --user incoming_user1   
tgtadm -L iscsi -m account -o bind -t 1 --user incoming_user2 

tgt-admin -s | sed -n '/Account/,$p'
    Account information:
        incoming_malong
        incoming_user1
        incoming_user2
        outgoing_malong (outgoing)
    ACL information:
        192.168.100.0/24

用伺服器C即192.168.100.6來登錄一個看看。

vim /etc/iscsi/iscsid.conf
node.session.auth.authmethod = CHAP
node.session.auth.username = incoming_user1
node.session.auth.password = incoming_passwd1
node.session.auth.username_in = outgoing_malong
node.session.auth.password_in = outgoing_12345

發現並關聯。

iscsiadm -m node -U all
iscsiadm -m discovery -t st -p 192.168.100.151:3260
iscsiadm -m node -T iqn.2017-03.com.longshuai:test.disk1 -p 192.168.100.151:3260 -l

所以,incoming賬號可以有多個。

4.7 解綁和刪除用戶

先查看下有目前有哪些用戶。

tgtadm -L iscsi -m account -o show
Account list:
    outgoing_user1
    incoming_user2
    incoming_user1
    outgoing_malong
    incoming_malong

再查看下哪些用戶是已經綁定到target上的。

tgt-admin -s | sed -n '/Account/,$p'
    Account information:
        incoming_malong
        incoming_user1
        incoming_user2
        outgoing_malong (outgoing)
    ACL information:
        192.168.100.0/24

對incoming_user1和incoming_user2進行解綁。

tgtadm -L iscsi -m account -o unbind -t 1 -u incoming_user1
tgtadm -L iscsi -m account -o unbind -t 1 -u incoming_user2

對outgoing賬戶解綁。

tgtadm -L iscsi -m account -o unbind -t 1 -u outgoing_malong --outgoing

刪除多餘的賬戶。

tgtadm -L iscsi -m account -o delete -u incoming_user1 
tgtadm -L iscsi -m account -o delete -u incoming_user2
tgtadm -L iscsi -m account -o delete -u outgoing_malong
tgtadm -L iscsi -m account -o delete -u outgoing_user1 

第5章 快速配置iscsi兩端

這裡是對前文的一個總結,用於解釋要使用iscsi時對target端和initiator大致需要做哪些事情。

#############################
# target端所需要做的事情
#############################

tgtadm -L iscsi -m target -o new -t 1 -T iqn.2017-03.com.longshuai:test1.disk1
tgtadm -L iscsi -m logicalunit -o new -t 1 -l 1 -b /dev/sdb1
tgtadm -L iscsi -m logicalunit -o new -t 1 -l 2 -b /dev/sdc
tgtadm -L iscsi -m target -o bind -t 1 -I 192.168.100.0/24

#如果要CHAP認證,則繼續添加相關賬戶和密碼並綁定到target上
tgtadm -L iscsi -m account -o new -u USERNAME -p PASSWORD
tgtadm -L iscsi -m account -o bind -t 1 -u USERNAME [--outgoing]

#最後將配置放入到配置文件中
sed -i -r 's/#include(.*)/include\1/' /etc/tgt/targets.conf
mkdir /etc/tgt/temp
tgt-admin --dump | sed '/default/d' >/etc/tgt/temp/tgt1.conf

#不用重啟服務。
#如特殊情況,出現重啟tgtd伺服器但是配置文件不生效的情況,適應force-reload選項
#service tgtd force-reload


#############################
# initiator端所需要做的事情
#############################

#第一件事是決定是否要自定義initiator的名稱,如果需要自定義,則修改/etc/iscsi/initiatorname.iscsi文件
#首先discovery目標主機上有哪些可用的target
iscsiadm -m discovery -t st -p 192.168.100.151:3260

# 然後登陸target
iscsiadm -m node -T iqn.2017-03.com.longshuai:test1.disk1 -p 192.168.100.151:3260 -l

#如果需要CHAP認證,則啟用/etc/iscsi/iscsid.conf中的相關CHAP認證指令
#前三項實現單向認證,target端認證initiator是否合法
#同時啟用這5項實現雙向認證,target端和initiator都會認證對方是否合法
node.session.auth.authmethod = CHAP
node.session.auth.username = incoming_malong
node.session.auth.password = incoming_123456
node.session.auth.username_in = outgoing_malong
node.session.auth.password_in = outgoing_123456

第6章 windows上配置initiator

在"運行"中輸入iscsicpl.exe,打開iscsi發起程式。

但要註意,Windows中格式化的NTFS文件系統在Linux中預設是不支持的,所以iscsi的共用存儲不能跨Windows和Linux系統使用,除非安裝支持插件。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在做後臺管理系統的同學們,是否有用easyui的經歷。雖然現在都是vue、ng、react的時代。但easyui(也就是jquery為基礎)還是占有一席之地的。因為他對後端開發者太友好了,太熟悉不過了。要讓一個後端開發者來理解vue或者是react的VNode、狀態器、組件等,都是有那麼一點點的為難 ...
  • .NET Orm 性能測試 簡介 "OrmBenchmark" 這個項目主要是為了測試主要的Orm對於 SqlServer 資料庫的查詢並將數據轉換成所需 POCO 對象的耗時情況(好吧,實際上不完全orm,更像是SqlMapper ...) 測試結果: .NetFramework 4.6 有預熱 ...
  • 博客四元素 既然要寫一個博客類的網站,那就應該知道博客的相關信息。 標題|作者|時間|內容 | | | title|author|time|content 因為之前有瞭解過Redis,所以有點糾結於數據的存儲方式,最終決定還是按照書上寫的一步一步來,搞完了之後再決定是不是需要做修改。 書中介紹的存儲 ...
  • 正則表達式就是處理字元串的方法,它是以行為單位來進行字元串的處理行為,正則表達式通過一些特殊符號的輔助,可以讓用戶輕易達到查找、刪除、替換某特定字元串的處理程式。正則表達式基本上是一種“表示法”,只要工具支持這種表示法,那麼該工具就可以用來作為正則表達式的字元串處理之用。 ...
  • 用64位windows10的CMD命令安裝pip install scrapy出錯: Running setup.py bdist_wheel for Twisted ... error Failed building wheel for Twisted Running setup.py clean ...
  • sed是一個很強大的文件處理工具,主要是以行為單位進行處理,可以將數據行進行替換、刪除、新增、選取等特定工作 格式:sed [option] [command] [file] 常用命令: a ∶新增 c ∶取代 d ∶刪除 i ∶插入 p ∶列印 s ∶取代 選項: -i∶直接修改讀取的檔案內容,而 ...
  • 今天主要跟大家介紹2個非常霸道的工具,sed和awk,本篇文章將介紹這兩個工具在日常運維中的常用用法,工作中這兩個工具要掌握好了在結合一些管道命令、正則表達式,日常處理事務簡直666啦! l Sed 1.強大的地方 擅長對數據行進行處理,sed是一種流編輯器,處理時,把當前處理的行存儲在臨時緩衝區中 ...
  • 切換許可權: sudo chown -R 許可權名: 文件 tar -zcvf 文件夾.tar 文件夾--exclude=要過濾的文件夾路徑 重啟crontab :service crond restart 查看目錄占用磁碟大小 du -sh * 切換許可權: sudo su或者su root 切換roo ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...