이벤트 중심 아키텍처에서 초기 상태를 처리하는 방법은 무엇입니까?


33

에서 이벤트 구동 아키텍처 이벤트가 시스템을 통해 전송 될 때, 각 성분은 작용한다.

브레이크 페달과 브레이크 라이트가 장착 된 가상 자동차를 상상해보십시오.

  • 광 회전 브레이크 그것이 받으면 brake_on의 이벤트 및 오프 그것이 받으면 brake_off의 이벤트.
  • 브레이크 페달이 전송 brake_on의 버튼을 눌렀을 경우, 및 brake_off의 출시 이벤트.

브레이크 페달을 밟은 상태 에서 자동차를 켜는 상황이 될 때까지이 모든 것이 좋습니다 . 제동등이 제동 이벤트를 수신하지 않았 으므로 , 바람직하지 않은 상황이 계속 유지됩니다. 기본적으로 브레이크 표시등을 켜면 상황이 반전됩니다.

이 '초기 상태 문제'를 해결하기 위해 무엇을 할 수 있습니까?

편집 : 모든 답변에 감사드립니다. 내 질문은 실제 자동차에 관한 것이 아닙니다. 자동차에서는 계속해서 상태를 전송하여이 문제를 해결했습니다. 따라서 해당 도메인에는 시작 문제가 없습니다. 내 소프트웨어 도메인 에서이 솔루션은 많은 불필요한 CPU주기를 사용합니다.

편집 2 : @gbjbaanb의 답변 외에도 다음 과 같은 시스템을 사용하려고합니다.

  • 가상 브레이크 페달은, 초기화 후에, 그 상태와 이벤트를 전송 하고
  • 가상 브레이크 라이트는 초기화 후 브레이크 페달에서 상태 이벤트를 요청하는 이벤트를 보냅니다.

이 솔루션을 사용하면 구성 요소간에 종속성이없고 경쟁 조건이없고 오래된 메시지 큐가 없으며 '마스터'구성 요소가 없습니다.


2
가장 먼저 떠오르는 것은 initialize필요한 센서 데이터가 포함 된 "합성"이벤트를 생성하는 것입니다 .
msw

페달이 Brake_pedal_on 이벤트를 보내지 않아야하고 실제 브레이크가 Brake_on 이벤트를 보내지 않아야합니까? 브레이크가 작동하지 않으면 브레이크 라이트가 켜지지 않게하고 싶습니다.
bdsl

3
내가 가상의 예라고 언급 했습니까? :-) 질문을 짧고 요점으로 유지하기 위해 크게 단순화되었습니다.
Frank Kusters

답변:


32

여러 가지 방법이 있지만 메시지 기반 시스템을 가능한 한 분리 된 상태로 유지하는 것이 좋습니다. 이는 전체 시스템이 어떤 구성 요소의 상태도 읽을 수없고 어떤 구성 요소도 다른 구성 요소의 상태를 읽을 수 없음을 의미합니다 (그러므로 의존성의 스파게티 관계가 있음).

따라서 실행중인 시스템 자체를 돌보는 동안 각 구성 요소를 시작하도록 알려주는 방법이 필요합니다. 우리는 이미 구성 요소 등록에 이러한 기능이 있습니다. 즉 시작시 핵심 시스템은 각 구성 요소에 이제 등록되었습니다 (또는 등록 할 수 있도록 각 구성 요소에 세부 사항을 리턴하도록 요청합니다). 이 단계는 구성 요소가 시작 작업을 수행 할 수있는 단계이며 일반 작업에서와 같이 메시지를 보낼 수 있습니다.

따라서 시동이 걸렸을 때 브레이크 페달은 차량 관리로부터 등록 / 확인 메시지를 수신하고 "나는 여기 있고 작동 중입니다"메시지를 반환 할뿐 아니라 자체 상태를 점검하여 해당 상태에 대한 메시지 (예 : 페달을 밟은 메시지).

