스토리 홈

인터뷰

피드

뉴스

조회수 1481

30CUT의 탄생, 그 모든 이야기

기술의 시대입니다. 우리의 몸과 생각이 닿는 모든 곳들에 기술이 존재합니다. 우리가 미처 인지하지 못하는 작은 것들에도 기술이 스며들어 있습니다. 금융도 마찬가지입니다. 핀테크라 부르는 금융의 새로운 시류는 금융의 판을 바꾸고 다양한 산업을 만들어내고 있습니다. 저희 비욘드플랫폼 또한 핀테크의 흐름을 타고 만들어졌습니다. 우리는 전통적인 금융 구조에서 거대 기업과 시스템이 흡수하던 금융의 열매를 사람에게 나눠주고자 합니다. 다양한 방식으로요. 금융의 판을 새로 짜고자 합니다. 그래서 기존의 플랫폼을 넘어서는 새로운 플랫폼이라는 의미로 기업명을 '비욘드플랫폼(Beyond the platform)'이라고 지었습니다. 자, 이제부터 우리의 이야기를 시작하려고 합니다. 우리 스스로 어떤 일을 하고 있는지 생각할 기회를 갖고, 또 조금이라도 우리를 궁금해하는 어떤 사람들을 위해서. 우리의 첫 서비스, 30CUT한글로 써티컷이라고 읽는 30CUT은 P2P(Peer to Peer) 금융 플랫폼입니다. 비욘드플랫폼의 첫 프로젝트이자 첫 서비스죠. 사람과 사람을 이어주는 금융이라는 뜻의 P2P 금융은 말 그대로 돈이 필요한 사람과 돈을 빌려줄 수 있는 사람을 연결해 상호 간의 이익을 추구합니다. 빌리는 사람은 더 적은 이자를 내고 빌려주는 사람은 더 많은 투자 수익을 받음으로써 시장 참여자의 이익을 최대화합니다. 써티컷은 이들을 연결하는 플랫폼으로써 양 쪽이 원활하고 안전한 거래를 할 수 있도록 중간자 역할을 하고요. Peer가 꼭 개인만을 의미하는 것은 아닙니다. 기관이 될 수도 있습니다. P2P의 핵심은 Peer의 주체가 아니라 '어떻게 시장 참여자의 이익을 최대화할 수 있느냐'이거든요. 대출자의 이자가 줄어드는 동시에 투자자의 수익이 늘어날 수 있다면 P2P의 정신을 실현하고 있다고 볼 수 있죠. 써티컷은 이러한 P2P의 정신을 철저히 고수하면서 더 안전하고 더 효율적으로 이익을 나눌 수 있는 방법을 찾아왔습니다. 힘이 듭니다, 그래도 대충 갈 순 없습니다사실 써티컷은 아직도 론칭을 못했습니다. 작년 10월에 회사를 설립했으니 첫 서비스를 론칭하는데 꼬박 1년이 걸렸습니다. 아니, 10월에는 론칭된다는 가정 하에 1년입니다. 더 걸릴 수도 있겠죠. 사실 쉬운 방법을 선택할 수도 있었습니다. 여느 P2P 기업들처럼 대부업 자회사를 설립하고 개인투자자들을 받으면 당장이라도 사업을 시작할 수 있습니다. 금융 당국과 얼굴을 붉힐 일도, 사기가 아니냐는 고개들의 항의를 받을 일도, 그리고 직원들이 이렇게 머리를 싸매고 고민할 일도 없었겠지요. 하지만 종착점을 잃으면 우리의 정체성도 사라진다고 생각했습니다. 비욘드플랫폼의 목적은 '기존의 금융을 넘어선 새로운 금융'이고 써티컷의 모토는 '빚의 악순환을 끊다'입니다. P2P는 이 목표를 이루기 위한 수단일 뿐 목적이 되어서는 안 된다고 생각했습니다. 그래서 오래 걸려도 뚝심 있게 하나하나 말뚝을 박고 있습니다. 언젠가는 비바람에도 날아가지 않을 집이 완성되겠죠.  카드이자 30% 인하 프로젝트: 4가지 포인트그렇게 하나하나 박은 말뚝은 모두 하나의 목표를 위해서입니다. 신용카드 대출이자를 30% 낮춰준다그리고 이 목표는 다음 네 가지 중요한 특징을 기반으로 달성될 것입니다. 첫째, 써티컷은 은행제휴 P2P입니다. 지난 2월 NH농협은행과 제휴를 맺었습니다. 우리나라에서 두 번째 은행제휴 P2P이고 시중은행 중에는 첫 번째입니다. 은행이 투자금을 관리하고 대출을 내보내기 때문에 써티컷 대출은 은행 대출로 분류됩니다. 기존의 P2P 대출이 대부업 자회사를 통해서 대출과 투자를 집행한다는 점을 고려하면 은행제휴는 엄청난 플러스 요인입니다. 기존에 카드론 같은 제2금융권 대출을 쓰던 분들이 제1금융권 대출인 써티컷으로 갈아타면 신용등급이 상승될 수 있거든요. 신용등급이 올라가면 금융생활의 장벽이 낮아집니다. 높은 금리의 제2금융권 대출을 이용하지 않고 보다 좋은 조건의 제1금융권 사용이 가능해지게 되니까요. 안정적인 금융생활을 누릴 수 있게 됩니다. 둘째, 대환대출만을 합니다. 신규대출은 취급하지 않습니다. 앞서 써티컷의 모토가 '빚의 악순환을 끊다'라고 말씀드렸죠. 가계부채 1400조 시대, 대출 광고가 넘쳐나는 '빚 권하는 사회'가 되고 있지만 저희의 신념은 변하지 않습니다. 써티컷은 빚의 증가가 아니라 감소를 추구하기 때문에 또 다른 대출을 만들어서는 안 된다고 생각했습니다. 셋째, 신용카드대출에 집중합니다. 써티컷의 대환대출 대상자는 신용카드대출(현금서비스, 카드론, 리볼빙)을 사용하시는 분들에 제한됩니다. 이 부분은 비욘드플랫폼의 탄생 스토리와도 깊게 연관되는데요. 오랜 기간 회계법인에서 서민금융을 담당했던 서준섭 대표님은 빚에 허덕이는 수많은 분들을 보셨다고 해요. 그런데 빚이 많아 부채탕감을 위한 국가 프로그램까지 오신 분들의 대부분은 카드론에서 빚의 악순환이 시작됐다고 합니다. 카드론을 갚지 못해 캐피털에 손을 대고 대부업 대출까지 이용하신 분들 중 많은 분들이 파산신청을 하셨다고 해요. 그래서 대표님은 카드론에서 그 악순환을 끊어야 한다고 생각하셨답니다.물론 언제까지나 신용카드대출만 대환 하는 것은 아닙니다. 추후에 저축은행/캐피털, 대부업까지 사업 영역을 넓히고자 준비 중입니다.넷째, 기관투자자가 참여합니다. 저희가 론칭을 못하고 난항을 겪고 있는 이유이기도 하죠. 개인들이 투자를 하는 다른 P2P 금융 플랫폼과는 다르게 저희는 기관이 투자합니다. 이는 써티컷이 대부업 기반이 아니라 은행을 여신 기관으로 두고 있기에 가능합니다. 왜 기관투자자 모델을 추구하는지에 대해서는 하나의 단독 브런치로 게재할 예정입니다만, 간단히 말씀을 드리자면 '첫째, 전문적인 투자 리스크 관리가 어려운 개인투자자를 보호하기 위해서', '둘째, P2P 시장의 보다 안정적이고 건실한 성장을 위해서'입니다. 긴 이야기가 필요한 부분입니다.      할 이야기가 많은데, 한 페이지로 풀어내려니 쉽지 않습니다. 써티컷이 만들어 갈 한 권의 책에 대한 프롤로그 정도로 생각해주시면 고맙겠습니다. 앞으로 비욘드플랫폼의 철학, 써티컷의 비즈니스, 업계 인사이트, 그리고 비욘드플랫폼을 만드는 사람들까지 다양한 이야기를 해보려고 합니다. 응원해 주세요. #비욘드플랫폼서비스 #써티컷 #30CUT #서비스소개 #인사이트 #경험공유
조회수 1528

HBase 설정 최적화하기 - VCNC Engineering Blog

