반응형

클라우데라 하둡 네임노드 변경 작업 (노후화된 서버 장비 교체) 문제로 발생한 이슈에 대해 간략히 남겨보려 한다.

먼저 하둡 네임노드(Hadoop Namenode)의 가장 큰 역할은 하둡 HDFS 파일과 관련된 메타데이터를 관리하는 핵심 역할을 한다. 네임노드가 문제가 생기면 하둡에 있는 파일을 읽지 못하는 크리티컬한 이슈가 발생할 수 있다. 

보통 하둡클러스터의 네임노드를 통해 클러스터간 distcp가 진행되기 때문에 외부 클러스터에서 변경하려는 네임노드를 바라보고 있는지 확인하는 작업이 필요하고 클라우데라 설치되지 않은 Spark(스파크)의 설정파일에서도 별도로 네임노드를 변경해주어야 한다.

보통은 클라우데라 하둡설정에서 네임노드 재지정하고 재시작하면 클러스터에 종속된 시스템들의 설정이 변경되서 올라간다.

오늘 포스팅을 남기는 이유는 클라우데라에 설치된 Hive는 네임노드가 변경되고 재시작 되더라도 스스로 신규 네임노드를 Location을 바라보지 않아 이슈가 생겼기 때문이다.(전혀 예상하지 못함...)

Hive의 external table들은 생성되며 기본적으로 관련 메타데이터가 클라우데라 메타데이터를 관리하는 PostgreSQL 데이터베이스에 저장되는데 이부분을 명시로 수정해주어야 한다. 

보통은 이렇게 수동으로 말고 hive의 metatool을 이용해 변경하는 방법도 있다고 하지만 운영하고 있는 클러스터에서는 먹히지 않았다.

Metatool을 통한 NameNode locatcion update 관련내용은 아래 링크 참고

https://cwiki.apache.org/confluence/display/Hive/Hive+MetaTool

반응형
반응형

최근 운영하고 있는 하둡 클러스터의 노후 장비 교체건으로 데이터노드 한대를 제거 하는 작업이 진행되었다.

해당 로그는 클러스터에 붙어 hdfs을 쓰고 있던 외부 서버에서 발생한 로그이다.

org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.server.namenode.LeaseExpiredException): No lease on /user/example....log._COPYING_ (inode 428475201): File does not exist. Holder DFSClient_NONMAPREDUCE_-1052637306_1 does not have any open files.

로그가 발생한 이유는 해당 서버가 hdfs 해당 데이터노드 특정 파일에 write작업을 하고 있었는데 중간에 데이터노드가 내려가면서 write하고 있던 파일을 찾지 못해 발생한 것이다. 

HDFS에서 Lease는 다음과 같이 정의된다.

In HDFS these locks are called Leases. Leases are granted to a client which request to open a file for a write operation (e.g. create / append / truncate a file.) Every lease belongs to a single HDFS Client but could be for several HDFS files. Often enough a lease has several thousand files open for write by a single HDFS client. As the client opens and closes files, the appropriate lease must be identified and updated. The exact datastructures have been changed quite frequently over the years to provide better lookups, better reverse lookups, speed and space efficiency etc. However all this accounting obviously is done on the NameNode. This is in stark contrast to GFS, where a lease is tracked by the Namenode (master server in their parlance) and Datanodes (chunk servers in their parlance) (Section 3.1 in the Google File System paper). For HDFS this means the Namenode has a higher overhead of now maintaining these leases (something GFS expressly wanted to avoid). However this also allows HDFS to allow renames of files being written (which in my experience is not too uncommon an operation.)

 

이 경우 외에도 스파크(Spark)나 hive의 병렬 작업시에도 작업이 꼬여 발생할 수 있다는 걸 검색을 하다가 알게되었다.

해당 내용은 아래의 블로그를 참고하길 바란다.

https://knight76.tistory.com/entry/hadoop-No-lease-on-File-does-not-exist

 

[hadoop] No lease on .. File does not exist.