브레이크 라이트가 아직 등록되지 않은 것처럼 메시지가 수신되지 않는 것처럼 문제는 스타트 업 의존성 중 하나가되지만 코어 시스템이 스타트 업, 등록 및 점검 루틴을 완료 할 때까지 이러한 메시지를 모두 큐잉함으로써 쉽게 해결할 수 있습니다. .

가장 큰 장점은 이미 작성해야하는 경우를 제외하고 초기화를 처리하는 데 필요한 특수 코드가 없다는 것입니다. 하지만 처리기 논리와 밀접하게 연결된 코드를 작성하지 않고 정상적으로 서로에게 보내는 구성 요소를 제외하고는 구성 요소 간의 상호 작용이 없으면 일반적으로 문제가되지 않습니다. 이로 인해 메시지 전달 아키텍처가 매우 좋습니다!


1
모든 구성 요소가 분리되어 있으므로 귀하의 답변이 마음에 듭니다. 이것이이 아키텍처를 선택하는 가장 중요한 이유였습니다. 그러나 현재 시스템이 '초기화'상태임을 결정하는 실제 '마스터'구성 요소는 없습니다. 모든 것이 실행되기 시작합니다. 결과적으로 내 질문에 문제가 있습니다. 마스터가 시스템이 실행 중이라고 결정하면 '시스템 초기화'이벤트를 모든 구성 요소에 전송 한 후 모든 구성 요소가 상태 브로드 캐스트를 시작합니다. 문제 해결됨. 고맙습니다! (지금은 시스템 초기화 여부를 결정하는 방법에 문제가 생겼습니다 ...)
Frank Kusters

상태 업데이트 발송자가 각 개체로부터받은 최신 업데이트를 추적하고 새 구독 요청이 수신 될 때마다 등록 된 이벤트 소스에서받은 최신 업데이트를 새 구독자에게 보내 게됩니까?
supercat

이 경우 이벤트가 만료되는시기도 추적해야합니다. 등록 할 수있는 새로운 구성 요소에 대해 모든 이벤트를 영원히 유지할 수있는 것은 아닙니다.
Frank Kusters

@spaceknarf 음, "모든 것이 단지 시작되기 시작"하는 경우 구성 요소에 의존성을 만들 수 없으므로 조명 후에 페달이 시작되므로 순서대로 시작해야합니다. 그것들은 '올바른'순서로 (예를 들어, 처음 시작하는 서비스는 1.xxx이고 두 번째는 2.xxx 등이라고하는 systemd 전에 리눅스 시작 초기화 스크립트).
gbjbaanb

그런 순서의 스크립트는 깨지기 쉽습니다. 많은 암시 적 종속성이 포함되어 있습니다. 대신 '마스터'구성 요소가 있고 @Lie Ryan이 언급 한대로 실행되어야하는 구성 요소 목록이 정적으로 구성된 경우 모든 구성 요소가로드되면 '준비'이벤트를 브로드 캐스트 할 수 있다고 생각했습니다. 이에 대한 응답으로 모든 구성 요소는 초기 상태를 브로드 캐스트합니다.
Frank Kusters

4

로드 / 시작시 상태를 적절하게 설정하는 초기화 이벤트를 가질 수 있습니다. 이는 여러 하드웨어 부품을 포함하지 않는 간단한 시스템이나 프로그램에는 바람직하지만, 통신을 통해 "브레이크 온"이벤트가 누락되거나 손실 된 경우 전혀 초기화하지 않는 것과 동일한 위험을 실행할 때 여러 물리적 구성 요소가있는 더 복잡한 시스템의 경우 바람직 할 수 있습니다. 시스템 (예 : CAN 기반 시스템)은 브레이크를 밟은 채로 시작한 것처럼 실수로 시스템을 뒤로 설정할 수 있습니다. 자동차와 같은 컨트롤러가 많을수록 무언가 빠질 가능성이 높습니다.