커플 필수 앱 비트윈은 여러 종류의 오픈 소스를 기반으로 이루어져 있습니다. 그 중 하나는 HBase라는 NoSQL 데이터베이스입니다. VCNC에서는 HBase를 비트윈 서비스의 메인 데이터베이스로써 사용하고 있으며, 또한 데이터 분석을 위한 DW 서버로도 사용하고 있습니다.그동안 두 개의 HBase Cluster 모두 최적화를 위해서 여러 가지 설정을 테스트했고 노하우를 공유해 보고자 합니다. 아랫은 저희가 HBase를 실제로 저희 서비스에 적용하여 운영하면서 최적화한 시스템 구성과 설정들을 정리한 것입니다. HBase를 OLTP/OLAP 목적으로 사용하고자 하는 분들에게 도움이 되었으면 좋겠습니다. 아래 구성을 최적화하기 위해서 했던 오랜 기간의 삽질기는 언젠가 따로 포스팅 하도록 하겠습니다.HBaseHBase는 Google이 2006년에 발표한 BigTable이라는 NoSQL 데이터베이스의 아키텍처를 그대로 따르고 있습니다. HBase는 뛰어난 Horizontal Scalability를 가지는 Distributed DB로써, Column-oriented store model을 가지고 있습니다. 사용량이 늘어남에 따라서 Regionserver만 추가해주면 자연스럽게 Scale-out이 되는 구조를 가지고 있습니다. 또한, Hadoop 특유의 Sequential read/write를 최대한 활용해서 Random access를 줄임으로 Disk를 효율적으로 사용한다는 점을 특징으로 합니다. 이 때문에 HBase는 보통의 RDBMS와는 다르게 Disk IO가 병목이 되기보다는 CPU나 RAM 용량이 병목이 되는 경우가 많습니다.HBase는 많은 회사가 데이터 분석을 하는 데 활용하고 있으며, NHN Line과 Facebook messenger 등의 메신저 서비스에서 Storage로 사용하고 있습니다.시스템 구성저희는 Cloudera에서 제공하는 HBase 0.92.1-cdh4.1.2 release를 사용하고 있으며, Storage layer로 Hadoop 2.0.0-cdh4.1.2를 사용하고 있습니다. 또한, Between의 데이터베이스로 사용하기 위해서 여러 대의 AWS EC2의 m2.4xlarge 인스턴스에 HDFS Datanode / HBase Regionserver를 deploy 하였습니다. 이는 m2.4xlarge의 큰 메모리(68.4GB)를 최대한 활용해서 Disk IO를 회피하고 많은 Cache hit이 나게 하기 위함입니다.또한 Highly-Available를 위해서 Quorum Journaling node를 활용한 Active-standby namenode를 구성했으며, Zookeeper Cluster와 HBase Master도 여러 대로 구성하여 Datastore layer에서 SPOF를 전부 제거하였습니다. HA cluster를 구성하는 과정도 후에 포스팅 하도록 하겠습니다.HDFS 최적화 설정dfs.datanode.handler.countHDFS에서 외부 요청을 처리하는 데 사용할 Thread의 개수를 정하기 위한 설정입니다. 기본값은 3인데 저희는 100으로 해 놓고 사용하고 있습니다.dfs.replicationHDFS 레벨에서 각각의 데이터가 몇 개의 독립된 인스턴스에 복사될 것 인가를 나타내는 값입니다. 저희는 이 값을 기본값인 3으로 해 놓고 있습니다. 이 값을 높이면 Redundancy가 높아져서 데이터 손실에 대해서 더 안전해지지만, Write 속도가 떨어지게 됩니다.dfs.datanode.max.transfer.threads하나의 Datanode에서 동시에 서비스 가능한 block 개수 제한을 나타냅니다.과거에는 dfs.datanode.max.xcievers라는 이름의 설정이었습니다.기본값은 256인데, 저희는 4096으로 바꿨습니다.ipc.server.tcpnodelay / ipc.client.tcpnodelaytcpnodelay 설정입니다. tcp no delay 설정은 TCP/IP network에서 작은 크기의 패킷들을 모아서 보냄으로써 TCP 패킷의 overhead를 절약하고자 하는 Nagle's algorithm을 끄는 것을 의미합니다. 기본으로 두 값이 모두 false로 설정되어 있어 Nagle's algorithm이 활성화되어 있습니다. Latency가 중요한 OLTP 용도로 HBase를 사용하시면 true로 바꿔서 tcpnodelay 설정을 켜는 것이 유리합니다.HBase 최적화 설정hbase.regionserver.handler.countRegionserver에서 외부로부터 오는 요청을 처리하기 위해서 사용할 Thread의 개수를 정의하기 위한 설정입니다. 기본값은 10인데 보통 너무 작은 값입니다. HBase 설정 사이트에서는 너무 큰 값이면 좋지 않다고 얘기하고 있지만, 테스트 결과 m2.4xlarge (26ECU) 에서 200개 Thread까지는 성능 하락이 없는 것으로 나타났습니다. (더 큰 값에 관해서 확인해 보지는 않았습니다.)저희는 이 값을 10에서 100으로 올린 후에 약 2배의 Throughput 향상을 얻을 수 있었습니다.hfile.block.cache.sizeHBase 의 block 들을 cache 하는데 전체 Heap 영역의 얼마를 할당한 것인지를 나타냅니다. 저희 서비스는 Read가 Write보다 훨씬 많아서 (Write가 전체의 약 3%) Cache hit ratio가 전체 성능에 큰 영향을 미칩니다.HBase 에서는 5분에 한 번 log 파일에 LruBlockCache (HBase 의 Read Cache) 가 얼마 만큼의 메모리를 사용하고 있고, Cache hit ratio가 얼마인지 표시를 해줍니다. 이 값을 참조하셔서 최적화에 사용하실 수 있습니다.저희는 이 값을 0.5로 설정해 놓고 사용하고 있습니다. (50%)hbase.regionserver.global.memstore.lowerLimit / hbase.regionserver.global.memstore.upperLimit이 두 개의 설정은 HBase에서 Write 한 값들을 메모리에 캐쉬하고 있는 memstore가 Heap 영역의 얼마만큼을 할당받을지를 나타냅니다. 이 값이 너무 작으면 메모리에 들고 있을 수 있는 Write의 양이 한정되기 때문에 디스크로 잦은 flush가 일어나게 됩니다. 반대로 너무 크면 GC에 문제가 있을 수 있으며 Read Cache로 할당할 수 있는 메모리를 낭비하는 것이기 때문에 좋지 않습니다.lowerLimit와 upperLimit의 두 가지 설정이 있는데, 두 개의 설정이 약간 다른 뜻입니다.만약 memstore 크기의 합이 lowerLimit에 도달하게 되면, Regionserver에서는 memstore들에 대해서 'soft'하게 flush 명령을 내리게 됩니다. 크기가 큰 memstore 부터 디스크에 쓰이게 되며, 이 작업이 일어나는 동안 새로운 Write가 memstore에 쓰일 수 있습니다.하지만 memstore 크기의 합이 upperLimit에 도달하게 되면, Regionserver는 memstore들에 대한 추가적인 Write를 막는 'hard'한 flush 명령을 내리게 됩니다. 즉, 해당 Regionserver이 잠시 동안 Write 요청을 거부하게 되는 것입니다. 보통 lowerLimit에 도달하면 memstore의 크기가 줄어들기 때문에 upperLimit까지 도달하는 경우는 잘 없지만, write-heavy 환경에서 Regionserver가 OOM으로 죽는 경우를 방지하기 위해서 hard limit가 존재하는 것으로 보입니다.hfile.block.cache.size와 hbase.regionserver.global.memstore.upperLimit의 합이 0.8 (80%)를 넘을 수 없게 되어 있습니다. 이는 아마 read cache 와 memstore의 크기의 합이 전체 Heap 영역 중 대부분을 차지해 버리면 HBase의 다른 구성 요소들이 충분한 메모리를 할당받을 수 없기 때문인 듯합니다.저희는 이 두 개의 설정 값을 각각 0.2, 0.3으로 해 놓았습니다. (20%, 30%)ipc.client.tcpnodelay / ipc.server.tcpnodelay / hbase.ipc.client.tcpnodelayHDFS의 tcpnodelay 와 비슷한 설정입니다. 기본값은 전부 false입니다.이 설정을 true로 하기 전에는 Get/Put 99%, 99.9% Latency가 40ms 와 80ms 근처에 모이는 현상을 발견할 수 있었습니다. 전체 요청의 매우 작은 부분이었지만, 평균 Get Latency가 1~2ms 내외이기 때문에 99%, 99.9% tail이 평균 Latency에 큰 영향을 미쳤습니다.이 설정을 전부 true로 바꾼 후에 평균 Latency가 절반으로 하락했습니다.Heap memory / GC 설정저희는 m2.4xlarge가 제공하는 메모리 (68.4GB)의 상당 부분을 HBase의 Read/Write cache에 할당하였습니다. 이는 보통 사용하는 Java Heap 공간보다 훨씬 큰 크기이며 심각한 Stop-the-world GC 문제를 일으킬 수 있기 때문에, 저희는 이 문제를 피하고자 여러 가지 설정을 실험하였습니다.STW GC time을 줄이기 위해서 Concurrent-Mark-and-sweep GC를 사용했습니다.HBase 0.92에서부터 기본값으로 설정된 Memstore-Local Allocation Buffer (MSLAB) 을 사용했습니다. hbase.hregion.memstore.mslab.enabled = true #(default)hbase-env.sh 파일을 다음과 같이 설정했습니다. HBASE_HEAPSIZE = 61440 #(60GB) HBASE_OPTS = "-XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps"GC log를 Python script로 Parsing해서 STW GC 시간을 관찰하고 있습니다. 지금까지 0.2초 이상의 STW GC는 한 번도 발생하지 않았습니다.그 밖에 도움이 될 만한 설정들hbase.hregion.majorcompactionHBase는 하나의 Region에 대해서 여러 개의 StoreFile을 가질 수 있습니다. 그리고 주기적으로 성능 향상을 위해서 이 파일들을 모아서 하나의 더 큰 파일로 합치는 과정을 진행하게 됩니다. 그리고 이 과정은 많은 CPU usage와 Disk IO를 동반합니다. 그리고 이때 반응 속도가 다소 떨어지게 됩니다. 따라서 반응 속도가 중요한 경우에는, 이 Major compaction을 off-peak 시간대를 정해서 manual 하게 진행하시는 것이 좋습니다.저희는 사용자의 수가 상대적으로 적은 새벽 시간대에 crontab 이 실행시키는 script가 돌면서 전체 Region에 대해서 하나하나 Major Compaction이 진행되도록 하였습니다.기본값은 86,400,000 (ms)로 되어 있는데, 이 값을 0으로 바꾸시면 주기적인 Major Compaction이 돌지 않게 할 수 있습니다.hbase.hregion.max.filesizeHBase는 하나의 Region이 크기가 특정 값 이상이 되면 자동으로 2개의 Region으로 split을 시킵니다. Region의 개수가 많지 않을 때는 큰 문제가 없지만, 계속해서 데이터가 쌓이게 되면 필요 이상으로 Region 수가 많아지는 문제를 나을 수 있습니다. Region 수가 너무 많아지면 지나친 Disk IO가 생기는 문제를 비롯한 여러 가지 안 좋은 점이 있을 수 있기 때문에, split 역시 manual 하게 하는 것이 좋습니다. 그렇다고 Table의 Region 수가 너무 적으면 Write 속도가 떨어지거나 Hot Region 문제가 생길 수 있기 때문에 좋지 않습니다.HBase 0.92.1 에서는 기본값이 1073741824(1GB)로 되어 있는데, 저희는 이 값을 10737418240(10GB)로 늘인 후에 manual 하게 split을 하여 Region의 개수를 조정하고 있습니다.hbase.hregion.memstore.block.multipliermemstore의 전체 크기가 multiplier * flush size보다 크면 추가적인 Write를 막고 flush가 끝날때까지 해당 memstore는 block 됩니다.기본값은 2인데, 저희는 8로 늘려놓고 사용하고 있습니다.dfs.datanode.balance.bandwidthPerSec부수적인 설정이지만, HDFS의 Datanode간의 load balancing이 일어나는 속도를 제한하는 설정입니다. 기본값은 1MB/sec로 되어 있지만, 계속해서 Datanode를 추가하거나 제거하는 경우에는 기본값으로는 너무 느릴 때가 있습니다. 저희는 10MB/sec 정도로 늘려서 사용하고 있습니다.dfs.namenode.heartbeat.recheck-intervalHDFS namenode에만 해당되는 설정입니다.Datanode가 응답이 없는 경우에 얼마 후에 Hadoop cluster로부터 제거할 것인지를 나타내는 값입니다.실제로 응답이 없는 Datanode가 떨어져 나가기까지는 10번의 heartbeat가 연속해서 실패하고 2번의 recheck역시 실패해야 합니다. Heartbeat interval이 기본값인 3초라고 하면, 30초 + 2 * recheck-interval 후에 문제가 있는 Datanode가 제거되는 것입니다.기본값이 5분으로 되어 있는데, fail-over가 늦어지기 때문에 사용하기에는 너무 큰 값입니다. 저희는 문제가 있는 Datanode가 1분 후에 떨어져 나갈 수 있도록 이 값을 15,000 (ms) 으로 잡았습니다.Read short-circuitRegionServer가 로컬 Datanode로부터 block을 읽어올 때 Datanode를 통하지 않고 Disk로부터 바로 읽어올 수 있게 하는 설정입니다.데이터의 양이 많아서 Cache hit이 낮아 데이터 대부분을 디스크에서 읽어와야 할 때 효율적입니다. Cache hit에 실패하는 Read의 Throughput이 대략 2배로 좋아지는 것을 확인할 수 있습니다. OLAP용 HBase에는 매우 중요한 설정이 될 수 있습니다.하지만 HBase 0.92.1-cdh4.0.1까지는 일부 Region이 checksum에 실패하면서 Major compaction이 되지 않는 버그가 있었습니다. 현재 이 문제가 해결되었는지 확실하지 않기 때문에 확인되기 전에는 쓰는 것을 추천하지는 않습니다.설정하는 방법은 다음과 같습니다. dfs.client.read.shortcircuit = true #(hdfs-site.xml) dfs.block.local-path-access.user = hbase #(hdfs-site.xml) dfs.datanode.data.dir.perm = 775 #(hdfs-site.xml) dfs.client.read.shortcircuit = true #(hbase-site.xml)Bloom filterBloom filter의 작동방식에 대해 시각적으로 잘 표현된 데모 페이지HBase는 Log-structured-merge tree를 사용하는데, 하나의 Region에 대해서 여러 개의 파일에 서로 다른 version의 값들이 저장되어 있을 수 있습니다. Bloom filter는 이때 모든 파일을 디스크에서 읽어들이지 않고 원하는 값이 저장된 파일만 읽어들일 수 있게 함으로써 Read 속도를 빠르게 만들 수 있습니다.Table 단위로 Bloom filter를 설정해줄 수 있습니다.ROW와 ROWCOL의 두 가지 옵션이 있는데, 전자는 Row key로만 filter를 만드는 것이고, 후자는 Row+Column key로 filter를 만드는 것입니다. Table Schema에 따라 더 적합한 설정이 다를 수 있습니다.저희는 데이터 대부분이 메모리에 Cache 되고 하나의 Region에 대해서 여러 개의 StoreFile이 생기기 전에 compaction을 통해서 하나의 큰 파일로 합치는 작업을 진행하기 때문에, 해당 설정을 사용하지 않고 있습니다.결론지금까지 저희가 비트윈을 운영하면서 얻은 경험을 토대로 HBase 최적화 설정법을 정리하였습니다. 하지만 위의 구성은 어디까지나 비트윈 서비스에 최적화되어 있는 설정이며, HBase의 사용 목적에 따라서 달라질 수 있음을 말씀드리고 싶습니다. 그래서 단순히 설정값을 나열하기보다는 해당 설정이 어떤 기능을 하는 것인지 저희가 아는 한도 내에서 설명드리려고 하였습니다. 위의 글에서 궁금한 점이나 잘못된 부분이 있으면 언제든지 답글로 달아주시길 바랍니다. 감사합니다.
조회수 320

