Sorcery VS Devise

Sorcery 소개

ca62lrg

얘는 소서리스에요..

Devise는 워낙 유명해서 별도의 설명이 필요 없겠지만 Sorcery의 경우 상대적으로 덜 유명해서 간략하게 소개를 먼저 해본다.

이스라엘 개발자 Noam Ben Ari(이후 NoamB)가 만든 Authentication Gem으로 2010년 10월에 첫 커밋이 나왔다.
필자는 이전까진 restful-authentication를 사용했는데 Rails 3가 출시했음에도 불구하고 대응이 늦었다.
그때 혜성처럼 나타난 게 몇 가지 있었는데 Sorcery, Devise도 그것들 중 하나였다. (지금까지 살아남은 녀석들도 아마 이 두 녀석뿐일 듯)
처음에는 Devise를 사용했었지만 RailsCasts에서 Sorcery를 소개해줬고, 이때부터 쭉 Sorcery를 사용해왔다.

NoamB 거의 혼자서 개발을 해오다시피 했고, 지금은 개인 Repository가 아닌 Sorcery의 Repository를 만들어서 관리하고 있고, NoamB는 현제 일선에서 물러나 Chase GilliamJosh Buker 이 두 사람이 Maintainers로 관리를 하고 있다.

Sorcery만 소개해주면 Devise한테 미안하니 간략히 소개하자면 SimpleForm을 만든 plataformatec이 만들고 관리하고 있다.

기능 비교

사실 처음에는 그냥 느낀 점만 간략하게 쓸려고 했는데.. 그럼 너무 성의 없어 보일까 봐 간략하게 정리해봤다.
기능 위주로 선택하려 한다면 아래 표가 도움이 되시리라

기능설명 Sorcery Devise
Authentication Core Database Authenticatable
OAuth External Omniauthable
회원가입시 메일 인증 프로세스 User Activation Confirmable
암호 리셋 프로세스(메일 전송) Reset Password Recoverable
회원가입 Core Registerable
자동 로그인 Remember Me Rememberable
로그인/아웃등 유저 행적 기록 Activity Logging Trackable
Session Timout 설정 Session Timeout Timeoutable
Validation email, password Validatable
로그인 실패 여러번시 계정 잠금 Brute Force Protection Lockable
HTTP Authentication Basic HTTP Authentication Database Authenticatable

Validation이 Sorcery에는 없지만 이건 Rails의 Validators를 이용하면 해결된다. (Rails를 아시는 분이라면 Devise가 Validation을 왜 따로 제공하는지 이해가 안가실 수도 있는데, 그건 아래에 설명하겠다)
보면 알겠지만 방법의 차이만 있을 뿐 제공하는 기능은 동일하다.
그러므로 기능의 수는 안타깝게도 무승부.

간단히 Authentication 위주로만 쓸 경우

문서 살펴보고 맘에 드시는 걸로 선택하면 된다.

57f8la

장난 아니고, 진짜에요..;;

여러 부가기능을 쓰지만 수정 안 하고 쓸 경우

Devise를 추천한다.
Devise는 Boilerplate가 아주 많이 제공되어서 여러 부가 기능을 사용할 때 편리하다.
하지만 많은 커스터마이징이 필요한 경우에는 적합하지 않다. (우리가 알고 있듯 Boilerplate는 양날의 검인데, 그 단점이 여기에도 해당된다고 보면 된다)
왜냐하면 Devise는 많은 부분들이 감추어져 있다 보니, 구현 단계에서의 수정이 쉽지 않다.
그래서 커스터마이징이 필요한 사람들을 위해 Registerable, Validatable 같은 부가기능을 통해 커스터마이징을 하도록 하고 있지만 안타깝게 이마저도 쉽지 않다.  더욱이 문서 또한 레퍼런스가 아닌 API만 제공하다 보니 실제 Usage를 알기가 어렵다.

여러 부가기능 및 커스터마이징이 필요한 경우

