Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

솔리드 케이블이 포함된 마스터 레일 액션 케이블:Redis 없이 실시간 앱 구축

실시간 기능은 웹 애플리케이션에서 점점 더 중요해지고 있지만 모든 Rails 개발자가 프레임워크에 내장된 WebSocket 라이브러리인 Action Cable에 익숙한 것은 아닙니다.

Rails Action Cable은 오랫동안 웹 소켓을 지원해 왔지만 약간의 복잡성이 더해졌습니다. Rails 8에서는 단선 케이블을 소개합니다. , Redis가 필요 없는 새로운 Action Cable용 데이터베이스 지원 어댑터입니다. 이 가이드에서는 Solid Cable을 통해 Action Cable을 안내하고 실시간 기능을 구축하는 방법을 보여 드리겠습니다. Redis를 사용하지 않고도 Rails 8 앱에 실시간 기능을 추가하는 것이 얼마나 쉬운지 알게 될 것입니다.

저와 함께 앱을 제작해 보시는 것도 좋지만 GitHub에서 완성된 프로젝트를 확인해 보세요.

Rails Action 케이블을 사용하는 이유

최신 웹 앱은 클라이언트에 실시간으로 업데이트를 푸시해야 하는 경우가 많습니다. 몇 가지 확실한 예로는 즉시 나타나는 채팅 메시지나 실시간 대시보드 알림이 있습니다. 액션 케이블 WebSocket을 앱에 통합하여 서버와 클라이언트 간의 지속적인 양방향 통신을 가능하게 하는 Rails의 내장 솔루션입니다. 저는 개인적으로 Rails 프레임워크의 일부인 Action Cable에 감사드립니다. 이는 진정으로 유용한 웹 앱에 필요한 모든 것을 제공한다는 전반적인 주제를 지원하기 때문입니다. 액션 케이블을 사용하면 브라우저가 명시적으로 요청하지 않고도 서버가 브라우저에 데이터를 보낼 수 있습니다(사용자가 새로 고침을 요청하지 않습니다!).

Action Cable 및 WebSocket을 사용하면 Rails 앱은 역사적으로 서버 렌더링 앱에서 구현하기 어려웠던 라이브 대화형 기능을 제공할 수 있습니다. 이에 대한 일상적인 사용 사례는 다음과 같습니다:

  • 실시간 채팅 애플리케이션
  • 알림 및 피드
  • 실시간 업데이트가 가능한 공동작업 앱
  • 실시간 스포츠 또는 주식 시세

즉, Action Cable은 기존 요청-응답 주기와 실시간 이벤트 중심 업데이트 간의 격차를 해소합니다. 클라이언트 측에서 Rails는 채널을 구독하고 브로드캐스트를 수신할 수 있는 JavaScript 소비자를 제공합니다. 개발자는 프런트엔드 클라이언트가 구독할 수 있는 백엔드 채널(컨트롤러와 유사하지만 실시간 스트림용)을 정의하여 Action Cable과 상호 작용합니다.

그럼 솔리드 케이블이란 무엇인가요?

이전 Rails 버전에서 Action Cable을 사용한 적이 있다면 프로덕션 환경에서는 일반적으로 Redis(또는 PostgreSQL의 NOTIFY)에 의존한다는 것을 알고 계실 것입니다. ) 다양한 서버 프로세스에 걸쳐 메시지를 브로드캐스트합니다. 게시/구독 서비스(종종 Redis)는 하나의 Rails 프로세스의 메시지가 다른 모든 프로세스에 전달되어 연결된 WebSocket 클라이언트로 메시지를 전달할 수 있도록 합니다. 이 추가된 인프라는 역사적으로 Action Cable을 사용하는 데 반드시 필요했습니다.

Rails 8에 도입된 Solid Cable은 기존 데이터베이스를 백엔드로 사용하여 Redis와 같은 외부 게시/구독 서비스의 필요성을 대체합니다. Solid Cable은 Active Job용 Solid Queue 및 Active Cache용 Solid Cache와 마찬가지로 Action Cable용 데이터베이스 기반 어댑터입니다. 들어오는 각 WebSocket 메시지는 데이터베이스 테이블에 기록되고 모든 Action Cable 인스턴스는 해당 테이블을 폴링하여 새 메시지를 클라이언트에 브로드캐스팅합니다. 이는 매우 빠르게(기본적으로 100밀리초마다) 발생하여 거의 실시간 성능을 제공합니다. 메시지는 정리되기 전에 짧은 시간(기본적으로 24시간) 동안만 저장되므로 데이터베이스 공간에 대한 걱정 없이 최근 문제를 디버그할 수 있습니다.

