Microservice Architecture (MSA)

  • 하나의 어플리케이션을 여러개의 작은 서비스 유닛으로 구성

Pros

  • 각각의 독립적 서비스로 개발과 배포가 빠름
  • 서비스 장애의 경우 전체 시스템에 영향을 주지않음
  • 서비스마다 다른 기술스택을 가질 수 있음

Cons

  • 각 서비스간 통신 비용 증가
  • 개별 서비스간의 내부 통신 복잡성
  • 통합 테스트 및 배포의 어려움

Monolithic Architecture

  • 하나의 어플리케이션에 모든 구성요소가 통합되어 하나처럼 움직임

Pros

  • 소규모 프로젝트에 적합
  • 개발 / 빌드 / 배포 / 테스트가 용이

Cons

  • 프로젝트 규모가 커질수록 빌드 배포 시간이 길어짐
  • 작은 수정에도 프로젝트 재배포 필요
  • 일부의 오류가 시스템 전체에 영향
  • 한 종류 기술스택에 국한

MSA on Robotics

  • 모듈화되어 여러 컴포넌트가 하나의 시스템으로 동작하는 로보틱스 특성상 MSA가 적합
  • 로보틱스의 각 기능을 개별 서비스로 분리하면, 필요한 부분만 독립적 확장 가능
    • ex) SLAM 서비스가 높은 연산량을 요구할 경우 SLAM 컴포넌트만 스케일링하여 성능 최적화
  • 서비스별로 최적의 기술스택 사용 가능
    • ex) SLAM(C++) / perception(Python) / data logging(Go)
  • 하나의 서비스가 실패해도 전체 시스템이 중단되지 않도록 설계(Fault Tolerance)
    • ex) perception 서비스가 다운되도, navigation 기능은 유지
  • 분산 환경 및 클라우드 연계
    • 일부 서비스는 로컬에서 실행하고, 일부는 클라우드에서 활용(navigaion - local / data analysis - cloud)
  • 개발 생산성 향상 및 협업 용이
    • 컴포넌트 단위로 나누어 병렬 개발
    • CI/CD를 적용하여 빠르게 배포 및 테스트

MSA on Robotics 예시

서비스 설명 기술스택
SLAM 실시간 환경 매핑 및 로컬라이제이션 GMapping, OpenCV
Navigation 목표 위치까지 이동 제어 Dijkstra, A*, DWA
Perception 객체 인식 및 추적 YOLO, TensorFlow, OpenCV
Telemetry 센서 데이터 수집 및 모니터링 MQTT, Prometheus, Grafana
Cloud Integration 클라우드에 데이터 업로드 AWS IoT, Google Cloud

Monolithic Architecture on Robotics의 문제점

  • 다양한 센서, 액추에이터, 제어 알고리즘을 포함하므로 코드가 거대해지고 관리가 어려움
  • 하나의 모듈을 변경할 경우 전체 시스템을 재배포해야 함
  • 새로운 기능 추가 시 기존 코드와의 종속성이 증가

ROS와 연계

  • ROS2는 기존 ROS1보다 마이크로서비스 구조에 적합
    • DDS (Data Distribution Service) 사용하여 비동기 통신 지원
    • 노드 기반 설계를 통해 독립적인 서비스로 구성 가능
    • 컨테이너화하여 Kubernetes 기반 로봇 시스템 구축 가능

마이크로서비스 도입 시 고려할 점

서비스 간 통신 방식 결정

  • gRPC → 고속 바이너리 통신, 경량 로봇 시스템에 적합
  • REST API → HTTP 기반, 클라우드 연동 용이
  • MQTT → IoT 및 저지연 데이터 스트리밍에 적합
  • ROS2 DDS → 실시간 로봇 시스템에 최적

오케스트레이션 관리

  • Kubernetes 사용 시 로봇의 Edge 컴퓨팅 환경과의 적합성 검토 필요
  • Docker Compose를 이용하여 경량화된 마이크로서비스 구성 가능

데이터 처리 및 저장소 설계

  • 센서 데이터와 로깅 데이터를 적절히 분리하여 관리해야 함
  • 실시간 데이터는 Redis, 장기 저장 데이터는 PostgreSQL/MongoDB 사용 고려

