본문 바로가기메뉴 바로가기


FE개발자의 성장 스토리 08 : WebAssembly 개발기

안녕하세요, FE플랫폼팀에서 전사 에디터 및 웹 사진 편집기를 개발하고 있는 sky입니다. 기존 사진 편집기 성능 개선을 위한 방법으로 Web Assembly를 조사하게 되었습니다. Web Assembly를 사용해 본 경험을 공유하고자 합니다.

들어가기에 앞서, 해당 글은 웹 어셈블리를 체험 및 소개하려는 글입니다. 자료조사, 개발을 통하여 얻은 경험을 공유하여 더 많은 개발자들이 쉽게 WebAssembly에 접근하고자 하는 작은 바람으로 쉽게 작성하였습니다.


WebAssembly란?

WebAssembly(이하 웹 어셈, WASM)는 2015년부터 개발된 기술로 2017년에 처음 발표되었습니다. 현재는 W3C WebAssembly Working group과 Community Group 서 웹 표준으로 개발 되고 있습니다.

IE11을 제외한 최신 브라우저에서 대부분 사용 가능하며 기존 JS로 개발되던 패러다임을 떠나, C, C++, Rust를 사용한 효과적이면서, 더 넓은 기능을 제공할 수 있도록 개발되고 있습니다.

WebAssembly 시작하기

WebAssembly를 사용하기 위해서는 Emscripten을 설치해야 합니다.

emscripten은 현재 npm에 배포되어 있지 않아. emscripten github에서 clone 받아 사용합니다.
공식 홈페이지에서 안내하는 설치 스크립트입니다.

window 사용자라면 source ./emsdk_env.sh을 emsdk_env.bat로 바꿔 사용해야 합니다. 

emscripten은 python script로 되어 있습니다. python 3.6 이상 버전부터 사용 가능합니다. OS에 따라 XCode cli, git, CMake 등 추가 설치가 필요합니다. 추가 설치 가이드

정상적으로 설치가 되었는지 확인을 위해 간단한 데모를 작성했습니다. 실행이 된다면 Hello world를 출력하는 main.cpp를 작성합니다.

이후 cpp를 컴파일 하기 위해 스크립트를 실행합니다.

em++ main.cpp -o index.html

설치 이후 터미널을 닫지 않고 스크립트를 실행하면 index.wasm, index.js, index.html 3개의 파일이 생성됩니다. 만약 터미널을 닫게 되면 em++: command not found 같은 에러를 만나게 됩니다.

아쉽게도 emscripten 환경설정 작업은 새로운 터미널이 실행될 때마다 필요합니다.
생성된 index.html 파일을 실행시키면,  

정상적으로 WASM이 불러와지고 실행이 됩니다. 생성된 wasm, html 파일의 목적은 각각 cpp를 컴파일한 결과와 데모 페이지입니다. 하지만 js 파일은 어떤 목적으로 생성이 되는 걸까요?

wasm 파일은 바로 읽어서 사용할 수 없습니다. 그래서 html과 wasm을 이어주기 위한 연결 다리가 필요합니다. 그 연결 다리 역할을 해주는 것이 js 파일이고, 이 파일을 glue(접착제) 코드라고 합니다.

Javascript vs WebAssembly

W3C 웹 어셈블리 그룹에서 웹 어셈블리의 목적을 아래와 같이 소개하고 있습니다.

  • 빠르고, 효율적이고, 높은 이식성을 가진다.
  • 읽기 쉬우면서 디버깅이 가능해야 한다.
  • 안전하고, 웹을 망치지 않아야 한다.

이번 경험기에서는 빠른 성능 목표에 대해서 다뤄보려고 합니다.

로딩

웹 어셈은 기존 js에 비해 파일을 읽는 로딩 시간이 빠릅니다. 먼저 js 파일은 텍스트로 되어있어 브라우저에서 모두 읽어야만 실행이 가능합니다. 읽어진 js 파일은 컴파일 이후 실행이 가능합니다.
반면 wasm 파일은 이미 컴파일이 되어있고, 이진 파일로 되어있어 브라우저가 더 읽기 쉬운 형태를 가집니다. wasm 파일도 실행을 위하여 컴파일 과정이 필요하지만 js보다 기계 친화적인 형태로 되어 있어 컴파일 시간이 짧습니다.

성능

효율성을 목적으로 설계가 된 만큼 성능 또한 빠릅니다.
실제로 실행 시간이 native code에 비해 20%밖에 느리지 않다는 결과가 있습니다. wasm이 샌드박스 환경과 보안을 위한 제약조건을 가진 상태에서 실행이 되는 것을 생각한다면 20%는 상당히 높은 성능을 가진다고 볼 수 있습니다.

성능 비교

실제로 성능이 얼마나 차이가 발생하는지 확인을 위하여 간단한 데모를 통하여 테스트를 진행하였습니다. 테스트는 이미지를 필터링하는 과정을 js와 wasm으로 구현하였으며 같은 시간 복잡도를 가지도록 로직을 구성하였습니다.

canvas를 사용하여 측정하였으며, canvas에서 imageData만 추출한 이후 필터링 과정만 성능 측정에 사용하였습니다.

비교 조건

  • 이미지 : 512 x 512, lena.jpg
  • 비교 방식 : 같은 필터링 과정을 50회 반복 후 평균 값 비교
  • 사용된 필터 : Gray scale, Threshold, Histogram equalize, Gaussian blur, Canny edge detection
각 이미지의 막대는 최대 런타임에 대한 현재 런타임 비율입니다.

50회 평균 실행 시간을 표로 정리하면 다음과 같습니다.

( 실행 시간, 단위: ms )

성능 비교 분석

결과

테스트에 사용한 5개 필터에 대해서 wasm으로 작성된 필터가 js에 비해 약 2 ~ 3배 빠른 성능을 나타냅니다.

원인

성능 차이가 발생하는 원인은 자바스크립트 엔진이 처리하는 과정에 있습니다. SpiderMonkey 엔진의 처리 과정과 비교하여 정리하였습니다.

각 막대의 길이는 참고용이며, 비교를 위한 표현입니다. 실제와는 차이가 있을 수 있습니다.

javascript 처리 과정

WebAssembly 처리 과정

각 과정을 비교하면 다음과 같습니다.

구문 해석 (parse – decode) :
js 파일이 브라우저에 전달되면, 추상 구문 트리 ( AST : Abstract Syntax Tree )로 변환이 되어야 합니다. AST는 각 엔진마다 다르지만 바이트 코드 형태로 변환이 됩니다. 반면, wasm 파일은 이미 바이트 코드 형태이기 때문에, 변환 과정이 필요 없이 해석(decode)만 하여 검증 과정만 거치면 됩니다.

컴파일 및 최적화 (compile + optimize) :
js는 각 브라우저마다 다르지만 컴파일 과정을 거칩니다. 기본 컴파일러나, JIT (Just-in-time) 컴파일러를 사용하는 방식입니다. 해당 과정은 여러 요인이 있지만 WASM은 LLVM 컴파일러를 사용하여 이미 많은 최적화가 진행된 상태입니다. 따라서 js에 비해 최적화 과정이 적어지게 됩니다.

재 최적화 (re-optimize) :
재 최적화는 js에서만 일어나는 과정입니다. 이는 JIT 컴파일러를 사용하는 과정에서 간혹 여러 이유로 인해 기존 최적화를 버리고 다시 최적화를 하는 과정입니다.
WASM은 명시적인 타입 같은 이유로, JIT에서 데이터를 수집, 타입 추론과 같은 과정이 필요 없습니다.

실행 (execute) :
js가 빠르게 실행되기 위해서는 JIT를 자세히 알아야 합니다. 하지만 이는 실제로 알기도 어렵고, 모든 브라우저에서 동일하게 적용되지는 않습니다. 반면 WASM은 이를 위한 노력이 필요 없습니다. 이미 최적화가 많이 진행되었기 때문이죠.
이는 js가 프로그래머를 위해 작성된 언어라면, wasm는 컴파일러를 위해 작성되었습니다. 결과적으로 더 이상적인 명령어 셋(instruction set)을 제공하여 10% ~ 800%의 성능 차이를 가져옵니다.

가비지 컬렉션 (GC : garbage collection) :
아직까지 WASM에서는 GC를 제공하지 않습니다.  C, C++처럼 메모리를 수동으로 관리하는 것이 어렵지만, 안정적인 성능을 제공할 수는 있습니다.

결과적으로 여러 이유를 통해 WASM이 js에 비해 좋은 성능을 가지게 됩니다. 몇몇 경우는 예외가 있을 수 있지만, 가까운 미래에 해결될 내용으로 보입니다. 개인적으로 사람 친화적인 js와 기계 친화적인 WASM이 가장 쉬운 설명 내용이었습니다.

WebAssembly의 미래를 위해서

이번 WebAssembly를 적용하면서 겪었던 WebAssembly의 주관적인 단점을 적어보고자 합니다.

추가적인 언어의 학습

WebAssembly를 사용하기 위해서는 js가 아닌 LLVM이 지원하는 C, C++, Rust 같은 언어로 작성을 해야 합니다. 이는 지원 언어를 학습한 적이 없다면, 사용을 위해 추가적으로 문법을 학습해야 합니다. 명시적인 타입이 없는 언어에서, 있는 언어를 학습한다는 것은 생각보다 쉬운 일은 아닐 것입니다.