전반적으로 Solid Cable은 캐싱, 백그라운드 작업 및 실시간 메시징을 위한 내장된 데이터베이스 지원 기능의 완전한 세트인 Rails 8의 철학인 "Solid Trifecta"에 적합합니다. Solid Cable을 사용하면 데이터베이스 전체에서 작업, 캐싱 및 WebSocket을 실행할 수 있는 마지막 부분이 있습니다.

Solid Cable을 사용하여 Rails 8 앱 구축

아마도 Solid Cable을 직접 사용해 보고 싶으실 겁니다. Rails 8 애플리케이션에 Solid Cable을 추가하고 여러 사용자가 실시간으로 메시지를 교환할 수 있는 최소 채팅방을 구축하는 과정을 살펴보겠습니다.

예제 앱 만들기

Solid Cable을 백엔드로 사용하면서 Action Cable의 기본 사항(채널, 구독, 방송)을 배우게 됩니다. 이 예에서는 Rails 8을 사용할 것이므로 다음을 사용하여 새 Rails 앱을 만드십시오.

rails _8.1.0_ new solid_cable_chat --database=sqlite3

그러면 cd 새로운 solid_cable_chat 디렉토리로 이동하세요.

Rails 8을 사용했으므로 작동을 위해 Solid Cable이나 다른 보석을 추가할 필요가 없습니다. 구성의 대부분 또는 전부가 당신을 위해 있을 것입니다. 이전 버전의 Rails를 사용하시는 경우를 대비해 모든 과정을 안내해 드리겠습니다.

솔리드 케이블 구성

Solid Cable 설정을 실행하는 것부터 시작하겠습니다:

bin/rails solid_cable:install

이 생성기는 두 가지 주요 작업을 수행합니다. config/cable.yml을 생성합니다. Solid Cable을 케이블 어댑터로 설정하는 구성 파일입니다. 또한 db/cable_schema.rb를 생성합니다. Solid Cable의 메시지 테이블에 대한 데이터베이스 스키마 정의가 포함된 파일입니다. 최신 버전의 Rails에서는 rails new를 실행할 때 자동으로 이러한 파일을 생성합니다. .

다음으로 Solid Cable에 대한 데이터베이스 설정을 구성해야 합니다. 기본적으로 Rails는 Solid Cable용 별도의 데이터베이스를 사용하여 실시간 메시징 데이터를 나머지 데이터와 분리합니다. 개발 중에는 동일한 데이터베이스를 사용하거나 별도의 데이터베이스를 설정할 수 있습니다. 개발 시 Solid Cable용으로 별도의 SQLite 데이터베이스를 사용하는 방법을 안내해 드리겠습니다. 이는 새로운 "케이블" 데이터베이스 연결을 추가하는 것을 의미합니다.

Solid Cable용 데이터베이스 설정

config/database.yml 열기 파일. 개발 섹션에 cable를 추가하세요. 데이터베이스. 예를 들어, SQLite(개발자의 Rails 기본값)를 사용하는 경우:

development:
 primary:
 <<: *default
 database: storage/development.sqlite3
 cable:
 <<: *default
 database: storage/development_cable.sqlite3
 migrations_paths: db/cable_migrate

production:
 primary:
 <<: *default
 database: storage/production.sqlite3
 cache:
 <<: *default
 database: storage/production_cache.sqlite3
 migrations_paths: db/cache_migrate
 queue:
 <<: *default
 database: storage/production_queue.sqlite3
 migrations_paths: db/queue_migrate
 cable:
 <<: *default
 database: storage/production_cable.sqlite3
 migrations_paths: db/cable_migrate

다시 말하지만, 최신 버전의 Rails를 사용하고 있다면 이 구성이 이미 있을 것입니다.