이를 설명하기 위해 "브레이크 온"논리가 "브레이크 온"이벤트를 반복적으로 보내도록 할 수 있습니다. 아마도 1/100 초마다 또는 무엇인가. 두뇌를 포함하는 코드는 이러한 이벤트를 수신하고 해당 이벤트를 수신하는 동안 "브레이크 온"을 트리거 할 수 있습니다. "브레이크 온"신호를 수신하지 않은 1/10 초 후에 내부 "브레이크 _ 오프"이벤트가 트리거됩니다.

다른 이벤트는 타이밍 요구 사항이 상당히 다릅니다. 자동차, 귀하의 브레이크 라이트 요구는 훨씬 더 빨리 말보다하는 수표 연료 (A multisecond 지연이 빛 아마 허용) 또는 다른 덜 중요한 시스템.

물리적 시스템의 복잡성으로 인해 이러한 접근 방식 중 어느 것이 더 적합한 지 결정할 수 있습니다. 차량 귀하의 예를 감안할 때, 당신은 아마 후자와 비슷한 뭔가를 원하는 것입니다.

어느 쪽이든 물리적 시스템을 사용하면 단일 이벤트가 올바르게 수신 / 처리되는 것을 원하지 않습니다. 이러한 이유로 네트워크 시스템의 연결된 마이크로 컨트롤러는 종종 "I 'm alive"타임 아웃을 갖습니다.


물리적 시스템에 당신은 철사를 실행하고 사용 이진 논리를 것 : HIGH 브레이크 우울하고 LOW는 우울하지 브레이크입니다
래칫 괴물

@ratchetfreak 이런 종류의 일에는 많은 가능성이 있습니다. 아마도 스위치가이를 처리 할 수 ​​있습니다. 간단하게 처리 되지 않는 다른 시스템 이벤트가 많이 있습니다 .
enderland

1

이 경우 브레이크를 단순한 온 / 오프로 모델링하지 않습니다. 오히려 "브레이크 압력"이벤트를 보내려고합니다. 예를 들어, 압력이 0이면 꺼짐이 표시되고 압력이 100으로 완전히 떨어집니다. 시스템 (노드)은 필요에 따라 지속적으로 브레이크 압력 이벤트를 일정 간격으로 컨트롤러에 전송합니다.

시스템이 시작되면 전원이 꺼질 때까지 압력 이벤트를 수신하기 시작합니다.


1

상태 정보를 전달할 수있는 유일한 방법이 이벤트를 통하는 것이라면 문제가있는 것입니다. 대신, 당신은 둘 다 할 수 있어야합니다 :

  1. 브레이크 페달의 현재 상태를 쿼리하고
  2. 브레이크 페달에서 "상태 변경"이벤트를 등록하십시오.

브레이크 라이트는 브레이크 페달의 관찰자로 볼 수 있습니다. 다시 말해, 브레이크 페달은 브레이크 라이트에 대해 아무것도 모르고 브레이크없이 작동 할 수 있습니다. (즉, 브레이크 페달의 모든 개념이 사전에 "초기 상태"이벤트를 브레이크 라이트에 보내는 것을 의미하지 않습니다.)

시스템을 인스턴스화하면 브레이크 표시등이 브레이크 페달에 등록되어 제동 알림을 수신하고 브레이크 페달 의 현재 상태를 읽고 자체적으로 켜거나 끕니다.

그런 다음 제동 알림을 다음 세 가지 방법 중 하나로 구현할 수 있습니다.

  1. 파라미터없는 "제동 페달 상태 변경"이벤트
  2. "제동 페달이 눌려 짐"및 "제동 페달이 눌려졌습니다"이벤트 쌍으로
  3. "눌림"또는 "릴리스"매개 변수가있는 "새로운 브레이킹 페달 상태"이벤트.

나는 첫 번째 접근 방식을 선호합니다. 즉, 알림을 받으면 브레이크 라이트가 이미 수행하는 방법을 알고 있습니다. 브레이크 페달의 현재 상태를 읽고 스스로 켜거나 끕니다.


0

