Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Pycon korea - 2018 2to3 converter를 활용한 django 프로젝트 python 버전업 삽질기

292 views

Published on

https://www.pycon.kr/2018/program/43

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Pycon korea - 2018 2to3 converter를 활용한 django 프로젝트 python 버전업 삽질기

  1. 1. 2to3 converter를 활용한 django 프로젝트 python 버전업 삽질기 남형걸
  2. 2. 발표자 소개 남형걸 HYPERCONNECT 백엔드 & 데이터 엔지니어 2017.05 ~ 2018.08 - API 서버 개발 (python, django) - 데이터 파이프라인 구축 (python, scala, spark, hive, django) - python, django, scala, spark, hive 등을 사용하(배우)면서 일하는 중 - https://github.com/namhyeongkeol 발표 소개
  3. 3. 진행 순서 발표 소개 1. 개요 및 2to3 소개 2. 2to3 conversion 진행 3. 호환성 코드 rollback 4. DB migration 신경쓰기 5. py3 환경에서 테스트 및 디버깅 6. py3 서버 배포 및 트러블 슈팅 7. 정리 발표 소개
  4. 4. 개요 및 2to3 소개
  5. 5. 무엇을 했나 ● Django 프로젝트의 python 버전업을 진행 ● 2to3라는 python 공식 version converter 사용 ● 기존에는 Django 1.9를 Python 2.7로 사용하고 있었음 ● 사내 Django의 쓰임새 ○ 서비스 백오피스 제공 ○ Data Infra 관리 개요
  6. 6. 진행해야 했던 이유 ● 조만간의 Django 버전업을 위해서 ○ django 2.0 부터는 python 2.7 을 지원하지 않는다 ● python3 기능 수요가 늘어남 ○ asyncronous programming 과 사용하려던 몇몇 라이브러리 ● python 2.7로는 폼이 안남 ○ 실력 있는 구직자가 python 2.7을 쓰는걸 보면 어떻게 느낄까? 개요개요
  7. 7. Error Driven Development ● 선택한 접근 방법론은 EDD ● Error-driven development is systems development, where everything is done in reaction to errors. ● 모든 것은 에러에 대한 대응으로 진행된다! 개요개요
  8. 8. EDD를 선택한 이유 ● 위험해 보이지만 가장 효율적이다 ● 설계 & 개발하는 것이 아니라 갈아엎는 작업에 적합 ● 비용의 차이 ○ 체계적인 계획과 실천 vs 일단 엎고 수습하기 개요개요
  9. 9. EDD에서 중요한 것들 ● TODO List & Check List 관리 ○ list up의 중요성은 아무리 강조해도 지나치지 않다! ● Monitoring Plan ○ 항상 action 대한 monitoring plan이 필요 ● Failover Plan ○ 안정화 되기 전까지는 항상 기존 상태로 회귀 가능해야 함 개요개요
  10. 10. ● fixer라고 부르는 unit converter들의 집합 ● python에 기본 탑재 & command line 명령으로 실행 ● 사용하고자 하는 fixer들만 골라서 conversion 할 수 있음 ● 백업파일 생성 가능 ○ git ignored 파일에 대해 유용하게 사용할 수 있음 ● https://docs.python.org/2/library/2to3.html 2to3 converter 개요개요
  11. 11. 2to3 converter ● 여러가지 옵션이 있다. ○ -f 옵션으로 사용할 fixer들을 골라서 단계적 진행 ○ -w 옵션으로 백업 파일 생성 (.bak suffix로 같은 dir에 생성) ○ -d 옵션으로 doctest 가능 ● default fixer들만 사용하는 것으로 정하고 -w 옵션만 사용 ○ 단계를 더 나눠서 진행하기 귀찮음 ○ 빨리 고치고 디버깅하는게 더 중요 개요개요
  12. 12. ● 당연하지만 문법 에러가 있으면 에러 발생 ● python2에는 없는 python3 문법이 있어도 에러 발생 ○ async, await, {**{}}, ... ○ 이런 류의 코드는 잠시 지워두고 2to3를 적용한 뒤 다시 첨가해야함 ○ 보통 2to3를 하게 되는 상황은 py2, py3 공존하던 상황이 py2 코드밖에 없던 상황보다 많다 2to3 converter 주의사항 개요개요
  13. 13. ● 2to3 결과를 따로 로깅하자 ○ 2to3 -w example_app >> 2to3_example_app.log 2>&1 ○ 그래야 에러로 진행되지 않은 부분이 무엇인지 알 수 있음 ● git ignored 파일들에 대해서도 진행하자 ○ 배포할 때도 기억해야 함 2to3 converter 주의사항 개요개요
  14. 14. ● .py 파일이 아니면 filepath를 명시해줘야 진행됨 ○ 하지만 다른 언어의 경우 당연히 python 문법 에러 발생 ○ 우리도 shell script 안의 python 코드 손수 고쳐주었다 ● 어떤 3.x로 변환하는지 알 수 없음 ○ 별 문제 없음 ○ 3.0으로 변환하는 것으로 추측 2to3 converter 주의사항 개요개요
  15. 15. ● 3rd party library에 대해서는 웬만하면 진행하지 말자 ○ 3rd party 쪽에서 알아서 python 버전 호환성을 맞춰 놓기 마련 ○ 2to3 커스터마이징을 하더라도 손수 진행하는게 낫다 ○ 라이브러리 코드는 버전관리가 되지 않고 있을 것이고, 따라서 2to3의 변화를 롤백하기 어렵다 ○ 예상치 못한 문제 발생시 대응하기 힘들고 귀찮음 2to3 converter 주의사항 개요개요
  16. 16. 1단계 - 2to3 conversion runserver error 없애기
  17. 17. 2to3 conversion 진행 ● 1st Phase 목표 - runserver 에러 고치기 ○ py3 interpreter로 django runserver 실행시 에러발생 ○ 그 때 발생하는 error 들만 없애는게 목표 ○ ImportError, SyntaxError 등이 있다. ○ 2to3로 conversion을 전부 진행하면 이는 대부분 없어진다. 1st Phase1st Phase
  18. 18. 2to3 conversion 진행 ● 하다보면 branch를 매우 많이 만들게 됨 ● 1st phase라는 걸 알아보기 쉽도록 branch 이름 앞부분에 숫자 1을 넣어서 표시 1st Phase
  19. 19. 2to3 conversion 진행 ● Django 프로젝트 내 app 별로 conversion 진행 ○ commit도 app 별로 하나씩 하자 ○ app에 속하지 않는 기타 파일들도 가장 상위 디렉토리별로 commit 1st Phase1st Phase
  20. 20. SyntaxError 예시 - Long ● py2 int vs long 이원화 ● py3 int 일원화 int -sys.maxint-1 ~ sys.maxint long bignum L을 붙여서 구분 int bignum L 안 붙임 1st Phase1st Phase
  21. 21. SyntaxError 예시 - Long ● 2to3에 의해 해결 1st Phase1st Phase
  22. 22. ImportError 예시 - relative import ● 모든 import statements는 absolute import로 하자 ● relative import를 하고 싶다면 leading dots라는 특수 문법을 동원하여 explicit relative import를 하자 PEP 328 1st Phase1st Phase
  23. 23. ImportError 예시 - relative import PEP 328 1st Phase1st Phase
  24. 24. ImportError 예시 - relative import ● 2to3에 의해 해결 ● 하지만 3rd party library에서 이 문제가 발생하면 어떨까? 손수 해결해줘야 함! PEP 328 1st Phase1st Phase
  25. 25. ImportError 예시 - umalqurra ● 3rd party library 내에서도 ImportError가 발생 가능 ● 대부분 library 버전업을 진행하면 해결된다 ● 하지만 간혹 많이들 사용하는 라이브러리 임에도 python 버전 호환성 대응이 안되어 있는 경우가 있다 1st Phase1st Phase
  26. 26. ImportError 예시 - umalqurra hijri_date.py py2.7 deprecated but OK py3.6 Error py2.7 OK py3.6 OK 1st Phase1st Phase
  27. 27. 2to3에 의해 새로이 생성되는 Error ● 앞서 얘기한대로 2to3 conversion은 py2와 py3가 공존하는 상황에서 진행되는 경우가 더 많다 ○ 이 때문에 2to3가 새로이 발생시키는 에러가 존재 ● 보통은 py-std library에 대한 import statements ○ 대개 분기문에서 에러가 발생 1st Phase1st Phase
  28. 28. 2to3에 의해 새로이 생성되는 ImportError before 2to3 after 2to3 py2 imap, map 이원화 map() imap() py3 map 일원화 list(map()) map() 1st Phase1st Phase
  29. 29. 2to3 conversion PR ● 하나의 app에 하나의 commit ○ 손수 고친 부분은 무조건 2to3가 고친 commit과 분리하여 commit ○ 손수 고친 부분이 많으면 branch도 분리해도 좋음 ● 사람이 다 읽은 것 중 가장 큰 PR ○ app별로 분리해서 PR 만드시길 추천 1st Phase1st Phase
  30. 30. 여기까지가 1st Phase ● 테스트 전 단계에서는 모든 에러를 해결한 셈 ○ 일단 django 서버가 로컬에서 돌아는 감 ○ 팀장님한테 어필할 수 있는 첫 단계 ● 지금까지 소개한 에러 말고도 여러가지 이슈가 있을 수 있다 ○ 인생의 좋은 경험이다 생각하고 열심히 수습하는거 밖에 방법이 없다 1st Phase1st Phase
  31. 31. 2단계 - 호환성 코드 rollback python 2, python 3 호환되는 코드는 롤백하기
  32. 32. py2 py3 호환성 코드만 Rollback ● 2nd Phase 목표 - 호환성 코드 rollback ● 필요없는 경우는 진행할 필요가 없다 ○ 호환성 코드가 없는 경우 ○ 별 문제가 없음이 확실히 확인된 경우 2nd Phase
  33. 33. Py-version diagram 1st Phase 1st Phase Py2 Py3 Py3 Compatible 1st Phase
  34. 34. Py-version diagram 1st Phase ● py2, py3가 호환되는 코드는 그냥 놔두는게 좋지 않았을까? ● 이대로는 팀장님을 설득하기 힘듦 1st Phase Py2 Py3 Py3 Compatible 1st Phase
  35. 35. Py-version diagram 1st Phase 2nd Phase 1st Phase Py2 Py3 Py3 Compatible Py3 Compatible 1st Phase
  36. 36. py2 py3 호환성 코드만 Rollback ● py2 interpreter로 실행하면 static 에러로서 상당수 나온다 ● 나머지는 장대한 diff 내역을 보며 호환성코드 복구 ○ 대체로 분기문, 예외처리문에 의한 import statements ○ 찾을 키워드는 six future past builtins stringIO urllib ○ 사람이니까 조금씩 놓칠 수 있음 ○ 빠르게 테스트하고 고치는게 중요 2nd Phase2nd Phase
  37. 37. 여기까지가 2nd Phase ● EDD를 본격적으로 시작하기 전에 반드시 해야할 작업이 아직 남아 있다 ● DB migration! ○ 코드가 아주 많이 변경되었으니 꼭 고려해주어야 함 2nd Phase2nd Phase
  38. 38. 3단계 - DB migration django DB migration에서 발생가능한 이슈들 정리
  39. 39. ● django의 makemigrations 명령을 실행 ○ py3로 실행해야 함 ○ 경우에 따라 무언가 마이그레이션이 생성될 수 있음 ○ 바뀐것도 없는데 왜? Django makemigrations after 2to3 3th Phase
  40. 40. ● Django에는 각 앱 별로 migrations 파일이 존재 1. migrations 폴더 내용을 가지고 project state 만들고 2. model 파일로도 project state 만들어서 3. 둘을 비교 4. 변경사항 있으면 새로운 migration 파일을 생성 Django makemigrations 3th Phase3th Phase
  41. 41. py2 vs py3 - unicode, str, bytes py2 py3 3th Phase3th Phase
  42. 42. from __future__ import unicode_literals py2 py3 3th Phase3th Phase
  43. 43. from __future__ import unicode_literals py2 py3 3th Phase3th Phase
  44. 44. ● 2to3를 거쳐도 ‘PYCON’은 그대로 ‘PYCON’ ○ 왜냐하면 str은 그대로 str이어야 하므로 2to3 conversion 주의사항 3th Phase3th Phase before 2to3 after 2to3
  45. 45. ● verbose_name, choices, validators, default 등의 값들이 문제 ● 장고는 models.py에 unicode_literals를 넣어준다 Django makemigrations 주의사항 3th Phase3th Phase
  46. 46. ● 하지만 아래와 같다면? Django makemigrations 주의사항 3th Phase3th Phase commonapp.utils.py
  47. 47. ● commonapp/utils.py는 우리가 만든 파일이고 unicode_literals feature import가 없을 수 있다 ● 이 경우 py2에서는 bytes py3에서는 unicode Django makemigrations 주의사항 3th Phase3th Phase
  48. 48. 1. py2 makemigrations bytes로 migration 생성 이런 경우 아래처럼 된다 3th Phase3th Phase
  49. 49. 2. 2to3 conversion 코드 그대로 유지 py2 str(bytes) ➝ py3 str(unicode) 이런 경우 아래처럼 된다 3th Phase3th Phase commonapp.utils.py
  50. 50. 3. py3 makemigrations unicode로 migration 하나 더 생성 이런 경우 아래처럼 된다 3th Phase3th Phase
  51. 51. ● 3rd Phase 목표 - migration 관련 발생가능한 이슈 제거 ● 새롭게 생성된 migration을 어떻게 처리하나? ○ 그냥 fake migration 하고 넘어가도 된다 ○ python migration 파일에서 bytes로 정의하든 unicode로 정의하든 DB에 영향 주는 부분은 없기 때문 Django makemigrations after 2to3 3th Phase3th Phase
  52. 52. ● 이 이슈는 library에서도 발생 가능 ○ django-axes가 그 예시 ○ 마찬가지로 fake처리하면 된다 (in development env) ○ 하지만 git ignored 파일이므로 배포할때는 해당사항 없다 Django makemigrations after 2to3 3th Phase3th Phase
  53. 53. ● py2로 makemigrations 실행하면? ○ 2to3를 거친 코드는 py3로만 돌릴 것이므로 아무 의미가 없음 ○ 이상한 migration이 무더기로 생성됨 ○ 생성되는 이유는 2to3가 migration 파일에서 아래를 지워버리기 때문 ○ 정말 만에 하나 2to3를 거친 코드를 py2로 돌려야 한다면 이 또한 진행 그리고 마찬가지로 fake 처리 Django makemigrations after 2to3 3th Phase3th Phase
  54. 54. ● migration 관련 주의사항 ○ 3rd Phase까지의 완료물을 바로 master에 머지할 수는 없다! ○ 따라서 master에 머지하기 전에 co-worker들이 생성하는 migration이 중간에 끼어들 가능성이 아주 높다 ○ 이를 배포전에는 renumbering 해주는 것을 절대 잊지 말자 Django makemigrations after 2to3 3th Phase3th Phase
  55. 55. ● 여기까지가 3rd Phase 끝 ○ 여기서 배포하면 테스트하지 않은 수 많은 에러가 발생 ○ 그러면 배포 전에 무엇을 할 것인가? ● 이제 4th Phase ○ 프로젝트 규모가 크다면 모든 것을 다 테스트할 수 없다 ○ 꼭 해야 할 것들만 추려서 테스트 진행 Start EDD? 3th Phase3th Phase
  56. 56. 4단계 - Test & Debug 주요기능만 test하고 넘어가자
  57. 57. ● 4th Phase 목표 - py2에서랑 똑같이 동작하도록 만들기 ○ 모든 코드 모듈간 인터페이스를 py2에서와 같게 만들면 모든게 해결 ○ 최소한의 수정만으로 같게 만드는 것이 중요 ○ 그래야 뒤끝이 없다 ● 꼭 해야 하는 최소한만 테스트 하고 넘어가자 Test & Debug 4th Phase
  58. 58. ● 수 없이 많은 에러를 최대한 빠르게 캐치하고 트러블슈팅 ○ 기록해둔 것만 서로 다른 에러 20여건 ○ 상당수는 배포 이후 발견한 것들 ● 특히 만나기 쉬운 에러들 소개 ○ Library Issue (non-std library) ○ Python Issue (std library) Runtime Error 소개 4th Phase4th Phase
  59. 59. ● MacOS sierra 이상에서 발생 ● 2.1.0에서 6.2.1로 업그레이드 Library Issue - ipython 4th Phase4th Phase
  60. 60. Library Issue - Supervisor in py3 ● py2에서 Supervisor를 사용 ○ process management & daemonizing ● Supervisor가 py3를 지원하지 않는다! ○ 최신 버전은 3.3.4 ○ 4.0.0 버전업에서 py3 지원예정 4th Phase4th Phase
  61. 61. Library Issue - Circus ● py3에서는 Supervisor 대신 alternative로 circus 사용 ● Supervisor보다 장점이 많다 ○ configuration이 명시적이고 documentation이 더 잘되어 있음 ○ stderr redirection customizing 가능 ○ more developer friendly ○ advanced web interface 제공 ○ circus-top 등 여러가지 강력한 monitoring feature 제공 ○ 생태계가 작다는건 단점 4th Phase4th Phase
  62. 62. Library Issue - Circus 주의사항 5th Phase ● circusd도 같은 환경에서 실행 필요 ○ copy_env, virtualenv값 반드시 정의 4th Phase4th Phase
  63. 63. ● hive-python interface library ● pyhive[hive]==0.2.1에서 ● PyHive==0.5.1로 바꿔서 해결 Library Issue - pyhive 4th Phase4th Phase
  64. 64. Library Issue - botocore ● AWS python SDK ● botocore==1.4.66에서 ● botocore==1.9.22로 바꿔서 해결 4th Phase4th Phase
  65. 65. ● 두 라이브러리 모두 사용 ○ Unirest가 py3를 지원하지 않음 ○ Requests는 py2, py3 호환 ● Requests만 사용하는것으로 변경 ● 두 라이브러리의 usage가 꽤 다름 ○ Unirest에는 callback이 있고 Requests에는 없음 ○ Response 구조도 달라서 다 대응해줘야 함 Library Issue - Unirest vs Requests 4th Phase4th Phase
  66. 66. ● django-revproxy==0.9.13 사용하는데 아래 에러 발생 ● urllib3==1.22 사용중인 것이 원인 ● pip check ○ django-revproxy==0.9.13 urllib3 <1.17,>=1.12 Library Issue - django-revproxy 4th Phase4th Phase
  67. 67. Library Issue - django-revproxy ● 하지만 requests때문에 urllib3 다운그레이드 섣불리 못함 ● pip check ○ django-revproxy==0.9.13 urllib3 <1.17,>=1.12 ○ requests==2.18.4 urllib3 <1.23,>=1.21.1 ● 구서버에서는 requests==2.4.2 사용 ○ 이 버전은 py3에서 사용 불가능 4th Phase4th Phase
  68. 68. Library Issue - django-revproxy ● requests==2.14.0가 py3지원하는 가장 낮은 버전 ● requests==2.14.0은 urllib3 version dependency 정보를 홈페이지를 뒤져도 찾을 수 없음! ○ EDD답게 requests==2.14.0로 일단 downgrade하고 critical feature test 진행 → 이상 없음! 4th Phase4th Phase
  69. 69. ● cryptography를 사용해 private key 생성시 에러 발생 ○ encryption할 피암호화 값은 당연히 bytes여야 함 Python Issue - encoding for encryption 4th Phase4th Phase
  70. 70. ● cryptography를 사용해 private key 생성시 에러 발생 ○ encryption할 피암호화 값은 당연히 bytes여야 함 Python Issue - encoding for encryption 4th Phase 변경전 변경후 4th Phase
  71. 71. ● hashlib.sha512 사용할 때도 마찬가지 Python Issue - encoding for encryption 4th Phase4th Phase
  72. 72. ● hashlib.sha512 사용할 때도 마찬가지 Python Issue - encoding for encryption 4th Phase 변경전 변경후 4th Phase
  73. 73. ● open 함수 decode codec ○ py2 byte strings ○ py3 utf-8 ○ 문제는 utf-8 codec은 0x1f 0x8b라는 gz 파일의 magic number를 decode하지 못한다! Python Issue - read gzip by utf-8 4th Phase4th Phase
  74. 74. ● gzip.open으로 바로 initiation해서 해결 ● 물론 open 함수를 rb로 열어도 된다 Python Issue - read gzip by utf-8 4th Phase4th Phase
  75. 75. Python Issue - read gzip by utf-8 4th Phase error error OK bytes OK bytes OK but str OK bytes 4th Phase
  76. 76. ● gzip을 사용하는 다른 코드에서도 encoding issue Python Issue - read gzip 4th Phase 변경전 변경후 4th Phase
  77. 77. ● gzip을 사용하는 다른 코드에서도 encoding issue ● 이를 아래처럼 고치려 했다면? Python Issue - read gzip 4th Phase4th Phase
  78. 78. Python Issue - read gzip by utf-8 4th Phase ● 당연히 상기한 에러 발생! 왜냐면 gz 파일을 utf-8로 decode했으므로 ● 이를 아래처럼 고치려 했다면? Error 4th Phase
  79. 79. ● gzip을 read할 때 말고 write할 때도 encoding 이슈 발생 Python Issue - write gzip 4th Phase json obj newfilegzip file read & parsing by str write with wb mode 4th Phase
  80. 80. ● gzip을 read할 때 말고 write할 때도 encoding 이슈 발생 Python Issue - write gzip 4th Phase json obj newfilegzip file read & parsing by str write with wt mode 변경전 변경후 4th Phase
  81. 81. ● Mysql Bit(1) Field에 대해 django cursor로 SQL select 쿼리를 call하면 ○ b‘True’, b‘False’ 가 아닌 ○ b‘x00’, b‘x01’ 를 return Python Issue - Mysql Bit(1) edge case 4th Phase4th Phase
  82. 82. ● Mysql Bit(1) Field에 대해 django cursor로 SQL select 쿼리를 call하면 ○ b‘True’, b‘False’ 가 아닌 ○ b‘x00’, b‘x01’ 를 return ● 그래서 다음과 같은 함수를 사용해야 했다 Python Issue - Mysql Bit(1) edge case 4th Phase4th Phase
  83. 83. ● Mysql Bit(1) Field에 대해 django cursor로 SQL select 쿼리를 call하면 ○ b‘True’, b‘False’ 가 아닌 ○ b‘x00’, b‘x01’ 를 return ● 그래서 다음과 같은 함수를 사용해야 했다 ● 하지만 이는 에러나기 딱 좋은 사용법 Python Issue - Mysql Bit(1) edge case 4th Phase4th Phase
  84. 84. ● py2에서는 str, bytes가 똑같아 b‘x00’가 들어올 때 정상동작 ● py3에서는 str, bytes가 달라서 b‘x00’가 들어와도 True 리턴! ○ 이 때문에 수많은 False여야 할 데이터가 True로 저장 ○ Exception 발생이 아니니까 온갖 에러가 다 발생하고서야 알아챔 Python Issue - Mysql Bit(1) edge case 4th Phase4th Phase
  85. 85. ● py2에서는 str, bytes가 똑같아 b‘x00’가 들어올 때 정상동작 ● py3에서는 str, bytes가 달라서 b‘x00’가 들어와도 True 리턴! ○ 이 때문에 수많은 False여야 할 데이터가 True로 저장 ○ Exception 발생이 아니니까 온갖 에러가 다 발생하고서야 알아챔 ● 근데 더 문제는 이 함수의 사용처 Python Issue - Mysql Bit(1) edge case 4th Phase4th Phase
  86. 86. Python Issue - Mysql Bit(1) edge case 4th Phase before 2to3 ● 데이터 적재 전 전처리 하는 함수 ● b‘x00’을 False로 바꾸는 작업 등을 했던 것 ● 문제는 두번째 if 조건이 bytes가 아니라 str ● 물론 py2에선 str == bytes 이므로 이상 무 4th Phase
  87. 87. Python Issue - Mysql Bit(1) edge case 4th Phase before 2to3 after 2to3 4th Phase
  88. 88. Python Issue - Mysql Bit(1) edge case 4th Phase after 2to3 ● py3에선 str != bytes ● 따라서 더 이상 조건문의 의도대로 되지 않음 ● 조건문의 위치까지 공교롭게도 convert_to_boolean이 quote_or_null 보다 먼저 4th Phase
  89. 89. Python Issue - Mysql Bit(1) edge case 4th Phase after 2to3 ● 조건문의 위치까지 공교롭게도 convert_to_boolean이 quote_or_null 보다 먼저 ● 온갖 스트링이 다 True가 됨 after 2to3 4th Phase
  90. 90. ● 만약 b‘x00’, b‘x01’ 대신 b‘False’, b‘True’였다면? ○ eval(value) 사용으로 py2, py3에서 모두 문제 없이 동작 ● 조건문 고쳐서 해결 Python Issue - Mysql Bit(1) edge case 4th Phase4th Phase
  91. 91. ● __unicode__ vs __str__ ○ py2에선 __unicode__만 정의해둬도 print를 할 때 __str__ 정의된 것처럼 실행 (bytes로 return) ○ py3에선 str == unicode 이므로 그렇지 않음 ○ py3는 그래서 __str__ 함수를 따로 만들어주어야 함 Python Issue - __unicode__ vs __str__ 4th Phase 4th Phase4th Phase
  92. 92. ● django decorator 중 python_2_unicode_compatible라는 것 존재 ○ py3에서 __str__을 unicode return 하도록 정의하면 ○ py2에서 __str__ returns bytes, __unicode__ returns unicode ○ 이를 이용해 py2, 3 공존 가능 Python Issue - __unicode__ vs __str__ 4th Phase 4th Phase4th Phase
  93. 93. ● django orm .count ○ py2에서는 .count > 0 도 가능 ○ py3에서는 .count() > 0 만 가능 Python Issue - Comparison 4th Phase 4th Phase4th Phase
  94. 94. Python Issue - Comparison 4th Phase 4th Phase ● NoneType Comparison ○ py2 ○ py3 4th Phase
  95. 95. ● django dispatcher의 request ○ requests.body가 bytes 타입! ○ str vs bytes 문제 발생하기 좋음 Python Issue - 여러가지 위험요소들 4th Phase4th Phase
  96. 96. ● 나눗셈 변화 ○ py2 ○ py3 Python Issue - 여러가지 위험요소들 4th Phase4th Phase
  97. 97. ● __cmp__ deprecated ○ py2에는 class 내의 __cmp__ 함수로 compare함수 정의 가능 ○ py3에는 __cmp__ 없음 ○ __lt__, __le__, __gt__, __ge__, __eq__, __ne__ 각각 정의해줘야 함 Python Issue - 여러가지 위험요소들 4th Phase4th Phase
  98. 98. ● Exception 구조 변화 - message 없어짐 ○ py2 ○ py3 Python Issue - 여러가지 위험요소들 4th Phase4th Phase
  99. 99. ● flush() 함수 사용할 필요 없어짐 ● py2에서는 5초뒤 한꺼번에 0, 1, 2, 3, 4 ● py3에서는 1초에 한번씩 0, 1, 2, 3, 4 ● py2에서 의도한대로 출력하려면 주석처리된 flush함수 사용해야 함 Python Issue - 여러가지 위험요소들 4th Phase4th Phase
  100. 100. ● 여기까지가 4th Phase 끝 ○ 여기에 소개된 에러들 중 상당수는 배포 이후에 만남 ○ EDD의 현장 기록들 Test & Debug 3th Phase3th Phase
  101. 101. 5단계 - Deploy 배포한 이후에도 에러를 많이 만날 수 있음
  102. 102. ● 주요 테스트를 끝내고 이제 서버를 새로 띄우자 ● py2 서버는 바로 내리지 말고 안정화 될 때까지 상비 ● server migration todo list 다섯 가지 배포 crontab supervisor & circus django 외 다른 nginx servers batch job cache & message queue 5th Phase
  103. 103. 배포 흐름에 따른 Branch 관리 1. new server 구축 2. 상기한 5가지 migration 작업 진행 및 트러블 슈팅하며 안정화 3. branch feature/5-phase-deploy-for-py2 from master merge feature/5-phase-deploy-for-py3 into master 4. 배포 branch 변경 5th Phase new server feature/5-phase-deploy-for-py3 old server master 5th Phase new server master old server feature/5-phase-deploy-for-py2 5th Phase
  104. 104. crontab migration ● crontab task들은 진행전 체크할 것이 많다 ○ 구 서버 system timezone은 어디인가 ○ 여러번 재실행해도 되는 task인가 ○ 아무때나 재실행해도 되는 task인가 5th Phase5th Phase
  105. 105. crontab migration ● crontab task들은 진행전 체크할 것이 많다 ○ 구 서버 system timezone은 어디인가 → KST ○ 여러번 재실행해도 되는 task인가 → 그런 것도 있고 아닌 것도 있다 ○ 아무때나 재실행해도 되는 task인가 → 그런 것도 있고 아닌 것도 있다 5th Phase5th Phase
  106. 106. crontab migration ● 실서버 테스트 할 수 있는건 즉각 테스트 및 migration ● 테스트 불가능하면 테스트 환경에서 테스트 ○ 하루 정해진 횟수, 정해진 시간에만 실행되도록 조건부 migration 진행 5th Phase5th Phase
  107. 107. crontab migration ● timezone UTC에서 KST로 변경 및 crontab 재시작 5th Phase5th Phase
  108. 108. crontab migration ● timezone UTC에서 KST로 변경 및 crontab 재시작 ● 이를 해주지 않으면? ○ timing depend한 cron job에서 문제 발생 5th Phase5th Phase
  109. 109. crontab migration ● 만약 system time을 변경하지 않은걸 나중에서야 발견했다면? ○ 늦게라도 timezone 바꾸고 하루에 한 번씩만 돌아가야 하는 task들 정리 ○ KST(target timezone) 기준으로 하루 한 번씩만 돌아가도록 조건부 migration 5th Phase5th Phase
  110. 110. django 외 다른 nginx servers ● 에러날 경우 구 서버에 proxy 해주는게 방법 5th Phase5th Phase
  111. 111. ● crontab이 아니더라도 여러가지 batch job이 돌아갈 수 있다 ○ data engineering을 한다면 특히 많을 수밖에 ● 이를 하나하나 새로운 서버로 옮기는걸 잊지 말자 ○ airflow를 사용하는데 일부 batch job이 서버 이전 작업에서 누락되어 구서버에서 돌아가는 문제를 겪음 ○ py2, py3 환경이 아예 다르기 때문에 큰 문제 발생 가능 Batch Job 5th Phase5th Phase
  112. 112. ● cache와 message queue도 py3 서버용 새로 구축 ○ cache, MQ의 python interface protocol이 달라질 수 있다 cache & message queue 5th Phase5th Phase
  113. 113. ● django cache를 사용하다 보니 이 에러 발생 ● py2 서버와 py3 서버 모두 운용할 때 발생 ● 이게 뭘까? unsupported pickle protocol: 4 5th Phase5th Phase
  114. 114. ● pickle은 python의 serialization 모듈 이름 ○ pickling == serialization, unpickling == deserialization ○ py2.7는 protocol 2 ○ py3.6은 protocol 4 unsupported pickle protocol: 4 5th Phase5th Phase
  115. 115. ● py2 서버와 py3 서버가 cache를 공유하면서 발생한 것 ○ py3에서 protocol 4로 pickling해서 cache에 set data ○ py2에서 protocol 2로 해당 data를 unpickling할 때 발생 ○ 각 서버에서 서로 다른 cache를 사용하도록 따로 설정해줘야 함 unsupported pickle protocol: 4 5th Phase5th Phase
  116. 116. ● gitignore 된 파일들의 python version ● py3 코드가 py2 interpreter로 돌아가는 경우 ○ 반대의 경우도 존재 주요 이슈들의 contexts 5th Phase5th Phase
  117. 117. ● python 버전업 문제도 많지만 서버 migration 문제도 아주 많다 ● 심오한 기술적인 문제보다 human error가 훨씬 많이 발생 ○ 작업이 잘못된다거나, 누락된다거나, 멈춘다거나 등등 ● system entropy 관리 문제가 human error의 근본 원인 ○ 항상 간단한 List up을 하는 것이 문제 해결의 시작! 주요 이슈들의 contexts 5th Phase5th Phase
  118. 118. 정리
  119. 119. ● 기본적으로 여섯 가지 branch를 만들자 ● 앞의 1 ~ 4단계 개별로 하나씩 Git branch 관리방법 정리
  120. 120. ● 기본적으로 여섯 가지 branch를 만들자 ● 앞의 1 ~ 4단계 개별로 하나씩 ● 이전 단계의 브랜치의 변경사항이 생기면 ○ 뒤 단계 브랜치들에는 바로바로 merge! Git branch 관리방법 정리정리
  121. 121. ● 추가적으로 배포용 브랜치 두 개 ○ 하나는 py3 베타테스트 용도, 다른 하나는 py2 백업 용도 ○ py2 백업 브랜치는 django 서버가 두 종류라면 무조건 있어야 한다! Git branch 관리방법 정리정리
  122. 122. ● py2, py3 공생시키기 vs py3로 갈아 엎기 ○ porting에 어려움이 있는게 아니라면 후자가 낫다 ○ 처음 시작하는 프로젝트는 무조건 python3로 개발하자 ○ py2가 필요한 부분이 분리가능하다면 레포를 분리 ○ 그래도 해야 한다면? Py2, Py3 공생시키기 정리정리
  123. 123. Py2, Py3 공생시키기 ● future, six 사용하기 ● py2, py3의 차이점들 이해하기 ● 추천자료 ○ 김태환, Python 2 와 3 공존하기, pycon 2017, https://www.pycon.kr/2017/program/151 ○ Ed Schofield, Writing Python 2-3 compatible code, python-future, http://python-future.org/compatible_idioms.html 정리정리
  124. 124. ● EDD가 효율적인 이유? ○ 계획 세우는 비용을 아낄 수 있어서 ○ 보통은 테스트 & 디버깅 한 번 만에 해결이 돼서 ○ 목표에 바로 도달할 수 있어서 소감 정리정리
  125. 125. ● 하다보니 그냥 한 번에 에러가 나서 서버가 바로 죽어주는게 차라리 고마웠다. ○ 데이터가 바뀌거나 무결성 깨져서 나중에야 그걸 알게되고 뒷수습하는 일이 더 힘들었음 소감 정리정리
  126. 126. ● 2to3 conversion을 안전하고 빠르게 하려면? ○ 첫 째도 list up, 둘 째도 list up ○ list up이 한계가 있다면 의존성 관리를 사람이 하지 말고 코드에게 시키는 것만으로도 어느 정도 개선됨 소감 정리정리
  127. 127. ● 좋았던 점 ○ Pycon 2018 발표 ○ asyncio 사용 중 ○ ipython 추가기능, 여러가지 django extension들 사용 ○ django 버전업 가능 ○ 버전업하고 팀내 신규 입사자 6명 소감 정리정리
  128. 128. ● Kristjan Wager, Error-driven Software Development, http://errordrivendevelopment.blogspot.com/2009/06/error-driven-software-development.html ● 김태환, Python 2 와 3 공존하기, pycon 2017, https://www.pycon.kr/2017/program/151 ● Ed Schofield, Writing Python 2-3 compatible code, python-future, http://python-future.org/compatible_idioms.html ● Timothy Bramlett, Strings Bytes and Unicode in Python 2 and 3, https://timothybramlett.com/Strings_Bytes_and_Unicode_in_Python_2_and_3.html ● python, Standard Encodings, Python Library Reference https://docs.python.org/2.4/lib/standard-encodings.html 참고 문헌 정리정리
  129. 129. 감사합니다

×