이제 config/cable.yml를 열어보세요 . Solid Cable은 이미 생산 시 기본 어댑터로 설정되어 있어야 합니다. 우리는 개발 중에도 Solid Cable을 활성화하고 싶습니다(그래서 localhost에서 채팅을 테스트할 수 있습니다). cable.yml 수정 solid_cable를 사용하려면 개발 중인 어댑터를 확인하고 cable를 가리킵니다. 방금 구성한 데이터베이스:

development:
 adapter: solid_cable
 connects_to:
 database:
 writing: cable
 polling_interval: 0.1.seconds
 message_retention: 1.day

test:
 adapter: test

production:
 adapter: solid_cable
 connects_to:
 database:
 writing: cable
 polling_interval: 0.1.seconds
 message_retention: 1.day

위의 cable.yml에서 , 개발 어댑터를 solid_cable로 설정했습니다. 프로덕션 설정에서 설정을 복사했습니다. connects_to 설정은 액션 케이블에 케이블을 사용하도록 지시합니다. 데이터베이스(database.yml에 정의됨) ) 메시지를 저장하는 데 사용됩니다. 최신 버전의 Rails에서도 이 변경 작업을 수행해야 합니다.

소규모 앱의 경우 동일한 기본 데이터베이스를 사용하여 Solid Cable의 테이블을 보관할 수 있습니다(스키마를 마이그레이션에 복사하고 별도의 DB 구성을 제거하여). 그러나 기본 앱 데이터에 대한 잠재적인 성능 간섭을 방지하려면 별도의 데이터베이스를 사용하는 것이 좋습니다.

마지막으로 rails db:prepare을 실행하세요. 데이터베이스가 준비되었는지 확인합니다. 앱을 출시하는 경우에도 프로덕션 단계에서 이 작업을 수행해야 합니다.

Action Cable 채널 설정

Action Cable은 데이터 스트림을 처리하는 Ruby 클래스인 채널을 통해 작동합니다. 이는 HTTP 요청을 처리하는 컨트롤러와 다소 유사합니다. 채팅 기능을 위한 채널을 만들어 보겠습니다. UserChatChannel라고 부르겠습니다. . 생성기를 사용하세요:

rails generate channel UserChat

생성된 app/channels/user_chat_channel.rb을 엽니다. , 새로운 로직을 포함하도록 업데이트하세요.

클라이언트가 UserChatChannel을 구독하는 경우 (채팅 페이지를 열어서) subscribed 콜백이 호출됩니다. stream_from "user_chat_channel"에 전화하고 싶습니다 이 콜백에서 "user_chat_channel"이라는 방송에서 스트리밍을 시작합니다. .

본질적으로, "user_chat_channel으로 전송되는 모든 데이터를 수신한다는 뜻입니다. 스트리밍하여 이 채널의 고객에게 전달합니다." 이 채널을 구독하는 모든 사용자는 "user_chat_channel"로 메시지 방송을 받습니다. .

또한 사용자 정의 작업을 정의하고 싶습니다. 이를 talk(data)이라고 하겠습니다. . 채널의 모든 공개 메소드는 클라이언트 측에서 호출될 수 있습니다. 이 경우 클라이언트가 perform("talk", { content: "Hello World" })를 호출하면 , talk 메소드가 서버에서 실행됩니다.

talk 구현 클라이언트가 보낸 메시지 내용을 가져와 ActionCable.server.broadcast을 사용합니다. "user_chat_channel"를 구독하는 모든 사람에게 보내려면 . 이는 모든 구독자(발신자를 포함)가 실시간으로 메시지 데이터를 수신한다는 의미입니다. 우리는 단순히 메시지 텍스트가 포함된 해시를 브로드캐스트합니다. 필요에 따라 다른 정보(예:사용자 이름 또는 타임스탬프)를 포함할 수 있습니다. 참고: 실제 앱에서는 메시지를 데이터베이스에 유지하거나 여기에서 유효성 검사를 수행할 수도 있습니다. 단순화를 위해 방송만 하겠습니다.

class UserChatChannel < ApplicationCable::Channel
 def subscribed
 stream_from "user_chat_channel"
 end

 def unsubscribed
 # Any cleanup needed when unsubscribing from the channel
 end

 def talk(data)
 message = data["content"]
 ActionCable.server.broadcast("user_chat_channel", { content: message })
 end
end

클라이언트에서 채널 소비자 구축

이제 백엔드를 구축했으므로 사용자가 WebSocket을 통해 메시지를 보내고 받을 수 있도록 프런트엔드를 연결하여 실시간 기능을 시연해야 합니다.