Sorcery를 추천한다.
Sorcery는 Boilerplate가 없다고 봐도 무방하다. 그렇기 때문에 많은 부분들을 처음부터 쌓아올려야 한다.
별도의 수정 없이 사용할 때는 이게 그렇게나 귀찮고 짜증 나지만, 반대로 커스터마이징을 많이 해야 하는 경우 이처럼 좋을 수도 없다.
기본적인 건 다 Sorcery가 제공하고 그것들을 어떻게 사용할지는 내 입맛에 맞춰서 만들 수 있으니!!

권한 관리가 필요한 경우

Devise의 막강한 기능 중 하나가 CanCan, Rolify 같은 녀석들 때문이다.
CanCan은 권한 관리 Gem으로 페이지, Row(DB의 row) 단위로도 권한 설정이 가능하다고 한다. (실 서비스에 써본 적은 없다. 사용하려고 했는데, 커스터마이징을 너무 많이 해야 해서 그냥 하나 만들어서 사용했다)
CanCan은 Object에 대한 권한 관리라면, Rolify는 역할 관리라고 보면 된다. 예를 들자면 ‘유저’, ‘관리자’, ‘스텝’ 등으로 역할별로 권한을 관리할 때 사용하는 Gem이다.
(역시 실 서비스에 써본 적은 없다. Rolify가 등장하기 전에 이런 기능이 필요해서 만들어서 쓰고 있..)

암튼 이러한 녀석들이 공식적으로 Devise에 잘 붙는다고 적혀있고, 많은 사람들이 Devise + CanCan + Rolify 이렇게 트리플 콤보세트로 사용한다.

근데 CanCan, Rolify를 써보니 어랏? 딱히 Devise와의 Dependency가 안 보인다. 즉 Sorcery에서도 사용할 수 있을 것 같긴 한데.. 나중에 시간 나면 한번 해봐야겠다.
혹 해보신 분 계시면 알려주세요~!

정리

Sorcery Devise
소상공인 기업
가난하다 부자다
Screen Shot 2018-04-04 at 11.19.22 PM Screen Shot 2018-04-04 at 11.19.09 PM
로고도 없다 부자는 다르다.
가난해서 Boiler못킨다. 돈 많아서 Boilerplate가 빵빵하다
가난해서 감출게 없다. 많은 부분들이 감추어져 있다.
그래서 커스터마이징이 쉽다. 그래서 커스터마이징이 어렵다.
github wiki가 아주 깔끔하게 정리가 되어있어서 다른 문서 볼 필요가 없다.
Boilerplate와 설명까지 다 빵빵하다.
github wiki 또한 보기 어렵게 되어있다.
공식 문서는 API만 제공되고, Usage는 찾기 힘들다.
Boilerplate가 있긴 하지만 설명도 없고, Boilerplate를 어떻게 사용해야 하는지 알려주는 문서 또한 없다.
github wiki 페이지 수가 25개로 아주 깔끔하게 되어 있다.
(내가 만들거나 기여한 페이지들도 몇 개 있..읍읍)
github wiki 페이지 수가 130개다. 역시 부자는 다르다.

Sorcery를 오랫동안 사용하기도 했고, 기여도 해서 그런지.. 나도 모르게 글 자체가 Sorcery에 조금 더 편향되게 쓰여진것긴 한데.. 사실 아주 오래전 Devise를 주제로 글을 썼었다. 그것도 2개나! (언제까지 restful-authentication을 쓸것인가! devise도 써보자!devise에서 sign_out시 서버가 기절할 경우. (Ruby Or Rails Bug인듯))
블로그 이사하면서 양식이 다 깨져서 지금은 내용을 알아보기 힘들지만, 어쨌든 썼었다!

아, 그게 중요한 게 아니고.. 흠흠
둘 다 모두 검증된 Authentication 툴이니 믿고 사용하시길

Advertisements

서버를 Rails5로 할것이냐, Meteor(nodejs)로 할것이냐

뒤늦게 Rails 5Action Cable Demo 동영상을 보았다.
동영상은 20분이 조금 넘는 런닝타임이지만 익숙해지면 3분 내외로 개발할 수 있을것 같다.
그런데 생각보다 많이 풀어져있는(풀이되어있는) 느낌으로 각 사이드별로 코드를 다 작성해야한다.
“웹소켓을 하기 위해서, 여기는 이렇게, 거기는 그렇게, 저기는 이렇게, 마지막으로 이렇게 해주면 끝. 짜잔~!! 참 쉽지?”

3591057515594fc8

공들고 뛰어가다 그냥 점프해서 골대에 공 넣으면돼

처음 시도하는 사람들에겐 개념이 명확해서 이해하기 쉬울수있겠지만..
아직까지는 복잡하다는게 내 생각이다.

그리고 사실 Rails는 쓸대없는 코드 작성을 최소화하여 빠르고 간결하게 개발하는것이 장점이자 철학이라고 생각하는데 Action Cable은 그렇지 못한 느낌이다.
뭐 아직 베타니깐 버전업이 되면 아마 조금씩 이 철학에 맞춰서 수정되지 않을까 싶다.

내가 만약 Meteor​를 해보지 않았다면 이런 생각을 안했을수도 있겠지만
Meteor는 “그냥 했을뿐인데 웹소켓통신이 되고있네?” 랄까..

restmb_idxmake

그냥했는데 펜타킬..

Meteor랑 비교하는것 자체가 어폐가 있을지모르겠지만, 그래도 이미 맛봐서 비교를 안할수가없다.

사실 Rails를 버리고 Meteor + React​ 조합으로 서비스를 꾸려나갈 생각이었는데..
Rails 5선택지가 생겨서 고민이된다.

1-kyrdrgja-esr1w8taqong

아직 당장은 웹소켓을 쓸일이 없다보니 이 옵션은 선택에 큰 영향을 끼치진 않을것같다.
다만 Rails 5의 API mode가 어떻냐에 따라 갈라지지 않을까싶다.

API mode가 내가 원하는(상상하는)모습이라면
Rails 5 API mode + React로 구성을 해도 괜찮지 않을까?

Rails, Meteor 둘중 무엇이 더 가벼운가? 무엇이 개발하기 빠른가? 등등의 이슈로 열거해놓고 선택할 수 있겠지만..
사실 Ruby할래? Javascript할래? 의 문제이지 않을까 싶다.
무엇이 더 재밌고 즐겁게 개발을 할 수 있을것인가?
선택하기 어렵다. Ruby도 Javascript도..

Ruby는 10년이 넘는 기간동안 오랜시간을 함께한 친구같고..
Javascript는 Ruby보다 훨씬 오래전부터 알았지만 서먹한 관계였다 최근 몇년동안 급 친해진 친구랄까..

1431853362247

어떤거쓰지?

 

참고링크:
http://rubyonrails.org
http://weblog.rubyonrails.org/2015/12/18/Rails-5-0-beta1/
https://github.com/rails/rails/tree/master/actioncable
https://www.meteor.com/
https://facebook.github.io/react/

 

Meteor Up 삽질기

Meteor Deployment 검색해보면 모든 예제가 전부 Ubuntu였음.
개인적으로 서버는 항상 Debian을 선호해서 찜찜하지만 ‘Debian이나 Ubuntu나~’하면서 Debian 강행.
배포 안됨.

Debian이라서 문제인건지.
apt로 mongodb를 설치해서 문제인건지
nvm으로 node를 잡아놔서 문제인건지..
mup 계속 실패. deb-mup(데비안용 mup)또한 마찬가지.
설정 바꾸며 삽질해도 안됨.
5초 설정 바꾸고 배포 결과 떨어지는데 5분~10분..
결국 모든 설정과 의심되는 부분 다 작업해도 안됨.
이것때문에 반나절 날림.
큰맘먹고 Ubuntu로 바꿈.
정말 한.번.에됨.

결론.
Meteor Server는 Ubuntu를 쓰자 -ㅅ-;

Elasticsearch dynamic scripting

Elasticsearch 1.2.x 미만 버전에서는 dynamic scripting이 기본으로 활성화(able)되어있다.
이건 보안 이슈를 가지고 있는데 자세한 정보는 아래 첨부해드린 링크를 참고하시면 되고
http://bouk.co/blog/elasticsearch-rce/
http://www.elasticsearch.org/community/security/
http://www.elasticsearch.org/blog/scripting-security/

해결책은 간단하다. elasticsearch.yml에서

script.disable_dynamic: true

를 추가해주고 재시작하면 된다.

Rails AR 속도 테스트

전 포스팅에 이어 각 케이스별 Benchmark 결과 공유해볼까 한다.
Benchmark 사용법 및 자세한 내용은 아래 링크를 확인하시면 된다.
http://www.ruby-doc.org/stdlib-2.0/libdoc/benchmark/rdoc/Benchmark.html

1. 우리가 흔히 사용하는 100% AR을 사용한 경우.
puts Benchmark.measure{User.limit(100000).to_a;nil}
120.070000 1.790000 121.860000 (122.293380)
총 소모된 시간 약 122초

2. 컨넥션만 AR을 이용한 후 row값을 배열로 받는 경우
puts Benchmark.measure{ActiveRecord::Base.connection().select_rows(‘select * from users limit 100000’);nil}
8.110000 1.560000 9.670000 ( 9.995749)
총 소모된 시간 약 10초

3. 컨넥션만 AR을 이용한 후 row값을 해쉬로 받는 경우 (mysql2만 사용한것과 같은 리턴 타입)
puts Benchmark.measure{ActiveRecord::Base.connection().select(‘select * from users limit 100000’);nil}
8.790000 1.320000 10.110000 ( 10.415056)
총 소모된 시간 약 10초

4. 컨넥션만 AR을 이용한 후 날것(raw)로 받는 경우
Benchmark.measure{ActiveRecord::Base.connection().execute(‘select * from users limit 100000’);nil}
0.160000 0.030000 0.190000 ( 0.501308)
총 소모된 시간 약 0.5초

5. mysql2를 이용한 경우.
puts Benchmark.measure{mysql.query(“select * from users limit 100000”);nil}
0.150000 0.030000 0.180000 ( 0.469528)
총 소모된 시간 약 0.5초

6. mysql2에서 row값을 Array로 받는 경우.
puts Benchmark.measure{mysql.query(“select * from users limit 100000”, as: :array).to_a;nil}
0.140000 0.020000 0.160000 ( 0.474315)
총 소모된 시간 약 0.5초

7. mysql2에서 결과값을 Array로 변환한 경우.
puts Benchmark.measure{mysql.query(“select * from users limit 100000”).to_a;nil}
27.890000 3.050000 30.940000 ( 31.259377)
총 소모된 시간 약 31초

같은 결과값 타입끼리 비교를 해보면

결과값 타입 AR mysql
배열 2. 컨넥션만 AR을 이용한 후 리턴값을 배열로 받는 경우
약 10초
7. mysql2에서 타입을 Array로 요청한 경우.
약 0.5초
해쉬 3. 컨넥션만 AR을 이용한 후 리턴값을 해쉬로 받는 경우
약 10초
5. mysql2를 이용한 경우.
약 0.5초

mysql2의 압도적인 승리다.

사실 4.AR이용 날것(raw)과 5.mysql2의 리턴받는 객체는 똑같다.
둘다 Mysql2::Result를 따라간다.
하지만 4번은 Array로 형변환을 하고, 5번은 Hash로 형변환을 한다는 차이점이 있다.
Screen Shot 2013-06-14 at 10.22.25 PM

Rails의 AR이 대량의 데이터를 읽어올때 생기는 속도 문제.

DB에는 약 500,000개의 rows가 있다.

A액션을 하게되면
DB에 쿼리를 날리게 되고 약 75,000개의 rows가 return된다.
이 데이터를 가지고 알고리즘을 돌리게 되는데
문제는 고작 75,000개의 데이터를 처리하는데 시간이 너무 오래 걸리는 것이다.
약 80초가 걸리는데 이건 뭔가 문제가 있다.
SELECT 쿼리는 최적화가 되어있는 상태로 문제가 없었다.

도대체 어디서 이렇게 시간을 많이 잡아먹나 확인을 해보니
DB에 쿼리를 날리고 난 후 알고리즘 들어가기 전까지가 엄청나게 많은 시간을 잡아먹는 것이었다.

ActiveRecord가 DB 결과값을 변환하는데 걸린 시간: 약 75초 알고리즘 로직이 돌아간 시간: 약 3.4초

