사전 버스
개념

버스

gabury1고친 사람 github-actions[bot]

버스는 컴퓨터 안의 여러 부품이 통로 하나를 나눠 쓰며 데이터를 주고받게 해 줍니다. 부품끼리 전선을 따로 잇지 않고 모두 같은 통로에 붙습니다. 통로가 하나라서 한 번에 한 부품만 데이터를 실을 수 있습니다. 소프트웨어에서 말하는 이벤트 버스와 메시지 버스는 이 이름을 빌려 온 것입니다.

쉽고 빠른 이해

버스는 프로세서와 메모리, 장치들이 통로 하나를 같이 써서 데이터를 주고받게 해 줍니다. 예를 들어 프로세서가 메모리에서 값 하나를 읽으면 그 값은 버스를 타고 프로세서로 옵니다.

이게 없으면 부품 둘마다 전선을 따로 이어야 합니다. 부품이 하나 늘 때마다 기존 부품 전부와 새로 이어야 해서 선이 빠르게 불어납니다. 버스가 있으면 새 장치는 통로 하나에만 붙으면 됩니다.

어떻게 도는가:

  1. 데이터를 보내려는 부품이 먼저 통로를 쓸 차례를 얻습니다
  2. 어디로 보낼지와 무엇을 할지를 통로에 싣습니다
  3. 받는 부품이 제 몫인 줄 알아보고 값을 받거나 내줍니다

대가는 둘입니다.

  • 한 번에 한 부품만 쓰므로 붙은 부품이 많을수록 저마다 기다리는 시간이 늘어납니다
  • 통로가 1초에 나르는 양은 정해져 있습니다. 붙은 부품들이 그 양을 나눠 가집니다

상세

아파트 한 동의 복도를 떠올리면 됩니다. 집집마다 서로 오가는 길을 따로 내지 않고 모든 집 문이 복도 하나로 나 있습니다. 복도가 좁아서 한 번에 한 사람만 짐수레를 끌고 지나갈 수 있습니다. 짐을 옮길 사람은 복도가 빌 때까지 기다립니다.

이 절은 버스를 이루는 선과 그 위의 주고받기부터 봅니다. 그리고 운영체제와 백엔드에서 버스를 만나는 때까지 갑니다.

부품을 한 통로에 붙이는 까닭

컴퓨터 안에서 데이터를 주고받는 부품은 여럿입니다. 계산을 맡는 CPU(Central Processing Unit, 중앙 처리 장치), 데이터를 담아 두는 메모리, 바깥과 데이터를 주고받는 입출력 장치가 있습니다. 디스크와 네트워크 카드가 입출력 장치의 예입니다.

이 부품들을 두 개씩 짝지어 전선을 따로 이으면 선이 금방 불어납니다. 부품이 넷이면 짝이 여섯, 여덟이면 스물여덟입니다. 부품이 하나 늘 때마다 기존 부품 전부에 새 선을 이어야 합니다.

버스는 이 선들을 통로 하나로 모읍니다. 모든 부품이 같은 통로에 붙습니다. 새 장치도 그 통로 하나에만 붙으면 됩니다.

flowchart TD
    subgraph P["짝마다 따로 잇기 · 선 여섯"]
        A1["CPU"] --- A2["메모리"]
        A1 --- A3["디스크"]
        A1 --- A4["네트워크 카드"]
        A2 --- A3
        A2 --- A4
        A3 --- A4
    end
    subgraph Q["버스 하나에 붙이기 · 선 넷"]
        B1["CPU"] --- B0["버스"]
        B2["메모리"] --- B0
        B0 --- B3["디스크"]
        B0 --- B4["네트워크 카드"]
    end
    P ~~~ Q

위 그림은 부품 넷을 잇는 두 방법을 견줍니다. 짝마다 이으면 선이 여섯입니다. 버스에 붙이면 부품 수만큼 넷입니다. 부품이 늘수록 이 차이는 더 벌어집니다.

