제품 품질 저하 없이 개발팀을 확장하는 방법
개발팀을 확장하고 계신가요? 제품 품질을 저하시키지 않고 성장하는 방법을 알아보세요. 이 가이드에서는 확장할 시기의 징후, 팀 구조, 채용, 리더십 및 도구와 더불어 The Codest가 어떻게...
많은 장점에도 불구하고 Ruby on Rails는 여전히 상대적으로 느린 웹 프레임워크로 간주됩니다. 트위터가 Rails를 버리고 Scala를 선택했다는 것은 우리 모두 알고 있습니다. 하지만 몇 가지 개선 사항을 적용하면 앱을 훨씬 빠르게 실행할 수 있습니다!
Ruby 는 고도로 객체 지향적인 언어입니다. 사실, (거의) 모든 Ruby 는 객체입니다. 불필요한 객체를 만들면 프로그램에 많은 추가 메모리 사용량이 발생할 수 있으므로 이를 피해야 합니다.
차이를 측정하기 위해 메모리 프로파일러 겜과 내장된 벤치마크 모듈을 통해 시간 성능을 측정할 수 있습니다.
"memory_profiler" 필요
report = MemoryProfiler.report do
data = "X" * 1024 * 1024 * 100
데이터 = 데이터.소문자
end
report.pretty_print
아래 목록에서 100MB의 문자열을 생성하고 그 안에 포함된 각 문자를 대소문자로 구분했습니다. 벤치마크 결과 다음과 같은 보고서가 나옵니다:
총 할당량: 210765044 바이트(객체 6개)
그러나 6번 줄을 다음과 같이 바꾸면
데이터.다운케이스!
CSV 파일에서 2백만 개의 레코드로 구성된 방대한 데이터 모음을 가져와야 한다고 가정해 보겠습니다. 일반적으로 다음과 같은 형태가 될 것입니다:
'벤치마크' 필요
Benchmark.bm do |x|
x.report do
File.readlines("2mrecords.csv").map! {|line| line.split(",")}
end
end
사용자 시스템 총 실제
12.797000 2.437000 15.234000 (106.319865)
파일을 완전히 다운로드하는 데 106초가 넘게 걸렸습니다. 꽤나 긴 시간입니다! 하지만 이 프로세스의 속도를 높일 수 있습니다. 지도! 메서드를 사용하여 간단한 동안 루프:
'벤치마크' 필요
Benchmark.bm do |x|
x.report do
file = File.open("2mrecords.csv", "r")
while line = file.gets
line.split(",")
end
end
end
사용자 시스템 총 실제
6.078000 0.250000 6.328000 ( 6.649422)
이제 런타임이 크게 감소했습니다. 지도! 메서드는 다음과 같은 특정 클래스에 속합니다. Hash#map 또는 Array#map에서 Ruby 는 실행되는 동안 구문 분석된 파일의 모든 줄을 메모리 내에 저장합니다. 루비의 가비지 컬렉터 는 해당 이터레이터가 완전히 실행되기 전에는 메모리를 해제하지 않습니다. 그러나 한 줄씩 읽으면 GC를 통해 필요하지 않은 경우 이전 줄에서 메모리를 재배치합니다.
이것은 좀 더 일반적인 예를 들어 앞의 요점을 확장한 것입니다. 앞서 언급했듯이 Ruby 이터레이터는 객체 메서드이며 수행되는 동안에는 메모리를 해제하지 않습니다. 소규모에서는 그 차이가 무의미합니다(그리고 다음과 같은 메서드는 지도 가 더 읽기 쉬워 보입니다). 그러나 데이터 세트가 큰 경우에는 항상 더 기본적인 루프로 대체하는 것을 고려하는 것이 좋습니다. 아래 예시처럼 말입니다:
numberofelements = 10000000
randoms = Array.new(numberofelements) { rand(10) }
randoms.each do |line|
#한다
end
리팩토링 후
numberofelements = 10000000
randoms = Array.new(numberofelements) { rand(10) }
randoms.count > 0인 동안
line = randoms.shift
#한다
end
"`
이것은 빠르고 특히 유용한 팁입니다. 뒤에서 += 연산자를 사용하여 한 문자열을 다른 문자열에 추가하는 경우. Ruby 는 추가 객체를 생성합니다. 그래서 이것입니다:
a = "X"
b = "Y"
a += b
실제로는 이런 의미입니다:
a = "X"
b = "Y"
c = a + b
a = c
운영자는 이를 방지하여 메모리를 절약할 수 있습니다:
a = "X"
b = "Y"
a << b
그리고 레일즈 프레임워크 많은 "문제"를 최적화할 수 있는 코드 많은 추가 노력 없이 신속하게 처리할 수 있습니다.
포스트와 글쓴이라는 두 가지 관련 모델이 있다고 가정해 보겠습니다:
Author < ApplicationRecord 클래스
has_many :posts
end
클래스 Post < ApplicationRecord
belongs_to :작성자
end
컨트롤러에서 모든 게시물을 가져와 작성자와 함께 뷰에 렌더링하고 싶습니다:
컨트롤러
def index
@posts = Post.all.limit(20)
end
view
컨트롤러에서, 액티브 레코드 는 글을 찾기 위한 쿼리를 하나만 생성합니다. 하지만 나중에 각 작성자를 찾기 위해 20개의 쿼리가 추가로 트리거되어 시간이 더 걸리게 됩니다! 다행히도 Rails에는 이러한 쿼리를 하나의 쿼리로 결합하는 빠른 솔루션이 제공됩니다. 다음과 같이 포함 메서드를 사용하면 컨트롤러를 이런 식으로 다시 작성할 수 있습니다:
def index
@posts = Post.all.includes(:author).limit(20)
end
지금은 필요한 데이터만 하나의 쿼리로 가져옵니다.
다음과 같은 다른 보석도 사용할 수 있습니다. bullet 를 클릭하여 전체 프로세스를 사용자 지정할 수 있습니다.
액티브 레코드 속도를 높이는 또 다른 유용한 기술은 현재 목적에 필요한 속성만 호출하는 것입니다. 앱이 성장하기 시작하고 테이블당 열 수가 증가할 때 특히 유용합니다.
이전 코드를 예로 들어 작성자의 이름만 선택해야 한다고 가정해 보겠습니다. 따라서 컨트롤러를 다시 작성할 수 있습니다:
def index
@posts = Post.all.includes(:author).select("name").limit(20)
end
이제 컨트롤러에 필요한 속성을 제외한 모든 속성을 건너뛰도록 지시합니다.
이전 예제에서 게시물을 위한 별도의 파트를 만들려고 한다고 가정해 보겠습니다:
언뜻 보기에는 이 코드가 올바르게 보입니다. 그러나 렌더링할 게시물의 수가 많으면 전체 프로세스가 상당히 느려집니다. 그 이유는 다음과 같습니다. 레일 는 다시 한 번 새로운 반복으로 파트를 호출합니다. 이 문제를 해결하려면 컬렉션 기능:
지금, 레일 은 어떤 템플릿을 사용해야 하는지 자동으로 파악하여 한 번만 초기화합니다.
이메일 보내기, 통계 수집, 정기 보고서 제공 등 시간이 많이 걸리고 현재 흐름에 중요하지 않은 모든 프로세스는 백그라운드 처리의 좋은 후보로 고려할 수 있습니다.
사이드키크 은 백그라운드 처리에 가장 일반적으로 사용되는 보석입니다. 이 젬은 Redis 를 사용하여 작업을 저장할 수 있습니다. 또한 백그라운드 프로세스의 흐름을 제어하고, 별도의 대기열로 분할하고, 각 대기열별로 메모리 사용량을 관리할 수 있습니다.
레일 는 여러분의 삶을 더 편하게 해줄 뿐만 아니라 개발 프로세스를 사용하면 애플리케이션의 성능 속도를 높일 수 있습니다. Devise 또는 Pundit과 같은 도구는 일반적으로 속도와 관련하여 많은 테스트를 거쳤으며 동일한 목적으로 사용자 정의된 코드보다 더 빠르고 안전하게 작동합니다.
개선할 사항이 있는 경우 레일즈 성능도달 범위 The Codest 엔지니어 를 통해 궁금한 점을 상담하세요.
자세히 읽어보세요: