본문 바로가기

Back_End(Ruby on Rails)

Rails_추천 시스템에 Redis 적용(Implementaion of Redis in Ruby on Rails)

반응형

대략 100,000 건의 rows에서 20개 정도의 추천 row를 내려주는 api를 만들게 되었다. 이때 추천 rows들은 거의 변하지 않고, 모든 Client들에게 항상 동일한 추천 rows를 보여주는 로직이었다. 추천 rows는 거의 변하지 않음에도 불구하고 요청시마다 100,000개의 rows가 있는 테이블에 Query를 날리는 것보다는 캐싱을 해두고 쿼리 없이 보여주는게 좋다고 생각했다. 

Redis Setting in Rails Application

Config/initializers/redis.rb

위와 같이 Redis Object 와 args 를 url 과 드라이버와 함께 Initialize 해준다.

아 물론, initializers directory 내 파일 들은 rails 내 library에 있는 run_intializers method에 rails app 이나 rails console 실행시 일괄로 실행된다. (referecnce: https://guides.rubyonrails.org/initialization.html )

 

The Rails Initialization Process — Ruby on Rails Guides

The Rails Initialization ProcessThis guide explains the internals of the initialization process in Rails. It is an extremely in-depth guide and recommended for advanced Rails developers.After reading this guide, you will know: How to use rails server. The

guides.rubyonrails.org

 

공식문서에 정의되어있는 initialize method다! 이 method를 호출하면서 실행되는 것이다.

Db 환경 세팅: 총 약 110,000 개 db rows 중 추천 데이터는 대학교 21개, 고등학교 19개임 실제 db 는 이정도지만, 테스트 환경에서는 더 작은 사이즈의 rows 를 가진 db로 세팅을 해보았다.

이렇게 가정하자. 1,000개의 학교 데이터를 만들고, 이 중 20개의 학교만이 추천학교다. 즉, 1,000개 중 무작위의 20개를 pick attr 값을 1로 설정한다. FactoryBot을 사용해서 학교를 만들었다.(#create_list Method 로 Multiple objs 를 만들어두자.)

FactoryBot.create_list(:model_1, 3)

Rspec을 이용해 Single Test 를 실행하여, 성능을 측정했고, Rspec 테스트 코드는 아래와 같다.

물론, 실서버에 저렇게 올리진 않았고, 로컬 측정 용도로 Rspec에 작성했다..

그럼 본격적으로 No Caching버전, Caching버전으로 한번 비교해보자.

Case1: No Caching (기존 리퀘스트마다 쿼리를 날리는 방식)

Case2: Caching(Redis Caching)

Redis를 적용해보자. Rails redis 관련 method 정리는 https://www.rubydoc.info/github/redis/redis-rb/Redis#current-class_method 에서 찾을 수 있다.

 

RubyDoc.info: Documenting RubyGems, Stdlib, and GitHub Projects

RubyDoc.info is your source for open source Ruby library documentation, generating fresh docs for Gems and popular Git repositories. This site uses YARD to generate docs on the fly. To make your docs look better, you can check out some of YARD's killer fea

www.rubydoc.info

아래와 코드에서 기존 쿼리 동작 방식을 주석 처리 해두고, fetch 로 시작하는 새로운 method를 추가하여, 새 method에 Redis cache 기능을 구현했다.

fetch_picked_schools method를 별도로 분리하여 작업했다.
표시한 부분은 Redis 를 설정하고(set) 키 값으로 찾는(get) 부분이다.

 

local 환경에서는 Redis나 쿼리나 유의미한 차이를 얻기 힘들다.. 

음.. 별로 차이가 없다고 볼 수 있다. . (물론 로컬환경에서 테스트를 한 것이니, 실서버 환경에선 다를 것이긴하다..) 그럼에도 불구하고 큰 차이는 없는듯... 오히려 추천학교의 table구조를 생각했을 때 굳이 Cache를 먹이고, id로 또 찾으면서까지 해야할 일이 있나 싶었다.. 그래서 생각한게, Redis Cache에 아예 json을 통째로 박아두면 어떨까 하고 생각하였다. 또, Redis Data Type은 기본 타입이 String 이고, 길이는 512 megabyte까지 저장된다고 한다. (reference: https://redis.io/topics/data-types ) 그래서 아예 추천학교 리스트를 통째로 string 으로 Redis 에 캐싱해두는 것으로 변경.. DB에 쿼리를 날리는 대신 Redis 에서 값을 찾아서 쓰는게 더 빠르다고 가정했다.

학교 리스트를 통째로 json 모양의 string value로 redis에 저장했다..!

그 결과, Qa 서버에서 api call test 및 응답 시간(x-runtime 시간 기준) 약 18% 감소했다.

1. NoCache Version: avg.time ( 0.0190416s)

0.020402

0.018153

0.022165

0.018348

0.018986

0.018383

0.018846

0.018647

0.017826

0.018660

 

2. Cache Version: avg.time (0.0155736s) -> 더 빠르다. 

0.015812

0.015351

0.014474

0.015593

0.016387

0.013836

0.018404

0.015558

0.014440

0.015881

 

결론: 어느정도 Redis Cache 로 값을 불러오는게 빠르긴하지만, 애초에 쿼리 타임도 빠른 편이라 엄청난 이득을 본 건 아닌듯싶다(?) 거기다 Redis 서버 자원은 더 비싸지 않을까..? 

반응형