소프트웨어 공학/Theorem

[소프트웨어 공학] 11. Reliability Engineering

lumana 2024. 5. 17. 15:32

Software reliability

  • 일반적으로, 소프트웨어 고객은 모든 소프트웨어가 신뢰할 수 있기를 기대합니다.
    • 그러나, 비중요 응용 프로그램의 경우, 일부 시스템 실패를 수용할 수도 있습니다.
  • 일부 응용 프로그램(중요 시스템)은 매우 높은 신뢰성 요구 사항을 가지며, 이를 달성하기 위해 특별한 소프트웨어 공학 기술이 사용될 수 있습니다.
    • 의료 시스템
    • 통신 및 전력 시스템
    • 항공우주 시스템

Faults, errors and failures

용어설명

Human mistake 시스템에 결함을 도입하게 되는 인간 행동
System fault 시스템 오류로 이어질 수 있는 소프트웨어 시스템의 특성
System error 시스템 사용자가 예상하지 못한 시스템 상태
System failure 시스템이 기대한 서비스를 제공하지 못할 때 발생하는 이벤트

Faults and failures

  • 고장은 일반적으로 시스템의 결함(faults in the system)으로부터 파생된 시스템 오류(system errors)의 결과입니다.
  • 그러나, 결함이 반드시 시스템 오류를 초래하는 것은 아닙니다.(faults do not necessarily result in system errors)
    • 결함으로 인해 발생한 오류 상태는 일시적일 수 있으며, 오류가 발생하기 전에 '수정'될 수 있습니다.
    • 결함이 있는 코드가 실행되지 않을 수 있습니다.
  • 오류가 반드시 시스템 고장을 초래하는 것은 아닙니다.(Errors do not necessarily lead to system failures)
    • 오류는 내장된 오류 감지 및 복구 메커니즘에 의해 수정될 수 있습니다.
    • 고장은 내장된 보호 메커니즘에 의해 방지될 수 있습니다.

Fault management and Reliability Achievement

  • 결함 회피(Fault avoidance):
    • 시스템은 인간 오류를 방지하고 시스템 결함을 최소화하도록 개발됩니다.
    • 개발 프로세스는 시스템의 결함이 배포 전에 감지되고 수정되도록 조직됩니다.
  • 결함 감지(Falut detection):
    • 검증 및 검증 기술은 배포 전에 시스템의 결함을 발견하고 제거하는 데 사용됩니다.
  • 결함 허용(Fault tolerance):
    • 시스템은 전달된 소프트웨어의 결함이 시스템 고장을 초래하지 않도록 설계됩니다.

The increasing costs of residual fault removal

  • 잔여 결함 제거 비용의 증가 그래프

Availability and reliability

  • 신뢰성(Reliability):
    • 특정 환경에서 주어진 목적을 위해 지정된 시간 동안 시스템이 고장 없이 작동할 확률.
    • 예상하는 대로 작동하는 것을 말함.
  • 가용성(Availability):
    • 특정 시점에서 시스템이 운영 가능하고 요청된 서비스를 제공할 수 있는 확률.
    • ex) 서버가 터져서 접속하지 못하는 경우
  • 이 두 가지 속성 모두 정량적으로 표현될 수 있습니다.
    • 예: 0.999의 가용성은 시스템이 99.9%의 시간 동안 작동하고 있음을 의미합니다.

Reliability and specifications

  • Reliability는 시스템 Specification과 관련하여 formal하게 정의될 수 있습니다.
    • 즉, failure는 Specification에서 벗어나는 것입니다.
  • 그러나 많은 Specification이 불완전하거나 부정확할 수 있습니다. 따라서, Specification을 준수하는 시스템이 사용자 관점에서 'fail'할 수 있습니다.
  • 또한, 사용자는 Specification을 읽지 않기 때문에 시스템이 어떻게 작동해야 하는지 모릅니다.
    • 따라서 실제로는 인식된 신뢰성이 더 중요합니다(perceived reliability is more important in practice).

