Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Info

장애에 대응하기 위해서는 크게 두가지 방법이 있습니다.

  • 시스템및 서비스가 절대로 장애가 발생하지 않아서 아무것도 하지않는 경우
  • 반대로 모든 장애에 대해 대응책을 세우는것입니다.

전자는 거의 불가능하고, 후자또한 어떠한 장치로 모든것에 대응하는 전략을 세우는것은 아주 어렵고

서비스코드에 썩임으로 서비스코드의 흐름을 복잡하게 만들수가 있습니다.


AKKA자체로 이러한 장애에대한 대응을 자동으로 할수 있는것은 아닙니다.

단지 ,이러한 대응을 일괄적이고 유연한 방법을 제시하고 개발자는 다양한 전략중

하나를 선택하고 그것을 서비스코드와 분리하여 설계할수 있는 우아한 장치를 제공해줍니다.



기능에따른 장애처리 전략 분리

OneForOneAllForOne

Image Modified

Image Modified

하나가 망가져도 나머지가 그 역활을 하는경우

  • 그냥 놔둔다
  • c1죽은 기능을 살리려노력한다.

하나가망가지만 완전한 기능을 못하는경우

  • c3죽은 기능을 살리려 노력한다.
  • b3 하위 전체를 리셋한다.

AKKA 장애처리 모델은 크게 두가지 전략을 선택하여 설계에 반영할수 있습니다.

그러면 이와같은 장애처리에대한 정의가 어떻게 분리되고 이용되는지 코드를 통해서 살펴보겠습니다.

...

Code Block
languagejava
themeEmacs
@Component("BadChild")
@Scope("prototype")
public class BadChild extends AbstractActor {
	//우리가 생성한 클래스는 항상 착하지 않다.
	private final LoggingAdapter log = Logging.getLogger(getContext().system(), "BadChild");	
	int state = 0;
  
	@Override
	public Receive createReceive() {
		return receiveBuilder()
			.match(Exception.class, exception -> {
				log.error(exception.toString());
				/*
				전통적인 익센셥처리의 문제는, 익센셥은 스택구조이기때문에
				자기자신에게 발생한 익센셥을 해결하지못하는데 있고
				서비스코드에 처리방법이 썩임으로 예외처리코드가 서비스코드를 덮는데 있다.
				Akka의 예외처리는 예외가발생하도록 놔두고, 예외처리정책을 우아하게 분리할수가 있다.
				이것이 Let it Crash 전략이다.
				*/
				throw exception;
			})
			.match(Integer.class, i -> state = i)
			.matchEquals("get", s -> getSender().tell(state, getSelf()))
			.build();
	}
}


상황별 복구테스트코드

Code Block
languagejava
themeEmacs
	protected void supervisorTest(ActorSystem system,SpringExtension ext) throws Exception {
		new TestKit(system) {{
			Props superprops = ext.props("Supervisor");
			ActorRef supervisor = system.actorOf(superprops, "supervisor");
			ActorRef probe = getRef();
			
			//나쁜아이를 허용하는 전략으로 부모(감독)를 통해 아이를 생성합니다.
			final CompletableFuture<Object> future = PatternsCS.ask(supervisor, ext.props("BadChild") , 5000).toCompletableFuture();
			ActorRef badChild = (ActorRef)future.get();
			
			//나쁜아이의 상태를 42로 만든다...
			badChild.tell(42, ActorRef.noSender());
			
			//나쁜아이의 상태를 물어보고, probe에 전달하도록한다
			badChild.tell("get", probe);
			
			//prove에 저장된 메시지가 42인지 확인한다.
			expectMsgEquals(42);
			
			// ArithmeticException 예외는 그냥 진행하도록 정의를 하였다.
			badChild.tell( new ArithmeticException(), ActorRef.noSender() );
			
			//아이가 살아있는지 확인...
			badChild.tell("get", probe);
			expectMsgEquals(42);
			
			// NullPointerException 예외는 아이를 다시 초기화하도록 정의하였다.
			badChild.tell( new NullPointerException(), ActorRef.noSender() );
			
			//아이가 초기화 되었는지 확인 ( 초기상태 0)
			badChild.tell("get", probe);
			expectMsgEquals(0);
			
			//액터를 확인하기위한 Util 액터로, 죽은지 여부를 확인할수가 있습니다.
			TestProbe probe2 = new TestProbe(system);
			probe2.watch(badChild);
			
			// IllegalArgumentException 익센셥이 발생하면 아이를 보내기로 결정하였다.
			badChild.tell( new IllegalArgumentException(), ActorRef.noSender()  );
									
			// 아이가 사라진지 체크...
			probe2.expectMsgClass(Terminated.class);
			
		}};		
	}