지난 루비 매직(Ruby Magic) 아티클 동시성 마스터하기에서는 루비 개발자가 활용할 수 있는 세 가지 동시성 구현 방법을 소개했습니다. 이번 글은 각 방법을 하나씩 깊이 있게 파헤치는 3부작 시리즈의 첫 번째 편입니다.첫 번째 주제는 바로 다중 프로세스(Multi-process)입니다. 이 방식에서는 마스터 프로세스가 자기 자신을 여러 워커 프로세스로 복제(포크)하고, 실제 작업은 워커 프로세스가 수행하며 마스터 프로세스는 이들을 관리하는 역할을 맡습니다.본문 예제에 사용된 전체 소스 코드는 GitHub에 공개되어 있으니 직접
Ruby Magic 이전 호에서는 여러 프로세스를 활용해 채팅 시스템을 구현하는 방법을 소개했습니다. 이번에는 같은 기능을 멀티스레딩(Multi-threading)으로 구현하는 방법을 알아보겠습니다. 빠른 복습 기본 설정에 대한 자세한 설명이 필요하다면 이전 글을 먼저 참고하세요. 간단히 요약하자면, 우리가 만들 채팅 시스템은 다음과 같은 구조로 되어 있습니다. 클라이언트는 이전에 사용했던 것과 동일합니다: # client.rb # $ ruby client.rb require socket client = TCPSocket.open(
Ruby Magic 동시성 시리즈의 마지막 아티클에 오신 것을 환영합니다. 지금까지 우리는 여러 프로세스와 여러 스레드를 사용해 채팅 서버를 구현해 보았습니다. 이번에는 같은 기능을 이벤트 루프(event loop) 방식으로 구현해 보겠습니다.복습이전 글에서 사용한 것과 동일한 클라이언트와 서버 설정을 그대로 사용합니다. 목표는 다음과 같은 채팅 시스템을 만드는 것입니다.기본 설정에 대한 자세한 내용은 이전 아티클을 참고해 주세요. 이 글의 예제에서 사용된 전체 소스 코드는 GitHub에서 확인할 수 있으니 직접 실험해 보셔도 좋습
Ruby Magic 시리즈에 다시 오신 것을 환영합니다! 이번 글에서는 Ruby가 우리가 작성한 코드를 어떻게 해석하는지 살펴보고, 이 지식을 실제 개발에 어떻게 활용할 수 있는지 알아보겠습니다. 코드가 해석되는 과정을 이해하면 더 빠른 코드를 작성하는 데 큰 도움이 됩니다.심볼 하나가 만드는 미묘한 차이이전 Ruby Magic 아티클인 Ruby에서 문자 이스케이프 처리하기에서 줄바꿈 문자를 이스케이프하는 예제를 소개한 적이 있습니다.아래 예제를 보면 두 개의 문자열을 여러 줄에 걸쳐 하나의 String으로 합치는 방법이 두 가지
AppSignal을 사용하는 앱이 실행 중인 모든 서버는 30초마다 샘플과 메트릭 데이터를 저희 Push API로 전송합니다.각 요청에는 해당 데이터가 어떤 앱에서 전송된 것인지 식별하기 위한 키가 포함되어 있습니다. 이를 확인하려면 수신되는 모든 요청에 대해 데이터베이스를 조회해 해당 앱을 찾아야 합니다. 월 300억 건에 달하는 요청을 처리하는 만큼, 저희는 AppSignal의 속도를 높이기 위해 쿼리 수를 줄일 방법을 끊임없이 고민하고 있습니다.캐싱 도입 후 오히려 늘어난 쿼리데이터베이스 클러스터의 부하를 줄이기 위해 저희는
애플리케이션에서 오류가 발생하면 Ruby는 예외(exception)를 발생시키고 스택 트레이스(stack trace)를 로그에 출력합니다. 이 글에서는 스택 트레이스를 읽는 방법과, 이를 활용해 애플리케이션 내에서 예외의 발생 지점을 찾아내는 방법을 살펴보겠습니다.호출 스택(Call Stack)메서드를 호출할 때마다 Ruby는 호출 스택(call stack, 런타임 스택이라고도 하며 흔히 그냥 스택이라 부릅니다)에 스택 프레임(stack frame)을 쌓습니다. 스택 프레임은 메서드의 인자, 내부 변수를 위한 공간, 그리고 호출자의
Rails 애플리케이션에서 오류가 발생하면 예외(exception)와 스택 트레이스(stack trace)는 문제가 어디서 발생했는지 파악하는 데 큰 도움이 됩니다. 하지만 무엇이 어디서 일어났는지 아는 것만으로는 부족하며, 그다음 단계는 왜 그런 일이 발생했는지 밝혀내는 것입니다. 이 글에서는 백트레이스를 활용해 Rails 애플리케이션의 버그를 추적하는 방법을 살펴보겠습니다.NoMethodError (undefined method `request_uri for #<URI::Generic >): app/models/pr
Ruby Magic 시리즈에 다시 오신 것을 환영합니다! 이번 에피소드에서는 Ruby가 구문 설탕(syntactic sugar)을 활용해 코드를 더 표현력 있고 읽기 쉽게 만드는 방법을 살펴봅니다. 글을 끝까지 읽고 나면 Ruby의 몇 가지 마법 같은 기능이 내부적으로 어떻게 동작하는지, 그리고 직접 이런 설탕을 활용한 메서드를 작성하는 방법까지 알게 될 것입니다.Ruby 애플리케이션을 개발하다 보면 클래스 속성, 배열(Array), 해시(Hash)를 다른 언어에서는 낯설게 느껴지는 방식으로 다루게 됩니다. 과연 속성을 할당하고 배
대부분의 예외는 평소에는 잘 작동하던 메서드에 예상치 못한 데이터가 전달되면서 발생합니다. 따라서 오류의 원인을 찾으려면 해당 데이터가 애플리케이션 내에서 어떻게 흘러가는지 추적해 보는 것이 큰 도움이 됩니다. 이 글에서는 Ruby와 Rails 애플리케이션에서 데이터를 검사(inspect)하는 다양한 방법을 살펴보겠습니다. puts, #inspect와 p Ruby의 puts 메서드는 콘솔에 메시지를 출력할 때 사용합니다. unknown = This is a string puts unknown 위 스크립트를 실행하면 변수 안의 값이
루비는 표준 라이브러리에 코드 성능을 측정할 수 있는 벤치마킹 도구를 기본으로 제공합니다. 이 도구는 특히 두 가지 구현 방식을 비교해 어느 쪽이 더 빠른지 확인해야 할 때 가장 큰 빛을 발합니다. 예제 소개: 문자열 키를 심볼 키로 변환하기 이번 예제에서는 문자열 키를 가진 해시(예: {foo => bar})를 심볼 키를 가진 해시(예: {:foo => bar})로 변환하는 작업을 다룹니다. 예제 전반에서는 영어 알파벳 26개 글자를 키와 값으로 갖는 해시를 사용합니다. 매번 직접 입력하지 않고도 이 해시를 손쉽게 만들
루비에서 예외(Exception)는 애플리케이션에서 발생하는 비정상적인 상황에 대한 정보를 담고 있는 특별한 데이터 구조입니다. 프로그램이 특정 상황을 처리할 방법을 알지 못해 더 이상 실행을 지속할 수 없을 때 보내는 신호가 바로 예외입니다. 루비에서는 이러한 신호를 보내는 행위를 예외 발생(raise)이라고 부릅니다.raise this is an exception puts This message wont be printed.예외를 실제로 확인해보는 가장 빠른 방법은 직접 하나를 발생시켜 보는 것입니다. raise 메서드에 메
Rails 애플리케이션이 요청을 받으면 컨트롤러는 일반적으로 모델에 필요한 데이터를 조회하도록 지시합니다. 모델은 데이터베이스에서 데이터를 가져와 컨트롤러에 전달하고, 컨트롤러는 최종적으로 사람이 읽기 좋은 형태로 데이터를 표현하는 뷰를 렌더링합니다.하지만 어떤 상황에서는 뷰를 렌더링하는 작업이 상당히 무겁습니다. 특히 스토어의 모든 상품 목록처럼 많은 양의 데이터를 한 화면에 표시해야 하는 경우가 대표적입니다. 이럴 때 반환되는 뷰의 일부를 캐싱하면 응답 속도를 크게 개선할 수 있으며, 데이터가 자주 변경되지 않는 경우 그 효과는
top, uptime, w 같은 명령어나 AppSignal의 호스트 메트릭에서는 부하 평균(load average)이라는 지표를 확인할 수 있습니다. 이 지표는 여러 시간 구간에 걸쳐 평균을 낸 값으로, 시스템이 얼마나 부하를 받았는지 알려줍니다.$ uptime 10:14:14 up 60 days, 17:42, 1 user, load average: 0.44, 0.28, 0.25 부하 평균은 보통 세 개의 숫자로 표시됩니다. 위 uptime 출력 결과 마지막의 세 숫자는 각각 최근 1분(0.44), 최근 5분(0.28), 최근
이번 글에서는 Rails에 내장된 프래그먼트 캐싱(fragment caching)을 한 단계 더 발전시킬 수 있는 기법인 러시아 인형 캐싱(Russian Doll Caching)에 대해 자세히 알아보겠습니다. 프래그먼트 캐싱이란? Rails의 내장 프래그먼트 캐싱을 사용하면 렌더링된 뷰의 일부가 뷰 프래그먼트 형태로 저장되고, 동일한 요청이 다시 들어오면 이를 재사용합니다. 캐시된 프래그먼트는 stale(만료) 상태가 될 때까지 계속 재사용됩니다. 여기서 stale란 프래그먼트 생성 이후 화면에 표시되는 데이터가 변경되어 더 이상
발생한 예외(exception)는 호출 스택(call stack)의 최상단에 도달해 애플리케이션 전체를 중단시키기 전에 구조(rescue)하여 막을 수 있습니다. Ruby에서는 이를 위해 rescue 키워드를 사용합니다.Ruby에서 예외를 구조할 때는 어떤 에러 클래스를 구조할지 구체적으로 지정할 수 있습니다.begin raise This exception will be rescued! rescue StandardError => e puts Rescued: #{e.inspect} end참고: raise를 사용할 때 예외
새로운 Rails 앱을 생성하면 캐싱은 이미 설정되어 있습니다. 덕분에 cache 헬퍼로 뷰 조각을 감싸거나 Rails.cache.fetch로 외부 API 결과를 저장하는 것만으로도 빠르게 시작할 수 있습니다. 캐시된 데이터는 Rails의 캐시 저장소(cache store) 중 하나에 보관되며, 메모리, Memcached, Redis에 저장하거나 디스크에 직접 기록할 수도 있습니다.그렇다면 여러 캐시 저장소 중 어떤 것이 어떤 상황에 가장 적합할까요? 이 글에서는 각 옵션의 특징과 장단점을 하나씩 살펴보겠습니다.👋 이 글이 마음에
AppSignal은 개발자들의 애플리케이션 성능 향상을 돕는 서비스입니다. 수십억 건의 요청을 처리하는 수많은 앱을 모니터링하다 보니, Ruby와 성능에 관한 블로그 글 몇 편으로도 여러분에게 도움을 드릴 수 있겠다는 생각을 했습니다. N+1 쿼리 문제는 Rails 애플리케이션에서 흔히 발견되는 안티패턴입니다.Rails의 ActiveRecord를 비롯한 많은 ORM은 지연 로딩(lazy loading)을 기본 내장하고 있어, 연관 관계(association) 조회를 실제로 필요한 시점까지 미룰 수 있습니다. 덕분에 어떤 연관 데이터
Rails 애플리케이션의 성능을 높이는 방법은 러시아 인형 캐싱(Russian doll caching)만 있는 것이 아닙니다. 이번 글에서는 Rails에 내장된 조건부 GET(Conditional GET) 지원 기능을 살펴보겠습니다. 이 기능을 활용하면 렌더링된 페이지를 사용자의 브라우저 캐시에 저장해 서버 부담과 응답 시간을 크게 줄일 수 있습니다. 👋 캐싱 외적인 성능 최적화 주제에 관심이 있다면, Ruby(on Rails) 성능에 관한 다른 글들도 확인해 보세요. 저희가 정리한 Ruby 성능 모니터링 체크리스트도 큰 도움이
Ruby에서 발생한 예외는 rescue로 잡아 문제가 생겼을 때 다른 코드 경로를 실행할 수 있습니다. 하지만 예외 처리 방법은 이것만이 아닙니다. 이번 AppSignal Academy 아티클에서는 retry와 ensure 키워드를 살펴보고, 잡은 예외를 다시 던지는(재발생시키는) 방법까지 알아보겠습니다.신뢰할 수 없는 웹 API와 통신한다고 가정해 보겠습니다. 이 API는 가끔씩 다운되기도 하고, 너무 느려서 요청 하나에 몇 초씩 걸리기도 합니다. 우리 라이브러리는 이 API에 의존하고 있으므로 최대한 탄력적으로 동작하도록 만들어
Turbolinks는 페이지 전환과 에셋 재로딩을 지능적으로 처리해 체감 성능을 끌어올리는 최적화 기술입니다. 조건부 GET 요청 방식과 달리 Rails 앱의 Ruby 코드를 전혀 수정할 필요가 없습니다. Turbolinks 5는 어디서든 동작하는(Rails 없이 정적 페이지에서도) 자바스크립트 라이브러리로, 지원하지 않는 브라우저에서는 우아하게 기능을 포기하는 방식으로 안전하게 작동합니다.Turbolinks 5란?Turbolinks는 Rails 4부터 Rails에 기본 번들되어 새 애플리케이션에 포함되었습니다. Rails 5에는