Perceptions of reliability

  • Reliability에 대한 formal definition은 항상 System's reliability에 대한 user's perception을 반영하지 않습니다.
  • 시스템이 사용될 환경에 대한 가정이 잘못될 수 있습니다.
    • 이 시스템을 개발하는 환경과, 사용하는 환경이 크게 다를 수 있음 
    • 붐비는 교통에서 사용되는 시스템의 사용은 집에서 동일한 시스템을 사용하는 것과 상당히 다른 환경을 제공합니다.
    • ex) 지옥철에서 사람이 엄청 많을 때, 인터넷 서비스가 원활하지 않음
    • ex) 티켓팅 시스템이 트래픽이 튀는 시간에 접속이 안됨 -> availability와 reliability에 문제가 있음
  • System failures의 결과는 reliability에 대한 perception에 영향을 미칩니다.
    • 심각한 결과를 초래하는 failures(예: 자동차 엔진 고장)은 사용자에게 불편함을 주는 failure보다 더 큰 비중을 차지합니다.

Availability perception

  • 가용성(Availability)은 일반적으로 시스템이 서비스를 제공할 수 있는 시간의 비율로 표현됩니다. 예: 99.95%.
    • 물론, 수치가 높다고 해서 Availability가 좋은게 아니다.
    • ex) Ticketing system에서 24시간중 4분만 접속이 제대로 되지 않더라도 availability가 좋지 않은 것.
  • 그러나 이는 두 가지 요소를 고려하지 않습니다:
    • 서비스 중단으로 영향을 받는 사용자 수(The number of users affected by the service outage): 많은 시스템에서 서비스 중단이 발생할 때, 한밤중의 서비스 중단은 피크 사용 기간 동안의 서비스 중단보다 덜 중요합니다.
    • 중단의 길이(The length of the outage): 중단이 길어질수록 혼란이 커집니다. 여러 번의 짧은 중단은 한 번의 긴 중단보다 덜 방해가 됩니다. 긴 수리 시간은 특별한 문제입니다.

Reliability in use

  • 시스템의 결함 X%를 제거한다고 해서 신뢰성이 X% 향상되는 것은 아닙니다.
  • 프로그램 결함(defection)은 드물게 실행되는 코드 부분에 있을 수 있어 사용자가 거의 만나지 않을 수 있습니다. 
    • 이를 제거해도 인식된 신뢰성에는 영향을 미치지 않습니다.
    • ex) 0.01% 정도의 defect --> 해결해도 reliability에 영향을 거의 주지 않음
  • 사용자는 실패할 수 있는 시스템 기능(feature)을 피하기 위해 행동을 적응시킵니다.
    • 결함이 있는 프로그램은 여전히 사용자에게 신뢰할 수 있다고 인식될 수 있습니다.

 

시스템 신뢰성 요구사항 (System reliability requirements)

  • 기능적 신뢰성 요구사항 (Functional reliability requirements)는 시스템과 소프트웨어 기능을 정의하며, 소프트웨어의 결함을 피하거나 탐지하거나 허용하여 이러한 결함(faults)이 시스템 실패(system failure)로 이어지지 않도록 합니다.
  • 소프트웨어 신뢰성 요구사항 (Software reliability requirements)에는 하드웨어 고장이나 운영자 오류를 대처하기 위한 내용도 포함될 수 있습니다.
    • 신뢰성 (Reliability)은 측정 가능한 시스템 속성이므로 비기능적 신뢰성 요구사항 (non-functional reliability requirements)은 정량적으로 명시될 수 있습니다(may be specified quantitatively).
    • 이는 시스템의 정상 사용 중 허용되는 실패 횟수 또는 시스템이 사용 가능해야 하는 시간을 정의합니다.

신뢰성 메트릭스 (Reliability metrics)

  • 신뢰성 메트릭스 (Reliability metrics)는 system reliability의 측정 단위입니다.
  • 시스템 신뢰성 (System reliability)은 운영 실패 횟수를 세고(measured by counting the number of operational failure), 적절할 경우 이를 시스템에 가해지는 요구와 시스템이 운영된 시간에 관련지어 측정합니다.
  • 중요한 시스템의 신뢰성을 평가하려면 장기적인 측정 프로그램이 필요합니다.
  • 메트릭스 (Metrics)
    • 요구 시 실패 확률 (Probability of failure on demand)
      • Perception과 관련됨
    • 실패 발생률/평균 고장 간격 (Rate of occurrence of failures/Mean time to failure)
    • 가용성 (Availability)