MSA 기반 로보틱스 시스템

1. 물리 계층 - 리소스의 효율적 관리 및 확장성 제공

  • 서버, 스토리지, 네트워크 등의 자원을 관리
  • 퍼블릭 클라우드 (IaaS) 기반이거나 프라이빗 클라우드로 구축 가능
  • OpenStack을 이용해 리소스를 가상화하고 동적 할당 수행
  • Docker 컨테이너를 통해 리소스 격리 및 배포
  • Kubernetes(k8s) 를 사용하여 자동화된 운영 및 유지보수 관리

2. 통신 인터페이스 계층 - 로봇과 클라우드 간의 데이터 통신을 담당

  • Ubuntu 운영체제 및 개발 도구를 사전 설치
  • ROS (Robot Operating System) 통합 → 로봇과 클라우드 간의 원격 통신 지원
  • ROS의 토픽(topic) 기반 통신 방식을 활용하여 모듈 간 결합도 감소
  • 로봇과 클라우드 플랫폼의 ROS 버전이 일치하면 ROS_MASTER를 통해 원격 연결 가능

3. 마이크로 애플리케이션 계층 - 경량 RESTful 프로토콜 기반의 마이크로서비스 관리

  • 주요 컴포넌트
    • Zuul: API 게이트웨이 → 동적 라우팅, 모니터링, 부하 분산 수행
    • Consul: 마이크로서비스 등록 및 발견 기능 제공
    • Ribbon: 클라이언트 측 부하 분산 → AWS 환경에서 중간 계층 서비스 관리
    • Message Bus: 마이크로서비스 간 메시지 통신 담당
    • Config Center: GitHub 등의 저장소에서 설정 파일을 관리하여 배포 및 유지보수 간소화

4. 비즈니스 계층 - 로봇이 필요로 하는 다양한 소프트웨어 및 데이터 처리 서비스 제공

  • 자율주행 관련 서비스: 자율 주차, 자동 추종, 차선 유지 등
  • 기본 클라우드 서비스: 오프라인 연산, 데이터 저장, 지도 생성 등
  • 클라우드에서 센서 데이터를 수집 → 이종 데이터 융합, 머신러닝, 분석 수행
  • 분석된 데이터는 다른 로봇과 공유되어 더욱 효율적인 자율주행 지원

로보틱스 시스템의 CI/CD

CI/CD Components

  • Kubernetes (K8s)
    • 컨테이너화된 애플리케이션을 자동 배포, 확장, 관리하는 도구
    • 클러스터링 및 리소스 분배를 최적화하여 서비스의 가용성 유지
  • Jenkins
    • CI/CD 프로세스를 자동화하는 웹 기반 플랫폼
    • 코드 작성 → 빌드 → 테스트 → 배포 과정을 자동화
    • GitHub, GitLab 등의 코드 저장소와 연동하여 최신 코드 자동 배포
  • Harbor
    • Docker 이미지를 관리하는 프라이빗 저장소
    • 보안 강화를 위한 RBAC(Role-Based Access Control), LDAP 연동
    • 네트워크 최적화 및 확장성 제공
  • Pipeline
    • Jenkins의 공식 플러그인으로, CI/CD 프로세스를 단계별로 정의하고 자동 실행
    • 수동 배포 없이 사용자 정의 자동화 프로세스 구축 가능

CI/CD Process

  1. 개발자가 코드 작성 → GitLab에 푸시
  2. Jenkins가 GitLab에서 코드 가져오기
  3. Jenkins가 코드 컴파일 및 빌드 진행
  4. 빌드된 Docker 이미지를 Harbor 저장소에 업로드
  5. Docker가 Harbor에서 이미지를 가져와 프로덕션 환경에 배포
  6. Kubernetes(K8s)가 컨테이너 오케스트레이션 수행
    • Pod(가장 작은 단위의 컨테이너 그룹) 생성
    • Pod가 자동으로 코드 빌드, 이미지 푸시 수행
    • 작업 완료 후 Pod는 자동 삭제 및 리소스 해제
  7. 로봇 애플리케이션 개발자는 Harbor에서 이미지를 가져와 원하는 환경에 배포 가능

https://doi.org/10.1155/2021/6656912

로그 레벨

1. FATAL (치명적 오류)

애플리케이션이 더 이상 실행될 수 없는 심각한 오류

  • 시스템이 즉시 종료될 정도로 중요한 문제
  • 반드시 즉각적인 조치가 필요

예시

  • 중요한 설정 정보가 누락됨
  • 데이터베이스 연결이 끊어져 필수 기능 수행 불가
  • 디스크 공간 부족으로 시스템 중단
  • 해킹 시도 감지

2. ERROR (오류)

특정 기능이 작동하지 않지만, 전체 시스템은 계속 실행 가능

  • 긴급 대응 필요하지만, 시스템 전체가 멈추는 것은 아님
  • 일부 기능이 비정상적이거나 실패했을 때 기록됨

예시

  • API 요청이 실패하여 서비스에 영향
  • 네트워크 연결 실패 (자동 복구가 안 되는 경우)
  • JSON 데이터를 읽는 중 오류 발생

3. WARN (경고)

예상치 못한 상황이지만, 시스템이 정상적으로 동작함

  • 즉각적인 오류는 아니지만, 조치가 필요할 가능성이 높음
  • 시스템이 정상적으로 동작하더라도 미래에 문제로 발전할 수 있음

예시

  • CPU, 메모리 사용량이 위험 수준 근접
  • 로그인 실패 횟수가 비정상적으로 많음 (보안 위험)
  • 오래된 설정값 사용 중

4. INFO (정보)

시스템의 정상적인 동작을 기록하는 로그

  • 문제 해결보다는 시스템의 중요한 상태 변화 기록
  • 일반적으로 프로덕션 환경에서 기본적으로 활성화됨

예시

  • 서비스 시작 및 종료 기록
  • 작업이 정상적으로 완료됨 (예: 파일 업로드 성공)
  • 주기적인 상태 점검 결과

5. DEBUG (디버그)

개발자가 문제 해결을 위해 사용하는 상세한 로그

  • 개발 및 테스트 환경에서만 사용
  • 많은 양의 데이터를 기록하기 때문에 운영 환경에서는 비활성화하는 것이 일반적

예시

  • 데이터베이스 쿼리 내용 확인
  • API 요청 및 응답 정보
  • 설정값 및 실행 시간 기록

6. TRACE (추적)

코드 실행 경로를 상세하게 추적하는 로그

  • 디버깅보다 더 세밀한 로그로 코드가 어떻게 실행되는지 확인
  • 보통 성능 분석이나 복잡한 문제 해결 시 사용
  • 운영 환경에서는 사용하지 않음 (너무 많은 데이터 생성)

예시

  • 함수가 호출될 때 입력값 및 반환값 기록
  • 반복문 내에서 처리되는 데이터 추적
  • 알고리즘의 동작 과정 확인

정리

로그 레벨 설명 예시
FATAL 시스템이 멈춰야 할 정도로 치명적인 문제 발생 데이터베이스가 완전히 다운됨
ERROR 기능이 실패했지만 시스템은 계속 작동 가능 외부 API 호출 실패, 네트워크 오류
WARN 이상 징후가 있지만 큰 문제는 아님 CPU 사용량 급증, 보안 위협 가능성
INFO 시스템의 정상적인 상태 변화 기록 서비스 시작/종료, 작업 완료 메시지
DEBUG 개발자가 문제 해결을 위해 추가적인 정보를 보고 싶을 때 API 요청/응답 상세 내용, SQL 쿼리 실행 결과
TRACE 코드 실행 과정을 매우 상세히 추적할 때 함수 호출 과정, 알고리즘 수행 과정

 

 

운영 환경(production): INFO, WARN, ERROR, FATAL
개발 환경(development): DEBUG, TRACE 포함 모든 로그

#include <chrono>
#include <functional>
#include <memory>

