jam2in / arcus-java-client

Arcus Java client
Apache License 2.0
0 stars 0 forks source link

Test Case 중 testTimeout() 실패 케이스 #5

Closed aiceru closed 8 years ago

aiceru commented 8 years ago

travis CI 테스트 도중 아래와 같은 문제가 있어 이슈 남깁니다.

testTimeout() 테스트가 request 를 날린 다음, 바로 future.get 을 수행하는데 timeout 을 1ms 또는 1ns 로 아주 짧게 주어 타임아웃 발생을 유도하는 방식입니다.

상황에 따라 다른 것 같긴 한데 현재까지 확인한 바로는 BopInsertBulkTest.testTimeout() FlushByPrefixTest.testTimeout()future.get() 에서 타임아웃이 발생하지 않아 테스트 Failure 되는 사례가 있었습니다.

모든 테스트 클래스의 testTimeout() 테스트에 대해 재고가 필요할 것 같습니다.

whchoi83 commented 8 years ago

그동안 local 에서 잘 수행되던 timeout 테스트들이 fail 되는 것을 보면, 일반적인 local 과 travis-ci 의 환경이 다른 것이 아닌가하는 의심이 됩니다.

timeout 테스트 자체는 특성상 부하가 많은 operation 을 요청한 뒤에 짧은 operation timeout 을 지정하여야 하는데 아래와 같이 동작합니다.

직관적으로 판단했을 때는 충분할 것으로 보이는데, 환경적인 요인을 판단해보고 (cache?) 방법이 없 경우, count 를 증가하는 등의 방법을 찾아야 할 것 같습니다.

혹시 제가 놓친 부분이 있거나, 다른 아이디어가 있으면 코멘트 부탁드립니다. 😅

aiceru commented 8 years ago

환경 문제는 아니라고 보입니다. travis CI 에서 최초 클론 후 한두 번 timeout test fail 이 난 뒤, 현재는 timeout 으로 인한 fail 이 거의 나지 않는 상황입니다. (간혹 한두번씩 나오긴 합니다) 게다가 기억을 더듬어 보면, 이전에 local 에서도 이런 적이 있었습니다. (그 때는 뭔가 빌드 과정에서 꼬였거나 했을 거라 생각해서 다시 mvn test 를 수행했고, 재 수행한 테스트에서 Fail 이 나지 않아 넘어갔었습니다)

직관적으로 보았을 때 1 ns 의 타임아웃이라면 확실히 타임아웃 exception 이 발생하여야 하는 상황이지만, 100% 발생한다고 논리적으로 보장이 없는 한 테스트 로직의 정당성(?) 을 보장하기는 힘들다고 봅니다.

전 일단 당장 어떻게 수정하면 되겠다는 아이디어가 없어서 ㅠㅠ Future 의 timeout 을 100% 확실하게 발생시킬 수 있는 아이디어를 좀 찾아봐야 할 것 같습니다.

whchoi83 commented 8 years ago

실제 arcus-java-client 를 사용하는 유저와 동일한 환경 구성으로 논리적으로 100% 의 보장이 쉽지 않을 것 같습니다. arcus-memcached 를 건드리는 것은 불가능하니, test 가 진행하는 동안 특정 시점(future.get()) 에 GC가 동작하는 등의 방법을 찾아봐야겠네요. (쉽지는 않겠네요 😢 )

jhpark816 commented 8 years ago

future.get()이 주어진 시간만큼만 wait하는 지 확인해 보면 좋을 것 같습니다. 1 ms or 1 ns 이더라도, 사실 더 기다리는 경우가 있을 수 있어서요..

jhpark816 commented 8 years ago

정확한 원인을 파악하고 나서, 어떻게 수정할 지를 결정하는 게 좋을 것 같습니다.

whchoi83 commented 8 years ago

@jhpark816 내부적으로 sleep 등의 방법을 사용한다면 real time os 가 아닌 이상 최소 10ms 이상은 소요될 것 같습니다.

테스트의 목적이 operation timeout 을 확인하는 것인데, 실제 유저와 동일한 환경에서 timeout 발생만 보장되면 방법은 크게 문제가 없을 것 같습니다. 현재 테스트는 (실패 확률이 극히 낮을 뿐) 환경에 따라서 이것이 보장되지 않을 수 있습니다. 논의 여지가 있을 수가 있긴 하지만, (어쩄든 본래 테스트가 실패할 여지를 갖고 있기 때문에) 현재 테스트가 실패하는 조건 혹은 원인을 파악하는 것 보다 새로운 방법을 찾는 것도 괜찮다고 생각합니다.

jhpark816 commented 8 years ago

wait time이 10ms 까지는 되지는 않겠지만, 제법 길 거라고 예상합니다. 대략적인 wait time을 정확히 알고 있으면, cache server에서 이 이상의 시간이 걸리는 연산을 요청으로 보내면 될 것 같습니다.

aiceru commented 8 years ago

지금까지 여러가지로 머리 굴려봤는데, 딱히 해결책이 안나옵니다.

마음 같아서는 timeout 과 관련한 test 를 모두 제거해 버리고 싶네요 ㅠㅠ