org.apache.hadoop.ipc.RemoteException: No lease on /google/public_plus/20181127/23_merged (inode 2683729964): File does not exist. [Lease. Holder: DFSClient_NONMAPREDUCE_-39928930_1, pending creates..

knight76.tistory.com

 

반응형
반응형

특정서비스의 로그를 spark으로 분석하기 위해 하둡커맨드 서버로 데이터를 가져와 hdfs에 put하는 과정 중 발생한 내용이다.

 

특정서비스(10대 서버)에서 한 달치의 로그(약 4.4g - 각 서버당)를 커맨드서버에서 wget으로 가져와 작업을 진행하였다.

 

wget으로 network bandwidth 옵션을 줘서 네트워크 대역폭을 모두 사용하지 않도록 했어야했지만 별다른 생각없이 wget을 하게 되었다.

 

문제는 해당 하둡 클러스터가 카프카(KAFKA)와 연결되어 있고 실시간으로 consuming하여 streaming하는 서비스에서 발생하였다.

 

네트쿼으 대역폭을 모두 사용하게 되어 카프카로부터 정상적인 컨슈밍이 되지 못했던 것이다.

 

앞으로는 데이터를 하둡클러스터로 가져올 때 혹은 다른 서버로 데이터를 옮길 때 항상 wget에 network bandwidth옵션을 주도록 하자.

 

wget으로 가져오는 과정에서 네트워크 인바운드가 훅....튀었다.

 

ex) wget으로 데이터가져올 때 limit으로 50kbyte를 주는 예시

wget --limit-rate=50k {데이터 떙겨올 서버주소}

--limit-rate=amount Limit the download speed to amount bytes per second. Amount may be expressed in bytes, kilobytes with the k suffix, or megabytes with the m suffix. For example, --limit-rate=20k will limit the retrieval rate to 20KB/s. This is useful when, for whatever reason, you don't want Wget to consume the entire available bandwidth.

 

주의하도록하자!!!

반응형
반응형

새롭게 구축한 클러스터에 기존 하둡클러스터의 데이터를 distcp를 하려고했을 때 다음과 같은 에러가 발생했다.

[irteam@am~~~server ~]$ hadoop distcp -m 30 -bandwidth 10 /user/hdfs1/20190916 hdfs://newcluster:8020/user/hdfs/20190916

19/09/24 14:02:47 ERROR tools.DistCp: Invalid arguments:
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.ipc.StandbyException): Operation category READ is not supported in state standby. Visit https://s.apache.org/sbnn-error
        at org.apache.hadoop.hdfs.server.namenode.ha.StandbyState.checkOperation(StandbyState.java:88)
.
.
(생략)
.   
Invalid arguments: Operation category READ is not supported in state standby. Visit https://s.apache.org/sbnn-error
.
(생략)
.  

문제는 신규클러스터의 standby의 네임노드 주소로 distcp를 하려고 하였던게 원인이였다.

active상태의 네임노드의 주소로 바꾸어주니 정상적으로 되었다.

 

distcp를 할 떄는 active상태의 namenode주소로 해주어야 한다!

반응형
반응형

이번에 hadoop mapreduce작업을 진행하는겸 reducer개수 설정에 따라 처리속도가 어떻게 달라지는지 간단히 확인해보았다.

(물론 cluster의 환경 작업의 데이터처리 사이즈 및 작업의 종류에 따라 달라질 수 있다.)

 

작업내용

- parquet형태의 데이터를 읽는다.

- 컬럼별 특정 rule에 의해 match가 되지 않는 데이터에 대해 counting을 한다.

- MisMatch된 데이터에 대해 최종적으로 hdfs에 write한다. (MultipleOutput)

- 컬럼별 데이터 분포도를 counting해서 컬럼별로 결과 file로 남긴다. (local)

- 컬럼별 나올 수 있는 모든 조합들의 집합의 데이터 분포도도 hdfs파일에 write한다. (MultipleOutput)

 

데이터 사이즈/데이터 라인수

362.5 M / 22,766,706

 

컬럼개수 

6개

 

Reducer 1 개일 때 : 2 34

19/06/27 14:28:18 INFO client.RMProxy: Connecting to ResourceManager at acenmd-dmp001.svr.toastmaker.net/10.160.231.113:8032

19/06/27 14:28:19 INFO input.FileInputFormat: Total input paths to process : 50

19/06/27 14:28:19 INFO mapreduce.JobSubmitter: number of splits:50

19/06/27 14:28:19 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1559692026802_4638

