왜 미션크리티컬한 곳에서 Repcached 를 사용하면 안되는가?

memcached 에 대한 설명을 하다보면 항상 받게 되는 질문이 하나 있습니다. “memcached로 replication을 하는 방법은 없나요?” 라는 질문, 여기에 대한 항상 저의 답변은 “캐시는 캐시로 쓰는게 좋다” 입니다. 그래도 또 원하고 원하는 질문이 바로 replication 입니다. 결국 이런 상황에서 소개해 드리게 되는 것이 repcached라는 것입니다. repcached는 memcached 1.2.8을 기본으로 Master/Master 리플리케이션 기능을 추가해둔 것입니다. (http://repcached.lab.klab.org/ 에서 다운 받을 수 있고 libevent 1.4.x 를 설치하시길 바랍니다. libevent 2.0.x대에서는 컴파일 되지 않습니다.)

그런데 이렇게 좋은 기능을 제공하는 repcached의 경우 미션 크리티컬한 곳에서는 사용하면 문제가 발생합니다. 왜 그럴까요? 원인은 일반적으로 분산 프로그램에서는 리플리케이션의 실패(정확하게는 오퍼레이션들의 실패) 에 대해 2pc등을 통해서 모두 성공할때만 커밋하게 해서 일관성을 유지하는 등의 방어적인 부분이 들어있습니다. 그런데 repcached의 경우는 그런 부분이 없습니다. 소스를 살펴보면 process_command 는 process_update_command 를 호출하고 이는 결과적으로 complete_nread를 호출하게 됩니다.

store_item 을 하게되면 현재 메모리에 저장하게 되고 replication_call_rep를 통해서 실제로 replication을 할 서버에 데이터를 전달하게 됩니다. 그런데 소스 코드는 다음과 같습니다.


ret = store_item(it, comm);
 if (ret == 1) {
#ifdef USE_REPLICATION
 {
 if( c != rep_conn ){
 replication_call_rep(ITEM_key(it), it->nkey);
 }
 out_string(c, "STORED");
 }
#else
 out_string(c, "STORED");
#endif /* USE_REPLICATION */

}

즉 replication_call_rep 에 대한 에러 체크가 전혀 없습니다. 물론 에러 체크를 한다고 해도 store_item 등으로 인한 부분을 rollback하는 코드가 필요한데 이런 부분도 없습니다. 실제로 메모리로만 처리하므로 그런 일이 별로 없긴 하지만, memcached 서버등에서 결과를 처리하지 못하고 에러를 리턴하는 케이스들도 존재하기 때문입니다.

이런 이유로 인해서 repcached를 미션 크리티컬 한 곳에서 쓰는 것은 위험합니다. 결국 캐시는 캐시답게 사용하는 것이 좋지 않을까 라는 생각이 듭니다.