ActiveRecord가 DB 결과값을 변환하는데 걸린 시간: 약 75초
알고리즘 로직이 돌아간 시간: 약 3.4초
총 연산시간: 약 80초

쿼리도 문제없고, 알고리즘도 문제없다.
하지만 둘 사이에 알 수 없는 작업으로 시간이 오래 걸린다면..
의심해볼 건 ORM.. 바로 ActiveRecord(이하 AR)

그래서 과감하게 AR을 버리고 mysql2(gem)만 이용하도록 수정을 했다. (mysql2… mysql을 사용하면 필수적으로 설치하는 그 gem 맞다.)
그랬더니 시간이 급속적으로 향상되었다.

DB 결과값을 변환하는데 걸린 시간: 약 0.3초
알고리즘 로직이 돌아간 시간: 약 0.7초
총 연산시간: 약 1.1초

80초에서 1초로 줄었. 응?
눈을 비비고 다시 한번 확인.
혹시나 싶어서 여러번 A액션 재실행.
헐.. 대박 ㅋㅋ
말도 안되는 성과 도출!
쩔어 쩔어

여기서 주목할 점은 알고리즘부분까지 소모시간이 줄었다는 것이다.
이것 또한 같은 이유로 인함인데
여기서 AR의 동작원리라고 하기엔 좀 거창하지만를 이해할 필요가 있는데
mysql2은 결과값을 해쉬(Hash)로 보관하게 되는데
(엄밀히 따지면 Mysql2::Result에 Hash형태로 각 row가 보관이 된다.)
사실 AR도 mysql2를 이용해서 넘겨받은 해쉬를 AR(데이터 타입)로 변환하게 된다.
알다시피 AR(데이터 타입)에는 각종 모듈 및 헬퍼등 살이 디룩디룩 찌고 다리가 4개인 우르곳이라면
반면 해쉬는 Ruby Core lib 모듈 포함된 녀석으로 아주 앙상하게 마른 뼈밖에 없는 피들스틱이랄까?
(Rails에서 사용하는 해쉬는 포식시켜 스택이 3정도 쌓은 초가스랄까? 뭐래는겨 ㅋㅋㅋ)

결론
결국 AR이 무겁고, 이렇게 무거운 AR을 사용하기 때문에 생기는 이슈인 것이다.
그렇다고 AR이 나쁘다! 구리다! 하자다! 라고 하기엔 어폐가 있다.
Rails는 웹 개발 프래임웍이다. 웹 개발이 목적이고 이를 위해 만들어진 ORM이 AR이다.
이런 AR에게 데이타를 몇 만건씩 가져오는걸 기대하는것 자체가 문제가 있다.
보편적인 웹 서비스에선 몇 만건씩 데이터를 가져오는 일 따위는 일어나지 않을것이니

그러므로 배치성 작업 혹은 많은 량의 데이트를 컨트롤해야 하는 경우에
Rails가 필요 없다면 그냥 Ruby로만 짜는것이 좋고,
Rails를 써야만 한다면 AR사용은 고민해볼 필요가 있다.

덤.
3,500개의 rows를 AR이 변환하는데 걸리는데 1.8초정도 소모가 되었다.
고작 3,500개밖에 안되는데도 약 2초가 소모된다.
소량의 작업에선 속도가 문제가 안되지만..
1,000건이 넘어갈 경우에는 꼭 테스트를 해보길 권장한다.

+ 추가
아직 확인은 못해봤지만.. Sangmin Ryu님의 실서비스 테스트 결과를 보면 속도가 느리지 않다
물런 하드웨어 스펙이 차이가 좀 많이 나는것 같지만.. ㅋㅋ 그걸로 설명하기엔 속도차가 너무 크다.
모델의 덩치와도 관계가 있다고 추측된다.
일단 해당 이슈가 발생한 모델의 필드가 약 50개이고 그 중 10개는 text이다.
뿐만 아니라 메소드 또한 많은데 이 모델의 소스 코드가 약 600줄정도 된다.

AR이 해야할 작업이 많아져서 속도가 느려졌던걸로 판단된다.

+ 추가
AR 속도 테스트