통로가 하나로 모이면 장치를 붙이는 방법도 하나로 정할 수 있습니다. 장치를 꽂는 홈을 슬롯이라고 합니다. 슬롯 모양과 신호 규칙을 한 번 정해 두면 누가 만든 장치든 같은 슬롯에 꽂힙니다.

버스를 이루는 세 갈래 선

버스는 전선 한 가닥이 아니라 여러 가닥의 묶음입니다. 가닥들은 맡은 일에 따라 세 갈래로 나뉩니다. 아래 표가 갈래마다 무엇을 싣는지 보입니다.

갈래 싣는 것 방향
주소 버스 읽거나 쓸 곳의 주소 요청하는 쪽 → 응답하는 쪽
데이터 버스 오가는 값 양쪽
제어 버스 읽기인지 쓰기인지, 언제 값을 읽어도 되는지 알리는 신호 양쪽

한 번 주고받을 때 세 갈래가 다 쓰입니다. 주소 버스가 어디를, 제어 버스가 무엇을 할지를, 데이터 버스가 그 값을 맡습니다.

가닥의 수를 버스 폭이라고 합니다. 가닥 하나는 한 번에 0 이나 1 한 비트를 싣습니다. 그래서 데이터 버스가 64가닥이면 한 번에 64비트를 나릅니다.

주소 버스의 폭은 가리킬 수 있는 주소의 수를 정합니다. 가닥이 32개면 서로 다른 주소를 2의 32제곱, 약 43억 개 만들 수 있습니다. 주소 하나가 한 바이트를 가리키면 약 4기가바이트까지 닿습니다.

값 하나를 읽을 때 오가는 순서

이 소절은 CPU 가 메모리에서 값 하나를 읽어 오는 한 번을 따라갑니다.

sequenceDiagram
    participant C as CPU
    participant M as 메모리
    C->>M: 주소 버스 · 읽을 주소
    C->>M: 제어 버스 · 읽기 신호
    M-->>C: 데이터 버스 · 그 주소의 값
    Note over C,M: 이 한 번 동안 버스는 둘이 쓴다

CPU 가 주소 버스에 주소를 싣고 제어 버스로 읽기 신호를 보냅니다. 메모리는 그 주소의 값을 데이터 버스에 실어 돌려줍니다. 쓰기는 방향만 다릅니다. CPU 가 주소와 값을 함께 싣고 쓰기 신호를 보냅니다.

많은 버스는 이 주고받기를 클럭에 맞춰 돌립니다. 클럭은 일정한 간격으로 뛰는 박자 신호입니다. 클럭에 맞춰 주고받아야 받는 쪽이 아직 덜 실린 값을 잘못 읽지 않습니다.

버스를 쓸 차례를 정하는 중재

두 부품이 한 버스에 동시에 값을 실으면 신호가 섞여 둘 다 망가집니다. 그래서 지금 누가 버스를 쓸지 정하는 절차가 따로 있습니다. 이 절차를 버스 중재라고 합니다.

버스를 쓰고 싶은 부품은 중재기에 먼저 요청을 보냅니다. 중재기는 요청들 가운데 하나를 골라 허락을 내줍니다. 허락을 받은 부품만 버스에 값을 싣습니다. 다 쓰면 버스를 내놓습니다.

sequenceDiagram
    participant D1 as 장치 1
    participant D2 as 장치 2
    participant A as 중재기
    D1->>A: 버스를 쓰고 싶다
    D2->>A: 버스를 쓰고 싶다
    A-->>D1: 허락
    Note over D2,A: 장치 2 는 기다린다
    D1->>A: 다 썼다 · 버스를 내놓는다
    A-->>D2: 허락

그림은 두 장치가 한꺼번에 요청한 경우입니다. 중재기가 장치 1 에 먼저 허락을 줍니다. 장치 2 는 장치 1 이 버스를 내놓을 때까지 기다립니다.