출근이 즐거워지는 바로고의 복지문화 13가지

바로고의 복지 문화바로고 직원들은 말합니다."출근이 즐겁다!"바쁘고 정신없는 업무 속에서도우리의 출근을 즐겁게 만드는 비결바로 바로고의 복지 문화입니다.과연 어떤 복지문화 이길래바로고 직원들의 마음은 설렘심쿵주의!지금 알려드릴게요~^^출근이 즐거워지는바로고의 복지문화13가지출근이 즐거워지는바로고의 복지 문화지금 공개합니다!첫 번째-잠수 가능 모드방해금지 모드(그래도 예고는 하고 가자아~)개인적인 업무, 나만의 시간,휴식이 필요할 때는방해금지 모드로 1시간을 드려요~두 번째-지적인 삶을 위한문화생활 즐겨찾기매월 마지막 주 수요일!문화의 날을 지나칠 수 없습니다~영화? 전시? 공연? 스포츠? 뭐하지, 뭐하지?세 번째-일상을 더 풍요롭게맘대로 3시 퇴근월 1회, 내 맘대로 조퇴한다 전해라~태클 절대 없는 월 1회눈치 보지 말고 3시 퇴근!네 번째-HAPPY BIRTHDAY TO YOU생일 선물 배달이번 달 생일을 누구일까요~?바로고 라이더가 케이크와 선물을 배달!여기서 끝이 아니에요~생일자는 4시 퇴근!다섯 번째-당신의 마음에 양식이 되어줄도서 구입비 지급지적인 그대에게 도서 구입비 지급,뇌가 섹시한 당신을 응원합니다원하는 책을 구입하세요~여섯 번째-더 나은 내일을 위한교육비 지원나를 위해 공부하자.업무능력 향상을 위한재직자 국비지원 프로그램 2회 지원!일곱 번째-365일 정신을 맑게 해줄고급 커피 무한 제공커피값 걱정 NO!바로고 전문 바리스타가 엄선한고급 로스팅 원두로 잠든 뇌를 번쩍!여덟 번째-촉촉한 단비 같은 맥주타임스파클링 데이지친 당신을 위해 시각 정화! 촉각 정화!월 1회 영화와 고급진 수다가 함께하는핑거푸드 & 맥주타임!아홉 번째-피부에 양보하세요.비타민 데이열심히 일한 당신 먹어라!엄부에 지친 당신을 위한 비타민 준비 완료.비타민 보충하고 힘내세요!열 번째-먹는 게 남는 거!먹방 활동비 지원월 1회 바로고 F&B 제휴사 음식을무료로 탐방합시다!대신 SNS 후기 잊지 말기로 해~열한 번째-뇌를 맑게 해줄 잠시의 휴식두뇌학습 팀워크 활동업무를 내려놓고 두뇌학습을 시작해볼까요?건담 조립해보셨어요?아님 퍼즐 맞추기?팀과 함께 만들어 봅시다!열두 번째-뼈가 되고, 살이 되는외부 인사 초청  강연훌륭한 팀워크와 업무 효율을 높이는유익한 외부 인사 초청 강연!맛있는 음식과 함께해봐요~열세 번째-함께 해서 행복해요해피 근속 시리즈1년 차영화 관람권3년 차1day 포상휴가 및호텔 레스토랑 식사권5년 차제주도 항공권 및리조트 숙박권지금 바로고와 함께 하세요!www.barogo.com바로고 복지문화13가지이렇게 많은 복지문화가바로고와 함께 하고 있습니다.보다 나은 바로고를 위해보다 나은 복지문화로함께 하겠습니다.감사합니다.https://goo.gl/W5CEbY
조회수 868

비트윈의 HBase 스키마 해부 - VCNC Engineering Blog