Rails 8에는 Action Cable의 JavaScript가 내장되어 있습니다. 생성기는 app/javascript/channels/user_chat_channel.js을 생성했습니다. 우리를 위해 파일을 보내세요. 다음에는 클라이언트 동작을 구현하겠습니다.

app/javascript/channels/user_chat_channel.js 열기 다음으로 업데이트하세요:

import consumer from "channels/consumer";

const userChatChannel = consumer.subscriptions.create("UserChatChannel", {
 connected() {
 console.log("Connected to UserChatChannel.");
 },

 disconnected() {
 console.log("Disconnected from UserChatChannel.");
 },

 received(data) {
 const messagesDiv = document.getElementById("messages");
 if (messagesDiv && data.content) {
 const messageElement = document.createElement("p");
 messageElement.textContent = data.content;
 messagesDiv.appendChild(messageElement);
 }
 }
});

function sendMessage(content) {
 userChatChannel.perform("talk", { content: content });
}

export { sendMessage };
window.sendMessage = sendMessage;

여기서는 consumer.subscriptions.create("UserChatChannel", {...})을 사용합니다. UserChatChannel 구독을 생성하려면 서버에서. 이는 채널과 상호작용하는 데 사용할 수 있는 구독 개체를 반환합니다.

connected() 연결이 설정되면 콜백이 실행됩니다. 여기에서는 콘솔에 로그인하여 작동하는지 확인합니다.

disconnected() WebSocket 연결이 끊어지면 콜백이 실행됩니다.

received(data) 콜백이 중요해요! 이 콜백은 채널이 서버로부터 브로드캐스트를 수신할 때마다 실행됩니다. UserChatChannel#talk에서 우리는 { content: message }를 방송합니다 . data 여기서 인수는 동일한 해시가 됩니다. 그러면 새 메시지가 오면 연결된 모든 클라이언트의 채팅 로그가 즉시 업데이트됩니다.

도우미 sendMessage(content)도 정의합니다. userChatChannel.perform("talk", { content: ... })을 호출하는 것입니다. . 그러면 서버 측 talk에 요청이 전송됩니다. 사용자가 입력한 메시지 내용을 포함하여 우리가 정의한 작업입니다.

이제 사용자가 메시지를 보내고 받을 수 있는 간단한 UI가 필요합니다. 이를 위한 매우 기본적인 뷰를 만들어 보겠습니다.

예제 앱을 위한 간단한 UI 구축

먼저 컨트롤러를 생성합니다:

rails generate controller UserChat index

다음으로, 인덱스 뷰를 열고 몇 가지 기본 설정을 지정하세요:

<h1>Chats from Users</h1>

<div id="messages" style="border: 1px solid #ccc; padding: 1em; height: 200px; overflow-y: auto; margin-bottom: 1em;">
 <!-- Messages will appear here -->
</div>

<form id="chat-form" onsubmit="event.preventDefault(); sendMessage(document.getElementById('chat-input').value); document.getElementById('chat-input').value = '';">
 <input type="text" id="chat-input" placeholder="Type a message..." autocomplete="off" style="width: 80%;" />
 <button type="submit">Send</button>
</form>

마지막으로 config/routes.rb의 이 새 경로를 가리키도록 루트 경로를 설정합니다. :

root "user_chat#index"

모든 것이 어떻게 함께 작동하는지 보여주기

간단한 채팅 앱을 테스트할 준비가 되었습니다! bin/dev로 프로젝트를 실행하세요. localhost:3000을 방문하세요. :

솔리드 케이블이 포함된 마스터 레일 액션 케이블:Redis 없이 실시간 앱 구축

실시간 업데이트를 표시하려면 두 개의 서로 다른 브라우저 탭에서 앱을 엽니다. 한 탭에 "Hello from tab number 1!"과 같은 메시지를 입력하세요.

솔리드 케이블이 포함된 마스터 레일 액션 케이블:Redis 없이 실시간 앱 구축 두 번째 탭에서 메시지를 보내면 첫 번째 탭에 나타나는 것을 볼 수 있습니다!

솔리드 케이블이 포함된 마스터 레일 액션 케이블:Redis 없이 실시간 앱 구축

Rails Action Cable을 프로덕션에 배포