19/06/27 14:28:19 INFO impl.YarnClientImpl: Submitted application application_1559692026802_4638

19/06/27 14:28:19 INFO mapreduce.Job: The url to track the job: http://acenmd-dmp001.svr.toastmaker.net:8088/proxy/application_1559692026802_4638/

19/06/27 14:28:19 INFO mapreduce.Job: Running job: job_1559692026802_4638

19/06/27 14:28:26 INFO mapreduce.Job: Job job_1559692026802_4638 running in uber mode : false

19/06/27 14:28:26 INFO mapreduce.Job:  map 0% reduce 0%

19/06/27 14:28:40 INFO mapreduce.Job:  map 2% reduce 0%

(생 략)

19/06/27 14:30:48 INFO mapreduce.Job:  map 100% reduce 99%

19/06/27 14:30:52 INFO mapreduce.Job:  map 100% reduce 100%

19/06/27 14:30:52 INFO mapreduce.Job: Job job_1559692026802_4638 completed successfully

 

Reducer 5개일 때 : 1 9

19/06/27 18:32:26 INFO client.RMProxy: Connecting to ResourceManager at acenmd-dmp001.svr.toastmaker.net/10.160.231.113:8032

19/06/27 18:32:27 INFO input.FileInputFormat: Total input paths to process : 50

19/06/27 18:32:27 INFO mapreduce.JobSubmitter: number of splits:50

19/06/27 18:32:27 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1559692026802_4692

19/06/27 18:32:27 INFO impl.YarnClientImpl: Submitted application application_1559692026802_4692

19/06/27 18:32:28 INFO mapreduce.Job: The url to track the job: http://acenmd-dmp001.svr.toastmaker.net:8088/proxy/application_1559692026802_4692/

19/06/27 18:32:28 INFO mapreduce.Job: Running job: job_1559692026802_4692

19/06/27 18:32:35 INFO mapreduce.Job: Job job_1559692026802_4692 running in uber mode : false

19/06/27 18:32:35 INFO mapreduce.Job:  map 0% reduce 0%

19/06/27 18:32:50 INFO mapreduce.Job:  map 8% reduce 0

(생 략)

19/06/27 18:33:32 INFO mapreduce.Job:  map 100% reduce 99%

19/06/27 18:33:35 INFO mapreduce.Job:  map 100% reduce 100%

19/06/27 18:33:35 INFO mapreduce.Job: Job job_1559692026802_4692 completed successfully

 

Reducer 10개 일 때 : 1분 2초

19/06/27 18:18:08 INFO client.RMProxy: Connecting to ResourceManager at acenmd-dmp001.svr.toastmaker.net/10.160.231.113:8032

19/06/27 18:18:09 INFO input.FileInputFormat: Total input paths to process : 50

19/06/27 18:18:09 INFO mapreduce.JobSubmitter: number of splits:50

19/06/27 18:18:09 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1559692026802_4688

19/06/27 18:18:10 INFO impl.YarnClientImpl: Submitted application application_1559692026802_4688

19/06/27 18:18:10 INFO mapreduce.Job: The url to track the job: http://acenmd-dmp001.svr.toastmaker.net:8088/proxy/application_1559692026802_4688/

19/06/27 18:18:10 INFO mapreduce.Job: Running job: job_1559692026802_4688

19/06/27 18:18:17 INFO mapreduce.Job: Job job_1559692026802_4688 running in uber mode : false

19/06/27 18:18:17 INFO mapreduce.Job:  map 0% reduce 0%

19/06/27 18:18:31 INFO mapreduce.Job:  map 2% reduce 0%

(생 략)

19/06/27 18:19:07 INFO mapreduce.Job:  map 100% reduce 99%

19/06/27 18:19:10 INFO mapreduce.Job:  map 100% reduce 100%

19/06/27 18:19:10 INFO mapreduce.Job: Job job_1559692026802_4688 completed successfully

 

Reducer 20개 일때 : 1분 1초

19/06/27 18:27:45 INFO client.RMProxy: Connecting to ResourceManager at acenmd-dmp001.svr.toastmaker.net/10.160.231.113:8032

19/06/27 18:27:46 INFO input.FileInputFormat: Total input paths to process : 50

19/06/27 18:27:47 INFO mapreduce.JobSubmitter: number of splits:50