비트윈에서는 HBase를 메인 데이터베이스로 이용하고 있습니다. 유저 및 커플에 대한 정보와 커플들이 주고받은 메시지, 업로드한 사진 정보, 메모, 기념일, 캘린더 등 서비스에서 만들어지는 다양한 데이터를 HBase에 저장합니다. HBase는 일반적인 NoSQL과 마찬가지로 스키마를 미리 정의하지 않습니다. 대신 주어진 API를 이용해 데이터를 넣기만 하면 그대로 저장되는 성질을 가지고 있습니다. 이런 점은 데이터의 구조가 바뀔 때 별다른 스키마 변경이 필요 없다는 등의 장점으로 설명되곤 하지만, 개발을 쉽게 하기 위해서는 데이터를 저장하는데 어느 정도의 규칙이 필요합니다. 이 글에서는 비트윈이 데이터를 어떤 구조로 HBase에 저장하고 있는지에 대해서 이야기해 보고자 합니다.비트윈에서 HBase에 데이터를 저장하는 방법Thrift를 이용해 데이터 저장: Apache Thrift는 자체적으로 정의된 문법을 통해 데이터 구조를 정의하고 이를 직렬화/역직렬화 시킬 수 있는 기능을 제공합니다. 비트윈에서는 서버와 클라이언트가 통신하기 위해 Thrift를 이용할 뿐만 아니라 HBase에 저장할 데이터를 정의하고 데이터 저장 시 직렬화를 위해 Thrift를 이용합니다.하나의 Row에 여러 Column을 트리 형태로 저장: HBase는 Column-Oriented NoSQL로 분류되며 하나의 Row에 많은 수의 Column을 저장할 수 있습니다. 비트윈에서는 Column Qualifier를 잘 정의하여 한 Row에 여러 Column을 논리적으로 트리 형태로 저장하고 있습니다.추상화된 라이브러리를 통해 데이터에 접근: 비트윈에서는 HBase 클라이언트 라이브러리를 직접 사용하는 것이 아니라 이를 래핑한 Datastore라는 라이브러리를 구현하여 이를 이용해 HBase의 데이터에 접근합니다. GAE의 Datastore와 인터페이스가 유사하며 실제 저장된 데이터들을 부모-자식 관계로 접근할 수 있게 해줍니다.트랜잭션을 걸고 데이터에 접근: HBase는 일반적인 NoSQL과 마찬가지로 트랜잭션을 제공하지 않지만 비트윈에서는 자체적으로 제작한 트랜잭션 라이브러리인 Haeinsa를 이용하여 Multi-Row ACID 트랜잭션을 걸고 있습니다. Haeinsa 덕분에 성능 하락 없이도 데이터 무결성을 유지하고 있습니다.Secondary Index를 직접 구현: HBase에서는 데이터를 Row Key와 Column Qualifier를 사전식 순서(lexicographical order)로 정렬하여 저장하며 정렬 순서대로 Scan을 하거나 바로 임의 접근할 수 있습니다. 하지만 비트윈의 어떤 데이터들은 하나의 Key로 정렬되는 것으로는 충분하지 않고 Secondary Index가 필요한 경우가 있는데, HBase는 이런 기능을 제공하지 않고 있습니다. 비트윈에서는 Datastore 라이브러리에 구현한 Trigger을 이용하여 매우 간단한 형태의 Secondary Index를 만들었습니다.비트윈 HBase 데이터 구조 해부페이스북의 메시징 시스템에 관해 소개된 글이나, GAE의 Datastore에 저장되는 구조를 설명한 글을 통해 HBase에 어떤 구조로 데이터를 저장할지 아이디어를 얻을 수 있습니다. 비트윈에서는 이 글과는 약간 다른 방법으로 HBase에 데이터를 저장합니다. 이에 대해 자세히 알아보겠습니다.전반적인 구조비트윈에서는 데이터를 종류별로 테이블에 나누어 저장하고 있습니다. 커플과 관련된 정보는 커플 테이블에, 유저에 대한 정보는 유저 테이블에 나누어 저장합니다.각 객체와 관련된 정보는 각각의 HBase 테이블에 저장됩니다.또한, 관련된 데이터를 하나의 Row에 모아 저장합니다. 특정 커플과 관련된 사진, 메모, 사진과 메모에 달린 댓글, 기념일 등의 데이터는 해당 커플과 관련된 하나의 Row에 저장됩니다. Haeinsa를 위한 Lock Column Family를 제외하면, 데이터를 저장하기 위한 용도로는 단 하나의 Column Family만 만들어 사용하고 있습니다.각 객체의 정보와 자식 객체들은 같은 Row에 저장됩니다.또한, 데이터는 기본적으로 하나의 Column Family에 저장됩니다.이렇게 한 테이블에 같은 종류의 데이터를 모아 저장하게 되면 Region Split하는 것이 쉬워집니다. HBase는 특정 테이블을 연속된 Row들의 집합인 Region으로 나누고 이 Region들을 여러 Region 서버에 할당하는 방식으로 부하를 분산합니다. 테이블을 Region으로 나눌 때 각 Region이 받는 부하를 고려해야 하므로 각 Row가 받는 부하가 전체적으로 공평해야 Region Split 정책을 세우기가 쉽습니다. 비트윈의 경우 커플과 관련된 데이터인 사진이나 메모를 올리는 것보다는 유저와 관련된 데이터인 메시지를 추가하는 트래픽이 훨씬 많은데, 한 테이블에 커플 Row와 유저 Row가 섞여 있다면 각 Row가 받는 부하가 천차만별이 되어 Region Split 정책을 세우기가 복잡해집니다. RegionSplitPolicy를 구현하여 Region Split 정책을 잘 정의한다면 가능은 하지만 좀 더 쉬운 방법을 택했습니다.또한, 한 Row에 관련된 정보를 모아서 저장하면 성능상 이점이 있습니다. 기본적으로 한 커플에 대한 데이터들은 하나의 클라이언트 요청을 처리하는 동안 함께 접근되는 경우가 많습니다. HBase는 같은 Row에 대한 연산을 묶어 한 번에 실행시킬 수 있으므로 이 점을 잘 이용하면 성능상 이득을 얻을 수 있습니다. 비트윈의 데이터 구조처럼 특정 Row에 수많은 Column이 저장되고 같은 Row의 Column들에 함께 접근하는 경우가 많도록 설계되어 있다면 성능 향상을 기대할 수 있습니다. 특히 Haeinsa는 한 트랜잭션에 같은 Row에 대한 연산은 커밋시 한 번의 RPC로 묶어 처리하므로 RPC에 드는 비용을 최소화합니다. 실제 비트윈에서 가장 많이 일어나는 연산인 메시지 추가 연산은 그냥 HBase API를 이용하여 구현하는 것보다 Haeinsa Transaction API를 이용해 구현하는 것이 오히려 성능이 좋습니다.Column Qualifier의 구조비트윈은 커플들이 올린 사진 정보들을 저장하며, 또 사진들에 달리는 댓글 정보들도 저장합니다. 한 커플을 Root라고 생각하고 커플 밑에 달린 사진들을 커플의 자식 데이터, 또 사진 밑에 달린 댓글들을 사진의 자식 데이터라고 생각한다면, 비트윈의 데이터들을 논리적으로 트리 형태로 생각할 수 있습니다. 비트윈 개발팀은 Column Qualifier를 잘 정의하여 실제로 HBase에 저장할 때에도 데이터가 트리 형태로 저장되도록 설계하였습니다. 이렇게 트리 형태로 저장하기 위한 Key구조에 대해 자세히 알아보겠습니다.Column Qualifier를 설계할 때 성능을 위해 몇 가지 사항들을 고려해야 합니다. HBase에서는 한 Row에 여러 Column이 들어갈 수 있으며 Column들은 Column Qualifier로 정렬되어 저장됩니다. ColumnRangeFilter를 이용하면 Column에 대해 정렬 순서로 Scan연산이 가능합니다. 이 때 원하는 데이터를 순서대로 읽어야 하는 경우가 있는데 이를 위해 Scan시, 최대한 Sequential Read를 할 수 있도록 설계해야 합니다. 또한, HBase에서 데이터를 읽어올 때, 실제로 데이터를 읽어오는 단위인 Block에 대해 캐시를 하는데 이를 Block Cache라고 합니다. 실제로 같이 접근하는 경우가 빈번한 데이터들이 최대한 근접한 곳에 저장되도록 설계해야 Block Cache의 도움을 받을 수 있습니다.비트윈에서는 특정 커플의 사진이나 이벤트를 가져오는 등의 특정 타입으로 자식 데이터를 Scan해야하는 경우가 많습니다. 따라서 특정 타입의 데이터를 연속하게 저장하여 최대한 Sequential Read가 일어나도록 해야 합니다. 이 때문에 Column Qualifier가 가리키는 데이터의 타입을 맨 앞에 배치하여 같은 타입의 자식 데이터들끼리 연속하여 저장되도록 하였습니다. 만약 가리키는 데이터의 타입과 아이디가 Parent 정보 이후에 붙게 되면 사진 사이사이에 각 사진의 댓글 데이터가 끼어 저장됩니다. 이렇게 되면 사진들에 대한 데이터를 Scan시, 중간중간 저장된 댓글 데이터들 때문에 완벽한 Sequential Read가 일어나지 않게 되어 비효율적입니다.이렇게 특정 타입의 자식들을 연속하게 모아 저장하는 묶음을 컬렉션이라고 합니다. 컬렉션에는 컬렉션에 저장된 자식들의 개수나 새로운 자식을 추가할 때 발급할 아이디 등을 저장하는 Metadata가 있습니다. 이 Metadata도 특정 Column에 저장되므로 Metadata를 위한 Column Qualifier가 존재합니다. 이를 위해 Column Qualifier에는 Column Qualifier가 자칭하는 데이터가 Metadata인지 표현하는 필드가 있는데, 특이하게도 메타데이터임을 나타내는 값이 1이 아니라 0입니다. 이는 Metadata가 컬렉션의 맨 앞쪽에 위치하도록 하기 위함입니다. 컬렉션을 읽을 때 보통 맨 앞에서부터 읽는 경우가 많고, 동시에 Metadata에도 접근하는 경우가 많은데, 이 데이터가 인접하게 저장되어 있도록 하여 Block Cache 적중이 최대한 일어나도록 한 것입니다.Datastore 인터페이스비트윈에서는 이와 같은 데이터 구조에 접근하기 위해 Datastore라는 라이브러리를 구현하여 이를 이용하고 있습니다. HBase API를 그대로 이용하는 것보다 좀 더 쉽게 데이터에 접근할 수 있습니다. GAE의 Datastore와 같은 이름인데, 실제 인터페이스도 매우 유사합니다. 이 라이브러리의 인터페이스에 대해 간단히 알아보겠습니다.Key는 Datastore에서 HBase에 저장된 특정 데이터를 지칭하기 위한 클래스입니다. 논리적으로 트리 형태로 저장된 데이터 구조를 위해 부모 자식 관계를 이용하여 만들어 집니다.Key parentKey = new Key(MType.T_RELATIONSHIP, relId); Key photoKey = new Key(parentKey, MType.T_PHOTO, photoId); // 특정 커플 밑에 달린 사진에 대한 키 Datastore는 Key를 이용해 Row Key와 Column Qualifier를 만들어 낼 수 있습니다. Datastore는 이 정보를 바탕으로 HBase에 새로운 데이터를 저장하거나 저장된 데이터에 접근할 수 있는 메서드를 제공합니다. 아래 코드에서 MUser 클래스는 Thrift로 정의하여 자동 생성된 클래스이며, Datastore에서는 이 객체를 직렬화 하여 HBase에 저장합니다.MUser user = new MUser(); user.setNickname("Alice"); user.setGender(Gender.FEMALE); user.setStatus("Hello World!"); Key userKey = new Key(MType.T_USER, userId); getDatastore().put(userKey, user); user = getDatastore().get(userKey); getDatastore().delete(userKey); 또한, Datastore는 Key를 범위로 하여 Scan연산이 할 수 있도록 인터페이스를 제공합니다. Java에서 제공하는 Try-with-resource문을 이용하여 ResultScanner를 반드시 닫을 수 있도록 하고 있습니다. 내부적으로 일단 특정 크기만큼 배치로 가져오고 더 필요한 경우 더 가져오는 식으로 구현되어 있습니다.try (CloseableIterable> entries = getDatastore().subSibling(fromKey, fromInclusive, toKey, toInclusive)) { for (KeyValue entry : entries) { // do something } } Secondary Index 구현 방법HBase는 데이터를 Row Key나 Column Qualifier로 정렬하여 저장합니다. 이 순서로만 Sequential Read를 할 수 있으며 Key값을 통해 특정 데이터를 바로 임의 접근할 수 있습니다. 비트윈에서는 특정 달에 해당하는 이벤트들을 읽어오거나 특정 날짜의 사진들의 리스트를 조회하는 등 id 순서가 아니라 특정 값을 가지는 데이터를 순서대로 접근해야 하는 경우가 있습니다. 이럴 때에도 효율적으로 데이터에 접근하기 위해서는 id로 정렬된 것 외에 특정 값으로 데이터를 정렬할 수 있어야 합니다. 하지만 HBase에서는 이와 같은 Secondary Index 같은 기능을 제공하지 않습니다. 비트윈 개발팀은 이에 굴하지 않고 Secondary Index를 간단한 방법으로 구현하여 사용하고 있습니다.구현을 간단히 하기 위해 Secondary Index를 다른 데이터들과 마찬가지로 특정 타입의 데이터로 취급하여 구현하였습니다. 따라서 Index에 대해서도 Column Qualifier가 발급되며, 이때, Index에 해당하는 id를 잘 정의하여 원하는 순서의 Index를 만듭니다. 이런 식으로 원하는 순서로 데이터를 정렬하여 저장할 수 있으며 이 인덱스를 통해 특정 필드의 값의 순서대로 데이터를 조회하거나 특정 값을 가지는 데이터에 바로 임의 접근할 수 있습니다. 또한, Index에 실제 데이터를 그대로 복사하여 저장하여 Clustered Index처럼 동작하도록 하거나, Reference만 저장하여 Non-Clustered Index와 같이 동작하게 할 수도 있습니다. Datastore 라이브러리에는 특정 데이터가 추가, 삭제, 수정할 때 특정 코드를 실행할 수 있도록 Trigger 기능이 구현되어 있는데, 이를 통해 Index를 업데이트합니다. 데이터의 변경하는 연산과 Index를 업데이트하는 연산이 하나의 Haeinsa 트랜잭션을 통해 원자적으로 일어나므로 데이터의 무결성이 보장됩니다.못다 한 이야기각 테이블의 특정 Row의 Column들에 대한 Column Qualifier외에도 Row에 대한 Row Key를 정의 해야 합니다. 비트윈에서는 각 Row가 표현하는 Root객체에 대한 아이디를 그대로 Row Key로 이용합니다. 새로운 Root객체가 추가될 때 발급되는 아이디는 랜덤하게 생성하여 객체가 여러 Region 서버에 잘 분산될 수 있도록 하였습니다. 만약 Row Key를 연속하게 발급한다면 특정 Region 서버로 연산이 몰리게 되어 성능 확장에 어려움이 생길 수 있습니다.데이터를 저장할 때 Thrift를 이용하고 있는데, Thrift 때문에 생기는 문제가 있습니다. 비트윈에서 서버를 업데이트할 때 서비스 중지 시간을 최소화하기 위해 롤링 업데이트를 합니다. Thrift 객체에 새로운 필드가 생기는 경우, 롤링 업데이트 중간에는 일부 서버에만 새로운 Thift가 적용되어 있을 수 있습니다. 업데이트된 서버가 새로운 필드에 값을 넣어 저장했는데, 아직 업데이트가 안 된 서버가 이 데이터를 읽은 후 데이터를 다시 저장한다면 새로운 필드에 저장된 값이 사라지게 됩니다. Google Protocol Buffer의 경우, 다시 직렬화 할 때 정의되지 않은 필드도 처리해주기 때문에 문제가 없지만, Thrift의 경우에는 그렇지 않습니다. 비트윈에서는 새로운 Thrift를 적용한 과거 버전의 서버를 먼저 배포한 후, 업데이트된 서버를 다시 롤링 업데이트를 하는 식으로 이 문제를 해결하고 있습니다.
조회수 1164

나의 첫 번째 사업 이야기

내 첫 번째 사업은 초등학교 때 했던 만화책 대여 사업이었다. 거창하게 사업이라고 말하면 쑥스럽지만, 어쨌든 돈거래가 일어났던 엄연한 비즈니스였다. 난 어렸을 때 만화책을 정말 좋아했다. 동네 만화방에 거의 살다시피 했고, 그래서 동네 만화방에서 VVIP 고객이었다. 그 시절에는 비디오가 귀했고, 만화방에서는 만화를 볼 때마다 쿠폰을 주었고 쿠폰을 모아 오면 비디오를 상영할 때 볼 수 있도록 해주었다. 하지만 죽돌이 수준의 VVIP 고객이었기 때문에 쿠폰 없이도 언제든지 내가 원할 때 비디오를 볼 수 있었다. 난 그 정도로 만화책을 좋아했다.만화책을 좋아하다 보니 자연스럽게 만화책을 사고 싶었다. 하지만 부모님은 책은 사주셨어도 만화책을 사주지않으셨다. 그리고 집안 형편이 넉넉지 않아서 만화책을 살만큼의 용돈을 받을 수는 없었다. 그래서 생각한 것이 만화 대여사업이었다. 내가 원하는 만화책을 사서 이걸 친구들에게 대여해서 돈을 벌어 다시 그 돈으로 내가 원하는 만화책을 다시 사는 것이었다. 딱히 돈을 벌기 위해서 한 것은 아니고, 단순히 만화책이 너무 갖고 싶었기 때문에 시작한 사업이었다. 만화 대여업에 대한 개념은 이미 만화방의 고객으로 터득하고 있었기 때문에 '업'의 개념은 충실히 알고 있었다. 지금 기억으로는 꽤 사업이 번창했고, 내가 원하는 만화책을 많이 살 수 있었다. 하지만 나의 첫 번째 사업은 얼마 가지 못했다. 사업의 번창으로 사모은 만화책이 화근이었다. 아버지에게 발각된 것이다. 아버지는 무슨 돈으로 이 만화책을 산 것인지 물어보았고, 난 나의 사업에 대해서 이야기할 수밖에 없었다. 아버지는 친구 간에 돈을 받고 물건을 빌려주는 것이 옳지 않다고 하셨고, 나의 첫 번째 사업은 그렇게 허무하게 문을 닫았다.나의 아버지는 평생 장사를 하셨다. 하지만 내가 장사 혹은 사업을 하는 것을 바라지 않으셨다. 내가 커서 박사 학위를 받고 교수가 되기를 원하셨다. 나도 그러한 아버지의 꿈을 알고 있었고, 나도 그 길이 멋있어 보였기 때문에 그 길로 가는 것에 대해서 이견이 없었다. 그런데 내가 친구들을 상대로 장사를 하는 모습을 보시고 나서는 적잖이 실망하셨던 것 같다. 친구 간에 돈거래를 하고 장사를 한다는 것에 대해서 옳지 않다고 생각하셨던 것 같다.아버지는 어렸을 때 공부를 잘하셨다고 한다. 내가 확인할 수는 없지만, 지금도 종종 친척들을 만나면 우리 아버지가 초등학교, 중학교 때 언제나 반에서 1등을 놓치지 않으셨다는 이야기를 한다. 하지만 집안 형편이 심하게 안 좋은 관계로 고등학교를 중간에 그만 두실 수밖에 없었다. 치킨집에 들르시는 아버지 초등학교 동창분이 술 드시면서 반에서 1등 했던 우리 아버지는 치킨집을 하고 있고, 본인은 대학도 나오고 학원 선생도 하고 있다는 이야기를 하는 거 보면 잘하긴 잘 하셨던 것 같다. 그런 본인의 이루지 못한 꿈에 대한 '한'때문인지 아버지는 나와 동생의 교육에 대해서 관심이 많으셨다.  그리고 본인은 평생 작업복을 입고 육체노동을 하시고 계시지만 나는 그런 삶을 살지 않기를 바라셨다. 나 또한 그러한 아버지의 꿈대로 과학고를 가고, KAIST를 가서 '박사'가 되는 꿈을 이루기 위해서 노력했다.하지만 그런 꿈이 깨진 건 1997년도였다. 1997년도 IMF가 터지면서 대전에 연구단지는 흉흉한 소문이 돌았다. 수많은 연구원들이 구조조정 대상이 되었고, 이공계에 대한 천시 풍조가 과장되게 들려왔다. 대덕연구단지 횟집 사장이 박사 출신이라는 확인할 수 없는 소문도 돌았다. 그러한 모습을 보면서 내가 꿈꾸었던 '연구원', '박사'라는 이름이 생각만큼 좋지 않을 수 도 있다는 생각을 했다. 게다가 난 그때 학과 공부에도 적응하지 못하고 방황하고 있었다. 그래서 난 대학원을 가지 않고 경영학을 복수전공해 보기로 했다. 그리고 학부를 졸업하고 취직하기로 마음을 정하고 아버지에게 말씀을 드렸다. 아버지는 예상대로 나에게 많이 실망하셨다. 하지만 난 내 뜻을 굽히지 않았다. 그리고 아버지는 1998년도 5월에 갑자기 돌아가셨다.난 내가 어렸을 때 꿈꾸었던 삶을 살고 있지 않다. 아버지가 원했던 '연구원', '박사'와는 거리가 먼 삶을 살고 있다. 어쩌면 아버지가 원하지 않았던 '장사', '사업'이라는 것을 하고 있다. 아버지가 살아계셨으면 어떻게 생각하셨을까?  비록 내가  아버지가 원하지 않았던 삶을 살고 있지만 기뻐하셨을것 같다. 아버지는 언제나 내가 행복하기를 바라셨던 분이기 때문이다.#NEOFECT #개인경험 #경험공유 #인사이트 #성장
조회수 2590

웹 플러그인 개발기 - iframe의 재발견

채널 웹 플러그인을 개발하며 겪은 문제들과 우리 팀의 해결책을 소개합니다. 채널 웹 플러그인은 SDK의 형태로 고객사 웹사이트에 붙어서 고객이 매니저와 대화할 수 있는 인터페이스를 제공합니다. 이 글을 쓰고 있는 당시 약 2300개의 채널이 개설되었고, 하루 약 180만 명의 일반 유저가 웹사이트에 붙은 저희 플러그인을 보고 있습니다.플러그인은 고객사 웹사이트 (이하 호스트 웹사이트라고 함) 의 HTML 도큐멘트에 붙어서 실행됩니다. 이 말은 실행 환경 (자바스크립트, CSS, DOM 환경 등) 을 우리가 컨트롤하지 못한다는 것을 의미합니다. 이것이 일반적인 웹서비스와 플러그인 개발의 가장 큰 차이점이고 사실상 많은 이슈들은 이 차이로부터 기인합니다. 또 이것에 대응하기 위해 프레임워크의 선택부터 개발, 배포에 이르기까지 훨씬 신경 써야할 부분이 많았습니다. 이 글에서는 그 중 호스트 웹사이트와의 실행 환경 공유에 따른 문제들을 자바스크립트와 CSS로 나누어 나열하고 iframe 을 이용하여 해결한 과정에 대해 설명하겠습니다.채널 홈페이지에 웹 플러그인이 붙은 모습1. 자바스크립트와 관련된 이슈1-1. 네임스페이스 공유에 따른 충돌 문제브라우저에서 자바스크립트는 글로벌 네임스페이스를 공유합니다. 이 속성 때문에 플러그인에서 window 를 접근해서 수정한다던가 글로벌로 객체를 정의해서 사용하면 호스트 웹사이트에 영향을 미칠 수 있습니다. 이 문제는 코딩할 때 아래 항목을 주의하는 정도로 큰 비용 없이 방지할 수 있습니다.플러그인의 최상위 네임스페이스를 만든다.(ex. window.CHPlugin)플러그인에서 사용하는 모든 객체는 최상위 네임스페이스 아래에 정의되도록 한다.(ex. window.CHPlugin.outObject)window 객체에 접근할 때는 수정하거나 추가하는 부분이 없도록 주의한다.(ex. [removed] = function(){}와 같은 코드는 사용하면 안 됨. 기존에 [removed] 이벤트가 날아감)사용하는 라이브러리들 중에 window에 바인딩하는 것이 없는지 체크하고 있으면 직접 수정하여 모듈화한다. (ex. lodash는 기본적으로 window 에 _ 객체를 생성함)이건 사실 플러그인이 아니더라도 주의해야하는 거죠..1-2. 에러로 인한 오동작 가능성더 어려운 문제는 바로 예측하기 어려운 오동작의 가능성이 있다는 것입니다. 호스트 웹사이트에서 동작하는 자바스크립트에서 에러가 날 경우 플러그인의 동작에도 영향을 미칠 수 있으며, 반대로 플러그인에서 에러가 발생해서 호스트 웹사이트의 코드 실행을 멈출 수 있다는 것입니다. 양방향으로 영향을 미칠 수 있는 것이죠. 특히 후자의 경우는 우리의 실수로 고객사의 서비스에 피해를 끼칠 수 있으니 쉽게 넘길 문제는 아닙니다.아이디어 1: try/catch를 적절히 처리한다?이를 해결하기 위해 가장 쉽게 생각할 수 있는 방법으로는 호스트 웹사이트 쪽에서 try/catch를 적절하게 처리하도록 가이드를 하는 방법입니다. 예를 들어 플러그인 코드의 바깥 쪽에 try/catch처리를 하고 호스트 웹사이트의 자바스크립트에도 적당하게 처리를 하면 되지만 이 방법은 현실적으로 어려움이 있습니다. 우리의 타겟 고객사들은 일반 쇼핑몰들이고 이들은 대부분 개발자가 없거나 쇼핑몰 빌더를 이용해 만들어진 사이트들이기 때문에 개발력이 없는 경우가 많습니다. 또 설사 개발력이 있다 하더라도 플러그인을 붙이기 위해 가이드할 것이 너무 늘어나는 문제가 있죠.아이디어 2: 자바스크립트 실행 순서를 강제한다?생각해볼 수 있는 또 다른 방법은 호스트 웹사이트의 코드와 플러그인 코드의 실행 순서를 명확히 정해서 한 방향의 영향이라도 차단하는 것입니다. 예를 들어 플러그인 코드가 호스트 웹사이트의 코드보다 항상 먼저 실행되도록 고객사에게 가이드한다면 우리의 코드는 항상 문제 없이 실행될 것이고 호스트 웹사이트에서 에러가 발생하더라도 영향을 받지 않을 것입니다. 하지만 이 방법 역시 마음에 들지 않았는데요 양방향의 영향을 모두 차단하지는 못하기 때문입니다. 그리고 더욱 큰 문제는 플러그인은 한 번 실행되고 끝나는 단순한 스크립트가 아니라 계속해서 실행이 되는 애플리케이션이기 때문에 사실상 소용이 없습니다.2. CSS와 관련된 이슈채널 웹 플러그인은 UI도 포함합니다. 플러그인의 DOM이 호스트 웹사이트에 붙어있기 때문에 플러그인의 스타일을 정의하는 CSS도 호스트 웹사이트에 Inject 되어야합니다. 호스트 웹사이트의 CSS와 플러그인의 CSS가 같은 스코프에 존재하기 때문에 우리가 의도한 스타일이 제대로 표현되지 않을 가능성이 있습니다. 실제로 이 문제는 런칭 초기에 우리를 가장 괴롭혔던 문제입니다. 쉽게 생각해볼 수 있는 방법은 아래와 같습니다.플러그인의 CSS에 네임스페이스를 둔다.(플러그인 CSS가 호스트 웹사이트 CSS에 주는 영향을 차단함)CSS 의 우선순위를 이해하고 플러그인 CSS의 우선순위가 항상 높도록 처리한다. (CSS Specificity 링크 참조)하지만 위처럼 처리하더라도 모든 경우에 대해 해결이 되는 것은 아닙니다. 주된 이유는 우리가 개발을 할 때 모든 CSS 속성을 정의하지 않기 때문입니다. 플러그인에서 정의하지 않은 속성을 호스트 웹사이트에서 사용한다면 호스트 웹사이트의 스타일이 적용될 것입니다. 또 특수한 경우이긴 하지만 만약 호스트 웹사이트에 !important 가 적용되어 있다면 그 속성이 덮어씌워지게 됩니다.!important는 사용하지 맙시다..ㅜ아이디어: 스타일 Normalizing?여기에서 의미하는 Normalizing은 모든 DOM 엘리먼트에 가능한 모든 CSS 속성의 기본값을 정의하는 것을 의미합니다. 크로미움을 기준으로 모든 CSS 속성 목록은 이 곳을 참조하시면 됩니다. 이것을 바탕으로 normalize.css를 만들어 적용했습니다.이 방법을 적용한 이후로는 스타일이 오버라이딩되는 문제는 어느 정도 해결되었습니다. 물론 !important에 대한 대응은 여전히 되지 않지만요. 그런데 예상하지 못한 부작용이 발생했는데 첫번째는 디버깅할 때 크롬 인스펙터가 도저히 사용하지 못할 정도로 느리다는 것입니다. 두번째는 CSS가 inheritance 가 안 되고 기본 엘리먼트 셀렉터의 우선순위가 높아서 직접 코딩해야하는 CSS가 2~3배는 길어지는 불편함입니다. 위 두 이유로 개발 피로도가 상당히 높아져서 머지 않아 다른 방법을 알아보게 되었습니다.3. iframe 도입위에 나열한 문제들을 해결할 수 있는 아이디어로 iframe을 리서치하게 되었습니다. 사실 iframe은 최근 웹서비스에서는 잘 사용하지 않기도 하고, 보통은 사용하지 않는 것을 권장하기도 하죠. 따라서 저희 팀에서도 처음에는 고려사항이 아니었는데요 우리와 유사하게 채팅 인터페이스를 제공하는 인터콤에서 iframe 을 적용한 것으로부터 아이디어를 얻어왔습니다.원래 목적에 맞게 사용하지 않으면 독이 됩니다.iframe은 HTML 도큐멘트 안에서 또 다른 도큐멘트를 임베드합니다. iframe 내에 있는 도큐멘트는 호스트 도큐멘트와 자바스크립트 스코프가 분리되어 있고, CSS가 적용되는 스코프 역시 분리되어 있습니다.이런 속성 때문에 위에 나열한 문제들을 원천 차단할 수 있습니다. 자바스크립트 스코프가 분리되어 있기 때문에 글로벌 네임스페이스에 접근해도 호스트 웹사이트에는 전혀 영향이 없고, 자바스크립트의 에러로 인해 다른 쪽 자바스크립트까지 실행을 멈추는 오동작을 막을 수 있습니다. CSS 역시 Normalizing 을 하지 않더라도 호스트 웹사이트와 플러그인은 완벽히 분리가 됩니다.4. iframe 의 단점iframe을 도입하여 1, 2번에 나열한 문제들은 해결했지만 그에 따른 작은 문제들도 발생했습니다. 첫번째는 iframe도입 시 가장 먼저 고민해야할 부분인데 바로 3rd-party cookie 문제입니다. iframe 안에서 로드되는 도큐멘트는 3rd-party 컨텐츠로 인식합니다. IE에서는 기본 설정이 3rd-party cookie 허용을 하지 않기 때문에 쿠키를 사용해서 인증을 구현한 경우 문제가 될 수 있습니다.두번째는 도큐멘트가 분리됨에 따라 발생하는 코딩상의 여러 불편함들입니다. 여기에서는 범위를 벗어나 더 자세하게는 설명하지 않겠지만 도큐멘트가 분리되니 조금 더 신경써야할 것들이 있었습니다.저희 팀의 경우 쿠키 인증 방식이 아닌 토큰 형태의 인증도 지원을 하고 있었기 때문에 첫번째는 크게 문제되지 않았고 두번째 문제도 얻는 이득에 비하면 불편함을 감수하는 편이 훨씬 좋다는 판단이 들어서 도입을 결정했습니다.마무리플러그인 개발을 시작할 당시에 우리 팀은 웹 SDK 형태의 프로젝트 개발 경험이 없었습니다. 리서치를 해도 플러그인 개발과 관련된 아티클이나 리소스 그리고 보일러플레이트 프로젝트도 많지 않았습니다. 프레임워크, 아키텍쳐를 선택하는 것부터 프로젝트를 구성하는 것부터 개발, 배포 및 운영에 이르기까지 일반적인 웹서비스를 개발할 때와 조금 다른 고민들을 해왔던 것 같습니다. 앞으로 저희가 해 온 고민을 공유하려고 합니다. 저희와 같은 플러그인, SDK 형태의 제품을 개발하고 계신 분들에게 도움이 되었으면 좋겠습니다.#조이코퍼레이션 #개발자 #개발팀 #인사이트 #경험공유 #일지
조회수 1501

채권과 주식, 뭐가 다른가요?

투자형 크라우드 펀딩에는 채권과 주식, 이렇게 두 가지 종류가 있습니다. 채권은 돈을 빌려주는 거에요. 사전에 정해둔 기간이 지나면, 원금과 이자를 돌려받게 되는 거죠. 돈을 안 갚으면 영화 <범죄도시>의 장첸처럼 “손모가지 하나당 천만 원 깎아 줄게.”하게 되는 겁니다.주식은 채권과 달리 돈을 돌려받을 수 있는 날짜가 정해져 있지 않습니다. 대신 지분을 사 그 회사의 주주, 즉 주인이 되는 거죠. 회사의 주주가 되면 뭐가 좋으냐고요? 회사가 큰 결정을 내릴 때 의사결정에 참여할 수 있고, 회사가 이익을 내면 지분에 비례해 그 이익을 나눠 갖습니다. 기업이 성장하거나 다른 기업과 합병하면 주식을 산 가격보다 훨씬 비싸게 다른 사람에게 팔 수도 있습니다. 대신 회사가 망하게 되면 채무자들에게 먼저 돈을 갚아야 해서 회사의 주인인 주주들의 투자금 상환은 뒤로 밀리게 되죠.채권도 다 같은 채권이 아닙니다.와디즈에서 진행되는 채권 프로젝트는 기본금리만 있는 일반회사채, 추가금리까지 있는 일반회사채, 그리고 이익참가부사채 이렇게 세 가지로 나뉩니다. 기본금리만 있는 일반회사채는 간단해요. 돈을 빌리는 기간과 이자율을 미리 정하고, 투자 후 약속한 날이 되면 원금과 이자를 돌려받습니다. 얼마 전 만기 1년에 연이율 10%인 채권 프로젝트에 100만 원을 투자했습니다. 이 회사가 문을 닫거나 도망가지만 않으면, 저는 1년 뒤에 110만 원을 돌려받겠죠. 나라에서 세금은 조금 떼어가겠지만요. 추가금리가 있는 일반회사채의 경우, 기본 이자율에 회사 실적에 따라 추가금리가 더해집니다. 지난 화에서 제가 추가 수익 70%를 기대하고 투자했던 영화 프로젝트가 바로 이 경우입니다. 기본금리 3%에 관객 수가 많아질수록 더 높은 추가금리가 붙습니다.“영화가 잘 될 때 돈을 더 준다고? 그럼 영화가 흥행에 실패하면 돈을 덜 돌려주는 거야?”라고 물으시면 그건 아닙니다. 영화 실적과 관계없이 기본금리는 고정되어 있어요.이익참가부사채는 회사 전체가 아니라 특정 프로젝트의 이익과 손실을 투자자가 함께 공유합니다. 영화, 공연, 전시처럼 관객 수 등의 정확한 수치로 성패를 측정할 수 있는 일부 프로젝트에 한해 발행할 수 있습니다.관객 수에 따라 이자율이 플러스가 될 수도 마이너스가 될 수도 있어요. 프로젝트가 잘되면 정말 높은 이자 수익을 기대할 수 있지만, 프로젝트가 실패하면 손실도 함께 부담해야 합니다. 잘되면 대박이지만 원금손실의 위험도 크죠.주식은 조금 더 복잡합니다.주식은 보통주, 우선주, 상환우선주, 전환우선주, 상환전환우선주 이렇게 다섯 가지가 있는데요.보통주는 말 그대로 가장 일반적인 형태의 주식입니다. 보통주를 사면 회사의 의사결정에 참여할 수 있는 의결권과 발생하는 이익을 나눠가질 수 있는 배당청구권, 그리고 혹시나 회사가 망했을 때 남은 재산을 나눠 받을 수 있는 잔여재산분배청구권을 받게 됩니다. 나중에 주식을 내가 산 가격보다 비싸게 팔아 매매차익을 기대할 수도 있죠.보통주만 알면 나머지는 정말 쉽습니다. 의결권이 없는 대신 보통주보다 배당과 잔여재산을 먼저 받을 권리가 있는 주식을 우선주라고 합니다. 경영에는 참여하지 않고 수익만 먼저 나눠 받고 싶은 분들을 위한 주식 형태죠.상환우선주는 우선주의 개념에 상환권이 더해진 개념입니다. 상환우선주의 경우 채권이 아닌 주식임에도 만기일이 정해져 있습니다. 만기 전까지는 우선주처럼 배당을 받지만, 만기일이 되면 회사가 주식을 다시 매입해서 원금과 이자를 상환합니다. “뭐야 채권이랑 똑같은데 배당까지 해주는 거야? 대박이잖아?!” 하지만 회사가 만기에 이익잉여금이 있을 때만 상환을 받을 수 있습니다. 한마디로 회사에 남는 돈이 없으면 상환권은 보장되지 않는다는 거죠. 기업이 상환우선주 개념을 악용하는 것을 방지하고 투자자들을 보호하기 위해서 상환우선주는 이미 이익잉여금이 있는 회사만 발행할 수 있도록 하고 있습니다.전환우선주는 우선주인데 일정 기간이 지나면 보통주로 바꿀 수 있는 형태의 주식입니다. 지금은 회사의 의사결정에 관심이 없는데 회사가 좀 더 크면 개입하고 싶은 주주들을 위한 겁니다. 이를 전환권이라고 하죠. 상환전환우선주는 지금까지 말한 내용이 모두 더해진 개념입니다. 우선주+상환권+전환권인 거죠. 상환전환우선주는 채권의 성격을 가지고 있어 안전하기도 하면서 시간이 지나면 의결권도 가질 수 있어 요즘 유명한 VC(벤처캐피털)들이 스타트업에 투자할 때 가장 많이 선택하는 형태의 주식이기도 합니다. 권리가 많은 만큼 세세한 발행조건 설정에 따라 투자자 권리의 많은 부분이 달라지니 꼭 잘 살펴봐야 합니다.아니 그래서 어디에 투자하라는 거냐고요?주식과 채권은 얼핏 봐도 상당히 다릅니다. 채권은 회사 자체가 어려워지지 않는 한 약속된 기간이 지나면 원금과 이자를 받을 수 있습니다. 그래서 채권에 투자할 때는 기간과 이자율을 보고, 만기에 약속한 돈을 갚을 수 있는 능력이 되는 회사인지 확인하면 됩니다. 반면에 주식에 투자하기 전에는 이 회사가 당장 돈을 벌지는 못하더라도 미래에 성장해서 주식을 내가 산 가격보다 비싸게 되팔 수 있는지 생각해봐야 합니다. 배당은 받을 수 있는 건지, 내가 가진 상환권과 전환권이 실현될 수 있는지도 꼼꼼히 살펴봐야겠죠? 그래서 그걸 뭘 보고 어떻게 아냐고요? 그건 다음에 시간에… (총총)글 김영아와디즈의 막내 투자 콘텐츠 디렉터(CD)입니다. 우리의 작은돈이 필요한 곳에 모여 세상을 바꾸는 꿈을 꾸고 있어요. 아 물론 돈도 벌면서요. 더 많은 ‘우리’에게 크라우드 펀딩을 알리기 위해 어렵고 복잡한 투자 이야기를 쉽고 재미있게 풀어내는 일을 합니다.그림 이윤경와디즈의 브랜드 디자이너입니다. 좋은 '사람' 와디즈가 좋은 '브랜드'로 무럭무럭 자라나도록 물을 주고 있어요. 더 많은 사람들의 시작을 돕기를, 그리고 더 재미있는 세상을 만들어 가기를 기대하고 있습니다.#와디즈 #금융지식 #서비스소개
조회수 17352

Nodejs 기반의 개발 환경 클린하게 재 구성하기

