전체 글
Happy Hacking!
-
개요 며칠 전에 DB 부하로 인해 사내에서 작지 않은 장애가 났었다. write DB에서 CPU가 갑자기 높게 치더니 기어이 장애가 발생했다. 다행히 팀원 분들이 재빠르게 대처해 주셔서 곧바로 해결되었다. 그런데 생각해 보니 DB CPU가 언제 많이 쓰이는지 제대로 알지 못하고 있었다. IO에만 신경쓰고, CPU는 뭐 filesort할 때나 쓰이지 않을까 생각하고 있었는데 이번 일을 보니 꼭 그러한 건 아닌 것 같다. 따라서 이번 기회에 CPU가 언제 높게 치는지 몇가지 조사해 보았다. 1. 레코드 잠금 경합 트랜잭션 간 lock 경합이 발생할 때를 말한다. lock 경합을 확인할 때는 information_schema.innodb_lock_waits 테이블을 사용한다. 다음 쿼리는 block된 트랜잭션..
MySQL에서 CPU가 높게 칠때개요 며칠 전에 DB 부하로 인해 사내에서 작지 않은 장애가 났었다. write DB에서 CPU가 갑자기 높게 치더니 기어이 장애가 발생했다. 다행히 팀원 분들이 재빠르게 대처해 주셔서 곧바로 해결되었다. 그런데 생각해 보니 DB CPU가 언제 많이 쓰이는지 제대로 알지 못하고 있었다. IO에만 신경쓰고, CPU는 뭐 filesort할 때나 쓰이지 않을까 생각하고 있었는데 이번 일을 보니 꼭 그러한 건 아닌 것 같다. 따라서 이번 기회에 CPU가 언제 높게 치는지 몇가지 조사해 보았다. 1. 레코드 잠금 경합 트랜잭션 간 lock 경합이 발생할 때를 말한다. lock 경합을 확인할 때는 information_schema.innodb_lock_waits 테이블을 사용한다. 다음 쿼리는 block된 트랜잭션..
2024.03.15 -
개요 view에서 request 단위로 transaction.atomic()을 걸고 bulk_create와 그 후 생성한 obj를 find했으나 조회할 수 없는 현상이 있었다. @transaction.atomic() some_view(): svc1.create() svc2.bulk_create() svc3.retrieve() 이런 느낌의 view였는데, svc3에서 svc1에서 생성한 obj는 조회가 됐었으나, svc2에서 생성한 objs는 조회할 수 없었다. 본문 내가 기대했던 건, svc1이든 svc2든 같은 물리 트랜잭션 내에 존재하기 때문에 svc3에서 둘다 모두 조회되는 것이었다. 그럼에도 불구하고 svc1에서 생성된 것만 조회된다는 것은 무언가 문제가 있어 보였다. 여기서 조사했던 건 bulk..
django bulk_create시 같은 트랜잭션에서 created objects 조회할 수 없는 현상개요 view에서 request 단위로 transaction.atomic()을 걸고 bulk_create와 그 후 생성한 obj를 find했으나 조회할 수 없는 현상이 있었다. @transaction.atomic() some_view(): svc1.create() svc2.bulk_create() svc3.retrieve() 이런 느낌의 view였는데, svc3에서 svc1에서 생성한 obj는 조회가 됐었으나, svc2에서 생성한 objs는 조회할 수 없었다. 본문 내가 기대했던 건, svc1이든 svc2든 같은 물리 트랜잭션 내에 존재하기 때문에 svc3에서 둘다 모두 조회되는 것이었다. 그럼에도 불구하고 svc1에서 생성된 것만 조회된다는 것은 무언가 문제가 있어 보였다. 여기서 조사했던 건 bulk..
2024.03.09 -
용어들몰&몰 : 오프라인 매장을 온라인으로 그대로 들여오는 구조고객 관여도가 낮은 제품 : 고객이 온라인으로 주문해도 품질을 믿을 수 있는 제품. 반품할 가능성이 적다.GMV : Gross Merchandise Volume : 특정 기간동안 거래된 상품 총 금액. 실제 이익보다 거래된 상품의 판매가나 실결제 금액 총액으로 산정하는 경우가 많다오픈 마켓 : 입점이 오픈되어 있어 롱테일에 가장 적합한 형태리테일 : 생산자 / 도매업자가 아닌 측에서 낱개로 파는 일롱테일 : 80%의 사소한 다수가 20%의 핵심 소수보다 뛰어난 가치를 창출한다는 이론. 역 파레토의 법칙객단가(AOV) : 고객 1인당 평균 지불하는 금액. 보편적으로 매출액 / 고객 수. 해당 이커머스 판매하는 핵심 상품 가격대 / 한 번에 대략..
이커머스 관련 지식 용어들용어들몰&몰 : 오프라인 매장을 온라인으로 그대로 들여오는 구조고객 관여도가 낮은 제품 : 고객이 온라인으로 주문해도 품질을 믿을 수 있는 제품. 반품할 가능성이 적다.GMV : Gross Merchandise Volume : 특정 기간동안 거래된 상품 총 금액. 실제 이익보다 거래된 상품의 판매가나 실결제 금액 총액으로 산정하는 경우가 많다오픈 마켓 : 입점이 오픈되어 있어 롱테일에 가장 적합한 형태리테일 : 생산자 / 도매업자가 아닌 측에서 낱개로 파는 일롱테일 : 80%의 사소한 다수가 20%의 핵심 소수보다 뛰어난 가치를 창출한다는 이론. 역 파레토의 법칙객단가(AOV) : 고객 1인당 평균 지불하는 금액. 보편적으로 매출액 / 고객 수. 해당 이커머스 판매하는 핵심 상품 가격대 / 한 번에 대략..
2024.03.02 -
들어가면서 최근에 쿼리 자체로만 해결할 수 없는 일인데 쿼리에 집착해서 시간을 잡아먹었던 일이 2가지 있었다. 아무래도 쿼리는 수치로 얼만큼 느린지 바로 보이기도 하고, DB 영역이 문제 발생시 원인이 되는 주 영역이기 때문에 더욱 신경쓰느라 그런 것 같다. 이번 일기에서는 해당 사건들을 서술하고, 배운 점들에 대해 적어보았다. 사례 1: 쿼리 튜닝 말고 주어진 환경 이해하고 변경하기 재고의 수를 동기화하는 API에서 자꾸 timeout이 발생해서 동기화 태스크가 실행 안 된다는 문제가 있었다. 직접 실행하다 보니, 이 문제는 동기화 과정에서 특정 조건에 대한 COUNT와 column에 대해 GROUP BY SELECT하는 복합 쿼리가 문제였다. 나는 해당 쿼리의 문제점이 1. GROUP BY에 의해 임..
쿼리에 집착하지 않기들어가면서 최근에 쿼리 자체로만 해결할 수 없는 일인데 쿼리에 집착해서 시간을 잡아먹었던 일이 2가지 있었다. 아무래도 쿼리는 수치로 얼만큼 느린지 바로 보이기도 하고, DB 영역이 문제 발생시 원인이 되는 주 영역이기 때문에 더욱 신경쓰느라 그런 것 같다. 이번 일기에서는 해당 사건들을 서술하고, 배운 점들에 대해 적어보았다. 사례 1: 쿼리 튜닝 말고 주어진 환경 이해하고 변경하기 재고의 수를 동기화하는 API에서 자꾸 timeout이 발생해서 동기화 태스크가 실행 안 된다는 문제가 있었다. 직접 실행하다 보니, 이 문제는 동기화 과정에서 특정 조건에 대한 COUNT와 column에 대해 GROUP BY SELECT하는 복합 쿼리가 문제였다. 나는 해당 쿼리의 문제점이 1. GROUP BY에 의해 임..
2024.02.28 -
들어가면서 파이썬을 사용하다 보면 가끔 몽키패칭과 덕타이핑이란 키워드를 듣게 되는데, 이번 기회에 조사해 보면서 최근 읽는 러닝 파이썬이란 책에서 공부한 내용을 바탕으로 생각을 정리해 보았다 단순히 보았을 때 몽키패칭은 테스트 작성시 혹은 외부 모듈 수정시 유용하고, 덕타이핑은 타입 관계 없이 행위로 받아서 사용할 때 유용해 보인다. 몽키패칭 Java만 사용하던 사람들은 깜짝 놀라 기절할 수도 있지만 파이썬에선 이러한 행위가 가능하다. class BananaClient: def request_banana(self): return "banana" banana_client = BananaClient() class Monkey: def banana(self): return banana_client.reques..
파이썬 동적 타입 언어와 몽키패칭, 덕타이핑들어가면서 파이썬을 사용하다 보면 가끔 몽키패칭과 덕타이핑이란 키워드를 듣게 되는데, 이번 기회에 조사해 보면서 최근 읽는 러닝 파이썬이란 책에서 공부한 내용을 바탕으로 생각을 정리해 보았다 단순히 보았을 때 몽키패칭은 테스트 작성시 혹은 외부 모듈 수정시 유용하고, 덕타이핑은 타입 관계 없이 행위로 받아서 사용할 때 유용해 보인다. 몽키패칭 Java만 사용하던 사람들은 깜짝 놀라 기절할 수도 있지만 파이썬에선 이러한 행위가 가능하다. class BananaClient: def request_banana(self): return "banana" banana_client = BananaClient() class Monkey: def banana(self): return banana_client.reques..
2024.02.17 -
들어가면서 사내에서 사용하는 함수 중 @redis_cache라는 함수가 있다. 함수의 FQCN과 input을 기억해놓고 캐싱하는 역할의 함수이다. 이 함수를 사용하는데, 자꾸만 TypeError가 발생했다. TypeError라고 해서 인자 타입이 잘못된 것인줄 알았는데 Python의 TypeError는 호출하려는 함수의 시그니처가 다를 경우 발생하기도 한다. @redis_cache def get_feeds(feed_pk: int) { ... } Python에서는 시그니처 검사시 타입을 검사하지 않고 인수의 수만 검사한다. 동적 언어기 때문에 식별자에 담긴 타입이 언제든지 변할 수 있고, 참조값을 저장하기 때문에 타입 검사가 의미 없기 때문이다. 실제로 feed_pk에서 타입 힌팅을 int로 주고 있지만 ..
Python Decorator 선언시 호출하지 않으면 TypeError 발생했던 이유들어가면서 사내에서 사용하는 함수 중 @redis_cache라는 함수가 있다. 함수의 FQCN과 input을 기억해놓고 캐싱하는 역할의 함수이다. 이 함수를 사용하는데, 자꾸만 TypeError가 발생했다. TypeError라고 해서 인자 타입이 잘못된 것인줄 알았는데 Python의 TypeError는 호출하려는 함수의 시그니처가 다를 경우 발생하기도 한다. @redis_cache def get_feeds(feed_pk: int) { ... } Python에서는 시그니처 검사시 타입을 검사하지 않고 인수의 수만 검사한다. 동적 언어기 때문에 식별자에 담긴 타입이 언제든지 변할 수 있고, 참조값을 저장하기 때문에 타입 검사가 의미 없기 때문이다. 실제로 feed_pk에서 타입 힌팅을 int로 주고 있지만 ..
2024.02.04