요구 시 실패 확률 (Probability of failure on demand, POFOD)

  • 이는 서비스 요청 시 시스템이 실패할 확률입니다.
    • 서비스 요청이 간헐적이고 비교적 드문 경우에 유용합니다(Useful when demans for service are intermittent and relatively infrequent)
    • ex) 100번 중 10번의 실패가 발생하면 10%
  • 서비스가 가끔 요구되며, 서비스가 제공되지 않으면 심각한 결과를 초래하는 보호 시스템에 적합합니다.
  • 예외 관리 구성요소(exception management component)를 포함하는 많은 안전-중요 시스템(safety-critical systems)에 관련이 있습니다.
    • 화학 공장의 비상 정지 시스템.

실패 발생률 (Rate of occurrence of failures, ROCOF)

  • 시스템에서 실패가 발생하는 비율을 반영합니다.
  • ROCOF 0.002는 1000 운영 시간 단위당 2번의 실패가 발생할 가능성이 있음을 의미합니다. 예: 1000 시간 운영당 2번의 실패.(time unit이 1 hour라면)
  •  단시간에 유사한 요청을 많이 처리해야 하는 시스템에 관련이 있습니다.(Relevant for systems where the system has to process a large number of similar request in a shor time)
    • 신용카드 처리 시스템, 항공사 예약 시스템.
  • ROCOF의 역수(Reciprocal of ROCOF)는 평균 고장 간격 (Mean time to Failure, MTTF)입니다.
    • MTTF : 얼마나 Failure 없이 오랫동안 서비스 할 수 있는지를 나타낸다 
    • 긴 트랜잭션이 있는 시스템에 관련이 있으며, 예를 들어 CAD 시스템과 같이 처리 시간이 오래 걸리는 시스템에 적합합니다.
    • MTTF는 예상 트랜잭션 길이보다 길어야 합니다.

가용성 (Availability, AVAIL)

  • 시스템이 사용 가능한 시간의 비율을 측정합니다.
  • 수리 및 재시작 시간을 고려합니다.
    • ex) 카카오톡 업데이트로 인해 장애가 발생하여, 서비스 복구가 6시간이 걸렸다.
      • 24시간 기준 availability는 75%, 365일 기준이라면 availability가 매우 높아짐 -->기준에 따라 달라진다
  • 가용성 0.998은 1000 시간 단위 중 998 시간 동안 소프트웨어가 사용 가능함을 의미합니다.
  •  비정지, 지속적으로 실행되는 시스템에 관련이 있습니다.(Relevant for non-stop, continuously running systems).
    • 전화 교환 시스템, 철도 신호 시스템.

비기능적 신뢰성 요구사항 (Non-functional reliability requirements)

  • 비기능적 신뢰성 요구사항 (Non-functional reliability requirements)은 시스템의 신뢰성과 가용성(Reliability and availability of system)에 필요한 Specification을 신뢰성 메트릭스 (POFOD, ROCOF 또는 AVAIL)를 사용하여 명시합니다.
  • 정량적 신뢰성(Quantitative reliability)과 가용성 명시(availability specification)는 안전-중요 시스템(safety-critical systems)에서 수년간 사용되어 왔으나, 비즈니스 중요 시스템에서는 드뭅니다.
  • 그러나 점점 더 많은 회사가 시스템의 24/7 서비스를 요구함에 따라, 신뢰성과 가용성 기대치(reliability and availability expectation)를 명확히 하는 것이 합리적입니다.