현재 사용하고 좋아하는 이벤트 중심 시스템에서는 가능한 한 분리 된 상태를 유지하는 것이 중요합니다. 이 아이디어를 염두에두고 자세히 알아 보겠습니다.

기본 상태를 유지하는 것이 중요합니다. 브레이크 표시등의 기본 상태는 'off'이고 브레이크 페달의 기본 상태는 'up'입니다. 그 이후의 모든 변경 사항은 이벤트가됩니다.

이제 귀하의 질문에 답하십시오. 브레이크 페달이 초기화되고 눌려지고 이벤트가 발생하지만 이벤트를 수신 할 브레이크 표시등이 아직 없다고 상상해보십시오. 로직을 초기화 하기 전에 객체 생성 (이벤트 리스너가 초기화되는 위치)을 별도의 단계로 분리하는 것이 가장 쉽다는 것을 알았습니다 . 그것은 당신이 설명한대로 경쟁 조건을 방지합니다.

또한 실제로 동일한 것에 대해 두 가지 다른 이벤트를 사용하는 것이 어색하다는 것을 알았 습니다 . brake_offbrake_on로 단순화 할 수 e_brake매개 변수와 함께 bool on. 지원 데이터를 추가하여 이러한 방식으로 이벤트를 단순화 할 수 있습니다.


0

브로드 캐스트 이벤트 및 메시지받은 편지함이 필요합니다. 브로드 캐스트는 지정되지 않은 수의 리스너에 게시되는 메시지입니다. 구성 요소는 브로드 캐스트 이벤트를 구독 할 수 있으므로 관심있는 이벤트 만 수신합니다. 이것은 발신자가 수신자를 알 필요가 없으므로 디커플링을 제공합니다. 구독 테이블은 초기화 될 때가 아니라 구성 요소 설치 중에 정적으로 구성되어야합니다. 받은 편지함은 대상 구성 요소가 오프라인 일 때 메시지를 보관하는 버퍼 역할을하는 메시지 라우터의 일부입니다.

송장을 사용하면 한 가지 문제가 발생하는데, 이는받은 편지함 크기입니다. 더 이상 온라인 상태가되지 않는 구성 요소에 대해 점점 더 많은 메시지를 시스템에 보관하지 않아도됩니다. 이것은 메모리 제약이 엄격한 임베디드 시스템에서 특히 중요합니다. 받은 편지함 크기 제한을 극복하려면 브로드 캐스트 된 모든 메시지가 몇 가지 규칙을 따라야합니다. 규칙은 다음과 같습니다.

  1. 모든 방송 이벤트에는 이름이 필요합니다
  2. 주어진 시간에 브로드 캐스트 이벤트 발신자는 지정된 이름의 활성 브로드 캐스트를 하나만 가질 수 있습니다.
  3. 이벤트로 인한 영향은 dem 등원이어야합니다

브로드 캐스트 이름은 구성 요소 설치시 선언해야합니다. 수신기가 이전 방송을 처리하기 전에 컴포넌트가 동일한 이름으로 두 번째 방송을 보내면 새로운 방송이 이전 방송을 덮어 씁니다. 이제 정적받은 편지함 크기 제한을 가질 수 있으며, 이는 특정 크기를 초과하지 않도록 보장 할 수 있으며 구독 테이블을 기반으로 미리 계산할 수 있습니다.

마지막으로 방송 아카이브도 필요합니다. 브로드 캐스트 아카이브는 각 브로드 캐스트 이름의 마지막 이벤트를 보유하는 테이블입니다. 방금 설치된 새 구성 요소에는받은 편지함에 브로드 캐스트 아카이브의 메시지가 미리 채워져 있습니다. 메시지받은 편지함과 마찬가지로 브로드 캐스트 아카이브도 정적 크기를 가질 수 있습니다.

또한 메시지 라우터 자체가 오프라인 인 상황을 처리하려면 메시지 발신 함도 필요합니다. 메시지 발신 함은 발신 메시지를 일시적으로 보관하는 구성 요소의 일부입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.