19/06/27 18:27:47 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1559692026802_4689

19/06/27 18:27:47 INFO impl.YarnClientImpl: Submitted application application_1559692026802_4689

19/06/27 18:27:47 INFO mapreduce.Job: The url to track the job: http://acenmd-dmp001.svr.toastmaker.net:8088/proxy/application_1559692026802_4689/

19/06/27 18:27:47 INFO mapreduce.Job: Running job: job_1559692026802_4689

19/06/27 18:27:56 INFO mapreduce.Job: Job job_1559692026802_4689 running in uber mode : false

19/06/27 18:27:56 INFO mapreduce.Job:  map 0% reduce 0%

19/06/27 18:28:14 INFO mapreduce.Job:  map 19% reduce 0%

19/06/27 18:28:15 INFO mapreduce.Job:  map 39% reduce 0%

(생 략)

19/06/27 18:28:42 INFO mapreduce.Job:  map 100% reduce 99%

19/06/27 18:28:43 INFO mapreduce.Job:  map 100% reduce 100%

19/06/27 18:28:46 INFO mapreduce.Job: Job job_1559692026802_4689 completed successfully

 

결 론

Reducer를 많이 늘린다고해서 처리 속도가 비례해서 향상되는 것은 아니다. 해당 작업의 유형을 고려하고 Reducer개수를 조절해가며 최적의 개수를 찾는게 중요하다. Reducer개수에 따라 결과 데이터가 hdfs에 쓰여진다.(Reducer10개면 10개의 파티션으로, 5개이면 5개의 파티션으로)

 

마지막으로 하둡 완벽가이드(4판)의 내용을 첨부한다.

리듀서를 하나만 두는 것(기본값)은 하둡 초보자가 자주 범하는 실수다. 실제로 대부분의 잡은 리듀서 수를 기본값인 1보다 크게 설정하는 것이 좋다. 그렇지 않으면 모든 중간 데이터가 하나의 리듀스 태스크로 모여들기 때문에 잡이 굉장히 느려진다. 사실 잡의 리듀서 수를 결정하는 것은 과학보다는 예술에 가깝다. 보통 리듀서 수를 늘리면 병렬 처리 개수도 늘어나서 리듀스 단계에서 걸리는 시간을 줄일 수 있다. 그러나 너무 많이 늘리면 작은 파일이 너무 많이 생성되는 준최적화(suboptimal)에 빠지게 된다. 경험적으로 리듀서의 실행 시간은 5분 내외, 출력 파일의 HDFS 블록 수는 최소 1개로 잡는 것이 좋다.

 

반응형
반응형

하둡 MR작업 중 다음과 같은 에러를 만났다.

19/06/19 11:16:49 INFO mapreduce.Job: Task Id : attempt_1559692026802_2824_m_000031_2, Status : FAILED
Error: Found interface org.apache.hadoop.mapreduce.Counter, but class was expected
19/06/19 11:16:49 INFO mapreduce.Job: Task Id : attempt_1559692026802_2824_m_000047_2, Status : FAILED
Error: Found interface org.apache.hadoop.mapreduce.Counter, but class was expected
19/06/19 11:16:49 INFO mapreduce.Job: Task Id : attempt_1559692026802_2824_m_000011_2, Status : FAILED
Error: Found interface org.apache.hadoop.mapreduce.Counter, but class was expected
19/06/19 11:16:49 INFO mapreduce.Job: Task Id : attempt_1559692026802_2824_m_000034_2, Status : FAILED
Error: Found interface org.apache.hadoop.mapreduce.Counter, but class was expected

위와 같은 에러로 인해 map작업이 계속해서 실패하며 다음과 같은 에러를 내며 죽어버린다. 

Exception in thread "main" java.lang.NoSuchMethodError: org.apache.hadoop.mapreduce.Counters.getGroup(Ljava/lang/String;)Lorg/apache/hadoop/mapreduce/CounterGroup;

문제의 원인은 하둡 MR작업 중 Counter를 사용하는데 해당 라이브러리를 잘못 가져다 써서 문제가 발생한 것이였다.

maven pom.xml