신뢰성 요구사항 명시 (Specifying reliability requirements)

  • 다양한 유형의 실패(different types of failure)에 대한 availability과 reliability requirements을 명시하십시오.
    • 심각한 결과를 초래하지 않는 실패보다 고비용 실패 확률이 낮아야 합니다
  • 다양한 유형의 시스템 서비스(different types of system service)에 대한 availability과 reliability requirements을 명시하십시오.
    • 중요한 시스템 서비스는 가장 높은 신뢰성을 가져야 하지만, 덜 중요한 서비스에서는 더 많은 실패를 용인할 수 있습니다.
  • 높은 수준의 신뢰성이 정말로 필요한지(whether a high level of reliability is really required) 고려하십시오.
    • 다른 메커니즘을 사용하여 신뢰할 수 있는 시스템 서비스를 제공할 수 있습니다.

기능적 신뢰성 요구사항 (Functional reliability requirements)

cf) metric : verifiable NFR로 정의

  • 잘못된 데이터가 실패로 이어지기 전에 이를 탐지하기 위한 체크를 확인하는 요구사항 (Checking requirements).
  • 실패 발생 후 시스템이 복구될 수 있도록 돕는 복구 요구사항 (Recovery requirements).
    • ex) 널포인터 Exception : 구글 플레이 스토어 crash 발생 원인 1위
  • 시스템에 포함될 중복 기능을 명시하는 중복 요구사항 (Redundancy requirements).
    • Redundancy와 Diversity를 잘 준비해야 한다(비용은 많이 듬).
  • 사용할 개발 프로세스를 명시하는 프로세스 요구사항 (Process requirements).
    • 이 시점에서는 이러한 것들이 준비되어야 한다.

신뢰할 수 있는 프로그래밍 (Dependable programming)

  • 프로그램 결함 발생을 줄이기 위해 좋은 프로그래밍 실천 방법을 채택할 수 있습니다.
  • 이러한 프로그래밍 실천 방법은 다음을 지원합니다:
    • 결함 회피 (Fault avoidance)
    • 결함 탐지 (Fault detection)
    • 결함 허용 (Fault tolerance)

신뢰할 수 있는 프로그래밍을 위한 모범 사례 지침 (Good practice guidelines for dependable programming)

  • 신뢰할 수 있는 프로그래밍 지침 (Dependable programming guidelines)
    1. 프로그램에서 정보의 가시성을 제한합니다.
    2. 모든 입력의 유효성을 검사합니다.
    3. 모든 예외에 대한 핸들러를 제공합니다.
    4. 오류 발생 가능성이 높은 구조체 사용을 최소화합니다.
    5. 재시작 기능을 제공합니다.
    6. 배열 경계를 검사합니다.
    7. 외부 구성요소 호출 시 타임아웃을 포함합니다.
    8. real-world 값을 나타내는 모든 상수를 이름 짓습니다.

1. 프로그램 내 정보의 가시성 제한 (Limit the visibility of information in a program)

ex) public/private으로 나누는 것

  • 프로그램 구성요소는 구현에 필요한 데이터에만 접근할 수 있어야 합니다.
  • 이는 이러한 구성요소로 인해 프로그램 상태의 일부가 우발적으로 손상되는 것을 불가능하게 합니다.
  • 추상 데이터 타입 (abstract data types)을 사용하여 데이터 표현을 비공개로 하고, get() 및 put()과 같은 사전 정의된 연산을 통해서만 데이터에 접근하도록 가시성을 제어할 수 있습니다.

2. 모든 입력의 유효성 검사 (Check all inputs for validity)

  • 모든 프로그램은 환경으로부터 입력을 받고 이 입력에 대한 가정을 합니다.
  • 그러나 프로그램 명세는 입력이 이러한 가정과 일치하지 않을 경우 어떻게 해야 할지를 거의 정의하지 않습니다.
  • 그 결과, 많은 프로그램이 비정상적인 입력을 받으면 예측할 수 없는 동작을 하며, 때로는 시스템 보안에 위협이 됩니다.
  • 따라서, 입력을 처리하기 전에 항상 입력의 유효성을 검사해야 합니다.
  • ex) array index 범위 조사, 인스턴스, 키 입력 조사