다양한 언어 기반으로 개발 환경을 구축하여 만들다보면, 소프트웨어 버전관리 해야할 일이 흔히 생기곤 한다. 특히, 종종 대격변이 있는 버전의 판올림으로인해 충돌이 나거나 심볼릭 링크가 유실되는 경우들이 간혹 있는데 이번에도 그런 케이스였다.최근 node.js 기반으로 다양한 프로젝트 (vue.js, react.js등)를 진행하다가 이것저것 환경을 만지고 고치다보니 결국 node.js 를 완전히 클린하게 삭제해야 할 일이 생겼다.아마 이 환경에 결정타를 먹인 것이 OSX 환경에서 El Capitan에서 작업하던 Node.js를 그대로 high sierra로 OSX를 판올림 하면서 퍼미션 권한의 문제가 생긴건지, 노드 패키지 관리나 npm이 정상적으로 동작하지 않으면서 개발환경을 재 설정 할 수 밖에 없게 되었는데, 그 과정에 기름을 부어버리듯 당시에 brew로 설치한 노드가 brew로 삭제가 되지 않는 문제가 발생해버렸다.결국 환경을 처음부터 재 설치 해야하는 과정을 겪어야했는데 기존에 설치된 다양한 패키지 모듈의 찌꺼기들이 남아서 한방에 클린 설치를 할 수 있는 방법이 없을까 싶어 구글링을 해본 결과 앞서서 수많은 시행착오를 겪은 선배님들의 아주 좋은 작업 방식이 있어서 아래에 방법을 공유해본다.요세미티에서 nodejs 정리하는 법 [1]Uninstall nodejs from OSX Yosemite# 첫번째:lsbom -f -l -s -pf /var/db/receipts/org.nodejs.pkg.bom | while read f; do  sudo rm /usr/local/${f}; donesudo rm -rf /usr/local/lib/node /usr/local/lib/node_modules /var/db/receipts/org.nodejs.*# 완전히 nodejs + npm 을 날려버리는 방법 :# /usr/local/lib 경로로 가서 node 와 관련된 노드 모듈을 전부 삭제cd /usr/local/libsudo rm -rf node*# /usr/local/include 경로로 가서 node 와 관련된 노드 모듈 전부 삭제cd /usr/local/includesudo rm -rf node*# 만약 brew 로 인스톨을 했다면 아래와 같은 방법으로 삭제도 가능함. (저는 아래는 brew자체가 망가졌었는지 판올림으로 인한 권한 문제인지 brew로는 삭제 불가능했음.)brew uninstall node# home 디렉토리나 local, lib, include등의 폴더와 관련된 모든 파일은 아래의 경로에 있으니 찾아 들어가서 삭제cd /usr/local/binsudo rm -rf /usr/local/bin/npmsudo rm -rf /usr/local/bin/nodels -las# 아마 혹시 모르니까 클린하게 아래의 명령어도 한번 돌려주자sudo rm -rf /usr/local/share/man/man1/node.1sudo rm -rf /usr/local/lib/dtrace/node.dsudo rm -rf ~/.npmhomebrew를 사용하는 유저들 중에 npm이 제대로 동작하지 않으면 아래와 같은 방법으로도 처방이 가능하다. [2]rm -rf /usr/local/lib/node_modulesbrew uninstall nodebrew install node --without-npmecho prefix=~/.npm-packages >> ~/.npmrccurl -L https://www.npmjs.com/install.sh | sh클린하게 설치를 끝나고 react-native를 컴파일하는 과정에서 깃에 관련된 오류가 발생한다면 아래의 방법을 사용해보자. [3]오류메세지 :xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun솔루션 :xcode-select --install엘케피탄에서 하이시에라로 osx를 업데이트 하면서 homebrew의 링크가 깨졌다면 아래의 방법으로 다시 붙여준다. [4]sudo chown -R "$USER":admin /usr/localsudo chown -R "$USER":admin /Library/Caches/Homebrewbrew link libpng참고 출처 :[1] : https://gist.github.com/TonyMtz/d75101d9bdf764c890ef[2] : https://stackoverflow.com/questions/32893412/command-line-tools-not-working-os-x-el-capitan-macos-sierra-macos-high-sierra[3] : https://stackoverflow.com/questions/39778607/error-running-react-native-app-from-terminal-ios[4] : https://github.com/mikepurvis/ros-install-osx/issues/28 #더팀스 #THETEAMS #풀스택개발자 #Node.js #백엔드 #인사이트 #꿀팁
조회수 534

트리거 : 행동의 방아쇠를 당기는 힘

출처 : 네이버 책사고 방식을 바꾼 계기가 된 몇 권의 중요한 책들이 있다. 마셜 골드스미스(Marshall Goldsmith)의 트리거(Triggers)가 그 중의 하나다. 이 책은 ‘스스로를 변화시키는 방법'에 대해 다루고 있다. 우리가 왜 스스로를 바꾸는데 서툰 것인지, 어떻게 하면 더 잘 할 수 있을지. 우연히 서점에서 트리거를 처음 발견했을 때는 ‘여느 자기 계발 서적들과 비슷하게 원론적이고 추상적인 이야기 뿐이지 않을까’ 의심했었다. 하지만 이 책을 다 읽은 후 이제는 이 책의 내용이 습관적 자기회고(self-reflection)의 잣대가 되어 주고 있다. 스스로에 대해 실질적으로 변화를 만들어 내기는 무엇보다 어려운 일이다. 마음을 굳게 먹어도 얼마 지나지 않아 포기해 버리기 일쑤다. 변화를 만들기 힘들어지면 그것의 필요성마저 부정하게 된다. 심지어 이런 과정이 반복되면 변화하지 못하는 나 자신을 합리화하는 데 익숙해지기도 한다. 우리는 때로 타인에게 변화를 요구하고 기대하기도 한다. 하지만 스스로도 변화하지 못하면서 어떻게 타인에게 긍정적인 변화를 기대할 수 있겠는가. 흔히 자신에게 냉정하고 상대에게는 관대하라고 하지만, 오히려 자신에게는 관대하면서 상대에게는 냉정한 기준을 강요하는 것이나 마찬가지일 것이다. 규칙적인 생활하기렌딧을 창업한 이후 규칙적인 생활의 필요성이 커졌다. 함께 일하는 동료들도 늘어나고 일의 복잡도 역시 계속 높아져 왔기 때문이다. 절대적인 업무량이 비슷하거나 오히려 더 많아진 상황에서 복잡도는 이전보다 훨씬 더 높아졌기 때문에 롱런(long-run)하기 위해 수립한 나름의 목표다. 트리거를 접하기 전에도 나는 가끔씩 스스로를 되돌아 보며 ‘규칙적인 생활하기'라는 목표를 잘 지켜내고 있는지 평가하는 시간을 가졌다. 이것이 변화를 만들어 내기 위한 나 스스로의 방식이었다. 하지만 이 방식에는 결정적인 문제가 있었다. 목표 달성에 지장을 주는 그럴싸한 이유들이 자주 생겨났다는 점이다. 이를테면 중요한 미팅이 갑자기 생겨나는 일들이 자주 발생하게 된 것이다. 목표 달성에 실패하게 되었지만, 나는 중요한 미팅 같은 외부 요인 때문에 그렇게 되었다고 해석하게 된다. 이렇게 되면 자기회고가 사실상 의미없는 결과를 가져 오게 되고, 결과적으로는 변화의 정도 역시 미미하게 되어 버린다. 규칙적인 생활을 하기 위해 최선을 다했는가?트리거를 읽으며 깨우친 가장 중요한 한가지는 ‘능동적인 질문의 중요성' 이다. 단지 ‘규칙적인 생활을 했는가?’ 라고 묻는 것은 수동적인 질문이다. 규칙적인 생활을 하지 못한 여러가지 그럴싸한 이유를 얼마든지 생각해 낼 수 있기 때문이다. 이에 대한 능동적인 질문은 ‘규칙적인 생활을 하기 위해 최선을 다했는가?’ 이다. 이렇게 ‘최선을 다했는가?’ 라는 말을 추가하는 것으로 스스로의 노력을 회고할 수 있는 잣대로 삼을 수 있게 되었고, 비로소 스스로에게 정말 냉정해질 수 있게 되었다.
조회수 679

창업자의 일기장(6)-학생의 길

-----이전 이야기-----백수의 삶에서나름 도서관 전전하며 준비하다가...듣고 싶었던 교육에 선정되었다.퇴사한 후, 나의 계획 중에전문지식을 더 심화하여야 할교육이 있었다.창업하고자 하는 분야가제조업이다보니공장/공정에 대한 공부다.물론 신청해서 선정되어야 하고,3개월이라는 긴 시간을 각오해야 했다.350시간 공부해야하기에매일 아침 9시부터 저녁 6시까지 서초에서 공부하고, 시험치고발표하고...그리고 남는 시간에는 영어회화공부를 했다.전국각지에서 몰려온 청춘들과함께 공부하다보니 학생시절이 떠올랐다.물론 나보다 나이가 많은 형님들도 있었고,나처럼 직장을 관두고 공부하는 사람들도 있었다.갓 졸업하고, 취업 준비하면서공부하는 친구들이 많았는데특히나 분야가 플랜트쪽이다보니전공이 거의 화공이었다.그 중에 몇 안되는 타 과 전공자!그게 나였다.그래서인지 처음에는 못 알아 먹는 전문용어와기본적인 이론지식이 후달리더라.뒤처지는 것이 싫었던 나는정말 필사적으로 공부했다.감사하게도함께 공부한 학생들이 이런 나를 많이 도와주었다.특히나, 조별로 묶이게 된학생들은 나이 차이와지식의 차이가 현저하고,가족이 있는 나에게더욱 친절하게, 상세하게공부를 도와주었다.전체인원이 60명 정도 였는데 거기에서 나이로 치면 NO. 4 되었다.하긴 나보다 더 나이 많은 분들도그렇게 필사적으로 매달려서 공부하는데앓는 소리 할 수 없었지.중간중간 시험과 평가에서좋은 성적을 거두면서,처음에는 교육 수료가 목표였지만,조금씩 욕심이 생기기 시작했다.몸도 마음도 지친 상태로집에 들어가면,아내는 늘 웃으면서나의 일상을 물었다.그럴수록 정말 더 미친듯 집중해야겠다고다짐하고 또 다짐했다.새벽마다 경의선 첫 차타고 가고,밤이면 도서관 들려서 버스타고 들어왔다.게다가 그 때의 시기는 겨울이라눈이 많이 내렸다.빙판길과 눈길을 헤치고 다녔고,점심값을 아끼기 위해서편의점 삼각김밥이나 컵라면을 즐겼다.그래도 한없이 미안하더라.못난 남편이 자기 욕심에 던져버린,평범할 수 있던 삶에 대한 책임을같이 감당하는 아내에게,그리고 태 중의 아이에게너무 미안했다.늘 감사했고,나는 사치부리는거라 믿으며하루하루를 꽉꽉 채워갔다.결국 목적은 창업을 위한 준비다 보니우선순위를 두고, 부분별로 수행해 나갔다.1. 지금 당장 하고 있는 플랜트 공정 교육에 집중2. 꾸준한 영어회화 공부3. 사업계획서랑 팀원 꼬시기4. 실업급여 지급이 끝나고 먹고 살 것 찾기그리고 이 항목들은 시간별로 워크시트를 만들어서 체크해 나갔다.전체 스케쥴은 나중에 알게 된"프리마베라"라는 프로그램을 본 따서조정해 나갔다.시간이 쏜살같이 흘러가더라.그리고 예상보다 더디거나 로드되어 밀리는 현상도 생기고잘 안풀리는 것들도 많고....이런 것이 다 사업의 밑거름이다.지식의 향상도 있지만,이러한 경험들이 모든 사업 활동에서적용 되는, 마주하는 일상적인 패턴들이다.그래서 감사한 마음으로 배웠다.지금이 아니면언제 이렇게 배울 수 있으랴~!그리고 왠지 학생이라는 소속감이백수라는 내 현실을 잠시 잊게 해 주었다.
조회수 3747

프롤로그: 커뮤니티 매니저, 들어본 적 있나요?