#include "geometry_msgs/msg/twist.hpp"
#include "rclcpp/rclcpp.hpp"
#include "sensor_msgs/msg/laser_scan.hpp"

using namespace std::chrono_literals;
using std::placeholders:: _1;

class Sample{
    public:
        Sample(): ranges_size(0){};
        void LaserScanCallback(const sensor_msgs::msg::LaserScan::SharedPtr _msg){
            this->ranges_size = _msg->ranges.size();
            std::cout << this->ranges_size << std::endl;
        }
    private:
        unsigned int ranges_size;
};
class MovingRobot: public rclcpp::Node{
    public:
        MovingRobot(): Node("moving_robot"){
            sample_ptr_ = std::make_shared<Sample>();

            laserscan_subscription_ = this->create_subscription<sensor_msgs::msg::LaserScan>(
                "/scan", rclcpp::QoS(rclcpp::SystemDefaultsQoS()),
                std::bind(&Sample::LaserScanCallback, sample_ptr_.get(), _1));
        }
    private:
        rclcpp::Subscription<sensor_msgs::msg::LaserScan>::SharedPtr laserscan_subscription_;

        std::shared_ptr<Sample> sample_ptr_;
};

int main(int argc, char* argv[]){
    rclcpp::init(argc, argv);
    rclcpp::spin(std::make_shared<MovingRobot>());
    rclcpp::shutdown();

    return 0;
}

핵심은 subscription callback 등록할때 bind 함수에서 this 포인터 대신 클래스의 포인터를 등록

'etc' 카테고리의 다른 글

Microservice Architecture on Robotics  (2) 2025.02.04
How to set log level  (0) 2025.02.04
colcon graph  (0) 2025.01.16
Python Package Offline Install  (0) 2024.01.18
Fix client coordinates and set camera projection in Gazebo  (0) 2023.11.20

workspace dependency visualization

colcon graph --dot > graph.dot  
dot -Tpng graph.dot -o graph.png  

 

graph.png

sample code

// Sample code
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(){

    srand(time(NULL));

    int count = 0;

    for(;;){
        int random_number = rand() % 100;

        if(random_number > 95)
            break;
        else if(random_number > 100)
            continue;
        else
            count++;
    }

    printf("count : %d\n", count);

}

build & execute

gcc --coverage -o coverage coverage.c
./coverage
  • --coverage 옵션으로 컴파일 하고, 실행하면 같은 경로에 .gcda, .gcno 파일이 생성된다.
  • gcda: 커버리지 정보 및 실행 횟수가 포함(동일경로에 생성되지만 -fprofile-dir 옵션으로 경로 설정 가능)
  • gcno: 기본 블록 그래프를 재구성하고 블록에 소스 라인 번호를 할당하는 정보가 포함.(동일경로에 생성)

analysis

gcov

gcov coverage.c 
// 같은 경로에 coverage.c.gcov 파일 생성

cat coverage.c.gcov
/*
        -:    0:Source:coverage.c
        -:    0:Graph:coverage.gcno
        -:    0:Data:coverage.gcda
        -:    0:Runs:1
        -:    1:#include <stdio.h>
        -:    2:#include <stdlib.h>
        -:    3:#include <time.h>
        -:    4:
        1:    5:int main(){
        -:    6:
        1:    7:    srand(time(NULL));
        -:    8:
        1:    9:    int count = 0;
        -:   10:
       28:   11:    for(;;){
       29:   12:        int random_number = rand() % 100;
        -:   13:
       29:   14:        if(random_number > 95)
        1:   15:            break;
       28:   16:        else if(random_number > 100)
    #####:   17:            continue;
        -:   18:        else
       28:   19:            count++;
        -:   20:    }
        1:   21:    printf("count : %d\n", count);
        -:   22:
        -:   23:}
*/
  • 가장 왼쪽 숫자는 해당라인 실행횟수이며 #####은 미실행 라인

gcovr

  • gcov 파일을 시각화 하여 파싱해주는 툴
gcovr --html-details -r . --html coverage.html
gcovr -r . --csv coverage.csv
gcovr -r . --json coverage.json

 

 

'리눅스' 카테고리의 다른 글