3. 모든 예외에 대한 핸들러 제공 (Provide a handler for all exceptions)

  • 프로그램 예외는 오류 또는 전력 실패와 같은 예상치 못한 이벤트입니다.
  • 예외 처리 구문은 이러한 이벤트를 탐지하기 위해 지속적인 상태 점검 없이 처리할 수 있도록 합니다.
  • 일반적인 제어 구문을 사용하여 예외를 탐지하려면 많은 추가 명령문을 프로그램에 추가해야 합니다.
    • 이는 상당한 오버헤드를 추가하고 잠재적으로 오류가 발생하기 쉽습니다.
  • 예외 처리는 일부 결함 허용 (fault tolerance)을 제공하는 메커니즘입니다.
  • ex) nullpointerException 등을 handling

4. 오류 발생 가능성이 높은 구문의 사용 최소화 (Minimize the use of error-prone constructs)

  • 프로그램 결함은 대개 사람의 실수로 인한 결과입니다.
    • 이는 프로그래머가 시스템의 다른 부분 간의 관계를 추적하지 못하기 때문입니다.
  • 이는 프로그래밍 언어에서 본질적으로 복잡하거나 실수를 확인하지 않는 오류 발생 가능성이 높은 구문에 의해 악화됩니다.
    • 예: goto, FP 숫자, 포인터, 동적 메모리 할당 등.
  • 따라서 프로그래밍할 때 이러한 오류 발생 가능성이 높은 구문의 사용을 피하거나 최소화해야 합니다.

5. 재시작 기능 제공 (Provide restart capabilities)

  • 긴 트랜잭션이나 사용자 상호작용이 포함된 시스템의 경우,
    • 실패 후 시스템을 재시작할 수 있는 재시작 기능을 항상 제공해야 합니다.
    • ex) error->failure라고 하더라도, autosave 등의 메커니즘을 넣어줘야 한다
    • 프로그램 state를 잘 파악하고 관리해줘야 함
    • 사용자가 이미 한 작업을 모두 다시 해야 하는 것을 방지합니다.
  • 재시작은 시스템의 유형에 따라 다릅니다.
    • 문제가 있을 경우 사용자가 양식을 다시 작성할 필요가 없도록 양식의 사본을 유지합니다.
    • 주기적으로 상태를 저장하고 저장된 상태에서 재시작합니다.

6. 배열 경계 검사 (Check array bounds)

  • C와 같은 일부 프로그래밍 언어에서는 배열 선언에서 허용된 범위 밖의 메모리 위치를 참조할 수 있습니다.
  • 이는 잘 알려진 '경계 버퍼' 취약점으로 이어집니다.
    • 공격자가 배열의 최상위 요소를 넘어 의도적으로 쓰기를 하여 실행 가능한 코드를 메모리에 작성하는 경우.
  • 만약 사용하는 언어에 경계 검사가 포함되지 않는다면,
    • 항상 배열 접근이 배열의 경계 내에 있는지 확인해야 합니다.

7. 외부 구성요소 호출 시 타임아웃 포함 (Include timeouts when calling external components)

  • 분산 시스템에서 원격 컴퓨터의 고장은 '침묵'할 수 있습니다.
    • 따라서 해당 컴퓨터로부터 서비스를 기대하는 프로그램이 그 서비스를 받지 못하거나 고장이 발생했다는 어떤 표시도 받지 못할 수 있습니다.
  • 이를 방지하려면 외부 구성요소에 대한 모든 호출에 타임아웃을 항상 포함해야 합니다.
    • ex) DB에 저장하는데 너무 시간이 오래걸리는 경우 timeout 설정
  • 정의된 시간 기간 내에 응답이 없으면,
    • 시스템은 고장을 가정하고 이를 복구하기 위해 필요한 조치를 취해야 합니다.

8. 실제 값을 나타내는 모든 상수에 이름 지정 (Name all constants that represent real-world values)

  • 항상 실제 값 (예: 세율)을 반영하는 상수에 이름을 지정하고 숫자 값을 사용하지 말고 항상 이름으로 참조하십시오.
    • 예: public static final PI = 3.14159;
  • 이름을 사용할 때는 값 대신 이름을 사용하는 경우 실수를 줄이고 잘못된 값을 입력할 가능성이 적습니다.
  • 이는 이러한 '상수'가 변경될 때 (실제로는 변경될 가능성이 있습니다),
    • 프로그램 내에서 한 번만 변경하면 됩니다.