jhpark816 commented 8 years ago

Future.get() 요청부터 리턴될 때까지의 시간이 어느 정도 되나요 ?

BopInsertBulkTest.testTimeout()에서 10000개 element를 삽입하는 데, cache server에서 insert하는 데, 제법 시간이 걸릴거라 생각됩니다. 1개 insert에 1 us 시간이 걸린다고 가정하면, 전체가 10ms는 걸릴 것이고요..

Future.get 요청부터 리턴될 때까지의 시간이 그 이상 걸리는 것인가요 ?

jhpark816 commented 8 years ago

아. 무슨 말인지 알겠네요.. future.get 요청하여 await()하기 전에 이미 count down latch의 값이 0이 된 경우에는 방법이 없다는 것이네요... 이렇게 될 가능성이 희박하겠지만 이러한 것 조차도 발생하지 않게 하려면, cache server에서 시간이 오래 걸리는 아래의 operation을 여러개 만들어 먼저 요청하고, 그 요청들에 대해서는 future get하지 않은 상태에서 bop insert bulk를 수행하면 될 것 같습니다.

aiceru commented 8 years ago

build failed 케이스가 다시 발생하여... 여러가지로 궁리를 해봤는데 지금으로선 모든 경우를 커버할 수 있는 해결책이 없습니다. 딱 한가지 있다면... OperationFuture 를 상속하여 anonymous Future 객체를 만들어 리턴해주는 API 들에 대해서, anonymous Future 들을 전부 XXXFuture 로 정의한 다음 그 XXXFuture 들에 대해 timeout test 를 수행하는 방법인데, 거의 API 하나당 하나씩의 XXXFuture 클래스가 정의되어야 하기 때문에... 그닥 바람직한 방법은 아니라고 판단됩니다. (추후에 API 가 추가될 경우 매번 XXXFuture 클래스가 추가되어야 한다는 단점도 있구요)

현재 기존 Memcached 의 코드에서는 개별 API 의 Timeout test 는 TimeoutTest 클래스에 모아서 수행하고 있습니다. 이 클래스에서는 initClient() 로 MemcachedClient 를 생성시에 127.0.0.1:64213 이라는 fake address 를 주어 아예 connection 이 이루어지지 않은 상황에서 operation 을 날려 timeout 발생을 유도합니다.

ArcusClient 는 ZK 를 사용시에는 ZK connection 이 이루어질 때까지 ArcusClient 의 creation 작업이 block 되므로 이 시점에서 operation 을 날리는 것이 불가능해서 face address 를 이용할 수가 없습니다. 하지만 ZK 미사용 테스트에서는 Memcached client 의 test code 와 마찬가지로 face address 를 주어 timeout 을 발생시키는 것이 가능해 보입니다.

그래서... 어차피 각각의 API 내부에서 만들어진 anonymous Future 객체의 get() 에서 latch await 이 timeout 날 경우 TimeoutException 을 던진다는 로직은 ZK 를 사용하던 사용하지 않던 동일하게 동작하는 로직이므로, timeout Test 는 ZK 를 사용하지 않는 테스트에서만 수행하는 정책으로 가져가는 것이 어떨지 제안합니다.

@whchoi83 @jhpark816 의견 부탁드립니다.

말이 좀 횡설수설인데 ㅠㅠ 이해가 될려나 모르겠네요... 이해되지 않는 부분은 코멘트 달아주시면 다시 설명할게요.

jhpark816 commented 8 years ago

@aiceru timeout 테스트의 본래 목적인 timeout 발생 시의 코드가 정상적인 지를 확인하기 위한 것입니다. 이러한 본래 목적을 검증하는 데 있어 ZK 사용 여부가 무관한 관계인가요 ?? 무관한 관계라면, ZK 사용하지 않는 환경에서만 timeout 테스트하는 것이 맞다고 보입니다. 중복 테스트할 필요가 없기 때문입니다.

aiceru commented 8 years ago

Timeout 테스트의 목적이 "어떤 특정한 상황에서 타임아웃이 확실히 발생하는지" 가 아니라 "지정한 시간동안 서버로부터의 응답이 없을 경우 arcus client library 가 timeout exception 을 정상적으로 발생시켜 주는지" 를 테스트하는 목적이라고 보았을 때, ZK 사용 여부는 관계가 없다고 판단해도 괜찮다고 생각됩니다.

ArcusClient 는 두 가지 방법으로 생성/초기화할 수 있는데, 한가지는 spyMemcached 와 동일하게 memcached node 의 주소를 직접 파라미터로 주어 생성하는 방법이고 다른 한가지는 ZK 의 주소를 주어 ZK 로부터 memcached node 의 주소를 얻어오도록 하는 방법입니다.

어떤 방법으로 memcached node 의 주소를 획득하건 간에, ArcusClient 가 application 으로부터 request 요청 (API 호출) 을 받아 이를 서버로 전송하고 응답을 기다리는 과정은 [memcached 주소를 획득] 한 이후의 과정으로 여기에서 timeout이 발생하는 것은 ZK 사용 여부와는 무관하다고 볼 수 있습니다.

aiceru commented 8 years ago

Close by merge #12