linux共享存儲空間
㈠ 架構師進階:linux進程間如何共享內存
共享內存 IPC 原理
共享內存進程間通信機制主要用於實現進程間大量的數據傳輸,下圖所示為進程間使用共享內存實現大量數據傳輸的示意圖:
640
共享內存是在內存中單獨開辟的一段內存空間,這段內存空間有自己特有的數據結構,包括訪問許可權、大小和最近訪問的時間等。該數據結構定義如下:
from /usr/include/linux/shm.h
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms 操作許可權 */
int shm_segsz; /* size of segment (bytes) 段長度大小 */
__kernel_time_t shm_atime; /* last attach time 最近attach時間 */
__kernel_time_t shm_dtime; /* last detach time 最近detach時間 */
__kernel_time_t shm_ctime; /* last change time 最近change時間 */
__kernel_ipc_pid_t shm_cpid; /* pid of creator 創建者pid */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator 最近操作pid */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */|
};
兩個進程在使用此共享內存空間之前,需要在進程地址空間與共享內存空間之間建立聯系,即將共享內存空間掛載到進程中。
系統對共享內存做了以下限制:
#define SHMMAX 0x2000000 /* max shared seg size (bytes) 最大共享段大小 */
#define SHMMIN 1 /* min shared seg size (bytes) 最小共享段大小 */
#define SHMMNI 4096 /* max num of segs system wide */
#define SHMALL (SHMMAX/getpagesize()*(SHMMNI/16))|
define SHMSEG SHMMNI /* max shared segs per process */
Linux 共享內存管理
1.創建共享內存
#include <sys/ipc.h> #include <sys/shm.h>
/*
* 第一個參數為 key 值,一般由 ftok() 函數產生
* 第二個參數為欲創建的共享內存段大小(單位為位元組)
* 第三個參數用來標識共享內存段的創建標識
*/
int shmget(key_t key, size_t size, int shmflg);
2.共享內存控制
#include <sys/ipc.h> #include <sys/shm.h>
/*
* 第一個參數為要操作的共享內存標識符
* 第二個參數為要執行的操作
* 第三個參數為 shmid_ds 結構的臨時共享內存變數信息
*/
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
3.映射共享內存對象
系統調用 shmat() 函數實現將一個共享內存段映射到調用進程的數據段中,並返回內存空間首地址,其函數聲明如下:
#include <sys/types.h>
#include <sys/shm.h>
/*
* 第一個參數為要操作的共享內存標識符
* 第二個參數用來指定共享內存的映射地址,非0則為此參數,為0的話由系統分配
* 第三個參數用來指定共享內存段的訪問許可權和映射條件
*/
void *shmat(int shmid, const void *shmaddr, int shmflg);
4.分離共享內存對象
在使用完畢共享內存空間後,需要使用 shmdt() 函數調用將其與當前進程分離。函數聲明如下:
#include <sys/types.h>
#include <sys/shm.h>
/*
* 參數為分配的共享內存首地址
*/
int shmdt(const void *shmaddr);
共享內存在父子進程間遵循的約定
1.使用 fork() 函數創建一個子進程後,該進程繼承父親進程掛載的共享內存。
2.如果調用 exec() 執行一個新的程序,則所有掛載的共享內存將被自動卸載。
3.如果在某個進程中調用了 exit() 函數,所有掛載的共享內存將與當前進程脫離關系。
程序實例
申請一段共享內存,父進程在首地址處存入一整數,子進程讀出。
#include
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include
#include
#define SHM_SIZE 1024
int main()
{
int shm_id, pid;
int *ptr = NULL;
/* 申請共享內存 */
shm_id = shmget((key_t)1004, SHM_SIZE, IPC_CREAT | 0600);
/* 映射共享內存到進程地址空間 */
ptr = (int*)shmat(shm_id, 0, 0);
printf("Attach addr is %p ", ptr);
*ptr = 1004;
printf("The Value of Parent is : %d ", *ptr);
if((pid=fork()) == -1){
perror("fork Err");
exit(0);
}
else if(!pid){
printf("The Value of Child is : %d ", *ptr);
exit(0);
}else{
sleep(1);
/* 解除映射 */
shmdt(ptr);
/* 刪除共享內存 */
shmctl(shm_id, IPC_RMID, 0);
}
return 0;
}
輸出結果:
640
㈡ 如何設置linux的共享內存
在 Linux 中設置共享內存的方法有很多種,下面是一種常用的方法:
使用shmget()函數創建一塊共享內存,可以指定共享內存的大小和標識符。
使用shmat()函數將共享內存連接到進程的地址空間,返回指向共享內存的指針。
使用shmdt()函數斷開與共享內存的連接。
使用shmctl()函數刪除共享內存。
具體實現可以參考以下代碼示例:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
int main() {
// 1. 創建共享內存
int shmid = shmget(IPC_PRIVATE, 100, 0666 | IPC_CREAT);
if (shmid < 0) {
perror("shmget error");
return 1;
}
// 2. 連接共享內沒瞎存
void *shm = shmat(shmid, NULL, 0);
if (shm == (void *)-1) {
perror("shmat error");
return 1;
}
// 使用共享內存
// ...
// 3. 斷開連接
if (shmdt(shm) < 0) {
perror("shmdt error");
return 1;
}
// 4. 刪除共享內存
if (shmctl(shmid, IPC_RMID, 0) < 0) {
perror("shmctl error");
return 1;
}
return 0;
}
這是一個簡單的示枯雹空例,在這里我們創建了一個大小為100位元組的共享內肆備存,並使用shmget()、shmat()、shmdt()、shmctl()四個函數來創建、連接、斷開連接、刪除共享內存。
在實際應用中,我們需要根據需要來調整共享內存的大小,並在使用共享內存時進行相應的同步和互斥操作來保證數據的安全性。
需要注意的是,在使用共享內存時,我們需要確保共享內存在進程全部退出後能夠被釋放,這可以通過在父進
程中刪除共享內存來實現。另外在程序中也要考慮到異常處理,如果在程序運行過程中發生了異常,應該及時釋放所佔用的共享內存,以免造成資源浪費。
另外需要提醒的是,共享內存是一種高級的IPC(Inter-Process Communication)機制,使用時需要謹慎,避免出現數據競爭和死鎖等問題。
㈢ linux系統如何建一個用戶並給他分配1G的存儲空間
要麼做磁碟配額,這個比較復雜,悉殲要麼就分配一個1g的空間,掛載培陸滾到某處配余,再創建用戶的時候制定這個目錄為用戶的home即可
㈣ 探討一下 Linux 共享內存的 N 種方式
關於 Linux 共享內存,寫得最好的應該是宋寶華的 《世上最好的共享內存》 一文。
本文可以說是對這篇文章的學習筆記,順手練習了一下 rust libc —— shichaoyuan/learn_rust/linux-shmipc-demo
按照宋寶華的總結,當前有四種主流的共享內存方式:
前兩種方式比較符合傳統的用法,共享內存做為進程間通信的媒介。
第三種方式更像是通過傳遞內存「句柄」進行數據傳輸。
第四種方式是為設備間傳遞數據設計,避免內存拷貝,直接傳遞內存「句柄」。
這里嘗試了一下第二種和第三種方式。
這套 API 應該是最普遍的 —— shm_open + mmap,本質上來說 Aeron 也是用的這種方式(關於 Aeron 可以參考 我之前的文章 )。
看一下 glibc 中 shm_open 函數的實現就一清二楚了:
shm_open 函數就是在 /dev/shm 目錄下建文件,該目錄掛載為 tmpfs,至於 tmpfs 可以簡單理解為存儲介質是內存的一種文件系統,更准確的理解可以參考官方文檔 tmpfs.txt 。
然後通過 mmap 函數將 tmpfs 文件映射到用戶空間就可以隨意操作了。
優點:
這種方式最大的優勢在於共享的內存是有「實體」(也就是 tmpfs 中的文件)的,所以多個進程可以很容易通過文件名這個信息構建共享內存結構,特別適合把共享內存做為通信媒介的場景(例如 Aeron )。
缺點:
如果非要找一個缺點的話,可能是,文件本身獨立於進程的生命周期,在使用完畢後需要注意刪除文件(僅僅 close 是不行的),否則會一直佔用內存資源。
memfd_create 函數的作用是創建一個匿名的文件,返回對應的 fd,這個文件當然不普通,它存活在內存中。更准確的理解可以參考官方文檔 memfd_create(2) 。
直觀理解,memfd_create 與 shm_open 的作用是一樣的,都是創建共享內存實體,只是 memfd_create 創建的實體是匿名的,這就帶了一個問題:如何讓其它進程獲取到匿名的實體?shm_open 方式有具體的文件名,所以可以通過打開文件的方式獲取,那麼對於匿名的文件怎麼處理呢?
答案是:通過 Unix Domain Socket 傳遞 fd。
rust 的 UDS 實現:
rust 在 std 中已經提供了 UDS 的實現,但是關於傳遞 fd 的 send_vectored_with_ancillary 函數還屬於 nightly-only experimental API 階段。所以這里使用了一個三方 crate —— sendfd ,坦白說可以自己實現一下,使用 libc 構建好 SCM_RIGHTS 數據,sendmsg 出去即可,不過細節還是挺多,我這里就放棄了。
這套 API 設計更靈活,直接拓展了我的思路,本來還是受限於 Aeron 的用法,如果在這套 API 的加持下,是否可以通過傳遞數據包內存塊(fd)真正實現零拷貝呢?
優點:
靈活。
缺點:
無
㈤ multipath多路徑,Linux系統底層存儲擴容了,如何擴大文件系統
linux伺服器通過multipath多路徑連接到共享存儲,那麼當文件系統空間不足的時候,有幾種方式可以擴展文件系統的大小:
1、pv不變,原lun存儲擴大容量,擴大lv,擴大文件系統
2、新增pv,加入到vg中,擴大lv,擴大文件系統
下文是針對場景1的情況下如何操作(但是個人建議採取新建pv的方式2進行):
Environment
If you have this specific scenario, you can use the following steps:
Note: if these lv's are part of a clustered vg, steps 1 and 2 need to be performed on all nodes. 注意:集群模式下步驟1和步驟2兩個節點都需要執行。
1) Update block devices
Note: This step needs to be run against any sd devices mapping to that lun. When using multipath, there will be more than one. 通過multipath -ll命令查看每個聚合卷對應的路徑。
2) Update multipath device
例子:
3) Resize the physical volume, which will also resize the volume group
4) Resize your logical volume (the below command takes all available space in the vg)
5) Resize your filesystem
6) Verify vg, lv and filesystem extension has worked appropriately
模擬存儲端擴容testlv增加
查看客戶端多路徑情況
客戶端更新存儲
更新聚合設備
更新pv空間
更新lv空間
更新文件系統空間
㈥ linux共享內存存在於進程空間的什麼位置
共享內存方式:從物理內存裡面拿出來一部分作為多個進程共享。 共享內存是進程間共享數據的一種最快的方法,一個進程向共享內存區域寫入數據,共享這個內存的所有進程都可以立即看到其中內容。 共享內存實現步驟: 一、創建共享內存,使用shmget函數。 二、映射共享內存,將這段創建的共享內存映射到具體的進程空間去,使用shmat函數。 創建共享內存shmget: intshmget(key_t key, size_t size, int shmflg) 功能:得到一個共享內存標識符或創建一個共享內存對象並返回共享內存標識符。 key: 0(IPC_PRIVATE)會建立共享內存對象 size:大於0的整數,新建共享內存的大小,以位元組為單位。只獲取共享內存時,指定為0. shmflg: 0表示取共享內存標識符,如不存在則函數會報錯; IPC_CREAT,如果內核中不存在鍵值與key相等的共享內存時,則創建一個共享內存;如果存在這樣的共享內存則返回共享內存的標識符; IPC_CREATIPC_EXCL: 如果內核中不存在鍵值與key相等的共享內存,則新建一個消息隊列;如果存在這樣的共享內存則報錯; 函數返回值:成功則返回內存的標識符;出錯則返回-1,錯誤原因存在於error中 映射共享內存到調用進程的地址空間shmat: void*shmat(int shmid, const void *shmaddr, int shmflg) msqid:共享內存標識符 shmaddr:指定共享內存出現在進程內存地址的什麼位置,直接指定為NULL讓內核自己決定一個合適的地址位置。 shmflg: SHM_RDONLY 只讀模式,其他為讀寫模式 函數返回值:成功則返回附加好的共享內存地址;出錯返回-1,錯誤原因存在於error中 斷開共享內存連接shmdt: intshmdt(const void *shmaddr) 功能:傳入shmaddr,連接共享的內存起始地址;斷開成功則返回0,出錯則返回-1,錯誤原因存在於error中。 父子進程間通訊實例: #include #include #include #include #include #include int main(int argc, char **argv){ if(argc< 2){ //需要輸入共享的數據 printf("pleaseinput the shared data.n"); exit(-1); } intshmid; shmid= shmget(0,1024,IPC_CREAT); if(shmid== -1){ // 申請共享內存失敗 printf("createshare memory failed.n"); exit(-1); } if(fork()){ // 父進程之中 char*p_shmaddr; p_shmaddr= shmat(shmid, NULL, 0); // 映射到父進程之中的一個地址 memset(p_shmaddr,0, 1024); // 初始化共享內存 strcpy(p_shmaddr,argv[1]); // 拷貝共享數據到共享內存 wait(NULL); //等待子進程結束 exit(0); } else{ sleep(2); //等待父進程寫入數據 char*c_shmaddr; c_shmaddr= shmat(shmid,NULL,0); // 映射到子進程之中一個地址,具體由kernel 指配 printf("theshare data is: %sn", c_shmaddr); //子進程輸出共享的數據 exit(0); } }
㈦ linux查看共享內存命令
共享內存查看
使用ipcs命令,不加如何參數時,會把共享內存、信號量、消息隊列的信息都列印出來,如果只想顯示共享內存信息,使用如下命令:
[root@localhost ~]# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 1867776 root 600 393216 2 dest
0x00000000 1900545 root 600 393216 2 dest
0x00030021 1703938 zc 666 131104 1
0x0003802e 1736707 zc 666 131104 1
0x00030004 1769476 zc 666 131104 1
0x00038002 1802245 zc 666 131104 1
0x00000000 1933318 root 600 393216 2 dest
0x00000000 1966087 root 600 393216 2 dest
0x00000000 1998856 root 600 393216 2 dest
0x00000000 2031625 root 600 393216 2 dest
0x00000000 2064394 root 600 393216 2 dest
0x0014350c 2261003 cs 666 33554432 2
0x00000000 2129932 root 600 393216 2 dest
0x00000000 2162701 root 600 393216 2 dest
0x00143511 395837454 root 666 1048576 1
其中:
第一列就是共享內存的key;
第二列是共享內存的編號shmid;
第三列就是創建的用戶owner;
第四列就是許可權perms;
第五列為創建的大小bytes;
第六列為連接到共享內存的進程數nattach;
第七列是共享內存的狀態status。其中顯示「dest」表示共享內存段已經被刪除,但是還有用戶在使用它,當該段內存的mode欄位設置為SHM_DEST時就會顯示「dest」。當用戶調用shmctl的IPC_RMID時,內存先查看多少個進程與這個內存關聯著,如果關聯數為0,就會銷毀這段共享內存,否者設置這段內存的mod的mode位為SHM_DEST,如果所有進程都不用則刪除這段共享內存。