Solid Cable은 WebSocket 메시지를 데이터베이스 테이블에 저장하며 위의 예에서는 기본 cable를 사용했습니다. 데이터베이스. Rails 8은 또한 새 앱에서 Solid Cable용 SQLite를 기본적으로 사용하지만 cable를 추가하여 기술적으로 Rails 지원 데이터베이스를 가리킬 수 있습니다. config/database.yml 섹션 .

실제로 프로덕션에서는 Solid Cable에 대해 별도의 데이터베이스를 사용하는 것이 좋습니다 나머지 데이터로부터 실시간 메시징 로드를 분리합니다. 예를 들어 전용 app_production_cable를 프로비저닝할 수 있습니다. 기본 앱 데이터는 app_production에 유지되는 동안 Solid Cable용 데이터베이스 .

이러한 분리는 채팅 또는 알림 트래픽이 기본 애플리케이션 쿼리와 경합하는 것을 방지합니다. 즉, 소규모 앱의 경우 일반적으로 앱 데이터와 케이블 메시지 모두에 대해 단일 데이터베이스를 사용하는 것이 좋습니다.

분명하지 않은 부분은 Solid Cable 데이터베이스가 배포 설정에 포함되어 있는지 확인하는 것입니다. 별도의 데이터베이스를 사용하는 경우 rails db:prepare를 실행하는 것을 잊지 마세요. 또는 rails db:migrate Rails가 messages를 생성하도록 테이블이 제작 중입니다.

각 WebSocket 연결은 서버 메모리를 소비하므로 서버에 필요한 연결 수를 처리할 수 있는 충분한 리소스가 있는지 확인하세요.

폴링 간격 구성

Solid Cable의 폴링 빈도는 구성 가능하므로 대기 시간과 데이터베이스 부하의 균형을 맞출 수 있습니다. 간격을 줄이면 폴링이 더 자주 발생하여 새 메시지를 선택하는 시간이 줄어들지만 데이터베이스에서 SELECT 쿼리가 더 많이 발생합니다.

반대로 간격이 길어지면 데이터베이스 사용량은 줄어들지만 브로드캐스트 및 업데이트가 더 많이 지연됩니다. 실제로 기본 0.1초(초당 10개의 폴링)는 대부분의 데이터베이스에 부담을 주지 않으면서 실시간 업데이트처럼 보이는 좋은 시작점입니다.

솔리드 케이블은 솔리드 트리펙타(Solid Trifecta)의 핵심입니다

Rails Action Cable이 어떻게 실시간 통신을 위해 WebSocket을 Rails로 가져오는지, 그리고 Solid Cable이 어떻게 Redis 없이 이를 가능하게 하는지 살펴보았습니다. Rails에 두 개의 다른 "Solid" 라이브러리가 있다는 것을 알고 계셨나요? ? Solid Cache를 사용하면 Redis 없이 쉽게 캐시할 수 있으며, Solid Queue를 사용하면 Redis 없이 백그라운드 작업을 처리할 수 있습니다.

"Solid Trifecta"를 사용하면 최소한의 인프라 오버헤드로 대화형 애플리케이션을 구축하기 위한 놀라운 기능적 프레임워크를 얻을 수 있습니다.

Solid Cable과 그 형제 자매의 주요 장점은 단순성입니다. Rails 앱의 실시간 기능은 앱의 데이터베이스만 있으면 바로 작동합니다. 배포가 더 간단하며(Redis 또는 추가 서비스 없음) 많은 애플리케이션의 경우 성능이 충분합니다.

물론 프로덕션 환경에서 Rails 애플리케이션을 실행할 때 사용자에게 발생할 수 있는 문제가 있는지 모니터링해야 합니다. Action Cable 소비자와 채널에 문제가 발생하는 경우 사용자보다 먼저 알고 싶지 않으십니까? ?

Honeybadger는 실시간 애플리케이션 배포에 중요한 Rails 오류 및 성능 모니터링을 위한 탁월한 선택입니다. Honeybadger는 애플리케이션(백엔드 및 클라이언트측) 어디에서나 오류가 발생하면 즉시 경고하고 신속한 검색, 문제 해결을 위해 애플리케이션 로그 및 성능 데이터를 가져옵니다.

시작하려면 Honeybadger에 가입하세요!