DNA 포럼 API 서비스 모음 DNA Lens

서버간 메모리 동기화


  • 김중근(인프라본부 시스템기술팀), 2007년 1월

초록(Abstract)

서버간 특정영역 혹은 사용하고 있는 전체 메모리가 일치해야하는 경우가 있다. 여러가지 방법이 있으나 가장 간단한 방법을 예를 들어 표현해보려고 한다. 이번에 소개하는 방법은 NFS, MMAP, 그리고 Ram Disk를 사용했으며 성능치도 뽑아보았다. 사실 직접적인 메모리 동기화가 아닌 nfs로 연결된 ramdisk 파일을 mmap을 이용하여 메모리에 엑세스하는 것처럼 그대로 사용한 방식이다.

OS Setting #

  • 먼저 Ram Disk를 잡고 그 안에 파일을 생성한 뒤 NFS Server를 실행시켜 해당 마운트 포인트를 export한다.
  • NFS server 에서도 그 마운트 포인트를 바로 엑세스하면 안되고 mount 서버IP:/마운트포인트이런 형식으로 nfs mount를 해야한다. (mmap이 Update Time을 기록하지 않는다. Kernel 2.6)

  • NFS Server 상태
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1              4134900   2988756    936096  77% /
none                   1037468         0   1037468   0% /dev/shm
/dev/sda3             11432640   8116576   2735316  75% /data
/dev/ram0                15863      4253     10791  29% /ram
127.0.0.1:/ram           15872      4256     10816  29% /rr

  • NFS Client 상태
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1              4134900   2432048   1492804  62% /
none                   1027716         0   1027716   0% /dev/shm
/dev/sda3             29071616  24073352   4702912  84% /data
NFS Server IP:/ram        15872      4256     10816  29% /ram

보안상 NFS Server IP를 표현하지 않았다.

결과 #

  • 동시에 Server및 Client에서 프로그램 실행.
  • 4M의 영역을 2048번 엑세스한 값의 건당 평균 결과이다.
  • Test1 에서 mmap을 이용하여 Access 를 하며 Test2 에서는 로컬 메인메모리를 엑세스한 결과이다.

  • NFS Server
[root@서버1 /hanmail/user] ./test

Test1
Memory Mapping Address: 0xB7B02000

Count : 2047

Sync. Read               0.002398 Sec.
SYnc. Write              0.004640 Sec.


Test2
Memory Address: 0xB7700008

Count : 2047

Priv. Read               0.002606 Sec.
Priv. Write              0.004740 Sec.

  • NFS Client
[root@서버2 /hanmail/user] ./test 

Test1
Memory Mapping Address: 0xB71EB000

Count : 2047

Sync. Read               0.002665 Sec.
SYnc. Write              0.004579 Sec.


Test2
Memory Address: 0xB6DE9008

Count : 2047

Priv. Read               0.002823 Sec.
Priv. Write              0.004621 Sec.

Source #

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <linux/rtc.h>
#include <errno.h>

#define DEVICE_NAME     "/rr/ram.dat" //Client "/ram/ram.dat"
#define LOOP_CNT        2048


void    calc(struct timeval *s, struct timeval *e, struct timeval *res)
{
        struct  timeval r;

        if(s->tv_usec > e->tv_usec) {
                r.tv_usec = (1000000 + e->tv_usec) - s->tv_usec;
                r.tv_sec = e->tv_sec - s->tv_sec - 1;
        } else {
                r.tv_usec = e->tv_usec - s->tv_usec;
                r.tv_sec = e->tv_sec - s->tv_sec;
        }

        if(res == NULL)
                printf("Diff %u.%06u Sec.\n", r.tv_sec, r.tv_usec);
        else
                memcpy(res, &r, sizeof(struct timeval));
}

unsigned int            mmap_fd;
size_t                  mmap_size;

