왜 레진코믹스는 구글앱엔진을 선택했나

81,305 views

Published on

프리미엄 웹툰서비스, 레진코믹스는 구글 앱 엔진 위에서 서비스 되고 있습니다. 레진코믹스가 왜 구글 앱 엔진을 선택했는지, 주로 쓰고 있는 기능들과 함께 개발하면서 생긴 다양한 이슈와 팁들에 대해 이야기합니다. (2014.01.22 GDG Seoul Meetup)

Published in: Technology
7 Comments
432 Likes
Statistics
Notes
No Downloads
Views
Total views
81,305
On SlideShare
0
From Embeds
0
Number of Embeds
30,884
Actions
Shares
0
Downloads
668
Comments
7
Likes
432
Embeds 0
No embeds

No notes for slide

왜 레진코믹스는 구글앱엔진을 선택했나

  1. 1. 사용자, 즉 개발자는 왜 레진코믹스는 구글 앱엔진을 선택했나
  2. 2. 개발자 누구 • @curioe , http://curioe.com // 궁금한, 이상한 • 레진엔터테인먼트 • 만명 남김 •할 서버 개발자 1명 (2014.01) 기업 > 천명 기업 > 600명 기업 > 9명 기업에 코드를 일과 < 역할이 < 점점 더 < 많아짐
  3. 3. 다이나믹 타임트리 2013년 2월 3월 Open PaaS! 백수... Cloud Foundry No! 락 인 4월 말 레진 합류
  4. 4. 다이나믹 타임트리 3월 2013년 2월 Open PaaS! 4월 말 백수... 6월 초 레진 합류 ㅠ.ㅠ 서비스 오픈 40일 후! ! 서버 개발자 오직 나 하나... ! 기획/요구사항은 개발하면서 진행됨 orz
  5. 5. 다이나믹 타임트리 2013/04 Before 레진 합류 인프라는 인프라팀이! ! 데이터베이스는 DBA가! ! 개발은 분담
  6. 6. 다이나믹 타임트리 2013/04 Before 레진 합류 After 인프라는 인프라팀이! 인프라 내가 해야 함! ! ! 데이터베이스는 DBA가! 데이터베이스 내가 해야 함! ! ! 개발은 분담 개발 나 혼자 해야 함
  7. 7. “앱 엔진 씁시다” @xguru
  8. 8. 구글 앱 엔진 2013/04 Before 레진 합류 인프라는 인프라팀이! ! 데이터베이스는 DBA가! ! 개발은 분담 After PaaS 앱엔진으로 Datastore 앱엔진으로 개발 개발만 하면 됨
  9. 9. 구글 앱 엔진 4월 말 레진 합류 PaaS 앱엔진으로! ! Datastore 앱엔진으로! ! 개발 개발만 하면 됨 6월 초 일정 / 리소스 해결 미션 컴플리티드! I don’ care!! 락인
  10. 10. 서비스는 왜 레진코믹스는 구글 앱엔진을 선택했나
  11. 11. 레진코믹스 - 프리미엄 웹툰
  12. 12. 레진코믹스 - 부분유료화 D - 21 D - 21 D - 14 D-7 7일후 무료공개 예정 D-7 “ “ 7일이나 기다려?? D-7 먼저보는 즐거움!
  13. 13. Auto Scaling
  14. 14. 누적 회원 증가 12 11 10 6 7 8 9
  15. 15. 트래픽 - 시간대별 특성
  16. 16. Instance 샘플이미지
  17. 17. Images Service
  18. 18. 이미지 서비스 app engine 일반화질 업로드 CMS 저장 blobstore 변환 images service 고화질
  19. 19. 이미지 서비스 비용 app engine 일반화질 업로드 incoming bandwidth CMS bandwidth out 저장 blobstore storage 변환 고화질 images service image manipulation api 유료 무료
  20. 20. 서비스는 왜 레진코믹스는 아마존 EC2 가 아닌, 구글 앱엔진을 선택했나
  21. 21. 앱엔진 vs EC2 PaaS 구글 앱 엔진 IaaS EC2 내가 질 책임 애플리케이션 애플리케이션, 데이터베 이스, 웹서버, 운영체제, 모니터링, 로드밸런싱, 업 그레이드 sysadmin Google 필요 (상대적) 비용 비쌈 쌈 Google Compute Engine vs EC2
  22. 22. Platform as a Service Frontend Instance Blobstore Images Services Datastore Memcache Backend Instance Mail Cron Task Queue Admin Console
  23. 23. 해외에서는 왜 레진코믹스는 구글 앱엔진을 선택했나
  24. 24. Snapchat 월 활성 사용자(MAU) 3천만 55% 가 매일 사용함 - 1천6백만 하루에 1억 5천만 사진 업로드 “앱엔진은 우리가 애플리케이션을 개발하는데 집중할 수 있게 해줬어 요. 앱엔진이 우리에게 제공해준 개발의 편의없이 이렇게까지 못했을 꺼에요.” - 바비 머피, CTO 이며 co-Founder http://www.quora.com/Google-App-Engine/What-is-the-highest-traffic-website-built-on-top-of-Google-App-Engine-Python http://gigaom.com/2013/05/07/snapchats-act-of-faith-in-building-on-google-compute-engine/
  25. 25. Khan Academy 380만 월 UV 수업일에 150만 프랙티스가 제공 2000 개 이상의 동영상 “만약 구글 앱엔진이 없었다면, 서버를 셋업이나 라우터 설정에 정말 많은 시간을 보냈을꺼에요. 실 서비스에 집중할 수 있게 한 건 구글 앱엔진의 장 점입니다.” - 벤 카멘스, 리드 개발자 “개발 프로세스가 쉬워서 평균 하루에 한번, 많게는 10번도 배포를 합니다.” https://cloud.google.com/files/KhanAcademy.pdf
  26. 26. Rovio Angry bird friend for facebook MAU 1천 3백만 “구글 앱엔진은 우리가 게임당 한명 또는 두명의 개발자로만 매우 빠르 게 게임을 런칭하도록 해줬어요. 구글이 모든 서버들을 관리해주기 때 문에, 유지보수에 있어 우리가 할 일이 거의 없었어요.” - 스테판 호크, 웹 게임 리드 서버 개발자 https://cloud.google.com/files/Rovio.pdf
  27. 27. 왜 레진코믹스는 구글 앱엔진을 선택했나 • 개발이 빠르고 쉬움 • 자동으로 스케일링해줌 • 개발에만 집중 • 유용한 빌트인 기능들 제공 • 구글 노하우가 녹아있는 인프라 위에서 구동 (비즈니스)
  28. 28. 좋다고 생각없이 쓰면 패가망신
  29. 29. Language & Runtime Java Generally available features Communications Channel Google Cloud Endpoints Mail PHP
 Python preview App Identity Data Storage, Retrieval, & Search Datastore SSL for Custom Domains Blobstore Remote XMPP Traffic Splitting Users Preview features Cloud SQL Google Cloud Storage Client Library Capabilities Multitenancy Search Memcache Dedicated Memcache Logs Modules Sockets Experimental features Datastore Admin/ Backup/Restore MapReduce OAuth OpenID PageSpeed Prospective Search Task Queue Scheduled Tasks experimental App Configuration 
 & Management URL Fetch Process Management Go
 Computation Backends Images HRD Migration Tool Task Queue REST API Task Queue Tagging Appstats
  30. 30. Language & Runtime Java Generally available features Communications Channel Google Cloud Endpoints Mail URL Fetch PHP
 Python preview App Identity Data Storage, Retrieval, & Search Datastore SSL for Custom Domains Blobstore Remote Multitenancy Users Task Queue Preview features Cloud SQL Google Cloud Storage Client Library Capabilities Traffic Splitting Scheduled Tasks experimental App Configuration 
 & Management XMPP Process Management Go
 Search Memcache Dedicated Memcache Logs Modules Sockets Experimental features Datastore Admin/ Backup/Restore MapReduce OAuth OpenID PageSpeed Prospective Search Computation Backends Images HRD Migration Tool Task Queue REST API Task Queue Tagging Appstats
  31. 31. 드리고 싶은 이야기 배포/관리 My App App Engine API Mail 경험한 기능들 정말 팁 Task Queue Datastore Blobstore Dedicated Memcache Appstats Scheduled Tasks 참고사항 URL Fetch Logs Images 그 다음 북마크
  32. 32. 배포/관리
  33. 33. 앱엔진 애플리케이션 Application id: gdgseoulmeetup
  34. 34. 요청 http://gdgseoulmeetup.appspot.com Application id: gdgseoulmeetup
  35. 35. Dynamic 인스턴스 http://gdgseoulmeetup.appspot.com Application Instance dynamic id: gdgseoulmeetup
  36. 36. Resident 인스턴스 Application 늘 떠있음 Instance Resident id: gdgseoulmeetup
  37. 37. 요청 http://gdgseoulmeetup.appspot.com Application Instance Resident id: gdgseoulmeetup
  38. 38. Auto Scaling http://gdgseoulmeetup.appspot.com Application Instance Instance Resident dynamic id: gdgseoulmeetup Frontend Instance Auto Scaling 돈 먹는 하마
  39. 39. Auto Scaling http://gdgseoulmeetup.appspot.com Application id: gdgseoulmeetup Instance Instance Instance Instance Instance Instance Resident dynamic dynamic dynamic dynamic dynamic
  40. 40. 앱엔진 애플리케이션 http://gdgseoulmeetup.appspot.com id: gdgseoulmeetup Application Module Version Module Version Version Instance Instance Instance Instance Instance Instance Resident dynamic dynamic dynamic dynamic dynamic
  41. 41. 앱엔진 애플리케이션 http://gdgseoulmeetup.appspot.com id: gdgseoulmeetup Application Module D ef au lt Module Version Version Version Instance Instance Instance Instance Instance Instance Resident dynamic dynamic dynamic dynamic dynamic
  42. 42. 배포 - 버전 http://gdgseoulmeetup.appspot.com http://20140122.gdgseoulmeetup.appspot.com
  43. 43. local •앱엔진 샌드박스 제공 dev server •개발용 app id •개발자 별로 버전 배포 •노출 안되게 앱엔진 admin 권한 처리 production •새 버전 배포 -> 확인 -> 디폴트 변경 •/WEB-INF/appengine-generated/local_db.bin 앱/버전 property 로 관리 - 빌드타임에 정해지도록 함 appengine'web.xml. ! <application>${google.app.id}</application>. <version>${google.app.version}</version>
  44. 44. Datastore Key Ancestor Index
  45. 45. 데이터스토어 - Key Entity Comic String comicId * String title String artist User Long userId * String username boolean adult int coinBalance Purchase Long purchaseId * String episodeId int coin long purchaseTime Long userId Key - entity 의 ID / 구글앱엔진에서의 유일한 키 값 kind identifier ancestor path (optional)
  46. 46. 데이터스토어 - Key Entity Comic String comicId * String title String artist User Long userId * String username boolean adult int coinBalance Purchase Long purchaseId * String episodeId int coin long purchaseTime Long userId Key - entity 의 ID / 구글앱엔진에서의 유일한 키 값 kind identifier 지정 - 미리 아는 객체들 (string, long) ancestor path (optional) identifier 자동할당 - 실행시 생성되는 객체들 (long)
  47. 47. 데이터스토어 - Key Entity Comic String comicId * String title String artist Key - entity 의 ID / 구글앱엔진에서의 유일한 키 값 kind identifier ancestor path (optional) User Long userId * String username boolean adult int coinBalance Purchase Long purchaseId * String episodeId int coin long purchaseTime Long userId SELECT.*.FROM.Comic.
 WHERE.__key__.=.Key('Comic',.'badboss') SELECT.*.FROM.User.
 WHERE.__key__.=.Key('User',.1234123412341234)
  48. 48. Global Query User Long userId * String username boolean adult int coinBalance Purchase Long purchaseId * String episodeId int coin long purchaseTime Long userId SELECT.*.FROM.Purchase.
 WHERE.userId.=.1234123412341234. AND.episodeId.=.‘badboss'''13’
  49. 49. Eventual Consistency https://cloud.google.com/developers/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore
  50. 50. Eventual Consistency Purchase SELECT.*.FROM.Purchase.
 WHERE.userId.=.1234123412341234. AND.episodeId.=.‘badboss'''13’ https://cloud.google.com/developers/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore
  51. 51. Strong Consistency https://cloud.google.com/developers/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore
  52. 52. Ancestor User Long userId * String username boolean adult int coinBalance Purchase Long purchaseId * String episodeId int coin long purchaseTime Long userId SELECT.*.FROM.Purchase.
 WHERE.ancestor)is.Key(‘User’,.1234123412341234). AND.episodeId.=.‘badboss'''13’
  53. 53. Ancestor Entity Group User Long userId * String username boolean adult int coinBalance Purchase Long purchaseId * String episodeId int coin long purchaseTime <Parent>Long userId Key - entity 의 ID kind identifier ancestor path SELECT.*.FROM.Purchase.
 WHERE.ancestor)is.Key(‘User’,.1234123412341234). AND.episodeId.=.‘badboss'''13’
  54. 54. 데이터스토어 인덱스 User Long userId * String username boolean adult int coinBalance Purchase Long purchaseId * index String episodeId int coin long purchaseTime <Parent>Long userId SELECT.*.FROM.Purchase.
 WHERE.ancestor)is.Key(‘User’,.1234123412341234). AND.episodeId.=.‘badboss'''13’ 주의 index 는 entity 를 update 할 때 생김 나중에 추가하려면 entity 를 새로update 해야 함
  55. 55. composite 인덱스 추가 주의 운영 중에 index 조합을 추가한 경우, Serving 상태를 확인한 후에 default 로 배포할 것
  56. 56. 카운트 1. 카운트하는 엔터티를 둔다. - 동시에 엔터티를 수정하게 되면 Datastore Contention 문제 - 동시에 못하도록 한다면 한번에 한 카운트만 처리 문제 ! 2. Sharding Counter https://developers.google.com/appengine/articles/sharding_counters - 랜덤으로 카운터를 여러개 두고, 사용하지 않은 카운터를 읽고 씀 - 나중에 합쳐 확인하는 방법 - 정확 - 매 요청마다 데이터스토어 써 느린데다 데이터 엔터티가 무수히 많이 생김 ! 3. Deferred Task Queue 활용 - 데이터스토어에 permanent 카운트 - Memcache 에 current 카운트 - 주기적으로 Memcache 에서 데이터스토어로 씀 - 성능은 좋지만, 정확하지 않을 수 있다.
  57. 57. 비용 줄이기 • Appstats 써서 요청에 대한 비용이 어느정도인지 검토 • Memcache 를 되도록 많이 쓰기 • Urlfetch 는 될 수 있는 한 앱에서 할 것
  58. 58. Appstats
  59. 59. Memcache • Memcache 쓰면 빠르고 비용도 줄어듬 • 제한 1MB 이하 - Object 의 List 를 통째로 넣으려면 주의 (json 변환) • 자바의 경우 Objectify 사용 추천
 (Datastore + 기본 Memcache)
  60. 60.
  61. 61. 메일 Quota 요청 미리미리
  62. 62. 세션 삭제, 앱엔진이 안해줌 ! /_ah/sessioncleanup com.google.apphosting.utils.servlet.SessionCleanupServlet ! cron 으로 주기적으로 호출할 것 http://www.radomirml.com/blog/2011/03/26/cleaning-up-expired-sessions-from-app-engine-datastore/
  63. 63. Cron 문법 주의 • 매시간마다 ===> every 1 hours • 매시간인데 15분에 실행되면 좋겠음 ===> every 1 hours from 00:15 to 00:15 영원히 실행되지 않음 ! every 1 hours from 00:15 to 00:14
  64. 64. static 파일 만료 시간 조정 • Purge • 사용자 기능 없음. 브라우저에 의존하기 때문에 (자주 바뀐다면) 시간을 조정해둘 것
  65. 65. SSL URL • http://1.app-id.appspot.com • https://1-dot-app-id.appspot.com
  66. 66. 참고사항
  67. 67. Latency • 데이터센터 저 멀리 • cdn 이용 • • dynamic 데이터는 어쩔 수 없음 좋은 소식 • 아시아에 데이터센터 들어감
 http://googleasiapacific.blogspot.kr/2013/12/our-first-data-centers-in-asia-are-up.html
  68. 68. 앱엔진 + 스프링 최적화 • Component Scanning 줄이기/피하기 • Relationship Autowiring 줄이기/피하기 • 상용에서 XML Validation 하지 않기 • Lazy-Initialized Bean 사용하기 • Constructor Injection by Name 피하기 • https://developers.google.com/appengine/ articles/spring_optimization
  69. 69. 로그 / 파일 • 로그는 좀 많이 불편 • File API 안됨 • PG사 모듈 File 쓰기 안되어서 제외
  70. 70. 앱엔진 그 다음
  71. 71. AppScale 구글 앱엔진 호환되는 오픈소스 PaaS http://www.appscale.com/
  72. 72. AppScale Architecture
  73. 73. 북마크
  74. 74. 모니터링/커뮤니티 • 시스템 상태 페이지
 • 다운타임 알림
 • issue tracker
 • 토론
 • IRC
 https://code.google.com/status/appengine https://groups.google.com/forum/#!forum/google-appengine-downtimenotify https://code.google.com/p/googleappengine/issues/list https://groups.google.com/forum/#!forum/google-appengine http://webchat.freenode.net/ #appengine

  75. 75. 앱엔진 시작하기 • 입문자를 위한 앱엔진 튜토리얼
 http://googcloudlabs.appspot.com/codelabexercise1.html

×