제한된 지원 범위

아직까지 WebAssembly 도구인 Emscripten에서는 number, string, array 타입만 지원합니다. array 타입도 지원은 하지만 전달 간에는 포인터 형태로 변경해야 하기 때문에 사실상 number와 같습니다. 타입이 제한이 되어있기 때문에 활용 방안도 아직까지는 제한이 됩니다.

비교적 적은 참고 자료

WebAssembly를 체험하면서 가장 힘들었던 부분입니다. 발표된 지 올해로 4년 된 기술이지만 참고 자료가 적습니다. 개발 환경, 개발 언어가 여럿인 만큼 발생할 수 있는 에러 또한 넓은 범위에 걸쳐 나타납니다. 하지만 넓은 범위를 전부 덮을 만큼, 사용량이 많지 않아 참고 자료를 찾기 어렵습니다.

끝맺음

FE플랫폼팀에서는, WebAssembly를 이용하여 티스토리, 다음 카페에서 사용 중인 전사 에디터의 사진 편집기 성능 개선에 도전하고 있습니다.

현재 전사 에디터 사진 편집기는 대부분 필터링 서버에 요청을 통하여 이미지 처리를 진행합니다. 실제 이미지 처리를 진행하는 시간보다 더 많은 시간을 통신에 사용합니다. 이 과정을 웹 어셈으로 만든 필터를 제공해 통신에 걸리는 비용을 없애고 필터링 자체 성능을 올릴 수 있습니다.

성능 하나만 바라보며 정말 많은 시간을 투자해야 하는 기술이란 느낌을 많이 받았습니다. 아직까지는 활용 방안이 넓지 않아 메이저 기술로 인식되기까지는 시간이 필요한 기술로 느껴집니다. 이 글을 기점으로 웹 어셈블리를 한번 사용해보고 체험해 보시면서 활용 범위를 넓혀가는 건 어떨까요?

“카카오 FE플랫폼팀에서 함께 WASM을 딥드라이브 하실 여러분들을 찾고 있습니다.”
FE플랫폼팀에 합류하기


참고 자료