Transparent Huge Page  (0) 2024.03.20
get realtime output of ssh remote command  (0) 2023.11.08
Core dump not generated  (0) 2023.06.13
Linux Signal List  (0) 2021.06.10
How to use ctags  (0) 2020.11.04

C언어에서의 생성자 및 소멸자

  • main 함수 전후로 실행됨
  • OS에서 제공하는 기능은 아니고 어플리케이션 레벨에서 main함수 전후로 실행되기때문에, exit 함수등으로 프로그램 정상종료시 소멸자가 실행되지만 프로세스 강제종료시 소멸자가 실행되지 않음
  • gcc 제공기능이라 비쥬얼 스튜디오에서 안된다.
  • 여러개의 생성자를 사용 가능하며 prioirity로 순서 지정 가능(0 ~ 100번은 예약된 우선순위라 101번부터 지정가능)
#include <stdio.h>

void __attribute__((constructor (101))) my_constructor1(void) {
    printf("this is my_constructor1()\n");
}

void __attribute__((constructor (102))) my_constructor2(void) {
    printf("this is my_constructor2()\n");
}


void __attribute__((destructor (102))) my_destructor1(void) {
    printf("this is my_destructor1()\n");

}

void __attribute__((destructor (101))) my_destructor2(void) {
    printf("this is my_destructor2()\n");
}


int main(void) {

    printf("this is main()\n");

    return 0;
}
/*
this is my_constructor1()
this is my_constructor2()
this is main()
this is my_destructor1()
this is my_destructor2()
*/

'C&C++' 카테고리의 다른 글

Errno Setting Function List  (0) 2024.01.17
CMake Syntax  (0) 2020.01.21
How To Use Unit Test In C++  (0) 2020.01.13
WINAPI How To Hook ConnectEx  (0) 2019.11.06
WINAPI DLL_PROCESS_DETACH  (1) 2019.08.08

About Transparent Huge Page

리눅스에서 메모리를 관리할 때 사용하는 페이지의 크기는 일반적으로 4kb이다. 
이 페이지를 통해 메모리를 분할하여 관리하는데, 메모리의 크기가 커질수록 페이지 수가 많아진다.
이렇게 되면 페이지를 관리하는 TLB(Translation Lookaside Buffer)의 크기도 비례하여 커지는데 이를 방지하는 기법이 THP(Transparent Huge Page)이다.
THP를 통해 페이지의 크기를 증가시키고(기본적으로 4kb -> 2mb), 이렇게 되면 페이지의 갯수가 줄어들어 TLB의 크기도 작아지는 방식이다.

메모리가 100기가 이상인 서버급 컴퓨터에서 THP를 활용하거나, 
메모리 집약적인 워크로드를 수행하는 동작에 대해서 THP를 활용하는 경우에는 성능적으로 큰 효과가 있을 수 있지만, 
일반적으로 데스크탑 PC나 임베디드 보드의 경우에는 오히려 성능 저하를 야기할 수 있다.
때문에 리눅스가 동작하는 하드웨어의 스펙에 따라 THP를 끄는게 성능적으로 좋은 경우도 있다.

일반적인 PCHW나 서버급 워크스테이션에서는 THP가 조건부 적용되도록 설정되어있지만, 임베디드 보드의 경우 기본적으로 사용하는것으로 설정되어있다.

How to disable THP

# check whether enabled or disabled
cat /sys/kernel/mm/transparent_hugepage/enabled

# [always] madvise never

# always: madvise() 시스템콜에 인자로 MADV_NOHUGEPAGE 옵션을 전달하지 않은 모든 프로세스가 THP 사용
# madvise: madvise() 시스템콜에 인자로 MADV_HUGEPAGE 옵션을 전달한 프로세스가 페이지 폴트시 THP 사용
# never: 시스템에서 THP를 완전하게 비활성화

# https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/performance_tuning_guide/sect-red_hat_enterprise_linux-performance_tuning_guide-configuring_transparent_huge_pages

###############################################################

# turn off once
echo never > /sys/kernel/mm/transparent_hugepage/enabled

# turn off completely
vi /etc/systemd/system/disable-thp.service

