-
Notifications
You must be signed in to change notification settings - Fork 10
/
0205.txt
159 lines (159 loc) · 10.3 KB
/
0205.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
안녕하세요 포프입니다.
오늘은 DB(데이터베이스)쪽 얘기를 해보려고 해요
게임 쪽에서는 아직 그렇게 많이 안쓰지만
요즘은 좀 써요, 모바일게임에서
light SQL(북미권 발음 : 시퀄) 쓰고.. SQLite?(시퀄 라이트)
서버에는 쓰겠고
SQL Database 많이 써요
앞으로는 점점 NoSQL(노시퀄)로 가는 부분도 굉장히 많은데, 뭐 그거는 나중에 얘기하기로 하고
이제 SQL 데이터베이스의, 아 시퀄이라그러면 에스큐엘(SQL) 얘기하는 거군요. 저희는 그냥 시퀄이라 그래요.
SQL데이터베이스의
데이터를 박을 때 보통 프라이머리 키(primary key)를 넣잖아요.
아이디 키에서 identity(아이덴티티) 넣고 insert(인서트)할때마다 번호 늘려주는거 auto increment(오토 인크레먼트) 넣어갖고..
이렇게 해서 그걸 primary key로 많이 쓰거든요
이게 많이 썼었는데..
최근 들어서 새로운 패턴이 많이 나왔잖아요. CQRS(씨큐얼에스) 라던가 event sourcing(이벤트 소싱) 이라던가
이런거에서 보면, 디자인 패턴 쪽에서 얘기하면, Reader(리더) writer(라이터)가 분리되는 그런 패턴이거든요
메세지 큐(queue) 같은걸 이용해서 writer면 write 넣고, 그런 메세지가 막 온 다음에 이게 DB로 나중에 집어넣어 주는 거에요.
그리고 Read 할때는 약간 비동기가 될 수 밖에 없죠, Read를 여기서 해 오고.
이게 장점이 뭐냐하면, SQL에는 데이터를 집어 넣을 때마다 write 할때마다 lock(락)을 걸거든요.
현재 분산SQL 자체가 제대로 구축이 안돼있고, SQL이 워낙 오래된 시스템이고
그렇게 SQL 하나만, instance(인스턴스) 하나만 쓰거나 아니면
논리적으로 분리를 시키죠, 유저 넘버 0부터 1000번까지는 이거 데이터베이스
몇번부터 몇번까지는 저거 데이터베이스. 이런식으로.
뭐, 어찌보면은 Hack(핵)인데,
그런걸 하다보니까
문제가 뭐냐하면,
Lock이 너무 많이 걸려요. Lock이..
DB를 쓸 때 마다 Lock이 걸리니까
성능 향상을 위해서 별별짓을 다 하거든요.
그래서 그 중 하나가 CQRS고
나중에 어찌보면 이게 NoSQL 이라던가 아니면은
제대로 된, 분산SQL서버가 나오면 그걸 하겠죠.
근데 문제는, 언제나 문제는 이거에요.
만약에 이거를 여러개로 나눴다..
그러면
이거를 다시 원래대로 합치고 싶을 때 있잖아요.
떨어진거 두개를 합친다거나, 아니면 처음에 분산으로 했다가 뒤에가면 하나로 합쳐진다거나
그러면, Primary key가 id면요 autoincrement id면은
이거를 merge(머지) 할 수 있는 방법이 없어요. 아니 merge를 하긴 하는데..
이 integrity(인테그리티)라고 하나요? 이거를 유지하면서 할 방법이 없어요.
왜냐하면은 이 뒤에있는 DB에서는
이 primary key가 바뀌어 버려요.
여기서는 1,2,3,4 있었죠? 밑에서도 1,2,3,4가 있어요. 두 개를 합치면? 번호 어떻게 할거야..
그렇죠? 그럼 Primary key가 바뀌는 단점이 있어요.
그래서.. 이게 좀 안좋구나
그리고 CQRS 개념에서는..
처음 데이터를 집어 넣을 때
Queue에 집어 넣는 거거든요.
event sourcing도 비슷하고
반드시 그런건 아니지만 대부분 그래요.
queue에 넣으면은 그 queue에 들어 갈 때는 id 자체가
DB 의 id가 아니에요. Auto increment가 안돼니까..
아니, 안돼니까가 아니라 안들어갔으니까 아예 안돼는거죠.
그래서 그 대신에 이제
다른 id를 쓰거든요. 뭐 string(스트링) id를 쓴다거나 보통 요즘은 Guid(구이드)를 많이 써요. 쥐유아이디.
Guid가 64비트? 128비트 같애요. 128비트짜리 숫자인데
이게, Globally Unique Identifier(글로벌리 유니크 아이덴티파이어)라고 해 갖고
충돌이 왠만하면 없어요.
있을수는 있어요. 근데..
아직 제가 나는걸 못 봤어요.
그래서 Guid로 넣으면은 그냥..
숫자들 있죠? 94344-2222-5555-6666 이런식..
이런 패턴이 Guid거든요?
이제 그거를 넣어갖고 하면은..
Guid를 해갖고 DB에 넣으면 어떻게 되냐하면
Primary key가 Guid가 되는거에요.
string(타입)으로 집어넣을 수 있고.. Guid(타입)도 있어요 MySQ...아니 MSSQL에서는..
SQLite에서는 없고
그럼 string 으로 써야겠죠.
Primary키를 string으로 잡아두고 그거를 연산하는거에요.
물론 그러면 사람들이 얘기하기는 DB가 string을 넣으면 너무 느리지 않냐.. 그걸 Primary key로 쓰면 너무 느리지 않냐..
별로 안느려요 생각보다.
그거로 인해 오는 성능 저하는 10%미만으로 알고 있어요.
그래서 그걸로 넣고
그러면 나중에 merge하기도 쉽잖아요.
Guid가 여기 aaaa-bbbb였으면, 합칠 때 aaaa-bbbb들어가니까 문제는 없거든요
그러면 나중에 SQL서버가 아니고 다른걸 넣더라도 그걸 key로 쓰면 되니까 문제는 없어요.
제가 좀 전에 성능저하가 별로 없다라고 말씀을 드렸잖아요.
물론 그거는 제대로 index(인덱스) 걸고, id로 들어가는거는
그러니까, Primary key로 들어가는 거는 당연히 인덱스가 걸리기 때문에, 그거는 빠르지만,
string comparison(컴페리슨)이 느릴 수 있다? 그것도 제가 볼 때는 내부적으로 최적화가 되는거 같아요.
그걸로 인해서 Hash(해쉬)를 integer로 뽑은다음에 비교할 수도 있겠고..
아니면 string comparison을 해도 실제 생각보다 그렇게 느리지 않았어요.
그걸로 오는 성능저하는 10% 밖에 안돼요. 사실은.
물론 10% 때문에 어쩌구 저쩌구 저쩌구 해서 10%가 너무 느리다 못하겠다?
그러나 Write할 때 Lock 걸리는것보다는 SQRS통해서 그런식으로 Guid 배치해버리는게, 제가 볼 때는 훨-씬 빨라요.
DB는 Lock할때는 전체 Lock을 걸어야 되니까
write할 때마다.. Read는 상관없고
그래서 여기서 오는게, 다른 성능저하가 하나 있어요. 되게 재밌는게 다른 성능저하가 있어요.
이게 되게 재밌는게 뭐냐하면,
DB에 데이터를 넣을때,
1, 2, 3, 4, 5 이런식으로 넣잖아요.
그러면 DB 데이터 구조가
이 id 순서로 있잖아요
그거 순서대로 Disk 안에 이렇게 넣어요.(손짓)
그런데 Guid가 들어가면은, 만약 aaa-ccc가 있는데
bbbb가 들어오잖아요?
그러면 b를 중간에 넣고 c를 copy(카피) 하거든요?
그러면 이걸 보통 생각하는 array(어레이) 같은거 중간에
뭐 삽입할 때, 뒤에꺼 다 뒤로 미뤄야 되니까
그러면 그게 이제 O(n)이다 라는 문제 있잖아요. 그 문제가 똑같이 생겨요.
문제는 SQL서버는 Disk에서 써야되니까 굉장히 느려지죠.
그래서, 거기서 오는 성능저하가 전에 그래프를 본 게 있는데
굉장히 높아요. 뭐 한.. 몇십프로가 되요 진짜 그걸로.
그대신.. 그러면.. 이걸 어떻게 하냐?
그래서 제가 고민을 많이 했어요. 그러다가 최근에 발견한거가 뭐냐하면
여전히 10% 오버헤드만으로 할 수 있게 해놓은 방법이 있더라구요
이 아이디어가 뭐냐하면, 되게 간단해요.
"Primary key" 이거는
여전히 Guid로 써요
그러면 아까 말했던, 데이터 충돌의 문제가 없어요.
그 대신에, 실제 DB에 넣을 때 identity(아이덴티티)라는 section(섹션)이 따로 있거든요?
그게 이제, 예전에는 id를 숫자로 해서, primary key랑 identity랑을 같이 썼어요.
근데 이제.. 그게 identity인가?(혼잣말) 맞을거에요.
Guid는 PK로 써요 primary key로, 그리고
다른 Field(필드)를 하나 추가하는거에요. 예를 들어서.. 뭐라고 넣을까?
index id?(인덱스 아이디)
그런식으로 이름을 넣은 다음에, 아니면 뭐.. order id(오더 아이디)?
그러니까 순서를 정한다는 order id
그거를 옛날 방식으로 쓰는거에요.
그러면
DB는 언제나
순서를 넣을 때
1, 2, 3, 4, 5, 6 아까 그 숫자 있잖아요 그 순서로 넣고,
대신 primary key는 아까 string으로 보는거에요.
그래서 실제 DB를 집어넣을때(Disk로) 순서도 그대로 들어가고(숫자 순이나 알파벳 순)
대신 primary key는 언제나 Guid기 때문에
나중에 이거를 다른걸로 merge하거나 합칠 때
아니면 migration 할 때
그 떄는 그냥
아까 id section 있죠
제가 order id라고 했던거, 그거만 싹 무시하구요.
이 데이터만 뽑아갖고 다 insert 해버리는 되는거야.
그러면 primary key는 언제나 unique 하니까
충돌이 안나고 id는 여기서 새로워지는거죠.
그래서 나중에 데이터마이그레이션 할 때는, 순수하게
id 섹션 싹 무시하고, 숫자 무시하고
PK와 Guid 그거와 이제 나머지 데이터만 갖고 insert를 넣어버리면 되는거더라구요.
그래서 이제 제가 Benchmark(밴치마크) 나올것을 봤는데, 여전히 10% 정도의 overhead(오버헤드) 밖에 없어요.
보면서, 아~ 이런 꼼수가 있구나
제가 볼때는
모르겠어요. 과연 이게.. DB쪽에서 고쳐줄지는 모르겠는데,
Guid를 id와 PK로 같이 넣었을 때 이게 어떻게 될지는 모르겠는데
제 생각에는
좀, 가장 깔끔한 방법 같아요.
Insert 할 때, 이 id 섹션 새로 그냥 integer autoincrement로 냅두고
Primary key는 Guid로 가고
그러면 성능도 잡을 수 있고, 뭐 10%정도 저하야 상관 없으니까
말그대로 메세지 큐에 박은 다음에 write하는 방식으로 write하는.. 뭐 스레드라고 하죠.
그건 언제나 하나만 있게 하고, Read는 몇백개가 되도 상관없으니까
Lock을 안하고..
그래서 생각해봤을때, "아 이러면 정말 DB 성능은 빨리 잡을 수 있겠구나 생각이 들더라구요"
근데 이제, 이거의 단점은
실시간으로
Write 하자마자 Read해와야 되는 경우 있잖아요. 거기에는 조금 어려워요.
중간에 Event(이벤트)를 가로채고 갖고 오지 않는 한..
제가 최근에 봤던 꼼수중에 참 괜찮은 방법이다 라는 생각이 있어서..
소개를 드렸고
포프였습니다.