sky.blue
sky.blue 알고 싶은 것도 도전하고 싶은 것도 많은 개발자입니다.
Top Tag
2021
2021-new-krew
Ad Platform
Ad tech
adaptive-hash-index
adt
adtech
agile
agilecoach
ai
algorithm
Algorithm/ML
Algorithm/Ranking
almighty-data-transmitter
Analyzer
android
angular
anycast
App2App
applicative
Architecture
arena
ast
async
aurora
babel
babel7
Backend
BApp
bgp
big-data
binary
ble
blind-recruitment
block
Block Chain
blockchain
bluetooth
brian
business
Cache
cahtbot
canvasapi
Caver
cch
cd
CDR
ceph
certificate
certification
cgroup
chrome
ci
cite
client
clojure
close-wait
cloud
cloudera-manager
clustered-block
cmux
cnn
code-festival
code-review
codereview
coding
coding test
competition
Compliance
component
conference
consul
container
contents
contest
cookie
core-js@3
Corporate Digital Responsibility
couchbase
COVID-19
cpp
Data
data-engineering
DB
deep-learning
Dependency
dependency-graph
desktop
dev
dev-session
dev-track
developer
developer relations
developers
devops
digitalization
digitaltransformation
dns
docker
dr
Electron
employeecard
emscripten
eslint
extract-text
Feature List
Featured
Feedback
friendstime
front-end
frontend
functional-programming
funfunday
fzf
garbage-collection
gawibawibo
GC
github
globalpollution
go
graphdb
graphql
Ground X
growth
ha
hadoop
hate speech
hbase
hbase-manager
hbase-region-inspector
hbase-snashot
hbase-table-stat
hbase-tools
hri
id
if kakao
ifkakao
infrastructure
innodb
internship
ios
item
Java
javascript
javascript web-assembly
JCMM
JIRA
jsconf
jsconfkorea
json
k8s
kafka
kakao
kakao-Career-Boost-Program
kakao-commerce
kakao-games
kakaoarena
kakaobrain
kakaocommerce
kakaocon
kakaoenterprise
kakaok
kakaokey
kakaokrew
kakaomap
kakaopage
kakaotalk
KAS
KCDC
khaiii
Klaytn
Klip
kubernetes
l3dsr
l4
License
links
Linux
load-balancing
MAB
Machine Learning
machine-learning
map
marathon
meetup
melon
mesos
message
Messaging
microservice
Microsoft TypeScript
mm
mobil
monad
monorepo
ms-office
MSA
mtre
mysql
mysql-realtime-traffic-emulator
nand-flash
network
new
new-krew
nfc
Nickface
nomad
ocp
olive
onboarding
open
open source
opensource
openstack
OpenWork
OSS
page
parallel
PBA
performance
planning poker
Platform
polyfill
programming-contest
project-structure
pycon
python
quagga
react
reactive-programming
reactor
recap
recommendation
recommendation system
recruitment
redis
redis-keys
redis-scan
related-blind
Renderer
rest
Rome
rubics
ruby
rxjs
s2graph
scala
scalaz
seminar
Serve
server
service
sharding
shopping
socket
spark
spark-streaming
SpringBoot
ssd
Statistics/Analysis
Stomp
storage
storm
style-guide
summer internship
support
System
talk
talkchannel
tcp
tech
Techtalk
test
thread
Thread-Debugging
time-wait
tmux
Topic Modeling
typescript
Untact
update
User Story
vim
vim-github-dashboard
vim-plugin
vue
vue.js
WASM
web-cache
web-worker
webapp
webgl
WebSocket
webworkers
weekly
work
workplatform
개인화 추천
길찾기
라이선스
연관 추천
오픈소스
오픈소스검증
의존성분석
일하는방식
협업
All Tag
2021
2021-new-krew
Ad Platform
Ad tech
adaptive-hash-index
adt
adtech
agile
agilecoach
ai
algorithm
Algorithm/ML
Algorithm/Ranking
almighty-data-transmitter
Analyzer
android
angular
anycast
App2App
applicative
Architecture
arena
ast
async
aurora
babel
babel7
Backend
BApp
bgp
big-data
binary
ble
blind-recruitment
block
Block Chain
blockchain
bluetooth
brian
business
Cache
cahtbot
canvasapi
Caver
cch
cd
CDR
ceph
certificate
certification
cgroup
chrome
ci
cite
client
clojure
close-wait
cloud
cloudera-manager
clustered-block
cmux
cnn
code-festival
code-review
codereview
coding
coding test
competition
Compliance
component
conference
consul
container
contents
contest
cookie
core-js@3
Corporate Digital Responsibility
couchbase
COVID-19
cpp
Data
data-engineering
DB
deep-learning
Dependency
dependency-graph
desktop
dev
dev-session
dev-track
developer
developer relations
developers
devops
digitalization
digitaltransformation
dns
docker
dr
Electron
employeecard
emscripten
eslint
extract-text
Feature List
Featured
Feedback
friendstime
front-end
frontend
functional-programming
funfunday
fzf
garbage-collection
gawibawibo
GC
github
globalpollution
go
graphdb
graphql
Ground X
growth
ha
hadoop
hate speech
hbase
hbase-manager
hbase-region-inspector
hbase-snashot
hbase-table-stat
hbase-tools
hri
id
if kakao
ifkakao
infrastructure
innodb
internship
ios
item
Java
javascript
javascript web-assembly
JCMM
JIRA
jsconf
jsconfkorea
json
k8s
kafka
kakao
kakao-Career-Boost-Program
kakao-commerce
kakao-games
kakaoarena
kakaobrain
kakaocommerce
kakaocon
kakaoenterprise
kakaok
kakaokey
kakaokrew
kakaomap
kakaopage
kakaotalk
KAS
KCDC
khaiii
Klaytn
Klip
kubernetes
l3dsr
l4
License
links
Linux
load-balancing
MAB
Machine Learning
machine-learning
map
marathon
meetup
melon
mesos
message
Messaging
microservice
Microsoft TypeScript
mm
mobil
monad
monorepo
ms-office
MSA
mtre
mysql
mysql-realtime-traffic-emulator
nand-flash
network
new
new-krew
nfc
Nickface
nomad
ocp
olive
onboarding
open
open source
opensource
openstack
OpenWork
OSS
page
parallel
PBA
performance
planning poker
Platform
polyfill
programming-contest
project-structure
pycon
python
quagga
react
reactive-programming
reactor
recap
recommendation
recommendation system
recruitment
redis
redis-keys
redis-scan
related-blind
Renderer
rest
Rome
rubics
ruby
rxjs
s2graph
scala
scalaz
seminar
Serve
server
service
sharding
shopping
socket
spark
spark-streaming
SpringBoot
ssd
Statistics/Analysis
Stomp
storage
storm
style-guide
summer internship
support
System
talk
talkchannel
tcp
tech
Techtalk
test
thread
Thread-Debugging
time-wait
tmux
Topic Modeling
typescript
Untact
update
User Story
vim
vim-github-dashboard
vim-plugin
vue
vue.js
WASM
web-cache
web-worker
webapp
webgl
WebSocket
webworkers
weekly
work
workplatform
개인화 추천
길찾기
라이선스
연관 추천
오픈소스
오픈소스검증
의존성분석
일하는방식
협업

위로