# disable-thp.service contents
[Unit]
Description=Disable Transparent Huge Pages (THP)
DefaultDependencies=no
After=sysinit.target local-fs.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never | tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null'
[Install]
WantedBy=basic.target


systemctl daemon-reload
systemctl start disable-thp
cat /sys/kernel/mm/transparent_hugepage/enabled
systemctl enable disable-thp
reboot

'리눅스' 카테고리의 다른 글

How to measure code coverage using gcov  (0) 2024.04.24
get realtime output of ssh remote command  (0) 2023.11.08
Core dump not generated  (0) 2023.06.13
Linux Signal List  (0) 2021.06.10
How to use ctags  (0) 2020.11.04

download package(online)

pip3 download --platform linux_aarch64 pyelftools
  • 설치된 pyelftools 설치 압축파일을 설치목적지로 복사

install package(offline)

pip3 install --no-index --find-links pyelftools-xxxxxxxxxxxxxxxx.whl pyelftools

offline pip upgrade

pip3 download pip # online
python pip-xxxxxxxx.whl/pip install --no-index pip-xxxxxxxxxx.whl # offline

Functions That Set errno and Return an Out-of-Band Error Indicator

Function Name Return Value Error Value
ftell() -1L  Positive 
fgetpos(), fsetpos() Nonzero Positive
mbrtowc(), mbsrtowcs() (size_t)(-1) EILSEQ
signal() SIG_ERR Positive
wcrtomb(), wcsrtombs() (size_t)(-1) EILSEQ
mbrtoc16(), mbrtoc32() (size_t)(-1)  EILSEQ
c16rtomb(), c32rtomb() (size_t)(-1)  EILSEQ 

 

 

Functions that Set errno and Return an In-Band Error Indicator

Function Name Return Value Error Value
fgetwc(), fputwc() WEOF EILSEQ
strtol(), wcstol() LONG_MIN or LONG_MAX ERANGE
strtoll(), wcstoll() LLONG_MIN or LLONG_MAX ERANGE
strtoul(), wcstoul() ULONG_MAX ERANGE
strtoull(), wcstoull() ULLONG_MAX ERANGE
strtoumax(), wcstoumax() UINTMAX_MAX ERANGE
strtod(), wcstod() 0 or ±HUGE_VAL ERANGE
strtof(), wcstof() 0 or ±HUGE_VALF ERANGE
strtold(), wcstold() 0 or ±HUGE_VALL ERANGE
strtoimax(), wcstoimax() INTMAX_MIN, INTMAX_MAX ERANGE

'C&C++' 카테고리의 다른 글

How to use constructor and destructor in C language  (0) 2024.04.24
CMake Syntax  (0) 2020.01.21
How To Use Unit Test In C++  (0) 2020.01.13
WINAPI How To Hook ConnectEx  (0) 2019.11.06
WINAPI DLL_PROCESS_DETACH  (1) 2019.08.08

fix gazebo client coordinates

vi ~/.gazebe/gui.ini
[geometry]
x=0
y=0
width=1754
height=1043

set camera projection

vi warehouse.world
<?xml version="1.0" ?>
<sdf version="1.4">
  <world name="default">
    <include>
      <pose>4 1 30 0 0 0</pose>
      <uri>model://sun</uri>
    </include>
    <model name="warehouse">
      <include>
        <pose>0 0 0 0 0 0</pose>
        <uri>model://warehouse</uri>
      </include>
    </model>
    <gui fullscreen='0'>
      <camera name='user_camera'>
          <pose frame=''>0 0 0 0 1.57 0</pose>
          <!--projection_type orthographic or perspective-->
          <projection_type>orthographic</projection_type>
      </camera>
    </gui>
  </world>
</sdf>

'etc' 카테고리의 다른 글

colcon graph  (0) 2025.01.16
Python Package Offline Install  (0) 2024.01.18
Open source software Project License  (0) 2021.07.28
Adaptive AUTOSAR vs Classic AUTOSAR  (0) 2021.01.19
소프트웨어 마에스트로 10기 후기  (4) 2020.01.15

+ Recent posts