게시글 보니까 Typia쓰면 되는데 이런 거 왜 만들었냐고 하길래 글 써봄
ㅆㅇㅆ 본인의 말에 의하면 FlatBuffers를 대체하기 위해 만들었다고 하는데,
이 소리를 이해하려면 Flatbuffers가 왜 나왔는지를 먼저 이해해야 한다
FlatBuffers가 나온 이유는 직렬화가 느리기 때문이다.
그렇다면 직렬화란 뭘까?
1. 직렬화란 무엇인가
우리가 객체를 만들면 그 객체는 메모리에 저장된다.
문제는 이 객체를 남에게 보낼 때 발생한다.
해당 객체가 담긴 0x8as2 어쩌고 하는 특정 메모리 주소는
해당 컴퓨터에서만 유효하기 때문에 상대 컴에서는 아무 의미가 없다.
즉 내가 데이터를 보내봤자 상대가 알아먹을 수가 없다는 거다.
그래서 나온 게 직렬화다
직렬화에는 여러가지 방법이 있는데 제일 유명한 것 중 하나는 json이다
근데 json에는 심각한 문제가 있다.
2. json
일단 json은 아래와 같이 생겼다.
```
{
"id":7,
"age":41
}
```
딱 봐도 읽기가 쉽다.
근데 이걸 컴퓨터가 이해하고 사용하려면 아래의 3단계가 필요하다.
- id는 7이네, age는 41이네... 이렇게 파싱작업이 필요하고
- 숫자인지 문자인지 타입판단도 해야되고
- 위 단계들을 통해 종합적으로 새 객체를 만들어내야함
각 단계를 위해 내부적으로 2~3단계를 더 거치기 때문에
실질적으로는 7~10단계 쯤 된다.
딱 봐도 너무 느릴 것 같다.
그래서 더 빠르게 데이터를 주고받고자
바이너리 직렬화란 게 나왔다
3. 바이너리 직렬화
내가 상대에게 8바이트 데이터를 줄 건데,
앞 4바이트는 ID고
뒷 4바이트는 age면
데이터가
01 0a 03 04
02 0c 0d 01
이딴 식으로 갈테니깐
컴퓨터가 엄청난 속도로 읽을 수 있을 것이다.
이것이 바이너리 직렬화다.
근데 이러려면 어디서 어디까지가 id인지 등, 스키마를 미리 정해놓아야겠지?
이것들을 자기네 나름대로 해놓은 게 바이너리 직렬화 라이브러리들이다.
일반적으로 직렬화 라이브러리라고 함은
바이너리 직렬화 라이브러리들을 의미한다.
여기서 ProtoBuf나 FaltBuffers 같은 게 나왔다.
4. FlatBuffers
FlatBuffers 개발자들은 안그래도 빠른 바이너리 직렬화를 더더욱 빠르게 하려고 했다.
그래서 도입한 게 Zero Copy란 개념이다.
이게 뭔 소리냐면 일반적인 바이너리 직렬화는
1. 전체 바이너리를 읽어서
2. 객체로 복원하고
3. 그 객체를 사용한다.
이렇게 작동한다.
직관적으로 생각해봐도 느릴 것 같다.
실제로 피클이 이래서 느리다. (이거만 이유는 아니지만...)
잘 생각해보면
어차피 어디가 뭔지 알고있는데 굳이 객체로 저장하는 작업을 받자마자 해둘 필요가 있을까?
걍 필요할 때마다 보면 되지 않을까?
FlatBuffers가 바로 그렇게 구현된 라이브러리다.
이걸 제로 카피라고 부른다. 객체로 복원(Copy)하는 작업이 없기 때문.
딱 들어도 존나 빠를 것 같다. 실제로 빠르다.
대신 조금 귀찮다.
빌더 패턴을 강제당하고, 스키마도 정해야하는 등 여러 제약사항이 있는 것이다.
하지만 속도가 중요한 프로젝트에서는 어쩔 수 없이 쓴다.
그렇다면 Zeno는 여기서 뭘 더 개선한 걸까?
5. Zeno
간단히 말하자면 Zeno는 FlatBuffers보다 더 빠른 속도를 내기위해 만들어졌다.
FlatBuffers가 속도를 위해 빌더 패턴 등의 귀찮은 것들을 강제했듯이,
Zeno도 속도를 위해 귀찮은 것 하나를 더 강제한다.
스키마 고정 <-- 이게 Zeno의 핵심이다
Flatbuffers는 스키마를 진화시킬 수 있는데,
Zeno는 이걸 못하게 막은 것.
예를 들어 원래 스키마에서 ID를 추가했다고 치자.
User {
name:string;
age:int;
id:int;
}
flatbuffers는
4바이트는 name
4바이트는 age
4바이트는 id
이렇게 기억해두고 그에 따라 view를 한다. (정확히는 table과 vtable이란 걸 쓴다)
즉, 어디서 어디까지의 바이트가 id인지 age인지에 대한 오프셋 데이터를 들고 있는 것이다.
따라서 모르는 바이트가 들어오면 그냥 안보면 그만이다.
근데 zeno는 오프셋 데이터가 없다.
즉... 아래처럼 있다가 중간에 age의 위치를 바꾸면
[id 4바이트][score 8바이트][age 4바이트] ->
[id 4바이트][age 4바이트][score 8바이트]
에러가 난다. 더 심하게는 잘못된 값을 읽을 수도 있다.
score는 1100이고 age는 41인데
age를 1100으로 읽고 score가 41이 될 수도 있는 것이다.
근데 잘 생각해보면
스키마를 프로젝트 중간에 굳이 바꿀 이유가 별로 없고, 바꾼다 해도 양쪽을 동시에 업뎃하면 된다.
즉... 불필요한 걸 덜어내고 속도를 얻었다고 할 수 있다.
이러한 방식은 특히 대량스캔에 매우 유리하다
FlatBuffers에서의 대량스캔은
n번째 레코드 찾기
-> 그 레코드의 table 위치 찾기
-> vtable에서 age 필드 위치 찾기 (오프셋 탐색)
-> age 읽기
이렇게 되어있는데, Zeno의 대량스캔은 단순히 아래와 같다.
n번째 레코드의 age 위치 = 시작 + n * 레코드크기 + age오프셋
-> age 읽기
엄청나게 차이가 날 수 밖에 없다.
그러나 스키마를 고정한다는 것은 범용기능 상당수를 포기한다는 것이다.
예를 들어 선택필드라던지 필드 ID 기반 접근 등이 Zeno에선 불가능하다.
그리고 개발자의 결벽증스러운 부분들이 라이브러리에 반영되어있어서
TS타입을 그대로 안 받아주고 z.Vector<T>처럼 ABI를 다 명확하게 써놔야한다.
FlatBuffers가 속도를 위해 귀찮음은 것들을 강제했듯,
Zeno도 속도를 위해 귀찮은 것들을 강제한 것이다.
6. 그래서 얼마나 빨라지는데?
오일러 물리 (3d물체 회전 등에 쓰이는 계산, 읽고 쓰기 같이 돌림) 등등
게임에서 많이 쓰이는 연산 몇 개를 밴치마크로 돌려보니까 FlatBuffers보다 최대 22배까지 빨랐음
단순히 22배라고 하면 적어보일 수 있는데
초당 60프레임에서 22배면 1320프레임임
빠르기는 확실히 빠르다.
그야 걍 데이터 뷰 하는 거랑 동급이니깐 빠를 수 밖에 없음
근데 잘 생각해보면 Three.js 같은 애들은 속도가 중요하니깐
걍 자기네들이 데이터뷰하는 코드를 미리 내부에 구현해둔다.
그래서 FlatBuffers도 안쓰고 그보다 더 빠른 Zeno도 쓸 이유가 없다.
물론 새 프로젝트들은 Zeno를 쓰는 편이 머리가 덜 아플 테니까 좋겠지.
근데 딱 Zeno를 써야할 플젝이 얼마나 있을까?
내가 봤을 땐 게임 쪽은 좀 애매함
오히려 금융 쪽 프로그램에서 실시간성을 높게 확보해주는 용으로 쓰거나
아니면 아래의 그림처럼
옵시디언의 유사도 검색용 임베딩 플러그인 같은데서는 충분히 쓸만하다.
이 플러그인 존나 개느린데 Zeno쓰면 아주 극적으로 속도를 향상시켜줄 수 있을 것임
7. Typia를 쓰는 것이 더 나은가?
Typia는 JSON제대로 보냈는지, 잘 보냈는지 검증하기 위해서 쓰는 것이고 Ts의 type을 써서 빠른 라이브러리임.
즉 직렬화를 더 잘하기 위한 것이고
바이너리 직렬화와는 아예 결이 다르다
8. 마무리
나 좀 강의글 잘 쓰는 듯?
진짜 강의팔이 마렵네
WEBGL에서 게임정보 받아서 AI랑 연동하려고 그니까 AI가 겜 플레이하게 하려고 만든거
AI가 겜을 플레이하게 하려고 만들었다고? AI에게 게임을 왜 시킴? 오토겜 같은 건가? AI들 구경하라고 있는?
ㅇㅇ 그런 느낌으로
그래서 바이너리 프로젝션 컴파일러는 도대체 무슨 뜻임? 니말대로며뉴그냥 데이터뷰 조금 쓰기 편하게 만든 직렬화 라이브러리로 이해되는데
금융쪽은 속도도 중요하지만 그보다 중요한게 코드안정성과 정확성이라 자기들이 직접 데이터뷰 정의해서 통제할껄
내 생각에도 비슷함. 데이터뷰를 쓰기 편하게 만든 느낌인 듯 ㅋㅋ 데이터뷰를 그냥 쓰면 서로 작업하거나 할 때 실수가 발생하기 쉽고 협업이 사실상 불가능하니깐 그런 점에서는 의의가 있음
@ㅇㅇ(211.234) 아니 오히려 그런 경우면 이거 쓰는 게 더 낫긴 함 바퀴를 재발명할 필요는 없으니까
@에이도비 애초에 금융권에서 TS전용으로 뭘 만들일도 없고 코드 안정성은 바퀴 재발명과 상관없이 은행측에서 코드를 검증할 수 있는지가 중요한거임
@ㅇㅇ(211.234) 코드 검증이랑은 상관 없지. 불안하면 라이브러리를 직접 까보면 되니깐
@에이도비 그럴거면 직접 만든다는게 금융권의 입장임 3D그래픽스 애들도 필요하면 직접 만든것처럼
@ㅇㅇ(211.234) 3D그래픽스 애들은 성능 달성하려고 직접 만든 거잖아? 이미 코드가 있는데 그거 파악할 능력이 안돼서 새로 만드는 거랑은 아예 다르지
@에이도비 금융권이 실력이 없어서 파악할 능력이 안된다는 얘기가 아니었는데 왜 그렇게 생각함?
@ㅇㅇ(211.234) ? 금융권에선 코드를 검증할 수 있는지가 중요해서 Zeno 못쓴다며? Zeno는 깃헙에 싹 다 공개된 코드이고 패키지 저장소에서 npm으로 받는 것들은 node modules 열면 어차피 그 안에 Zeno 코드 다 보이는데 이걸 검증 못해서 못쓴다는 게 뭔 소린지 난 이해가 안되는데... 그건 걍 걔네들이 실력이 없으니까 못쓰는 거지 Zeno문제가 아님
@ㅇㅇ(211.234) 사실 금융권 애들이 실력이 떨어지긴 해. 그럴 수 밖에 없는 게 인터넷조차 접속 통제하는 곳에서 몇 년씩 있다보면 아무리 고수도 썩을 수 밖에 없음
@에이도비 그거 검증할 시간에 주어진 스펙대로 데이터뷰 직접 정의하면 깔끔하고 정확한데 왜 남의 코드 리뷰에 시간낭비를 하겠음
@ㅇㅇ(211.234) 하긴. 각자 처한 상황에 따라 시선이 다르긴 하지. 금융권 인하우스 개발자들은 작은 기능 아기자기하게 쌓아나가는 게 전부니까 직접 만드는 게 더 확실하다고 생각할 수 있음. 나는 시스템 전체 개발하거나 SW총괄하는 경우가 많아서 팀끼리 공유할 문서 만들고 프로토콜이랑 스펙 확정하고 어쩌고 저쩌고하면서 머리 쓸 시간에 걍 Zeno쓸 듯 냅다 개발하는 건 쉬운데 여러사람 얽히면 피곤해질 일이 너무 많아져서
@에이도비 할수있다랑 해야한다랑 다름 고수면 남의 코드 다 뜯어보고 이해하는게 가능하지만 그게 꼭 해야한다는 것은 아님
@ㅇㅇ(211.234) 고수 하수 문제를 떠나서 Zeno를 쓰는 게 Zeno를 구현하는 것보다 쉽다는 거야. 새로 만들려면 협의도 해야되고 문서도 관리해야되고 책임도 져야돼.
@에이도비 그런데 그 책임에 Zeno 라이브러리 코드 전체 리뷰가 들어있다면 그냥 안하고 직접 만들지
속도자체는 flat buffer보다 최대 18배 초기에는 5배 정도 빨랐음. 다만 플랫버퍼는 다중 언어 지원이고 나는 타입스크립트 단일언어지원이니
빠르긴 엄청 빠르더라. 수요는 분명 있을 듯. 타입 고정해놓은 것만으로도 100퍼 수요 있음 근데 표면 언어는 ts로 고정하더라도 백엔드는 python도 가능하게 하는 게 좋을 듯
아하 이거 타이피아랑 완전다르고 그뭐냐 프로토버프랑 경쟁할물건이구만
정확합니다 선생님
다 아는거라 ㅁㅈㅎ
ai딸깍글인줄 알았는데 생각보다 정성글이네