중재기가 고르는 방법은 여럿입니다. 급한 장치에 늘 먼저 주는 우선순위 방식이 있습니다. 돌아가며 한 번씩 주는 라운드 로빈 방식도 있습니다. 우선순위만 쓰면 순위가 낮은 장치는 오래 기다리기도 합니다.

버스에 주소와 명령을 실어 주고받기를 시작하는 부품을 버스 마스터라고 합니다. 부름을 받고 응답만 하는 쪽과 가르는 이름입니다. 오래된 컴퓨터에서 버스 마스터는 대개 CPU 하나였습니다.

디스크나 네트워크 카드처럼 큰 데이터를 옮기는 장치는 스스로 버스 마스터가 되기도 합니다. 장치가 이렇게 직접 버스를 잡는 일이 버스 마스터링입니다.

장치가 버스를 잡는 까닭은 CPU 를 거치지 않고 메모리와 데이터를 직접 주고받는 데 있습니다. 이 주고받기 방식이 DMA(Direct Memory Access, 직접 메모리 접근)입니다. 버스 마스터링은 수단입니다. 그 수단으로 이루려는 일이 DMA 입니다.

버스가 나를 수 있는 양

버스가 1초에 나를 수 있는 데이터 양을 대역폭이라고 합니다. 대역폭은 한 번에 나르는 양에 1초에 나르는 횟수를 곱해 얻습니다.

가령 데이터 버스가 64비트, 곧 8바이트라고 해 봅시다. 1초에 1억 번 나르면 대역폭은 초당 8억 바이트, 약 800메가바이트입니다.

붙은 부품들은 이 대역폭을 나눠 씁니다. 한 장치가 버스를 오래 쥐면 나머지는 그동안 기다립니다. 그래서 부품이 늘거나 빨라질수록 버스가 먼저 막히는 병목이 되기 쉽습니다.

느린 장치가 섞이는 것도 문제입니다. 한 버스 위의 부품은 그 버스의 클럭에 맞춰야 합니다. 빠른 부품과 느린 부품을 한 버스에 두면 빠른 쪽이 느린 클럭에 묶입니다.

그래서 컴퓨터는 버스를 여러 계층으로 나눕니다. CPU 와 메모리는 가장 빠른 버스로 잇습니다. 디스크나 키보드 같은 장치는 그 아래 느린 버스에 붙입니다.

계층과 계층 사이는 브리지가 잇습니다. 브리지는 한 버스에서 받은 요청을 다른 버스의 클럭과 규칙으로 바꿔 넘겨 주는 부품입니다. 덕분에 느린 장치가 빠른 버스의 클럭을 끌어내리지 않습니다.

flowchart TD
    subgraph F["빠른 버스"]
        C["CPU"]
        M["메모리"]
    end
    F --- BR["브리지"]
    BR --- S
    subgraph S["느린 버스"]
        D1["디스크"]
        D2["네트워크 카드"]
        D3["키보드"]
    end

그림에서 위 계층은 CPU 와 메모리만 쓰는 빠른 버스입니다. 장치들은 아래 계층에 모여 있습니다. 위 계층과 데이터를 주고받으려면 브리지를 거칩니다.

나란한 가닥에서 전용 직렬 연결로

지금까지 본 버스는 여러 가닥이 나란히 달리고 여러 부품이 함께 붙는 모양입니다. 이런 버스를 병렬 버스라고 합니다. 오래된 확장 슬롯 규격인 PCI(Peripheral Component Interconnect, 주변 장치 상호 연결)가 이런 모양이었습니다.

병렬 버스는 클럭을 빠르게 올리면 한계에 부딪힙니다. 나란히 달리는 가닥들의 신호가 조금씩 다른 때에 도착하기 때문입니다. 이 도착 시각의 어긋남을 스큐라고 합니다. 클럭이 빨라질수록 스큐가 한 클럭 주기 안에서 차지하는 몫이 커집니다. 그만큼 값을 제대로 읽기 어려워집니다.