한 번쯤 이 단어를 들어본 적이 있나요? 여러분이 '커뮤니티 매니저(Community Manager)'라는 단어를 들어본 적이 있다면, 이런 공간들을 알거나 방문해본 적도 있을 겁니다. 코워킹 스페이스(co-working space), 공유 공간, 협업 공간, 청년 공간, 마을 공간, 거점 공간 등등 다양한 이름과 형태를 가진 ‘커뮤니티 공간’을 말이죠. 다양한 커뮤니티 공간에서는 '커뮤니티 매니저'를 직업으로 하는 사람들을 만나볼 수 있다. ⓒ wework, 마이크임팩트스퀘어, 아트업서울, 무중력지대G밸리최근 몇 년 간 서울을 비롯한 전국 각지에는 다양한 형태의 ‘커뮤니티 공간’이 빠른 속도로 새롭게 만들어지고 있습니다. 이 흐름은 자연스럽게 공간 운영과 관리를 담당하는 사람들의 등장으로 이어집니다. 바로 ‘커뮤니티 매니저’라고 불리는 사람들이죠.  이들은 때론 공간을 넘나들며 다양한 활동과 문화를 만들어나가며, 커뮤니티 회복과 활성화, 사회적 가치 창출 등을 지향하기도 합니다.물론 각 공간/직무 등에 따라 이들에 관한 호칭은 다양합니다. 하지만 광범위하게 자주 쓰이는 것은 아무래도 ‘커뮤니티 매니저’인 듯합니다. (과연 그 단어가 적절한지 혹은 더 멋진 새로운 단어는 없을지에 대한 고민은 일단 차치하고) 그 낯설고 생소한 이름으로 활동하는 사람들이 ‘커뮤니티 공간’의 양적 확대와 더불어 많아지고 있습니다.    그런데 '커뮤니티 매니저'가 뭐하는 사람이죠?체인지메이커들을 위한 공유주택 '디웰하우스'에도 운영와 커뮤니티를 담당하는 '커뮤니티 매니저'가 있다.  ⓒ 루트임팩트‘커뮤니티 매니저’의 정확한 뜻은 무엇일까요? ‘커뮤니티 매니저’라고 하는 사람들은 구체적으로 무엇을 하고, 어떤 공통적인 특성을 가질까요? 실제로 얼마나 많은 ‘커뮤니티 매니저’들이 어떻게 일하고 있을까요? ‘커뮤니티 공간’과 ‘커뮤니티 매니저’는 또 어떤 관계가 있는 걸까요? 로모는 이제부터 ‘커뮤니티 매니저’와 관련된 여러 다양한 질문들을 던져보려 합니다. 그리고 그 질문의 답을 찾는 여정을 여러분과 함께 시작해보려고 합니다.왜 로모는 ‘커뮤니티 매니저’를 화두로 꺼냈을까요?       최근 연재를 시작한 <처음 만나는 커뮤니티 공간 디자인>에 이어, ‘커뮤니티 매니저’에 관한 이야기를 꺼낸 데에는 이유가 있습니다.그저 하나의 공간(a place)이 아니라 의미를 가진 공간(the place)이 되기 위해서는 다양한 요소들이 필요하다. ⓒ Tim Mossholder on Unsplash물리적 공간뿐만 아니라 그 공간의 정체성과 문화를 만들어가는 ‘사람’에 대한 이야기가 동시에 함께 이루어져야, 새롭게 조성되는 공간이 그저 하나의 공간이 아니라 다양한 사람들과 여러 비물질적인 가치들이 ‘공존’하는 유기적인 공간으로 기능할 수 있기 때문이죠.어쩌면 너무도 당연한 말로 들릴지 모르겠네요. 하지만 로모의 팀원들이 그동안 여러 지역에 수십 개의 커뮤니티 공간들이 조성/운영되는 과정에 직/간접적으로 참여해온 경험을 돌이켜보면, 꼭 그렇지만은 않습니다. 대부분 기획과 조성의 단계 이후 '운영'의 차원으로까지는 논의가 밀도 있게 이어지지 못합니다. 또한 운영주체와 인력의 문제 역시 '인건비 부담' 등을 이유로 크게 축소되어버리기 쉽고, 그나마 배치된 각 공간의 매니저들이 무엇을 어떻게 해야 하는가에 대한 이야기는 제대로 다루어지지 못한 채 "각자 알아서 눈치껏"의 수준에 머물고 맙니다. 실제로 로모의 팀원들이 지난 몇 년간 '커뮤니티 매니저'로 경험했던 현장도 크게 다르지 않습니다. '커뮤니티 매니저'의 정의와 역할은 불분명한 채, 아니 그보다도 "커뮤니티 매니저가 도대체 뭐길래?"라는 질문이 제대로 던져지거나 다뤄지지 못한 채, 일단 '커뮤니티 매니저'라는 이름으로 역할이 주어졌고 잘 수행해야 했습니다.  그렇다면 결국 의지할 곳은 현장뿐입니다. 맨 땅에 헤딩하듯이 때론 조심스럽게, 때론 과감하게 다양한 시도를 이어나가며 끊임없이 데이터를 축적해나갔고, 그 과정에서 소위 '커뮤니티 매니저'에 관한 우리만의 그림을 그려나갈 수밖에 없었습니다. 문제는 수많은 '커뮤니티 매니저'들이 유사한 상황에 처해있거나, 그럴 것이라 추측된다는 것입니다. 관련된 체계적인 교육이나 활용할 수 있는 자원, 서로의 경험과 노하우를 나눌 수 있는 네트워크도 부족하니까요. 결국 공간 운영의 경험과 노하우는 공유되거나 축적되지 못한 채, 커뮤니티 공간이 늘어나면 늘어날수록, 각 공간에서 다시금 '0'에서부터 시작하듯 고군분투하는 매니저들이 늘어날 뿐이죠.  결국은 ‘커뮤니티 공간의 질을 어떻게 높일까?’의 문제   그렇다면 '커뮤니티 매니저'가 해답이 될 수 있을까요?모든 문제를 손쉽게 해결할 수 있는 해답은 존재하지 않습니다. 단순한 결론은 때론 효과적일 수 있지만, 때론 중요한 맥락을 가려버리기도 합니다.‘커뮤니티 공간’이 잘 운영되기 위해서도, 다양한 요소들이 필요합니다. ‘하드웨어(hardware)’, ‘소프트웨어(software)’, ‘휴먼웨어(humanware)’, 이 세 가지 요소들이 각자 제 역할을 다 하며, 조화를 이루는 게 필수적입니다. (이 부분은 로모의 또 다른 브런치 매거진 <처음 만나는 커뮤니티 공간 디자인>에서 좀 더 자세히 전할 예정입니다.)그리고 그중 '휴먼웨어'가 꼭 ‘커뮤니티 매니저’에만 국한된 것도 아닙니다. 수많은 이용자들, 공간문화를 만들어나가는데 적극적으로 동참하는 소위 '단골'들, 유관된 다양한 협력 주체 및 기관들, 이들 모두가 공간의 질을 높이는 데 일정한 역할과 책임, 영향력을 행사합니다. 그래서 커뮤니티 공간은 특정 주체에 지나치게 의존하기보단, 커뮤니티 공간을 제대로 이해하는 다양한 주체들의 활동력과 네트워크에 기반하였을 경우보다 지속 가능할 수 있습니다. 다만 그럼에도 중요하고 분명한 사실은 현장에서 '커뮤니티 매니저'들이 '휴먼웨어'의 핵심을 차지하며, 공간의 '하드웨어'와 '소프트웨어'에도 강한 영향을 미친다는 점입니다. "설계자, 시공자, 운영자가 명확히 구분됐던 과거와 달리 최근에는 설계자, 시공자, 운영자의 간극이 좁아지는 사례가 증가하고 있다. 공간의 성패는 어쩌면 설계자보다 운영자가 쥐고 있는지도 모른다. 운영자의 취향과 캐릭터가 고스란히 반영된 공간을 조성하고 그 공간을 완성시키는 다양한 운영전략을 갖출 때 비로소 건축설계가 완성된다고 볼 수 있다" - 윤주원, 김주원, 김수정 공저 (건축도시공간연구소),  7쪽 中그래서 '커뮤니티 매니저'의 정의와 역할, 필수적인 역량이 무엇인지에 대한 문제들은 "각자 알아서 눈치껏"의 차원을 넘어서서, "커뮤니티 공간의 질을 어떻게 높일 수 있을까?"라는 질문 아래 구체화될 필요가 있습니다. 새로운 직업(군)으로서 커뮤니티 매니저  로모는 이제부터 새로운 직업(군)으로서 커뮤니티 매니저를 바라보고, 그에 대한 이야기를 본격적으로 꺼내보려 합니다. 커뮤니티 공간 안팎에서 벌어지는 A to Z를 발로 뛰며 해결하는 '커뮤니티 매니저'들을 하나의 직업군으로서 접근해야, 각 현장에서 개인들이 부딪히는 문제들과 그를 풀기 위한 각종 시행착오들이 흩어지지 않고 의미 있는 경험 자원으로 재해석될 수 있고, 각 공간 혹은 기관의 장벽을 넘어서서 우리 삶 속의 커뮤니티 공간의 질을 높이는 데 필요한 공유재가 될 수 있습니다. <커뮤니티 매니저가 뭐길래>, 앞으로의 이야기 로모의 새로운 프로젝트 <커뮤니티 매니저가 뭐길래>는 앞으로 구체적으로 이렇게 진행될 예정입니다. 먼저, 현재 일하고 있는 커뮤니티 매니저들의 현장성 있는 이야기들을 수집하고 기록할 것입니다. 여러 이야기 조각들을 짜 맞추어보면, "도대체 커뮤니티 매니저가 뭐길래?"라는 질문에 대한 윤곽이 나오겠죠. 그와 함께 현장의 실무자들이 주요하게 마주치는, 다르게 말하면 앞으로 풀어나가야 하는 구체적인 이슈들도 추려볼 수 있을 겁니다. 각자의 이야기가 모여, 함께 나눌 수 있는 서사가 되는 것이 기본이자 핵심이다 ⓒ Headway on Unsplash이야기들을 모은 다음에는, 이제 제대로 된 판을 만들어볼 차례입니다. 다양한 제안과 대안을 생산해내기 위한 담론장을 열어나갈 예정입니다. 커뮤니티 매니저들을 심층 인터뷰하며 발견한 주요 이슈들을 중심으로, 더 많은 커뮤니티 매니저들과 함께, 혹은 굳이 커뮤니티 매니저가 아니더라도 커뮤니티 공간 운영과 이번 프로젝트에 공감하는 사람들이 모두 모여 상상하고, 제안하고, 토론하는 자리도 열어보려 합니다. 그렇게 얼마간 함께 이야기를 하다 보면, 우리는 어쩌면 함께 발견할 수 있을지도 모릅니다. "커뮤니티 매니저가 뭐길래?"라는 질문의 끝에는, '커뮤니티 매니저'라는 애매모호하고 한정된 언어의 틀을 넘어서서, 우리의 고민들과 방향성을 더 적절히 담은, 더 멋지고 새로운 언어를 말이죠. 언어의 힘은 크니까요. 그 발견의 여정을 이제 시작합니다!  이번 편에서는 매거진 <커뮤니티 매니저가 뭐길래>를 왜 시작했는가에 대한 이야기를 중심으로 솔직하게 풀어보았습니다. 앞으로는 커뮤니티 매니저들의 인터뷰 내용을 바탕으로, 좀 더 구체적인 이야기들을 전할 예정입니다. 다음 편을 기대해주세요 :) 커뮤니티 매니저 심층 인터뷰에 참여해주세요! 서울에서 활동하고 있는 '커뮤니티 매니저'들의 이야기와 생각을 수집하고 있습니다.   인터뷰를 희망하시거나, 주변에 관련 일을 하고 있는 사람이 있다면, 아래 링크를 클릭해주세요! http://bit.ly/whoisacommunitymanagerBY 나무  CCO & Co-Founder다양한 삶의 방식과 공존 사례를 연구하고, 실험합니다. 루시드폴의 노랫말을 좋아합니다.   #로모 #기업문화 #조직문화 #사내문화 #기업소개

기업문화 엿볼 때, 더팀스

로그인

/