위와 같은 hadoop-core, hadoop-common 버전의 라이브러리를 사용해 작업을 했었다. 하지만 실제 하둡 MR을 구동하는 환경은 CDH 5.11.1에 설치된 하둡 패키지를 사용하고 있었기에 Counter메소드를 찾지 못해 NoSuchMethodError를 뱉는 것이었다.

 

따라서 pom.xml에 repository와 depency 수정으로 해결하였다.

cloudera repository추가

cdh5.11.1에서 동작하도록 수정해주었다.

 

끝~~~~신기한건 똑같은 기능을 spark, mr둘다 만들어서 테스트해보았는데 단순히 데이터 읽어가면서 filterling하고 간단한 통계자료 뽑고하는 로직만 있어서 그런지 하둡MR이 훨씬 빨랐다는거....

반응형
반응형

 

특정 경로에 다음과 같은 데이터가 있다고 치자.

drwxr-xr-x   - irteam irteam          0 2018-12-01 00:03 /log/de_log/2018
drwxr-xr-x   - irteam irteam          0 2019-05-01 00:02 /log/de_log/2019

 

특정 경로 아래의 directory별로 사이즈를 볼 때

hadoop fs -du -h /log/de_log

3.1 T  9.4 T  /log/dmp_log/2018
1.3 T  3.9 T  /log/dmp_log/2019

 

특정 경로 directory 사이즈를 볼 때

hadoop fs -du -s -h /log/dmp_log

4.4 T  13.3 T  /log/de_log

 

반응형
반응형

하둡 클러스터를 운영하다보면 데이터 노드마다 데이터 분포의 불균형 상태가 생길 수 있는데 이 때 실행시켜주어야 하는 작업이 '밸런서(balancer)'이다.


밸런서(balancer)에 대한 내용을 포스팅 해보겠다. 해당 내용은 '하둡 완벽 가이드(4판)'을 정리한 내용이다.


[ 하둡 밸런서 ] 

하둡 클러스터는 시간이 지남에 따라 데이터노드 사이의 블록의 분포는 불균형 상태가 될 수 있고 불균형 상태의 클러스터는 맵리듀스의 지역성(locality)에 영향을 받게 되므로 자주 사용되는 데이터노드에 큰 부하를 주게 된다. 따라서 불균형 상태가 되지 않도록 해야 한다.


밸런서란?

밸런서 프로그램은 블록을 재분배하기 위해 사용률이 높은 데이터노드의 블록을 사용률이 낮은 데이터노드로 옮기는 하둡 데몬이다. 블록 복제본을 다른 랙에 두어서 데이터 유실을 방지하는 블록 복제본 배치 정책은 그대로 고수한다. 밸런서는 클러스터가 균형 상태가 될 때까지 블록을 이동시킨다. 여기서 균형 상태란 각 데이터노드의 사용률(노드의 총 가용 공간과 사용된 공간의 비율)이 클러스터의 사용률(클러스터의 총 가용 공간과 사용된 공간의 비율)과 비교하여 지정된 임계치 비율 이내일 때를 의미한다. 


밸런서는 다음과 같이 실행할 수 있다.

start-balancer.sh


-threshold 인자에는 클러스터의 균형 상태를 의미하는 임계치 비율을 지정한다. 이 플래그는 선택사항이며, 지정하지 않으면 임계치는 10%다. 클러스터에는 오직 하나의 밸런서만 실행될 수 있다. 


밸런서는 클러스터가 균형 상태가 될 때까지 수행된다. 더 이상 블록을 이동시킬 수 없거나 네임노드와 통신이 단절될 수 있기 때문에 표준 로그 디렉터리에 로그파일을 생성하고 재분배 작업이 순환될 때마다 기록을 남긴다. 아래는 작은 클러스터에서 아주 짧은 시간 동안 밸런서를 실행한 결과다.


밸런서는 클러스터에 부담을 주는가???

밸런서는 클러스터에 과도한 부하를 주지 않고 클러스터를 사용하는 다른 클라이언트에 방해가 되지 않기 위해 백그라운드로 실행되도록 설계되었다. 밸런서는 한 노드에서 다른 노드로 블록을 복제할 때 필요한 대역폭을 제한할 수 있다. 기본값은 1MB/s지만 hdfs-site.xml 파일의 dfs.datanode.balance.bandwidthPerSec 속성에 바이트 단위로 값을 지정하면 대역폭을 변경할 수 있다. (대역폭을 늘린 순 있겠지만 늘리게 되면 클러스터에 미치는 영향이 커질 수 있음을 주의하자.)