그래서 요즘의 장치 연결은 가닥 수를 줄입니다. 대신 한 가닥으로 비트를 빠르게 차례차례 보냅니다. 이런 방식을 직렬 통신이라고 합니다. 이름에 버스가 든 USB(Universal Serial Bus, 범용 직렬 버스)도 직렬로 데이터를 나릅니다.

또 요즘은 여러 장치가 한 통로를 나눠 쓰지 않습니다. 장치마다 전용 연결을 받습니다. 이것을 점대점 연결이라고 합니다. 연결 하나에 두 끝만 붙으니 그 연결을 두고 차례를 다툴 상대가 없습니다.

PCI Express가 이 방식을 씁니다. CPU 쪽과 장치들 사이에는 스위치가 놓이기도 합니다. 스위치는 여러 전용 연결을 한데 모아 서로 이어 줍니다.

flowchart TD
    C["CPU 쪽"] --- SW["스위치"]
    SW --- D1["디스크"]
    SW --- D2["네트워크 카드"]

그림에서 선 하나하나가 전용 연결입니다. 공유 버스와 달리 서로 다른 연결 위로는 동시에 데이터가 오갈 수 있습니다.

앞에서 본 「통로 하나를 나눠 쓰는」 모양은 옛 병렬 버스의 모습입니다. 요즘은 전용 연결이라도 여전히 버스라고 부릅니다. 여러 장치가 같은 규칙으로 붙기 때문입니다. 운영체제도 그 규칙 하나로 장치들을 다룹니다.

기판 위의 작은 칩들은 가닥 몇 개짜리 느린 버스로 이어지기도 합니다. 온도 센서나 설정 값을 담는 작은 메모리 칩이 그런 칩입니다. I2C(Inter-Integrated Circuit, 집적 회로 간 통신)와 SPI(Serial Peripheral Interface, 직렬 주변 장치 인터페이스)가 이런 버스입니다.

운영체제가 버스를 다루는 법

운영체제는 장치를 쓰기 전에 어느 버스에 무엇이 꽂혀 있는지부터 알아내야 합니다. PCI Express 나 USB 같은 버스는 꽂힌 장치가 만든 회사와 장치 종류를 번호로 밝히게 해 둡니다. 운영체제는 버스를 훑어 이 번호들을 모읍니다. 이 일을 장치 열거라고 부릅니다.

장치 하나를 다루는 코드를 디바이스 드라이버라고 합니다. 장치마다 다루는 법이 달라서 그 장치를 아는 코드가 따로 있어야 합니다.

운영체제 안에는 버스 하나를 맡는 코드도 따로 있습니다. Windows 는 이 코드를 버스 드라이버라고 부릅니다. 버스 드라이버는 꽂힌 장치를 찾아냅니다. 그리고 그 장치를 맡을 디바이스 드라이버를 골라 붙입니다.

장치를 켠 채로 꽂거나 뽑는 일을 핫 플러그라고 합니다. 버스가 장치가 새로 붙거나 떨어진 것을 운영체제에 알려 주기 때문에 가능합니다.

백엔드 개발자가 버스를 만나는 때

백엔드 코드가 버스를 직접 다룰 일은 없습니다. 그래도 서버의 성능을 따질 때 버스는 자원 하나로 셉니다. USE(Utilization·Saturation·Errors, 사용률·포화·오류) 방법은 자원마다 얼마나 바쁜지, 얼마나 밀렸는지, 오류가 났는지를 차례로 봅니다. 이 방법은 점검할 자원 목록에 버스를 넣습니다.

SSD(Solid State Drive, 반도체 저장 장치)나 네트워크 카드를 새로 달아도 기대만큼 안 빨라지기도 합니다. 그때는 그 장치가 붙은 연결의 대역폭부터 봅니다. 장치가 아무리 빨라도 연결이 나를 수 있는 양을 넘지 못합니다.

CPU 와 메모리 사이도 같습니다. 큰 배열을 처음부터 끝까지 훑는 코드는 계산보다 메모리에서 값을 실어 오는 데 시간을 더 씁니다. 이때 코드를 붙잡는 것은 CPU 의 계산 속도가 아니라 메모리 대역폭입니다.