char    *sync_malloc(size_t s)
{
        char    *ret;

        mmap_size = s;
        if((mmap_fd = open(DEVICE_NAME, O_RDWR | O_SYNC)) == -1) {
                fprintf(stderr, "Device Open Error (%s)\n", DEVICE_NAME);
                return NULL;
        }

        if((ret = (char *)mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, 0)) == MAP_FAILED) {
                close(mmap_fd);
                return NULL;
        }

        return  ret;
}

void    sync_free(char *s)
{
        munmap(s, mmap_size);
        close(mmap_fd);
}

int     main(int        argc, char *argv)
{
        int                     j, i;
        unsigned char   *vret;
        struct  timeval start, end, wres[LOOP_CNT], rres[LOOP_CNT], rtot, wtot;
        char    buf[1024];


        srand(time(NULL));

        vret = sync_malloc(4*1024*1024);
        if(vret == NULL) {
                fprintf(stderr, "Allocation Error\n");
        }

        printf("\nTest1\nMemory Mapping Address: 0x%08X\n\n", vret);

        memset(&rtot, 0, sizeof(struct timeval));
        memset(&wtot, 0, sizeof(struct timeval));

        for(j = 0; j < LOOP_CNT; j++) {

                gettimeofday(&start, NULL);
                for(i = 0; i < 1024*4*1024;i+=1024) {
                        memcpy(buf, vret + i, 1024);
                }
                gettimeofday(&end, NULL);

                calc(&start, &end, &rres[j]);

                memset(buf, rand(), 1024);

                gettimeofday(&start, NULL);
                for(i = 0; i < 1024*4*1024;i+=1024) {
                        memcpy(vret + i, buf, 1024);
                }
                gettimeofday(&end, NULL);

                calc(&start, &end, &wres[j]);

                rtot.tv_sec += rres[j].tv_sec;
                rtot.tv_usec += rres[j].tv_usec;
                wtot.tv_sec += wres[j].tv_sec;
                wtot.tv_usec += wres[j].tv_usec;

                printf("Count : %d\r", j);
        }

        printf("\n\nSync. Read\t\t %u.%06u Sec.\n", rtot.tv_sec / LOOP_CNT, rtot.tv_usec / LOOP_CNT);
        printf("SYnc. Write\t\t %u.%06u Sec.\n", wtot.tv_sec / LOOP_CNT, wtot.tv_usec / LOOP_CNT);

        sync_free(vret);

        vret = malloc(4*1024*1024);
        if(vret == NULL) {
                fprintf(stderr, "Allocation Error\n");
        }

        printf("\n\nTest2\nMemory Address: 0x%08X\n\n", vret);

        memset(&rtot, 0, sizeof(struct timeval));
        memset(&wtot, 0, sizeof(struct timeval));

        for(j = 0; j < LOOP_CNT; j++) {

                gettimeofday(&start, NULL);
                for(i = 0; i < 1024*4*1024;i+=1024) {
                        memcpy(buf, vret + i, 1024);
                }
                gettimeofday(&end, NULL);

                calc(&start, &end, &rres[j]);

                memset(buf, rand(), 1024);

                gettimeofday(&start, NULL);
                for(i = 0; i < 1024*4*1024;i+=1024) {
                        memcpy(vret + i, buf, 1024);
                }
                gettimeofday(&end, NULL);

                calc(&start, &end, &wres[j]);

                rtot.tv_sec += rres[j].tv_sec;
                rtot.tv_usec += rres[j].tv_usec;
                wtot.tv_sec += wres[j].tv_sec;
                wtot.tv_usec += wres[j].tv_usec;

                printf("Count : %d\r", j);
        }

        printf("\n\nPriv. Read\t\t %u.%06u Sec.\n", rtot.tv_sec / LOOP_CNT, rtot.tv_usec / LOOP_CNT);
        printf("Priv. Write\t\t %u.%06u Sec.\n", wtot.tv_sec / LOOP_CNT, wtot.tv_usec / LOOP_CNT);

        free(vret);
}