실제로 경험상 밸런서를 실행하면 생각보다 수행시간이 오래걸린다.(20대 하둡 클러스터 기준) 하루 이상은 걸렸던 걸로 기억한다.


읽어 주셔서 감사합니다.

반응형
반응형

HDFS 네임노드의 파일시스템 이미지와 에디트 로그에 대한 내용은 하둡을 운영하기 위해 기본적으로 알아야 할 내용이기에 정리해본다.


해당 내용은 '하둡 완벽 가이드(4판)'을 정리한 내용이다.


파일시스템 이미지와 에디트 로그


[ 네임노드의 파일시스템 메타데이터 관리 방법 ]

파일시스템의 클라이언트가 쓰기 동작(파일 생성이나 이동)을 하면 일단 에디트 로그에 해당 내역이 기록된다. 네임노드는 파일시스템의 메타데이터를 인메모리(in-memory, 파일과 메모리 양쪽에 데이터를 유지하는 방식)로 관리하는데, 에디트 로그를 먼저 변경한 후 메모리상의 메타데이터도 변경한다. 클라이언트의 읽기 요청에는 인메모리 데이터만 사용된다. 


[ 에디트 로그 ]

에디트 로그는 개념적으로 단일 개체지만 디스크에는 다수의 파일로 관리된다. 각 파일을 세그먼트라고 하며 접두사 edits와 트랜잭션 ID를 의미하는 접미사로 구성되어 있다. 한번에 하나의 파일만 쓰기를 위해 열린다. 네임노드는 쓰기 동작이 끝날 때마다 성공했다는 결과를 클라이언트에 알려주기 전에 에디트 로그를 플러시(flush)하여 동기화시킨다. 네임노드는 여러 개의 디렉터리에 에디트 로그를 기록할 수 있기 때문에 변경 내역을 모든 에디트 로그 복제본 파일에 플러시하고 동기화한 후에 성공했다는 것을 알려주어야 한다. 이는 어떠한 기계적 결함에도 데이터가 손실되지 않도록 하기 위함이다. 


[ fsimage 파일 ]

각각의 fsimage파일은 파일시스템 메타데이터의 완전하고 영속적인 체크포인트다(fsimage 파일의 접미사는 파일시스템 이미지의 마지막 트랜잭션을 나타낸다). 파일시스템에서 쓰기 동작이 있을 때마다 fsimage 파일을 변경하지는 않는데, fsimage 파일이 기가바이트 크기로 커지면 성능이 매우 느려지기 때문이다. fsimage 파일을 바로 갱신하지 않더라도 하둡의 장애복구능력이 저하되는 것은 아니다. 만약 네임노드에 장애가 발생하면 먼저 fsimage를 메모리에 로드하고 에디트 로그파일에서 특정 지점 이후에 발생한 변경 내역들을 메모리에 반영하여 파일시스템의 메타데이터를 최신의 상태로 복원할 수 있기 때문이다. 


각 fsimage 파일은 파일시스템에 존재하는 모든 디렉터리와 파일의 아이노드(inode)정보를 직렬화한 파일이다. 각 아이노드는 파일이나 디렉터리 메타데이터의 내부 구조를 나타내며 파일의 복제 수준, 변경 및 접근 시간, 접근 권한, 블록 크기, 파일을 구성하는 블록 집합과 같은 정보를 가지고 있다. 디렉터리에는 파일과 달리 변경 시간, 권한, 할당 크기와 같은 메타데이터 정보가 저장되어 있다.


블록이 실제 저장된 데이터노드에 대한 정보는 fsimage 파일에 기록되지 않는다. 대신 네임노드는 매핑 정보(어떤 블록이 어느 데이터노드에 저장되어 있는지)를 메모리에서 따로 관리한다. 네임노드는 클러스터에 데이터노드가 추가될 때마다 블록 목록에 대한 정보를 데이터노드에 요청하여 매핑 정보를 구성하며, 주기적으로 네임노듣의 블록 매핑 정보를 최신 상태로 갱신한다. 


읽어주셔서 감사합니다. 포스팅을 마치도록 하겠습니다:)



반응형

+ Recent posts