이름에 버스가 든 오류도 있습니다. 유닉스 계열 운영체제는 하드웨어가 받아들일 수 없는 메모리 접근을 만나면 그 프로세스에 SIGBUS 신호를 보내 멈춥니다. 이것을 버스 오류라고 부릅니다. 메모리 접근이 버스 위에서 끝나지 못했다는 뜻에서 붙은 이름입니다.

받아들일 수 없는 접근의 한 예는 정렬이 어긋난 주소입니다. 어떤 CPU 는 4바이트 값을 4의 배수 주소에서만 읽습니다. 이런 CPU 에서 4의 배수가 아닌 주소로 4바이트를 읽으면 버스 오류가 납니다.

백엔드에서 더 자주 만나는 예는 메모리 매핑입니다. 메모리 매핑은 파일 내용을 메모리 주소처럼 읽도록 프로세스에 붙여 두는 일입니다. 파일을 읽을 때 읽기 함수를 부르지 않고 그 주소를 읽으면 됩니다.

파일을 메모리에 매핑해 두었다고 합시다. 그 뒤 다른 쪽에서 파일을 줄이면, 줄어든 끝 너머를 읽는 순간 버스 오류가 납니다. 그 주소에는 실어 올 파일 데이터가 더는 없기 때문입니다.

소프트웨어가 빌려 쓴 이름

소프트웨어에도 버스라는 이름이 붙은 구조가 여럿 있습니다. 여러 구성 요소가 서로를 직접 부르지 않고 통로 하나에 메시지를 올려 주고받는 구조입니다. 부품들이 한 통로에 붙는 모양이 같아서 이름을 빌려 왔습니다.

이벤트 버스·메시지 버스·서비스 버스가 그런 이름입니다. 리눅스 데스크톱에서 프로그램끼리 메시지를 주고받는 D-Bus도 같은 뿌리입니다. 이 문서의 버스는 하드웨어 버스를 말합니다. 소프트웨어 쪽 버스는 각 항목이 다룹니다.

관련 항목

버스로 이어지는 부품

CPU · 메모리 · 디스크 · SSD · 네트워크 카드 · GPU · 입출력 장치 · 메인보드

버스를 이루는 신호선과 클럭

주소 버스 · 데이터 버스 · 제어 버스 · 버스 폭 · 클럭 · 비트

버스를 쓸 차례를 정하는 방식

버스 중재 · 중재기 · 라운드 로빈 · 버스 마스터 · 버스 마스터링 · DMA · 기아 상태

버스가 나르는 양을 재는 지표

대역폭 · 메모리 대역폭 · 처리량 · 지연 시간 · 병목

버스를 계층으로 나누고 잇는 부품

시스템 버스 · 메모리 버스 · 브리지 · 칩셋 · 스위치

버스 모양을 가르는 연결 방식

병렬 버스 · 직렬 통신 · 점대점 연결 · 스큐

버스를 구현한 규격

PCI · PCI Express · USB · ISA · I2C · SPI

운영체제에서 버스를 다루는 구성 요소

버스 드라이버 · 디바이스 드라이버 · 장치 열거 · 핫 플러그 · 버스 자원 · 드라이버 스택 · 인터럽트

버스를 점검 대상에 넣는 성능 분석

성능 · USE 방법 · 사용률 · 포화

잘못된 메모리 접근이 내는 오류와 그 원인

버스 오류 · 세그멘테이션 폴트 · 정렬 · 메모리 매핑

버스라는 이름을 빌려 쓴 소프트웨어 구조

이벤트 버스 · 메시지 버스 · 서비스 버스 · D-Bus · 메시지 브로커 · 발행-구독

버스가 속하는 상위 분류

컴퓨터 구조 · 하드웨어 · 운영체제 · 디지털 회로

다른 이름: Bus · 컴퓨터 버스