스토리 홈

인터뷰

피드

뉴스

조회수 4100

[Tech Blog] Go 서버 개발하기

Go 서버 개발을 시작하며   특정 API만 다른 언어로 구현해서 최대의 성능을 내보자! 저희 서버는 대부분 Django framework 위에서 구현된 광고 할당 / 컨텐츠 할당 / 허니스크린 앱 서비스 이렇게 나눌 수 있는데 Python 이라는 언어 특성상 높은 성능을 기대하기가 어려웠습니다. 하지만 세가지 서비스에서 락스크린에서 어떤 컨텐츠나 광고를 보여줄지 결정하는 Allocation(할당) API 가 가장 많이 호출되고 있었는데 빈도로 보면 80% 정도로 높은 비중을 차지하고 있어서 이 Allocation API 들을 성능이 좋은 다른 언어로 구현하면 어떨까 하는 팀내 의견이 있었습니다. Why Go? 저는 예전부터 Java,  C# 등의 컴파일 언어에 익숙해서 기존 Java 와 C, 그리고 Go 라는 최근에 새로 나온 언어 중에서 아래 블로그글과 같이 여러 reference 들을 통해 성능이 좋다는 Go 로 이 API 들을 포팅하는 작업을 시작하게 되었습니다. Go 에 대한 첫 인상은 Java, C계열 언어보다 덜 verbose 보였고 python 보다는 strongly-typed, encapsulated 하다보니 자유도를 제한해서 코드를 보기 쉽게 하는 것을 선호하는 저의 성격과도 잘 맞는 언어였습니다.     출처: Carles Mateo, Performance of several languages서버 개발 환경   Server design How to import libraries  GVT (https://github.com/FiloSottile/gvt) – Go 는 vendering tool 을 통해 dependency 를 관리할 수 있습니다. GVT 의 경우 처음 도입했을 때 별로 유명하지 않았는데 사용법이 간단해서 도입하게 되었습니다. 아래와 같이 참조하고 있는 revision 을 관리해주며 update 통해서 최신 소스를 받아 올수 있습니다.   { "version": 0, "dependencies": [ { "importpath": "github.com/Buzzvil/go-env", "repository": "https://github.com/Buzzvil/go-env", "vcs": "git", "revision": "2d8489d40184a12c4d09d09ce1ff717e5dbb0745", "branch": "master", "notests": true }, ....  Design pattern  Go 언어에서는 package level cycling dependency 를 허용하지 않아서 좀더 명확한 구조를 만들기 좋았습니다. 예를들어 Service 에서는 Controller 를 참조할수 없고 Model 에서는 Controller / Service / DTO 등을 참조할수 없도록 강제했습니다. 모든 API 요청은 Route 를 통해 Controller 에게 전달되고 이 때 생성된 DTO (Data transfer object) 들을 Controller 가 직접 혹은 Service layer 에서 처리하도록 하였고 DB 에 접근할 때는 모델을 통해 혹은 직접 접근하도록 했지만 추후 구조가 복잡해지면 DB 쿼리 등을 담당하는 DAO (Data access object) 를 도입할 계획입니다   Libraries                  요소이름선택 이유NetworkGinWeb 서버이다 보니 네트워크 성능을 최우선으로 고려, 벤치마크 표를 보고 이 라이브러리를 선택Redis & cachego-redis역시 성능을 가장 중요한 지표로 보고 이 라이브러리 선택MysqlGormORM 없이는 개발하기 힘든 시대이죠. 여러 Database를 지원하고 ORM 중에서도 method chaining 을 사용하는 Gorm 을 선택Dynamoguregu dynamoAWS에서 제공하는 Dynamo 패키지를 그대로 사용하면 코드 양이 너무 많아지고 역시 method chaining 을 지원해서 선택Environment variablescaarlos0 envGo 에서는 tag 를 이용하면 좀더 코드를 간결하고 읽기 쉽게 사용할수 있는데 이 라이브러리가 환경변수를 읽어오기 쉽도록 해줌   Redis cache  func SetCache(key string, obj interface{}, expiration time.Duration) error { err := getCodec().Set(&cache.Item{ Key: key, Object: obj, Expiration: expiration, }) return err } func GetCache(key string, obj interface{}) error { return getCodec().Get(key, obj) }  Mysql  var config model.DeviceContentConfig env.GetDatabase().Where(&model.DeviceContentConfig{DeviceId: deviceId}).FirstOrInit(&config)  Dynamo if err := env.GetDynamoDb().Table(env.Config.DynamoTableProfile).Get(keyId, deviceId).All(&profiles); err == nil && len(profiles) > 0 { ... }  Environment variables  var ( Config = ServerConfigStruct{} onceConfig sync.Once ) type ( ServerConfigStruct struct { ServerEnv string `env:"SERVER_ENV"` LogLevel string .... } ) func LoadServerConfig(configDir string) { onceConfig.Do(func() {//최초 한번반 호출되도록 env.Parse(&Config) } }    Unit test   환경 구성 Test 환경에는 Redis / Mysql / Elastic search 등에 대한 independent / isolated 된 환경이 필요해서 이를 위해 docker 환경을 따로 구성하였습니다. Test case 작성은 아래와 같이 package 를 분리해서 작성했습니다.  package buzzscreen_test var ts *httptest.Server func TestMain(m *testing.M) { ts = tests.GetTestServer(m) // 환경 시작 tearDownElasticSearch := tests.SetupElasticSearch() tearDownDatabase := tests.SetupDatabase() code := m.Run() // 여기서 작성한 TestCase 들 실행 // 환경 종료 tearDownDatabase() tearDownElasticSearch() ts.Close() os.Exit(code) }  Mock server는 은 http.RoundTripper interface 를 구현해서 http.Client 의 Transport 멤버로 설정해서 구현했습니다. 아래는 Test case 작성 예제입니다.  httpClient := network.DefaultHttpClient mockServer := mock.NewTargetServer(network.GetHost(MockServerUrl)) .AddResponseHandler(&mock.ResponseHandler{ WriteToBody: func() []byte { return []byte(mockRes) }, Path: "/path", Method: http.MethodGet, }) clientPatcher := mock.PatchClient(httpClient, mockServer) defer clientPatcher.RemovePatch()  Unit test 관련해서는 내용이 방대해서 추후 다른 포스트를 통해 자세히 소개하도록 하겠습니다.  Infra API 요청 분할 AWS Application load balancer 여러 API 중에서 할당 API 를 제외한 요청은 기존의 Django 서버로 요청을 보내고 할당요청에 대해서만 Go서버로 요청을 보내도록 구현하기 위해 먼저 시도 했던 것은 AWS Application load balancer (이후 ALB) 였습니다. ALB 의 특징이 path 로 요청을 구별해서 처리할수 있었기 때문에 Allocation API 만 Go 서버 로 요청이 가도록 구현했습니다.  출처: Amazon Devops Blog, Introducing Application Load Balancer   하지만 이렇게 오랫동안 서비스 하지 못했는데 그 이유는 서버 구성이 하나 더 늘어나고 앞단에 ALB 까지 추가되다 보니 이를 관리하는데 추가 리소스가 들어가게 되어서 어떻게 하면 이러한 비용을 줄일수 있을까 고민하게 되었습니다.   Using docker & nginx  Go로 작성된 서버가 독립적인 Micro service 냐 아니면 Django 서버에서 특정 API 를 독립시켜 성능을 강화한 모듈이냐 의 정체성을 두고 생각해봤을때 후자가 조금더 적합하다보니 Go / Django 서버는 한 묶음으로 관리하는 것이 명확했습니다. Docker 를 도입하면서 nginx container 가 proxy 역할을 하고 path를 보고 Go container / Django container 로 요청을 보내는 구성을 가지게 되었습니다.  글을 마치며   시작은 미약하였으나 끝은 창대하리라 하나의 API를 이전했음에도 불구하고 Allocation API 에 대해서는 약 1/3, 서버 Instance 비용은 1/2.5 수준으로 감소했습니다.   설명: 기존 4개의 Django 인스턴스의 CPU 사용률이 모두 13% 정도 감소, Go 인스턴스의 CPU 사용율은 17% 정도   17 / (13 * 4)  ≒ 1 / 3  충분히 만족할만한 성과가 나와서 그 뒤로 몇가지 API도 Go 로 옮겼고 새로 작성하는 API 는 Go 환경 안에서 직접 구현하는 중입니다. 처음에는 호출이 많은 하나의 API 를 다른 언어로 포팅하기 위해 시작한 작업이었는데 Container 기술을 도입하는 등 서버 Infra 까지 변경하면서 상당히 큰 작업이 뒤따르게 되었습니다. 하지만 이 작업을 하면서 많은 동료들의 도움과 조언이 있었고 결국 완성할수 있었습니다. 이렇게 실험적인 도전을 성공 할수 있는 환경에 여러분을 초대하고 싶습니다! Go언어에 대한 문의나 좋은 의견도 환영합니다.
조회수 1138

[인공지능 in IT] 인공지능과 저널리즘

얼마 전, 재미있는 기사를 읽었다. 일본의 한 SF 공모전에 응모한 작품 1,400편 중 인공지능이 작성한 소설 두 편이 예선 심사를 통과했다는 내용이었다. 이 중 소설 한편의 제목은 '컴퓨터가 소설을 쓴 날'이다. 소설을 작성하는 인공지능 기술을 개발한 연구팀은 육하원칙 등의 제시어를 준 뒤, 연관어에 따라 소설을 쓰는 알고리즘을 활용했다.미디어 혹은 인공지능 분야에 생소한 독자들에게 다소 신기할 수 있겠지만, 사실 인공지능을 활용한 저널리즘은 수 년 전부터 진행 중이다. 국내에서는 2014년 서울대학교 언론정보학과의 'hci+d Lab' 이준환 교수팀이 개발한 알고리즘을 시초라고 할 수 있다. '프로야구 뉴스 로봇'이라고 불리는 소프트웨어는 KBL의 모든 경기를 자동으로 요약해 정리한다. 연구팀이 처음부터 이 같은 기능을 염두에 둔 것은 아니었고, 데이터를 시각화하는 과정에서 시각화 방식을 텍스트로 바꿔본 것이 연구의 시작이라고 한다. 위 사례는 사람이 아닌 기계가 직접 '글'을 작성했다는 점에 있어 의미가 크다. 미디어 업계에서도 디지털화는 불가항력 같은 존재가 되고 있다.얼마 전, 옥스퍼드-로이터 저널리즘 연구소에서 미디어 업계를 대상으로 조사를 시행했다. "2018년 실행해야 할 가장 중요한 과제는 어떤 것이라고 생각하는지"에 대한 물음에 "데이터 수용량을 증가시키는 것"을 가장 많이 답변했다. 모바일 알림, 웹사이트나 애플리케이션에 사용자를 등록시키는 일 등 여러 과제들이 있었지만, IT 솔루션 업계도 아닌 미디어 업계가 데이터 수용량 증가를 최우선 과제로 생각하고 있다는 사실은 개인적으로 매우 충격적이었다. 또한, "현재 귀사에서는 기사 보도에 있어 어떠한 용도로 적극적인 인공지능 기술을 도입할 예정입니까?"라는 질문에 '컨텐츠 추천', '업무 자동화', '기삿거리 탐색' 등 다양한 분야에서 인공지능 기술 도입을 계획하고 있었다. 그만큼 이미 언론에서도 인공지능 기술은 먼 세상 이야기가 아닌, 당장 피부로 느껴질 정도로 가까워졌다.세계 최대 통신사 중 하나인 'Associated Press(AP)'는 2017년 'The Future of Augmented Journalism: A guide for newsrooms in the age of smart machines'이라는 인공지능 활용 기술 가이드를 발간했다. 해당 가이드에 따르면, 인공지능은 언론에서 크게 다섯가지 영역으로 활용된다. 이에 대한 예시를 하나씩 살펴보도록 하자.첫번째로 'Machine Learning', 즉 기계학습이다. 기계학습을 이용하면, 방대한 데이터로부터 결론을 도출하는 과정을 쉽게 처리할 수 있다. 그리고 기계학습 알고리즘을 통해 기자들은 이미지를 포함한 막대한 양의 자료를 한 번에 처리할 수도 있다. 미국의 매체 'Quartz' 소속 'Sarah Slobin' 기자가 트럼프 미국 대통령의 취임 연설에 대한 기사에 기계학습을 이용한 분석 자료를 쓴 일례가 있다. 트럼프의 얼굴 표정과 연설에서 표현된 감정을 판단하는 데에 기계학습 알고리즘을 사용한 것.< 출처: Quartz, 제공: 스켈터랩스 >두번째 활용 영역은 'Language'다. 인공지능 분야에서 언어에 대한 연구는 꾸준히 이어지고 있는데, 언어 처리 분야 중에서도 저널리즘과 관련 있는 기술은 '자연어 생성'과 '자연어 처리'다. 당연하겠지만, 자동으로 문장을 생성하는 것은 언론에서 매우 유용하게 사용할 수 있는 기술 중 하나다. 'LA Times'는 'LA Quakebot'이라는 서비스를 개발했다. 'LA Quakebot'은 자연어 생성 기술을 활용해 지역에서 지진이 일어난 순간, 이미 작성된 프레임에 맞춰 기사를 작성하며, 완성된 기사는 트위터를 통해 송출한다.< 출처: LA QuakeBot 트위터, 제공: 스켈터랩스 >세번째는 'Speech'로, 저널리즘에서 대화형 인터페이스가 뉴스 소비 및 유통에 어떠한 영향을 미칠 지 관심을 가지고 있다. 이미 'AP', 'Wall Street Journal', 'BBC', 'Economist' 등 여러 미디어가 오디오 인터페이스 기술을 시도하는 것으로 알려졌다. Speech 역시 크게 두 가지로 나뉘는데, 'TTS'라고 불리는 'Text-To-Speech'를 활용하면 뉴스룸에서 제공하는 문자 기사를 음성으로 변환시키고, 합성된 음성을 콘텐츠로 송출할 수 있다. 반대로 'STT', 즉 'Speech-To-Text'를 활용하면 음성으로부터 의미를 잡아내고, 모든 의도와 목적에 맞춰 음성을 문자로 변환시키며, 이를 통해 기자들이 인터뷰 내용을 녹취하는데 소요하는 시간을 줄일 수 있다.< 출처: BBC NEWS LABS, 제공: 스켈터랩스 >네번째, 듣는 것과 녹취하는 것을 넘어 눈으로 본 것을 기록할 수 있는 'Vision' 기술이다. 컴퓨터 비전을 활용하면 빠르고 쉽게 이미지 및 영상을 분류하고 정리할 수 있다. 용이한 검색을 통해 궁극적으로 편집 속도까지 높일 수 있는 셈이다. 'AP'는 인공위성으로 수집한 영상 데이터를 공급하는 'Digital Globe'라는 기업을 통해 동남아 선박의 고해상도 위성사진을 확보했다. 이를 통해 노예선에 관한 탐사보도에 필요한 결정적인 증거를 찾으며, 2016년 공공서비스 부문 퓰리처상을 수상했다.< 출처: AP, 제공: 스켈터랩스 >마지막으로 'Robotics'를 꼽을 수 있다. 로봇 센서를 활용해 사건 사고에 대한 사람들의 반응을 실시간으로 측정할 수 있으며, 앞서 언급한 'Quakebot'의 예처럼 자연재해가 발생하는 것에 대해 다룰 수 있다. 'AP'는 2016년 하계올림픽 당시, 로봇과 원격 카메라를 이용해 기자들이 물리적으로 직접 접근할 수 없는 지역에 카메라를 설치하고, 원격 조종해 촬영했다. 또한, 드론을 이용해 이라크 모술 남동쪽 다이바가 근처에 추방된 이라크인들을 촬영해 중독 지역 난민 위기에 대해서도 보도한 바 있다.< 출처: AP, 제공: 스켈터랩스 >이렇듯 인공지능이 미디어 업계 전체에 긍정적인 영향을 주고 있으며, 이를 활용한 사례는 앞으로도 더욱 늘어날 것으로 전망한다. 다만, 지속적으로 발전하는 인공지능을 무조건 도입하는 것만이 능사는 아니다. 인공지능 기술의 확산으로 보도 속도, 보도 규모 및 범위 등에 도움될지라도, 데이터의 질에 따라 좋지 않은 기사가 나올 수 있기 때문이다. 'AP'의 스마트머신 시대 뉴스룸을 위한 가이드에도 언급된 포인트로 마무리를 해보자.1. 인공지능은 저널리즘의 도구이지, 저널리즘을 대체하지 않을 것이다.2. 인공지능은 인간과 마찬가지로 편향적이고, 실수를 할 수도 있다. 이는 데이터가 모든 것을 결정하기 때문이다.3. 인공지능이 만병통치약은 아니다. 최근 자율주행 자동차 사고 이슈처럼 기술이 극복하지 못하는 문제는 여전히 존재한다.4. 인공지능에 대해 더 많이 알아야 인공지능 활용 가능성의 문이 크게 열린다.5. 저널리즘의 도구가 변한다고 해서 저널리즘의 법칙이 변하지 않는다. 언제나 윤리와 기준은 매우 중요하다.이호진, 스켈터랩스 마케팅 매니저조원규 전 구글코리아 R&D총괄 사장을 주축으로 구글, 삼성, 카이스트 AI 랩 출신들로 구성된 인공지능 기술 기업 스켈터랩스에서 마케팅을 담당하고 있다 #스켈터랩스 #기업문화 #인사이트 #경험공유 #조직문화 #인공지능기업 #기술기업
조회수 1329

정확한 프로세스 모델을 측정하는 기준은?

이벤트 로그로부터 정확한 프로세스 모델을 도출하기 위해 고려해야 할 점은 무엇일까요?프로세스의 특성과 이벤트 로그에 맞는 적절한 알고리즘을 적용하는 것이 중요하지만 오늘은 좀 더 일반적인 사항에 대해 생각해 보겠습니다.프로세스 모델의 품질을 측정하는 4가지 기준은 Fitness, Generalization, Simplicity, Precision입니다.좋은 프로세스 모델을 발견하기 위해서는 이 4가지 기준 사이에서 균형을 잘 유지해야 합니다.[그림 1] 프로세스 모델 품질 측정의 4가지 기준Fitness(적합도)는 관찰된 이벤트 로그를 얼마나 잘 설명할 수 있는지를 나타냅니다. Fitness가 높을수록 모든 이벤트 로그의 경로를 표현하기 때문에 데이터 집합을 잘 설명할 수 있으나 수많은 경로가 프로세스 모델에 나타나게 되어 프로세스 모델이 복잡해지게 됩니다.Generalization(일반화)은 Overfitting을 피하는 것입니다. Overfitting된 모델은 모델 추출 대상이 되는 데이터(이벤트 로그)에 대해서는 정확도가 높으나 동일 프로세스에서 추출한 다른 데이터 집합에 대해서는 정확도가 낮고, 높은 오류율을 보여주게 됩니다. 따라서 Generalization 수준이 높을수록 다른 데이터에 적용했을 때의 적중률(설명 정도)이 높아져서 프로세스 모델을 다른 데이터에 적용하기가 좋습니다. 하지만, 지나치게 Generalization이 높을 경우 대상 데이터 집합에 대한 프로세스 모델 적중률만 높아지지 프로세스에 대한 의미 있는 정보를 전달하지 못하는 문제가 발생합니다.Simplicity(단순화)는 프로세스 모델을 단순하게 만드는 것입니다. 프로세스 모델이 단순할수록 쉽게 이해하고 한눈에 프로세스를 파악할 수 있으나 적합도가 떨어지게 됩니다. 적합도가 떨어지면 추출한 프로세스 모델로 설명할 수 없는 이벤트 로그가 많아지게 됩니다.Precision(정확도)은 Underfitting을 피하는 것입니다. Underfitting된 모델은 Overfitting과 달리 모델을 단순화하여 공통 경로만 표현하게 되어 프로세스를 정확하게 설명할 수 없게 됩니다. Precision이 높을수록 기존 데이터에 대해 정확하게 설명할 수 있으나 지나치게 높을 경우 다른 데이터 셋에 대한 오류율이 증가하는 문제가 생깁니다.4가지 품질 특성을 보면 Fitness와 Simplicity, Generalization과 Precision은 서로 반대되는 특성을 가지고 있습니다. 즉, Fitness가 너무 높으면 Simplicity가 낮은 문제가 생기고 Generalization이 높으면 Precision이 낮은 문제가 생기게 됩니다.Overfitting과 Underfitting 예제를 통해 좀 더 살펴보도록 하겠습니다.[그림 2] Underfitting과 Overfitting 그림[그림 2]에서 볼 수 있듯이 Underfitting은 데이터 분류 기준을 단순하게 구할 수 있으나 새로운 데이터 집합을 Underfitting된 모델에 대입하면 의미 있는 결과를 얻기가 힘듭니다. 이에 반해 Overfitting은 모든 데이터를 정확히 분류하고 있으나 데이터의 특성을 일반화시킬 수 없습니다. [그림 3] Underfitting 모델[그림 3]의 경우 모든 경로를 표현 가능하여 Fitness 만족, 다른 모델에도 적용 가능하여 Generalization 만족, 모델도 간단하여 Simplicity도 만족하지만 실제 프로세스가 어떻게 수행되는지 설명해 주지 못해 도출된 프로세스 모델에서 유의미한 정보를 얻을 수 없습니다. 즉, 모델이 Underfitting되어 Precision 조건을 만족시키지 못합니다.[그림 4] Overfitting 모델[그림 4]는 관찰된 이벤트 로그를 모두 나열한 프로세스 모델입니다. 이렇게 할 경우 모델을 도출할 때 사용한 이벤트 로그의 프로세스 패턴을 모두 나타내어 Fitness와 Precision은 만족하나 Simplicity와 Generalization은 만족하지 않습니다. Overfitting된 모델도 프로세스 모델에서 유의미한 정보를 얻을 수 없습니다.이상과 같이 Fitness, Generalization, Simplicity, Precision 4가지 기준을 잘 조화시켜야 정확한 프로세스 모델 도출이 가능합니다.#퍼즐데이터 #개발팀 #개발자 #개발후기 #인사이트
조회수 5953

유용한 Javascript UI Component 라이브러리 소개

웹 애플리케이션을 개발할 때 기능적으로는 무관하지만, 사용자에게 인터렉티브하고 심미적으로 예쁜 디자인을 제공하고 싶은 경험이 있을 것입니다. 하지만 막상 직접 구현을 하는 것은 생각보다 시간이 오래 걸리고, 구현하더라도 양질의 UI가 나오지 않는 경우들이 있습니다. 그래서 이번 글에서는 쉽고 빠르게 양질의 UI를 제공해주는 라이브러리를 소개해 드리려고 합니다.Spin.js작업을 완료하거나 페이지가 넘어갈 때 아무런 말도 없이 그냥 기다리는 경우가 있습니다. 이럴 경우 사용자에게 현재 기다리는 중이라는 것을 표현하는 것이 좋습니다. 이러한 기능을 제공해주는 라이브러리가 바로 Spin.js입니다.Spin.js는 위의 그림과 같이 로딩 중이나 무언가를 진행 중이라는 것을 알려주는 사용하기 쉬운 Javascript 라이브러리입니다. 이미지 없이 사용되어 매우 가볍게 사용할 수 있습니다. 그리고 사용할 때 쉽게 설정하여 사용할 수 있으며 대다수 브라우저를 지원합니다.Spin.js / DownloadDatatables많은 양의 정보를 쉽게 볼 수 있도록 테이블로 정리해야되는 경우가 있습니다. 그러나 많은 양의 정보를 처리할 때 쉽게 원하는 정보를 찾을 수 있어야 하고 정보가 쉽게 정렬이 될 수 있어야 합니다. 이러한 기능을 제공해주는 라이브러리가 바로 Datatables입니다.Datatables는 위의 그림과 같이 테이블을 동적인 테이블을 만들어주는 JQuery Javascript 라이브러리입니다. 다양하게 정렬할 수 있도록 테이블을 만들수 있으며, 따로 정보를 찾아주는 기능을 만들어주지 않아도 검색을 할 수 있는 기능을 제공하고, 정보를 편하게 볼 수 있도록 구성을 제공합니다. 그리고 DOM, Ajax, Server-Side Processing으로 쉽게 정보를 Datatables로 만들 수 있습니다.DatatablesCurtain.js긴 내용으로 된 하나의 페이지를 섹션별로 효과적으로 내용을 전환해야 되는 경우가 있습니다. 그러나 사용자에게 혼란을 주지 않으면서 전환 효과를 만들어 내야 합니다. 이러한 기능을 제공해주는 라이브러리가 바로 Curtain.js입니다.Curtain.js는 위의 그림과 같이 마치 커튼이 걷히는 것처럼 내용 전환 효과를 주는 JQueryJavascript 라이브러리입니다. 각 내용을 화면에 고정하고 스크롤이나 키보드를 통해 화면을 전환하여 트렌디하면서 인터렉티브한 느낌을 쉽게 제공할 수 있습니다.Curtain.js / DownloadTurn.js위의 Curtain.js가 세로형태의 전환 효과를 내는 것이었다면 가로형태의 전환 효과를 내야 하는 경우가 있습니다. 이러한 기능을 제공해주는 라이브러리가 바로 Turn.js입니다.Turn.js는 위의 그림과 같이 책장을 넘기는 듯한 내용 전환 효과를 주는 JQuery Javascript 라이브러리입니다. 하나에 페이지를 섹션별로 나눠서 키보드를 통해 화면을 전환하여 책장을 넘기는 느낌을 제공해 스마트폰이나 태블릿에서 책을 읽는 듯한 느낌을 쉽게 제공할 수 있습니다.Turn.js / DownloadGlfx.js이미지를 따로 수정해서 올리는 것이 아니라 웹에서 바로 밝기를 조정하거나 다양한 효과를 주고 싶은 때도 있습니다. 이러한 기능을 제공해주는 라이브러리가 바로 Glfx.js입니다.Glfx.js는 위의 그림과 같이 다양한 효과를 주는 WebGL기반의 Javascript 라이브러리입니다. 이미지에 Blur 효과, 세피아, 밝기 조절, 모자이크처리 등 다양한 효과를 다양한 설정을 통해 쉽게 사용 할 수 있습니다. 그러나 WebGL 기반으로 되어 있어서 WebGL을 지원하는 브라우저만 가능합니다.Glfx.js / DownloadJQuery Tag-it태그를 넣을 때 쉽게 수정 가능하게 하고 자동완성기능을 넣고 싶은 때도 있습니다. 이러한 기능을 제공해주는 라이브러리가 바로 JQuery Tag-it입니다.JQuery Tag-it은 위의 그림과 같이 태그에 대한 JQuery Javascript 라이브러리입니다. 쉽게 태그를 넣고 지울 수 있으며 태그에 대해 자동완성 기능을 지원합니다. 그리고 각 태그에 대해 이벤트를 줄 수 있어서 매우 유용하게 사용하실 수 있습니다.JQuery Tag-it / DownloadTinycon새 글의 개수나 접속자 수에 대한 정보를 사용자에게 알리고 싶은 때도 있습니다. 이럴 경우 브라우저 탭에 정보를 제공하는 경우가 있습니다. 이러한 기능을 제공해주는 라이브러리가 바로 Tinycon입니다.Tinycon는 위의 그림과 같이 파비콘에 동적인 숫자를 통해 정보를 알리는 Javascript 라이브러리입니다. 매우 쉽게 사용할 수 있으며, 설정을 통해 어떤 내용을 숫자로 표현할 것인지를 쉽게 사용자화 할 수 있습니다. 파비콘에 경우 브라우저 탭에 항상 보이기 때문에 아주 유용하게 사용할 수 있을 것 같습니다. 그러나 현재 크롬, 파이어폭스, 오페라 브라우저만이 지원 가능합니다.Tinycon / Download3D GALLERY사진이나 슬라이드 탭을 보여주기 위해 갤러리 공간을 만듭니다. 그래서 좀 더 효과적으로 보여주기 위해 다양한 효과를 넣는 경우가 있습니다. 이러한 기능을 제공해주는 라이브러리가 바로 3D GALLERY입니다.3D GALLERY는 위의 그림과 같이 내용을 3D로 나열해 보여주는 JQuery Javascript 라이브러리입니다. 간단한 설정으로 3D로 배치하고 움직이도록 할 수 있습니다. 그리고 자동으로 내용을 넘어가게 할 수도 있고 다양하게 바뀌는 효과를 줄 수 있습니다.3D GALLERY / Demo글을 마치면서이번 글에서는 UI Component Javascript 라이브러리들에 대해 알아봤습니다. 위의 라이브러리로 좀 더 쉽고 빠르게 양질의 웹 애플리케이션을 개발할 수 있었으면 좋겠습니다.#스포카 #개발자 #디자이너 #협업 #Javascript #라이브러리 #꿀팁 #유용한정보
조회수 1059

[인공지능 in IT] 구글이 말하는 인공지능의 혁신성

지난 2018년 5월 8일부터 5월 10일까지 3일간, 미국 샌프란시스코에서 '구글 I/O 2018(Google Input/Ouput 2018)'이 열렸다. 구글 I/O는 매년 구글이 혁신적인 제품을 선보이는 행사로, 구글의 신제품과 신기술을 가장 먼저 접할 수 있는 자리다. 필자는 지난 몇 년간 구글IO를 지켜봤지만, 개인적으로 이번만큼 신선한 충격을 받지는 못했던 것 같다.< 구글 I/O 2018, 출처: 구글, 제공: 스켈터랩스 >구글 선다 피차이(Sundar Pichai) CEO는 올해 구글 듀플렉스(Duplex)라는 음성 기술을 시연했다. 구글 듀플렉스는 시연을 통해 미용실과 레스토랑에 스케줄을 예약하며, "Mm-hmm"이나 "Aha"라고 자연스러운 대화 흐름을 선보여 많은 사람에게 경외 혹은 두려움을 불러 일으켰다. 구글 듀플렉스가 베이퍼웨어(Vaperware, 개발 중이지만 아직 완성되지 않은 또는 완성되지 않을 수 있는 소프트웨어)일 가능성도 있지만, 구글의 인공지능 기술 수준을 전세계에 알리기에 충분한 계기라고 생각한다.< 구글 듀플렉스, 출처: 구글, 제공: 스켈터랩스 >구글IO 2018을 보며 스스로에게 질문을 던졌다. 구글이라는 기술 공룡은 어떻게 혁신의 아이콘이 될 수 있었을까? 먼저 혁신의 사전적 의미를 살펴보면 다음과 같다. '묵은 풍속, 관습, 조직, 방법 따위를 완전히 바꾸어서 새롭게 함.' 여기서 가장 집중할 부분은 '완전히 바꾸어서 새롭게 한다는 것'으로, 대다수의 사람은 짠하고 나타나는 새로운 기술을 떠올릴 것이다. 틀린 말은 아니다. 다만, 조금 다른 관점으로 생각해본다면 기술이라는 결과물을 만들기 위해, 어떠한 방식으로 접근(Approach)했는지도 중요할 것이다.이번 구글IO 2018 중 듀플렉스를 시연하며 선다 피차이 CEO가 던진 질문을 끝으로 짧은 글을 마무리한다."60%의 소상공인들은 온라인 예약 시스템을 가지고 있지 않다. 이를 인공지능이 해결할 수 있지 않을까?"질문만 듣고 판단한다면, 구글 자체가 거대한 인공지능 기술기업이기에 당연히 온라인 예약시스템을 대체하거나 더 요긴하게 사용할 수 있는 인공지능 플랫폼을 만들 것이라고 생각할 것이다. 그러나 구글은 다른 관점에서 접근했다."온라인 예약 시스템이 없다면, 인공지능이 직접 전화를 걸면 된다"고.이호진, 스켈터랩스 마케팅 매니저조원규 전 구글코리아 R&D총괄 사장을 주축으로 구글, 삼성, 카이스트 AI 랩 출신들로 구성된 인공지능 기술 기업 스켈터랩스에서 마케팅을 담당하고 있다#스켈터랩스 #기업문화 #인사이트 #경험공유 #조직문화 #인공지능기업 #기술기업
조회수 1092

잔디 iOS 개발자 Chris, 그가 처음으로 공개한 '잔디 1호 사원' 스토리

편집자 주: 잔디와 함께 하고 있는 멤버는 총 50여 명. 국적, 학력, 경험이 모두 다른 이들이 어떤 스토리를 갖고 잔디에 합류했는지, 무슨 일을 하고 있는지 궁금해하는 분들이 많습니다. 잔디 블로그에서는 이 궁금증을 해결해 드리고자 ‘맛있는 인터뷰’를 통해 ‘잔디’ 멤버들의 이야기를 다루고 있습니다.◇ 우리가 앉아 있는 이 공간이 어떤 곳인지 소개해 달라Chris: 설마 했다. 내가 맛있는 인터뷰 대상자가 될지는.. 머리가 멍해 고통받던 중 당신이 추천한 그릴 타이로 오늘 장소를 선정했다. 이름만 들었을 땐 ‘거기 뭥미?’ 이랬는데, 와보니 알겠다. 예전에 와 본 적이 있다.◇ 자기소개 좀 해달라C: 반갑다. 잔디에서 iOS 개발 파트를 담당하고 있는 1호 사원 Chris라고 한다. 아주 오랜 기간 동안 원래 이름인 ‘봉규’라고 불렸다가 얼마 전 회사 내 호칭에 변화가 생겼다. 아직 Chris로 불리는 게 어색하다.◇ 어떤 일을 하며 월급을 받고 있는지?C: 앞서 소개했듯 난 iOS 개발자다. 이 글을 읽는 독자분들 중 아이폰으로 ‘잔디’를 사용 중이라면, 필시 내가 개발한 잔디를 이용하고 있는 거다. 마음이 조금 아프지만 기획에 대한 관심으로 지난 겨울 잠시 PM 팀으로 외도했었다. 하지만 결국 내 마음의 고향, iOS 개발로 돌아왔다.◇ PM팀으로 외도를 했던 이유가 궁금하다C: 기획이라는 업무에 관심이 많았다. 개발을 하다 보니 자연스레 기획에도 관심을 갖게 되었다. 한 번쯤 해보고 싶었던 일이었기 때문에 롤이 주어졌을 때 정말 재미있게 일했다.하지만 PM 일을 직접 해보니 마냥 재미있기만 하지는 않더라. 비즈니스는 물론이고 개발자와 디자이너의 의견을 수렴해 조율까지 해야 하는데 모두의 의견을 100% 반영할 수 없으니 여간 괴로운 일이 아니더라. 기획자의 길이 쉽지 않다는 것을 깨닫게 되었다.그리고 PM의 업무라는 게 쉽게 눈에 띄지 않는 일이다. 제품이 아무리 잘 나와도 기획자에게 ‘기획 참 잘나왔어요’ 라고 말하는 경우를 많이 접하진 않았을 거다. 여러분 주위에 기획자를 만나게 되면 ‘고생이 많으십니다’라고 응원 한마디 해줬으면 좋겠다.◇ iOS 개발자로 컴백한 이유는 무엇인가? 향간의 소문엔 코딩이 그리워 개발자로 돌아갔는 소문이 있다C: 회사 측에서 기획보다는 iOS 개발을 다시 맡아주면 좋겠다는 이야기를 들었다. 사실 별다른 고민 없이 제안을 받아들였다. 아무래도 초기부터 개발한 자식 같은 iOS가 늘 머리 한 구석에 있었다. 물론, 잔디를 사랑하는 마음도 크게 한 몫 했다. 결코 어필하고 싶어 이런 멘트를 남기는 게 아니다.◇ 보여주기 멘트인 것 같지만 감동 받았다. 그렇다면 Chris에게 잔디 iOS란 무엇인지 조금 더 말해달라C: 나의 분신이다.  iOS는 곧 Chris다. 아무것도 없는 백지상태에서 지금에 이르기까지 수많은 과정이 있었고, 그 과정의 중심엔 언제나 내가 있었다. iOS는 분신이라는 단어 외엔 표현할 방법이 없다. 오바가 아니라 사무실 어딘가에서 누군가 ‘iOS’ 라고 속삭이면 몸이 반응한다. iOS에 대한 이야기는 곧 나에 대한 이야기와 마찬가지이니까.내가 곧 잔디 iOS이자, 잔디 iOS가 곧 나이다.그만큼 애착을 갖고 개발 업무에 임하고 있다.◇ 멘트가 찰지다. 듣기론 PM 팀의 데니스와 특별한 인연이 있다고 하는데?C: 동아리 이야기를 하는 것 같다. 사회에 나오기 전 연합 동아리 활동을 한 적이 있는데, 데니스가 그 동아리 후배다. 기수 차이가 많이 나 직접적으로 알던 사이는 아니었다. 내가 동아리에 잔디 채용 공고를 공유해 데니스가 합류하게 되었다. 특별한 인연이라면 특별하다고 볼 수 있다.◇ 어떤 동아리인지 궁금하다SOPT라는 연합 동아리로 선배들이 후배들에게 개발/디자인 등에 대해 강의하는  동아리다. 당시 나는 학년 차가 조금 되어 수업을 듣기보단 가르치는 역할을 맡았어야 했는데, 매주 시간을 내어 수업을 준비할 자신이 없어 디자인 수업을 들었다.◇ 잔디 1호 사원은 역시 남다른 것 같다. 디자인 수업은 어땠는지?C: 그 수업을 통해 내가 디자인에 소질이 없다는 사실을 깨닫게 되었다. 그림을 그리면 늘 내가 생각한 것과는 다른 결과물이 나오더라.◇ 그런데 정말 잔디 1호 사원인가?C: 말 그대로 1호 사원이다. 회사가 법인으로 등록하기 이전부터 함께 했다. 얼마 전 잔디 2주년 파티가 있었다. 나는 입사한 지 2년이 넘었다. 격세지감을 느낀다. 처음 잔디에 들어왔을 때, 나를 제외한 모든 사람이 C-Level이었다. 그리고 나서 개발자, 디자이너가 순차적으로 들어왔던 걸로 기억한다.◇ 법인 설립도 전에 잔디를 어떻게 알고 지원했나?C: 제대를 3개월 앞둔 군인 시절, 아이폰 개발자를 찾는 연락을 받았다. 그렇지 않아도 제대하고 바로 개발 경험을 쌓을 수 있었으면 좋겠다고 생각했다. 솔직히 말하면 그 당시엔 잔디가 어떤 회사인지 탐색이나 해보자는 생각에 멤버들을 만났다.◇ 그럼 사람들을 만나고 입사를 결심한 건가?C: 당시에는 아무것도 없었다. 잔디라고 말은 해도 유형적인 형태의 무언가가 존재하지 않았다. 멋진 사람들과 함께하며 일을 배울 수 있을 것 같다는 생각에 합류했다.◇ 마음가짐이 남다를 것 같다C: 내 스스로 창립 멤버라 생각하고 있다. 어찌 되었든 잔디가 지금의 모습을 갖추기 전부터 함께 해서인지 애착이 남다르다. 첫 직장이라는 사실도 한 몫하고 있고.◇ 그때로 다시 돌아가면 똑같은 결정을 할 것인가?C: 물론이다. 솔직히 좋은 결정이었다고 생각한다. 잔디가 이렇게 잘 성장하고 있고, 지금은 누구보다도 잔디의 성공을 확신한다.◇ 마지막 질문이다. 여름 휴가 계획은?C: 스타트업인이 휴가라니? 하하. 농담이다. 아쉽지만 아직 여름 휴가 계획이 없다. 생기면 알려주겠다.◇ 맛있는 인터뷰의 공식 마무리! 다음 인터뷰이에게 묻고 싶은 질문이 있다면?C: 꼭 물어봐 주셨으면 한다. “잔디에서 이루고 싶은 꿈이 있다면?”을 물어봐 달라.#토스랩 #잔디 #JANDI #iOS #개발자 #모바일개발자 #앱개발자 #팀원소개 #팀원인터뷰 #팀원자랑 #기업문화 #조직문화 #사내문화
조회수 770

HBase상 트랜잭션 라이브러리 Haeinsa를 소개합니다 - VCNC Engineering Blog

비트윈에서는 서비스 초기부터 HBase를 주요 데이터베이스로 사용하였습니다. HBase에서도 일반적인 다른 NoSQL처럼 트랜잭션을 제공하지 않습니다. HBase, Cassandra와 MongoDB는 하나의 행 혹은 하나의 Document에 대한 원자적 연산만 제공합니다. 하지만 여러 행에 대한 연산들을 원자적으로 실행할 수 있게 해주는 추상화된 트랜잭션 기능이 없다면 보통의 서비스 개발에 어려움을 겪게 됩니다. 비트윈 개발팀은 이런 문제를 해결하기 위해 노력했으며, 결국 HBase에서 트랜잭션을 제공해주는 라이브러리인 Haeinsa를 구현하여 실제 서비스에 적용하여 성공적으로 운영하고 있습니다. VCNC에서는 Haeinsa를 오픈소스로 공개하고 이번 글에서 이를 소개하고자 합니다.Haeinsa란 무엇인가?Haeinsa는 Percolator에서 영감을 받아 만들어진 트랜잭션 라이브러리입니다. HAcid, HBaseSI 등 HBase상에서 구현된 트랜잭션 프로젝트는 몇 개 있었지만, 성능상 큰 문제가 있었습니다. 실제로 서비스에 적용할 수 없었기 때문에 Haeinsa를 구현하게 되었습니다. Haeinsa를 이용하면 다음과 같은 코드를 통해 여러 행에 대한 트랜잭션을 쉽게 사용할 수 있습니다. 아래 예시에는 Put연산만 나와 있지만, 해인사는 Put외에도 Get, Delete, Scan 등 HBase에서 제공하는 일반적인 연산들을 모두 제공합니다.HaeinsaTransaction tx = tm.begin(); HaeinsaPut put1 = new HaeinsaPut(rowKey1); put1.add(family, qualifier, value1); table.put(tx, put1); HaeinsaPut put2 = new HaeinsaPut(rowKey2); put2.add(family, qualifier, value2); table.put(tx, put2); tx.commit(); Haeinsa의 특징Haeinsa의 특징을 간략하게 정리하면 다음과 같습니다. 좀 더 자세한 사항들은 Haeinsa 위키를 참고해 주시기 바랍니다.ACID: Multi-Row, Multi-Table에 대해 ACID 속성을 모두 만족하는 트랜잭션을 제공합니다.Linear Scalability: 트래픽이 늘어나더라도 HBase 노드들만 늘려주면 처리량을 늘릴 수 있습니다.Serializability: Snapshot Isolation보다 강력한 Isolation Level인 Serializability를 제공합니다.Low Overhead: NoSQL상에서의 트랜잭션을 위한 다른 프로젝트에 비해 오버헤드가 적습니다.Fault Tolerant: 서버나 클라이언트가 갑자기 죽더라도 트렌젝션의 무결성에는 아무 영향을 미치지 않습니다.Easy Migration: Haeinsa는 HBase를 전혀 건드리지 않고 클라이언트 라이브러리만 이용하여 트랜잭션을 구현합니다. 각 테이블에 Haeinsa 내부적으로 사용하는 Lock Column Family만 추가해주면 기존에 사용하던 HBase 클러스터에도 Haeinsa를 쉽게 적용할 수 있습니다.Used in practice: 비트윈에서는 Haeinsa를 이용하여 하루에 3억 건 이상의 트랜잭션을 처리하고 있습니다.Haeinsa는 오픈소스입니다. 고칠 점이 있다면 언제든지 GitHub에 리포지터리에서 개선에 참여하실 수 있습니다.Haeinsa의 성능Haeinsa는 같은 수의 연산을 처리하는 트랜잭션이라도 소수의 Row에 연산이 여러 번 일어나는 경우가 성능상 유리합니다. 다음 몇 가지 성능 테스트 그래프를 통해 Haeinsa의 성능에 대해 알아보겠습니다.아래 그래프는 3개의 Row에 총 6개의 Write, 3개의 Read연산을 수행한 트랜잭션의 테스트 결과입니다. 두 개의 Row에 3Write, 1Read 연산을 하고, 한 개의 Row에 1Read 연산을 한 것으로, 비트윈에서 가장 많이 일어나는 요청인 메시지 전송에 대해 시뮬레이션한 것입니다. 실제 서비스에서 가장 많이 일어나는 종류의 트랜잭션이라고 생각할 수 있습니다. 그런데 그냥 HBase를 사용하는 것보다 Haeinsa를 이용하는 것이 더 오히려 좋은 성능을 내는 것을 알 수 있습니다. 이는 Haeinsa에서는 커밋 시에만 모든 변경사항을 묶어서 한 번에 반영하기 때문에, 매번 RPC가 일어나는 일반 HBase보다 더 좋은 성능을 내는 것입니다.HBase 클러스터가 커질수록 트랜잭션 처리량이 늘어납니다. HBase와 마찬가지입니다.HBase 클러스터의 크기에 따른 응답시간 입니다. HBase와 다르지 않습니다..아래 그래프는 2개의 Row에 각각 한 개의 Write, 나머지 한 개의 Row에는 한 개의 Read 연산을 하는 트랜잭션에 대해 테스트한 것입니다. 각 Row에 하나의 연산만이 일어나기 때문에 최악의 경우라고 할 수 있습니다. 처리량과 응답시간 모두 그냥 HBase를 사용하는 것보다 2배에서 3배 정도 좋지 않은 것을 알 수 있습니다. 하지만 이 수치는 DynamoDB 상의 트랜잭션과 같은 다른 트랜잭션 라이브러리와 비교한다면 상당히 좋은 수준입니다.HBase보다 처리량이 떨어지긴 하지만, 클러스터가 커질수록 처리량이 늘어납니다.HBase보다 응답시간이 크긴 하지만 클러스터 크기에 따른 변화가 HBase와 크게 다르지 않습니다.프리젠테이션Haeinsa에 대한 전반적인 동작 원리와 성능을 소개하는 프리젠테이션입니다. 좀 더 자세히 알고 싶으시다면 아래 프리젠테이션이나 Haeinsa 위키를 참고해주세요.<iframe class="speakerdeck-iframe" frameborder="0" src="//speakerdeck.com/player/2d4b2bd00fc201314ae312fe4cd13937?" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" style="border: 0px; background: padding-box rgba(0, 0, 0, 0.1); margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 750px; height: 563px;">
조회수 1307

공포의 Swift3

라이비오를 시작하며 이전 사업과는 다르게 어쩔 수 없이 안고 출발했던 핸디캡이 있었다."너는 개발자가 아니잖아."사실이다.아무래도 위제너레이션이나 오드리씨를 할 때는 영업과 마케팅 위주의 조직이었다보니 급하면 급한대로 내가 직접 할 수 있는 것들이 많았다. 하지만 앱 개발은 완전 다른 차원의 이야기라 (디자인은 직접 맡고 있지만) 새롭게 배워야 할 부분이 정말 많았다.'그래도 이제와서 어떻게 개발을 배우겠어.' 싶어서 공부를 시작했다가 그만두기도 몇 번.개발의 ㄱ자라도 잡아보자 싶어 HTML이나 CSS, PHP 같은 언어들을 끄적끄적 공부해보곤 했었는데, 기본서 수준이거나 Codecademy 따라해 본 것이 전부이다보니 실제로 뭔가를 해 볼 수준에는 전혀 미치지 못했다.그래서 이번에는 돈을 좀 쓰더라도 독학 말고 수업을 들어보자고 생각했다.새해를 맞아 큰 맘 먹고 백만원 상당의 패스트캠퍼스 수업을 질러 Swift3 를 배우게 되었다. (iOS 개발언어)(나만의 앱을 만들고 싶은데 넘나 어려운 것..........)벌써 오늘이 11강째인데 전체가 16강인 것을 생각하면 어느새 진도를 많이 뺐다.그런데 문제는,초기 문법 배울 때는 괜찮았는데예제 따라하기로 들어가면서부터 수준이 높아져 따라갈 수가 없다는 것이다.특히 지난 주에는 수업을 들으면서 동시에 절망하는 수준에 이르렀는데다들 아무 말도 없고 키보드 마우스 소리만 들리기에, 나만 이해를 못하고 있다는 생각에 중반부터는 아예 수업 듣기를 포기하고 조용히 yes24를 켜서 Swift 기본서를 주문했다. (빠른 상황판단ㅋㅋㅋㅠㅠㅠ)그런데 수업을 마친 후 강사님이 "오늘 너무 빨랐나요?"하고 물으니,수강생들이 너도나도 손을 들며 너무 빨랐다고, 놓쳤다고 얘길 하는 게 아닌가!나만 놓친게 아니라는 (어리석은..) 잠깐의 위로를 받았다.하지만 설날이 지나고,이제 좀 더 쉬워졌게지 하는 생각으로 오늘 11강에 들어갔더니 웬걸.여전히 어렵고, 이해가 0되는 현상이 발생했다.역시 공부에는 지름길도 속임수도 없다.아무래도 Swift 책을 때며 따로 복습해야 따라갈 수 있을 것 같다.슬프게도 두께가 이만큼이다. (1473페이지 중에 226페이지까지 복습했다^^............)*강사님이 쓰신 책도 있지만 Objective C 라는 다른 언어와의 비교를 중심으로 설명하셔서 초심자에게는 오히려 어려운 부분이 있었다. 아예 초보에게는 '꼼꼼한 재은씨의 스위프트3 (기본편)' 책을 추천한다. 제목만큼 꼼꼼하게 쓴 책이다. (홍보는 아닙니다만 책이 너무 좋아서 구매링크)뭐 하나 쉬운 것이 없지만, 그래도 서른이 되기 전에 좀 더 제대로 코딩 공부를 해 보게 되어서 다행이다.언어 + 수학 + 논리의 결합인 코딩은 어렵지만 꽤 아름답다.난 문돌이라 못 한다고 한계만 짓지 않으면 충분히 할 수 있을 것 같다.대신 만만하게 생각하지는 말고 꾸준히...........올해 안에 꼭 내 이름으로 된 앱 출시를 해봐야겠다.#라이비오 #비전공개발자 #iOS #Swift #인사이트 #경험공유
조회수 1799

Amazon SageMaker는 처음이지?

Overview브랜디 랩스를 사랑해주시는 여러분, 안녕하세요. 개발자 오-연주입니다. 지난 4월, Brandi Back-end 개발자 분들과 코엑스에서 열렸던 AWS Summit(04.18 - 04.19)에 다녀왔습니다!여러 세션을 듣는 와중에 우연히 AI machine learning 를 쉽게 도와주는 Cloud Machine learning Flatform인 Amazon SageMaker에 대해 들었습니다. 듣던 중 머닝러닝에서 학습을 시켜 그 데이터로 ‘Brandi 서비스와 연관지으면 어떨까’ 라는 생각을 했는데요. 그래서 오늘은 많은 분들의 관심사인 머신러닝 학습관련 Amazon Amazon SageMaker에 대한 글을 쓰려고 합니다.sage는 마법사, 현자라는 의미입니다.sageMaker를 create하자!“자, 퐈이팅 넘치게 신나게 sagemaker를 create해볼까요!” 했는데…Seoul Region이 없다!현재 지원되는 리전은 아직 네 군데입니다. 저는 제일 있어 보이는 미국 동부의 버지니아를 선택하겠습니다.1] EU (Iceland) 2] US West (Oregon) 3] USEast (N. Virginia) 4] US East (Ohio)SageMaker를 create하기 전에는 학습할 데이터와 학습 모델을 저장할 S3 Bucket이 필요합니다.1. Default 값으로 S3를 만드세요.중요한 점은, bucket 이름이 “sagemaker-” 로 시작되어야 한다는 것입니다. 그래야 나중에 notebook instance가 어느 곳에 데이터를 저장할지 알 수 있습니다.Next, Create bucket 버튼을 누르다 보니, S3 Bucket이 생성되었습니다.2. Create notebook instance 버튼을 눌러 SageMaker를 만들어 봅시다!원하는 이름을 지어줍니다. 저는 machineLearningTest 라고 지었어요. IAM role 선택하는 부분에서 None을 눌러 Default 값으로 sageMaker를 만듭니다.인고의 Pending 시간3. Pending이 끝나고 “open” action을 선택하면 Jupyter가 열립니다.Jupyter(Jupyter Notebook)는 오픈 소스로 라이브 코드, 등식, 코드에 대한 시각화를 위해 사용됩니다. 또한 description을 위한 텍스트 문서(마크다운 등)를 지원하는 웹 어플리케이션입니다. 이렇게 하면 코드에 대한 문서화가 가능합니다. 이 글에서는 Jupyter Notebook을 통해 데이터를 학습하고, 그 데이터를 테스트하겠습니다. 제가 진행한 전체 코드 스크립트(entire script)는 이 글의 마지막 부분에 기술있으니 참고해 주세요.자, 이제 드디어 머신러닝 학습을 시킬 차례입니다. 머신러닝 학습에 꼭 필요한 키워드 두 가지를 뽑아봤는데요. - Dataset: 정제된 데이터와 그 데이터에 대한 label을 정리해 놓은 데이터 모음      - Machine learning Algorithm: 기계학습 알고리즘 우리는 MNIST 데이터셋을 k-means 알고리즘으로 학습시킬 겁니다.1)MNIST Dataset기계학습 알고리즘을 사용할 때 가장 기본적으로 테스트하는 데이터셋으로 MNIST 데이터셋이 있습니다. 이것은 사람이 0부터 9까지 숫자 중 하나를 손글씨로 쓴 이미지 데이터와, 해당 이미지에 대한 레이블(0 - 9)이 6만 개 들어있는 학습 데이터셋입니다. 각 이미지는 가로와 세로가 각각 28 픽셀로서, 각 픽셀은 0부터 255 사이의 숫자가 있습니다. 다시 말해, 하나의 이미지는 28 x 28 = 784개의 숫자로 이루어진 데이터입니다. 하나의 이미지를 나타내는 데이터의 array > length가 784라고 표현할 수 있겠네요.MNIST dataset2)k-means지금 만든 SageMaker 학습 알고리즘은 AWS 튜토리얼에서 제시한 K-means를 사용할 예정입니다. k-means는 label 없이, 즉 정답을 모르는 상태로 학습을 하는 비지도 학습 (unsupervised learning) 알고리즘 중 가장 쉽고 많이 쓰입니다. 정답을 모르니, ‘비슷한 애들끼리 뭉쳐봐’ 라고 하고, 알고리즘은 비슷한 친구들끼리 뭉쳐 놓습니다. k-means에서 k는 ‘k개 덩어리로 뭉쳐주세요’라고 제시하는 숫자입니다. 우리는 0부터 9까지 비슷한 친구들끼리 모이게 하고 싶으니 k=10을 쓸 겁니다.지금부터 해야 할 TO DO!1. MNIST 데이터셋을 다운로드받고, 우리가 학습시키기 좋도록 정제하기(preprocessing)2. Amazon SageMaker를 통하여 데이터 학습시키기(training job)3. Amazon SageMaker를 통하여 학습된 데이터를 배포하기(Deploy the model)4. 배포된 모델에 요청을 보내 테스트 데이터에 대한 예측값을 받아오기(inference)4. Jupyter 노트북 인스턴스 생성하기Jupyter에 New Notebook(conda_python3)을 선택해 새로운 노트북을 생성합니다.5. 학습시키기 위한 기본 셋팅드디어 코딩 시작입니다! (의욕활활) 초기 설정해두었던 IAM role, S3 Bucket, MNIST 다운로드, 다운받은 데이터 등을 확인하세요. 글보다 코드로 주석을 보는 게 가독성이 더 좋습니다. 아래 노트북을 통해 마크다운, 주석처리를 통해 description을 해두었으니 참고 바랍니다.외부에서 MNIST 다운로드가 쉽도록 한 url로 MNIST를 다운받는데 성공했습니다. MNIST 데이터셋 내용물 중 하나를 jupyter notebook에 그려서 제대로 다운 받았는지 show_digit() 함수를 작성해 확인하겠습니다.서른 번째 데이터는 누군가 3을 손글씨로 쓴 이미지입니다.6. 머신러닝 학습하기이 세션에서는 기계학습 알고리즘 설정, 학습할 데이터 경로를 지정하겠습니다. 그 후 MNIST 학습 데이터를 S3 버킷에 옮겨 저장합니다.kmeans.fit() 함수를 호출해 직접 학습을 시켜볼까요? 학습 과정은 상당히 오래 걸린다고 했는데 다행히 4분 만에 학습이 끝났습니다.여기서 잠깐! 여기서 k = 10에 대해서 조금 더 알아보도록 할게요. cluster란 한 지점에 점을 찍고 데이터 분석을 한 뒤, 비슷한 데이터들의 군집을 만들어 주는 것입니다. k-means가 진행되면서 각 cluster의 중심이 서로가 잘 뭉치는 방향으로 이동합니다. 직접 그려봤어요(부끄).7. 학습된 모델을 배포하기학습을 시키면 테스트를 하거나 사용할 수 있어야겠죠? 학습된 모델을 배포해 주세요.8. 배포된 모델 테스트 진행하기배포된 모델에 valid_set 데이터로 검증 데이터를 진행합니다..predict() 함수를 호출하면 새로운 이미지가 어떤 cluster에 속했는지 예측 결과를 알려줍니다. 가장 가까운 cluster가 0번이라고 예측 결과를 반환했네요. 또한 cluster 중심과의 거리는 5.85라고 알려줍니다. 여기서 중요한 점은 cluster 번호와 실제 숫자는 일치하지 않는다는 겁니다. 알고리즘은 임의로 cluster 중심에 번호를 매기는데, 꼭 0번 클러스터가 숫자 ’0’을 뭉쳐놓은 건 아니에요!9. 데이터 예측해보기더 많은 데이터를 예측해볼까요? valid set에 있는 100개 데이터를 예측해봅시다! 각 cluster에 가까운 데이터들이 쭉 선정되었습니다. 정확하지는 않지만 비슷한 숫자 모양들이 서로 군집되어 나타납니다. 0과 2같은 숫자들은 잘 표현되지만, 알고리즘이 9랑 4를 헷갈리거나 5와 3을 헷갈리는 듯 하네요.FASHION MNIST로 SageMaker 머신러닝 학습 및 예측해보기자, 이제 몸도 풀었으니 제가 하고 싶었던 패션 관련 머신러닝 학습 및 예측을 진행해볼게요. 마침 옷 그림으로 MNIST와 매우 비슷한 데이터를 만들어 놓은 fashion-MNIST라는 데이터셋을 발견했어요!1. 패션 관련 MNIST 다운로드 받기패션 MNIST 데이터셋을 우선 다운받아 볼게요! 다운로드는 여기에서 받을 수 있습니다. 총 네 개의 파일을 다운로드 받으세요.- train-images-idx3-ubyte.gz : train set 이미지  - train-labels-idx1-ubyte.gz : train set 레이블  - t10k-images-idx3-ubyte.gz : test set 이미지  - t10k-labels-idx1-ubyte.gz : test set 레이블  다운로드 받은 패션 Mnist의 label은 아래와 같이 되어 있습니다. 숫자 0부터 9 대신에 각 이미지가 어떤 이미지인지 텍스트로 표현되어 있어요.LabelDescription0T-shirt/top1Trouser2Pullover3Dress4Coat5Sandal6Shirt7Sneaker8Bag9Ankle boot2. Fashion-MNIST 데이터셋을 이전에 사용했던 mnist.pkl.gz 와 같은 형태로 변환해주는 스크립트 작성해주기위에서 연습할 때는 mnist.pkl.gz 한 개 파일만 사용했는데요!?! 그래서 다운로드 받은 네 개의 파일을 똑같은 형식의 파일 하나로 만들어주는 파이썬 스크립트를 작성해 fashion-mnist.pkl.gz 파일로 만들었어요.import gzip import pickle import numpy as np # MNIST 데이터셋은 train, test 셋이 각각 image, label로 나누어 저장되어있는 4개의 파일로 구성 test_image_path = 't10k-images-idx3-ubyte.gz' test_label_path = 't10k-labels-idx1-ubyte.gz' train_label_path = 'train-labels-idx1-ubyte.gz' train_image_path = 'train-images-idx3-ubyte.gz' out_file_name = 'fashion-mnist.pkl.gz' # train label / images 추출 with gzip.open(train_label_path, 'rb') as train_label_f:     train_label = np.frombuffer(             train_label_f.read(), dtype=np.uint8, offset=8).astype(np.int64)   with gzip.open(train_image_path, 'rb') as train_image_f:     train_imgs = np.frombuffer(             train_image_f.read(), dtype=np.uint8, offset=16).reshape(-1, 784).astype(np.float32)   # test label / images 추출 with gzip.open(test_label_path, 'rb') as test_label_f:     test_label = np.frombuffer(test_label_f.read(), dtype=np.uint8, offset=8).astype(np.int64)   with gzip.open(test_image_path, 'rb') as test_image_f:     test_imgs = np.frombuffer(             test_image_f.read(), dtype=np.uint8, offset=16).reshape(-1, 784).astype(np.float32)   # 기존 60000개 training set에서 50000개는 train set으로 사용하고, 10000개는 valid set으로 활용 train_label, valid_label = train_label[:50000], train_label[50000:]  train_imgs, valid_imgs = train_imgs[:50000], train_imgs[50000:]   # train set, validati on set, test set을 튜플 자료형으로 저장 out_data = ((train_imgs, train_label),             (valid_imgs, valid_label),             (test_imgs, test_label))   # pickle file로 dataset 데이터 포맷 맞춰주기 with gzip.open(out_file_name, 'wb') as out_f:     pickle.dump(out_data, out_f) 이 과정을 통해 나온 결과물, fashion-mnist.pkl.gz 를 Jupyter Notebook이 있는 경로에 업로드합니다.fashion-mnist.pkl.gz가 업로드 되었습니다!3. 머신러닝 학습하기아까 사용했던 활용했던 숫자 MNIST 스크립트를 그대로 사용하겠습니다. show_digit()을 이름만 바꾼 show_fashion()으로 데이터를 살펴보니 드레스가 보입니다.조금 전에 했던 숫자 MNIST와 똑같은 과정을 SageMaker를 이용해, 학습 → 테스트 → 예측해보니 아래와 같은 예측 결과를 얻을 수 있었습니다. 신발은 신발끼리, 바지는 바지끼리, 가방은 가방끼리 분류된 게 너무나 신기합니다. (아까 진행한 숫자보다 더 학습이 잘 된 것 같은건 기분 탓일까요…?)머신러닝이라고 겁내지 않아도 됩니다! 유저들에게 더 좋은 서비스 제공할 수 있으니까요. 지금까지 브랜디 개발2팀의 단아한 개발자 오연ㅈ….참사를 막아주세요.앗, 잠시만요!! 중요한 것을 놓칠 뻔 했네요.저처럼 테스트를 하면 그냥 지나치지 마세요. 자동 결제로 출금되는 뼈 아픈 경험을 할 수도 있습니다. 반드시 이용했던 서비스들을 stop 하거나 terminate 해주세요. (Clean-up단계) 자세한 내용은 여기를 클릭하세요.지금까지 Brandi 개발 2팀, 단아한 개발자 오연주였습니다!# entire script (숫자 Mnist) # 오호 드디어 coding start! # 이제부터 Brandi의 단아한 개발자, 저를 따라오시면 됩니다 :) # 노트북 Block을 실행하는 방법은 Shift + Enter 입니다 from sagemaker import get_execution_role role = get_execution_role()  # 초기에 설정해 뒀던 IAM role 가져오기 bucket = 'sagemaker-julie-test' # 초기 단계에 만들었던 S3 Bucket 이름 적기 %%time import pickle, gzip, numpy, urllib.request, json   # 여기서 잠깐, 생소한 라이브러리 설명을 드릴게요! # pickle: python식 데이터 압축 포맷 # numpy: 수치 계산을 하기 위한 python package # Load the dataset urllib.request.urlretrieve("http://deeplearning.net/data/mnist/mnist.pkl.gz", "mnist.pkl.gz") with gzip.open('mnist.pkl.gz', 'rb') as f:     train_set, valid_set, test_set = pickle.load(f, encoding="latin1")     # matplotlib로 그리는 그림이 jupyter 노트북에 바로 보여줄 수 있도록 설정 %matplotlib inline import matplotlib.pyplot as plt # 도표나 그림을 그릴 수 있게 해주는 라이브러리 plt.rcParams["figure.figsize"] = (2, 10) # 그림의 크기 지정 def show_digit(img, caption='', subplot=None):     if subplot is None:         _,(subplot) = plt.subplots(1,1)         imgr = img.reshape((28, 28))     subplot.axis('off')     subplot.imshow(imgr, cmap='gray')     plt.title(caption)   # train_set의 그림과[0] 데이터 이름[1]을 예시로 보여준다 show_digit(train_set[0][30], 'This is a {}'.format(train_set[1][30]))   # 학습을 하기 위해 학습 알고리즘 및 데이터 경로 설정! from sagemaker import KMeans data_location = 's3://{}/kmeans_highlevel_example/data'.format(bucket) output_location = 's3://{}/kmeans_example/output'.format(bucket)   print('training data will be uploaded to: {}'.format(data_location)) print('training artifacts will be uploaded to: {}'.format(output_location))   kmeans = KMeans(role=role,                 train_instance_count=2,  # 장비 2대를 사용하여 학습하겠어요!                 train_instance_type='ml.c4.8xlarge',                 output_path=output_location,                 k=10,  # 아래 그림을 참고해 주세요!                 data_location=data_location) %%time   # 학습 시작! kmeans.fit(kmeans.record_set(train_set[0]))   %%time # 모델을 만든 후 사용하기 위하여 배포하기 kmeans_predictor = kmeans.deploy(initial_instance_count=1,                                 instance_type='ml.m4.xlarge')                                  # valid_set에 30번째 sample을 테스트 해보기 result = kmeans_predictor.predict(valid_set[0][30:31])  print(result)   %%time   # vaild_set에 있는 0번부터 99번까지의 데이터로 cluster를 예측 해보자 result = kmeans_predictor.predict(valid_set[0][0:100])   # 예측 결과에 대한 cluster 정보를 수집 clusters = [r.label['closest_cluster'].float32_tensor.values[0] for r in result]   # 각 cluster별 예측된 이미지 출력 for cluster in range(10):     print('\n\n\nCluster {}:'.format(int(cluster)))     digits = [ img for l, img in zip(clusters, valid_set[0]) if int(l) == cluster ]     height = ((len(digits)-1)//5)+1     width = 5     plt.rcParams["figure.figsize"] = (width,height)     _, subplots = plt.subplots(height, width)     subplots = numpy.ndarray.flatten(subplots)     for subplot, image in zip(subplots, digits):         show_digit(image, subplot=subplot)     for subplot in subplots[len(digits):]:         subplot.axis('off')     plt.show() 출처Getting Started - Amazon SageMaker CodeOnWeb - 머신러닝 초보를 위한 MNIST fashion-mnist 글오연주 사원 | R&D 개발2팀[email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유
조회수 2476

AWS 서비스를 활용한 Kubernetes 클러스터 구축 - VCNC Engineering Blog

Kubernetes 클러스터를 상용 환경에서 운영하기 위해서는 몇 가지 추가 구성요소를 설치해야 합니다. 예를 들어 Ingress를 만들더라도 실제로 트래픽을 받아줄 Ingress Controller를 설치해두지 않았으면 소용이 없습니다. 그리고 모니터링을 위해 컨테이너의 로그나 CPU/메모리 사용량 등을 수집, 조회할 수 있는 서비스도 필요합니다.다행히 이러한 추가 구성요소 또한 Kubernetes 클러스터 위에서 일반 애플리케이션과 거의 같은 방식으로 작동하므로 설치하는 것이 어렵지는 않습니다. 다만 클러스터를 원하는 대로 구성할 수 있는 만큼 선택의 폭이 넓어서 여러 가지 해법을 놓고 고민하게 될 수 있습니다. 이 글에서는 타다 서비스를 위해 Kubernetes 클러스터를 구성할 때 어떤 선택을 했는지, 특히 AWS 환경에서는 어떤 서비스들을 활용할 수 있는지 공유합니다.서비스를 외부에 노출: NGINX Ingress Controller + NLBIngress Controller 고르기Kubernetes에서 클러스터 내부 서비스를 외부에 HTTP(S)로 노출할 때는 Ingress를 사용할 수 있습니다. TLS 암호화, 로드밸런싱, 호스트명/경로 기반 라우팅 등을 제공해서 상당히 편리한데, Ingress가 실제로 작동하기 위해서는 Ingress Controller가 필요합니다.시중에는 다양한 종류의 Ingress Controller 솔루션이 나와 있습니다. 그중 Kubernetes 프로젝트에서 공식 지원하는 NGINX Ingress Controller와 AWS ALB 로드밸런서를 이용하는 AWS ALB Ingress Controller를 두고 고민을 했습니다.타다에서는 클라이언트(모바일 앱)에 실시간 이벤트를 전달하기 위해 gRPC를 사용하고 있어서 gRPC를 지원하지 않는 ALB는 선택할 수 없었습니다. 그리고 AWS ALB Ingress Controller는 현재 Ingress 하나마다 ALB를 1개 생성하는 구조여서 앞으로 노출할 서비스 수가 늘어난다면 비용 효율이 떨어진다고 판단했습니다. 따라서 NGINX Ingress Controller를 선택하게 되었습니다.NGINX Ingress Controller는 NGINX 웹서버를 기반으로 하므로 gRPC 모듈을 비롯하여 다양한 NGINX 모듈을 통해 굉장히 세세한 부분까지 설정할 수 있습니다. NGINX Ingress Controller는 Ingress나 Ingress가 가리키는 서비스의 엔드포인트에 변화가 생길 때마다 동적으로 NGINX 설정을 업데이트하는 방식으로 동작합니다.NGINX Ingress Controller 로드밸런싱NGINX Ingress Controller를 사용해도 외부에서 오는 트래픽을 적절히 분배해 줄 외부 로드밸런서는 필요합니다. AWS의 로드밸런서는 Classic ELB, ALB, NLB가 있습니다. 앞서 설명했듯이 ALB는 gRPC를 지원하지 않아서 Classic ELB를 TCP 모드로 사용하거나 NLB를 사용해야 합니다. Classic ELB는 동시에 많은 연결을 처리하려면 웜 업이 필요한 단점이 있어 NLB를 사용하기로 하였습니다.최근 NLB가 TLS termination을 지원하기 시작했지만, HTTP/2와 gRPC를 사용하기 위해 필요한 ALPN 정보를 설정할 수 없어서 NGINX 수준에서 TLS 암호화를 처리하고 있습니다. NLB 수준에서 TLS 처리를 하면 무료로 자동 갱신되는 ACM 인증서를 사용할 수 있는 등 여러 가지 이점이 있어서 아쉽습니다.Kubernetes에서 LoadBalancer 타입의 서비스를 생성하면 알아서 AWS 로드밸런서를 만들어줍니다. 하지만 이렇게 해서 NLB를 생성하는 방식은 아직 알파 기능입니다. 따라서 먼저 NodePort 타입의 서비스를 생성하여 모든 노드의 특정 포트에 NGINX를 노출한 다음, 별도로 생성한 NLB에 노드들이 속한 오토스케일링 그룹을 연결해주는 방식으로 직접 설정하게 되었습니다.정리해보면 외부에서 오는 트래픽을 처리할 때는 다음과 같은 과정을 거칩니다.모든 서브도메인(*.tadatada.com)은 NLB를 가리킵니다.NLB의 443 포트로 암호화된 HTTP 또는 gRPC 요청이 들어옵니다. NLB는 적절한 Kubernetes 노드 중 하나의 특정 포트(예: 30000번)로 요청을 전달합니다.Kubernetes 노드에서는 포트 번호를 보고 NGINX 서비스로 향하는 요청임을 알 수 있고 NGINX 컨테이너 중 하나로 요청을 전달합니다.NGINX는 복호화를 한 다음 HTTP Host 헤더를 확인하여 요청을 전달할 Ingress를 알아냅니다. 그리고 해당 Ingress의 엔드포인트 중 하나로 복호화한 요청을 프록시합니다.애플리케이션 컨테이너가 요청을 처리합니다.트래픽 흐름: NLB → NodePort → NGINX Ingress Controller → 내부 서비스Pod에 IAM 역할 부여: kube2iamS3, SQS 등 IAM으로 인증하는 AWS 서비스에 접근하려면 인증 정보가 필요합니다. EC2에서는 액세스 키를 직접 넣는 대신 EC2 인스턴스 프로파일로 인스턴스에 IAM 역할을 부여할 수 있습니다. 하지만 하나의 Kubernetes 노드 (=EC2 인스턴스)에는 여러 Pod이 실행될 수 있기 때문에 Pod마다 다른 IAM 역할을 부여하기를 원한다면 인스턴스 프로파일을 활용할 수 없게 됩니다. (인스턴스 프로파일에는 하나의 IAM 역할만 부여 가능)kube2iam을 사용하면 다음과 같이 Pod 어노테이션으로 IAM 역할을 지정할 수 있습니다.apiVersion: v1 kind: Pod metadata: name: aws-cli labels: name: aws-cli annotations: iam.amazonaws.com/role: role-arn spec: ... 설치나 사용법은 문서를 참고하면 어렵지 않은데, 원리를 간단히 설명해 보겠습니다. EC2 인스턴스 안에서는 특정 IP 주소(169.254.169.254)로 접속하면 EC2 메타데이터 API에 접근할 수 있습니다. AWS SDK는 EC2 메타데이터 API를 통해서 인스턴스 프로파일에 붙은 IAM 역할과 IAM 역할에 해당되는 액세스 키 쌍을 받아오게 됩니다.kube2iam은 모든 노드에 실행되면서 Pod 내부에서 EC2 메타데이터 서버 주소로 나가는 모든 요청을 가로챕니다. 그리고 인스턴스 프로파일 정보와 액세스 키 발급 요청을 kube2iam 서버가 대신 처리합니다. 따라서 Pod 안에서는 인스턴스 프로파일이 부여된 EC2 인스턴스 내부에 있는 것처럼 느껴지게 됩니다.추후 AWS SDK에 EKS 지원이 추가되면 별도로 데몬을 설치하지 않고도 Pod에 IAM 역할을 줄 수 있게 될 것으로 보입니다.로그 수집: fluentd + CloudWatch LogsKubernetes의 컨테이너가 stdout/stderr로 출력하는 로그는 노드에만 쌓이고 컨테이너를 재시작하거나 삭제하면 함께 삭제됩니다. 또한 노드의 디스크가 꽉 차는 것을 방지하기 위해 일정 크기를 넘으면 오래된 로그는 없어집니다. 그러므로 로그가 사라지지 않도록 계속 어딘가에 모아두어야 합니다.AWS에서 활용할 수 있는 로그 저장 서비스에는 CloudWatch Logs가 있습니다. fluentd를 DaemonSet으로 노드마다 하나씩 실행해서 컨테이너 로그를 CloudWatch Logs로 전송할 수 있습니다.CloudWatch Logs에 저장한 로그는 최근 나온 CloudWatch Logs Insights로 검색, 분석할 수 있습니다. 아직 나온 지 얼마 되지 않아서 기능이 많지는 않지만, 간단히 조회하는 용도로는 충분합니다.CloudWatch Logs Insights 사용 예모니터링: PrometheusEC2 인스턴스 하나에 서비스 하나를 띄워서 사용할 때는 CloudWatch로 CPU 사용률 등의 지표를 측정할 수 있었습니다. 하지만 Kubernetes를 사용하면 여러 서비스가 하나의 인스턴스에서 동시에 실행될 것이므로 인스턴스 수준의 지표는 무의미합니다. 특히 최소 실행 단위인 컨테이너 수준의 CPU 사용률 같은 값을 측정해야 하는데, CloudWatch를 사용하기에는 과금 체계가 적합하지 않습니다.기본 제공되는 5분 간격의 EC2 지표는 무료지만 CloudWatch에 커스텀 지표를 올리게 되면 지표 당 비용을 지불해야 합니다. 이 때 '지표'는 지표 이름 + 고유한 차원(dimension)의 조합입니다. 예를 들어 CPUUtilization이라는 이름의 지표가 PodName=server-aaaaaaaa과 PodName=server-bbbbbbbb라는 다른 차원으로 올라온다면 각각을 다른 지표로 취급합니다. 따라서 지표 수가 너무 많아지지 않게 조정해야 하는데 그러면 상세하게 모니터링하기가 어렵습니다.비용 문제도 있고, Kubernetes의 여러 가지 정보를 CloudWatch로 내보내는 기존 도구가 없었기 때문에 다른 방법을 찾아보게 되었습니다. 그래서 Kubernetes 모니터링을 위해 많이 사용하는 Prometheus를 선택했습니다. Prometheus를 온전히 사용하기 위해서는 다양한 컴포넌트들이 필요한데, Prometheus Operator Helm 차트를 사용하면 비교적 쉽게 구축할 수 있습니다.Prometheus는 Kubernetes 클러스터 모니터링 외에 애플리케이션 모니터링에도 사용할 수 있습니다. 타다의 애플리케이션들은 Spring Boot로 작성되어 있는데 Spring Boot Actuator와 Micrometer의 Prometheus 지원을 사용해서 애플리케이션 수준의 지표도 Prometheus로 모니터링하고 있습니다. 특히 Prometheus Operator를 사용하면 모니터링 대상을 추가할 때 Prometheus 설정 파일을 수정하지 않아도 Kubernetes에 ServiceMonitor 리소스를 등록하기만 하면 되어서 편리합니다.Prometheus로 수집된 지표는 Grafana 대시보드로 시각화하고, 정해진 조건에서 Alertmanager를 통해 PagerDuty와 Slack에 알림을 보냅니다.Grafana 대시보드의 모습자동 처리량 확장: Cluster AutoscalerKubernetes에서 자동 처리량 확장은 크게 두 종류로 나눌 수 있습니다. 먼저 Horizontal Pod Autoscaler로 CPU, 메모리 사용량에 따라 Pod의 수를 자동으로 조정할 수 있습니다. HPA가 실제로 동작하기 위해서는 오토스케일링을 위한 지표를 제공하는 Metrics Server를 설치해야 합니다. 그런데 부하가 증가해서 HPA가 Pod 수를 늘리려고 할 때 워커 노드에 여유가 충분하지 않으면 새로운 Pod을 실행할 수 없어서 소용이 없습니다. 이 때 워커 노드의 수를 자동으로 조정해주는 것이 Cluster Autoscaler입니다. Cluster Autoscaler는 노드 수를 증가시키기만 하는 것이 아니라 여유가 생겼을 때 노드 수를 자동으로 줄여서 불필요한 비용이 발생하지 않도록 해줍니다.AWS 환경에서 Cluster Autoscaler는 EC2 API를 통해 EC2 오토스케일링 그룹의 Desired Capacity 값을 필요한 노드 수로 조정하는 방식으로 작동합니다. 따라서 Cluster Autoscaler에는 EC2 API를 호출할 수 있는 IAM 권한을 주어야 합니다. 이를 위해 위에서 소개한 kube2iam을 사용할 수 있습니다. 그리고 Cluster Autoscaler가 오토스케일링 그룹을 자동으로 발견할 수 있도록 미리 정해진 태그를 붙여야 합니다.한 가지 주의할 점은 노드의 오토스케일링 그룹이 여러 가용 영역(AZ)에 걸쳐있으면 안 된다는 것입니다. 오토스케일링 그룹이 여러 AZ에 속한 경우 AZ 간 인스턴스 수의 균형을 맞추려고 하는데 이 과정에서 인스턴스가 예기치 않게 종료될 수 있습니다. 이 때 해당 노드에 실행되어 있던 Pod이 안전하게 종료되지 않을 수 있기 때문에 AZ마다 오토스케일링 그룹을 따로 만들고 AZ 간 균형은 Cluster Autoscaler가 맞추도록 설정해야 합니다.도움이 되는 링크들위에서 소개한 컴포넌트들은 다음과 같은 Helm 차트를 통해 설치해서 사용하고 있습니다.stable/nginx-ingressstable/kube2iamincubator/fluentd-cloudwatchstable/prometheus-operatorstable/metrics-serverstable/cluster-autoscalerEKS Workshop: AWS 환경에서 Kubernetes 운영할 때 참고할 만한 정보가 많이 있습니다.Kubernetes Slack 채널: #eks 채널에는 AWS 직원들도 접속해 있어서 높은 확률로 답변을 받을 수 있습니다.
조회수 1471

[H2W@NL] 전문가들의 고정밀 시너지, 하이브리드 HD 매핑

네이버랩스의 인재상은 passionate self-motivated team player입니다. 어쩌면 '자기주도적 팀플레이어'라는 말은 형용모순(形容矛盾)일 지도 모릅니다. 하지만 우린 계속 시도했고, 문화는 계속 쌓여갑니다. 다양한 분야의 전문가들이 경계없이 협력하고 스스로 결정하며 함께 도전하는 곳의 이야기를 전합니다. How to work at NAVER LABSH2W@NL 시리즈 전체보기지난해 11월, 네이버랩스는 국내 기업 중 최초로 도로 HD맵 데이터셋을 무상 배포했습니다. 수많은 국내 자율주행 연구자들을 위해서입니다. 그렇다면, 왜 자율주행 연구에 HD맵은 중요할까요? 안전하고 효과적인 자율주행을 위해서입니다. 센서 데이터와 HD맵을 연동하면 고층 빌딩이 즐비한 도심에서도 현재 위치를 끊김없이 정확하게 인식할 수 있도록 해주고, 복잡하게 얽혀있는 도로 구조를 광범위하게 파악해 효과적인 경로 계획을 세울 수 있으며, 신호등/횡단보도 등의 위치를 HD맵을 통해 미리 확인해 실시간 인지 정확도를 높일 수도 있습니다. 그래서 네이버랩스는 자율주행 연구 시작 시점부터 HD맵 솔루션을 함께 연구해 왔습니다. 그 결과가 하이브리드 HD 매핑입니다. 항공사진과 MMS 데이터를 융합해 고정밀 지도를 만드는 기술입니다. 다른 어디에서도 시도하지 못했던, 가장 독창적인 방식의 매핑 솔루션은 어떻게 개발되었을까요? 그 주역들의 이야기를 들어보았습니다.Q. 왜 HD맵 기술을 개발하나요?HD맵은 도로 자율주행을 위한 시작(김형준|시스템 소프트웨어 개발) 자율주행 시대가 온다고 합니다. 그렇다면, 반드시 그보다 먼저 필요한 것은 HD맵입니다. 자율주행 차량이 도로를 안전하게 주행하려면, 차선 단위의 아주 정밀한 정보가 필요하기 때문입니다. 보통은 MMS (Mobile Mapping System) 차량이 일일이 돌아다니며 수집한 도로 데이터로 HD맵을 제작하는 것이 일반적이지만, 이 방식은 소요되는 시간과 비용이 많습니다. 지역이 광범위해지면 더 많은 리소스가 필요하고요. 우리는 그걸 획기적으로 줄일 수 있는 방법을 찾고 싶었습니다. 정확도는 유지하되, 도시 단위의 넓은 지역을 더 빠르고 효율적으로 제작하는 솔루션을 찾았습니다. 그 결과가 네이버랩스의 하이브리드 HD 매핑 기술입니다. 항공 사진을 통해 대규모 지역의 도로의 레이아웃과 건물 정보 등을 얻고, 이 위에 자체 MMS 차량인 R1으로 취득한 데이터를 정합해서 HD맵을 만듭니다. R1이 최소한만 주행해도 HD맵을 제작할 수 있기 때문에, 소요되는 시간과 비용을 획기적으로 줄일 수 있습니다.(전준호|비주얼 피처맵 개발) 이렇게 완성된 HD맵에는 도로 자율주행에 필수적인 고정밀 정보들이 담겨 있습니다. 도로의 구조 정보인 로드 레이아웃 맵(Road Layout Map), 기하 정보를 가진 포인트 클라우드 맵(Point Cloud Map), 시각 정보를 가진 비주얼 피처 맵(Visual Feature Map) 등이죠.(신용호|센서 캘리브레이션) 우리가 하이브리드 HD 매핑이란 새로운 방식을 고안하고 완성할 수 있었던 건, 그 동안 지속적으로 개발해 온 자율주행 기술과 항공 사진 기반의 지도 생성 기술을 모두 내재화하고 있었기 때문이죠.도시 규모의 HD맵을 효율적으로 제작할 수 있는 독자 솔루션(이진한|PM/소프트웨어 개발) 사실 자율주행 기술을 연구하는 회사들은 많습니다. 그런데 독자적인 HD 매핑 기술까지 보유한 회사는 의외로 많지 않아요. 네이버랩스도 처음엔 그랬어요. 자율주행 프로젝트가 시작된 2016년 무렵엔 자체 HD 매핑 기술이 없다는 점이 아쉬웠어요. 센서만으로는 얻기 힘든 정보들을 미리 담아둘 수 있는 그릇이 HD맵인데, 바로 그 정보들이 자율주행의 성능을 높이는데 큰 역할을 하거든요. 결국 이 그릇을 만드는 방법을 내재화했죠. 이제는 도시 규모의 HD맵을 효율적으로 제작할 수 있는 독자 솔루션을 갖췄습니다. 실제로 이 결과물을 Localization에 바로 활용하여 자율주행 기술도 함께 고도화하고 있습니다.Q. 어떤 협업을 통해 개발되었나요?아웃풋이 바로 새로운 인풋이 되는(이진한|PM/소프트웨어 개발) 하이브리드 HD 매핑은 여러 분야의 전문가들이 함께 했습니다. 한 프로젝트의 결과물이 다른 프로젝트의 입력으로 연결되는 구조라고 할 수 있겠네요. 예를 들어 R1 하드웨어 장비 개발 프로젝트는 Sensor Calibration 프로젝트로 이어지고, 항공 매핑을 통해 만들어진 로드 레이아웃 데이터에 MMS 데이터를 연결하고… 이렇게 유기적인 의존 관계로 진행되었습니다.(이웅희|센서 데이터 툴 개발) 자체 개발한 MMS 차량인 R1에는 다수의 카메라, 라이다, GPS, 자이로센서 등 많은 센서들이 탑재되어 있어요. 이러한 개별 센서들에 대한 드라이버 개발은 물론 전체 센서 데이터가 동시에 들어왔을 때 유실 없이 저장할 수 있는 시스템 개발, 그리고 운용 소프트웨어 개발이 필요했습니다.(신용호|센서 캘리브레이션) R1이 수집된 데이터를 융합하기 위해서 반드시 필요한 과정이 있습니다. 캘리브레이션입니다. 각 센서간에는 상대적인 위치와 방향 등의 차이가 발생하는데, 캘리브레이션을 통해 정확하게 매칭을 시켜야 하죠. 그렇지 않으면 수집한 데이터들을 제대로 사용할 수가 없습니다.하늘과 도로에서 획득한 데이터를 융합하여 도시 규모의 HD맵 생성(김진석|항공 매핑) R1이 지상을 담당한다면, 저희는 하늘에서 찍은 정보를 활용합니다. 항공 사진을 통해 정확도를 획기적으로 높이는 방식을 개발했습니다. 항공 사진에서 8cm 해상도로 왜곡이 제거된 연직 정사영상(TrueOrtho)을 생성한 후, 도로 영역의 2D/3D 로드 레이아웃을 생성합니다. 여기에 R1이 수집한 포인트 클라우드 데이터를 정합하면, 대규모 지역의 HD맵을 빠르고 효율적으로 만들 수 있게 됩니다.(임준택|라이다 피처맵 개발) 이처럼 R1이 도로의 포인트 클라우드를, 항공기가 대규모 지역의 로드 레이아웃을 스캔해 결합하는 방식은 아주 새로운 솔루션입니다. 물론 그냥 붙인다고 HD맵이 바로 나오는 것은 아닙니다. 스캔 데이터에서 자동차나 사람같이 불필요한 부분을 지우는 딥러닝 모델을 만들고, HD맵을 사용할 차량이나 로봇을 위한 특징점을 추출하는 과정도 필수적입니다.서로 다른 분야의 전문가, 하나의 팀(전준호|비주얼 피처맵 개발) HD맵을 이루는 요소들, 즉 Road Layout Map/Point Cloud Map/Visual Feature Map 등의 구축 알고리즘을 각기 개발해, 이 데이터들을 잘 포함하고 있는 HD맵을 제작하는 거죠. 이렇듯 많은 팀의 협력으로 완성한 매핑 솔루션입니다. 항공 사진의 정합과 인식, MMS 차량의 데이터 수집을 위한 장비와 센서 시스템 구축, GPS와 LiDAR 데이터를 이용한 위치 인식 기술, 시각 정보 추출을 위한 딥러닝 기술 등 서로 다른 전문가가 하나의 팀으로 모여있어요. 같은 목적을 갖고 밀접하게 협업하기에 더 높은 수준의 연구와 개발이 가능한 것 같습니다.“결과도 중요하죠. 하지만 문제를 같이 정의하고, 함께 해법을 찾아가는 과정은 더 중요한 것 같아요. 그래야 좋은 결과가 이어질 수 있으니까요.”(김형준|시스템 소프트웨어 개발) 다양한 분야의 전문가들이 모여 유기적인 협업이 언제든 가능하다는 것은 프로젝트에서 난항을 겪을 때 큰 힘을 발휘합니다. 예전에, 데이터 취득 시스템의 안정성에 문제가 생긴 적이 있어요. 그때 하드웨어 엔지니어와 소프트웨어 엔지니어들이 모두 모여 동시에 검토를 했습니다. 필드를 돌며 문제 발생 시점의 상황을 함께 체크하고, 그 중 기구 엔지니어 분들이 원인을 찾아 문제를 해결했습니다.(김상진|하드웨어 설계) 저도 그때가 기억나요. 차량 진동으로 인한 간헐적인 회로 단락이 원인이었죠. 짧은 시간에 가장 정확한 답을 찾기 위해 필요한 것은, 역시 유기적인 팀웍인 것 같아요.(신용호|센서 캘리브레이션) 팀이 없는 것처럼 협업이 잘 된다는 점도 자랑하고 싶어요. 함께 잘하기 위해서라는 목표만으로 일에 몰입할 수 있다는 건 정말 좋은 경험이죠.Q. 경과, 그리고 목표는?서울시 2,000km 로드 레이아웃 지도 구축(김진석|항공 매핑) 서울시 4차선 이상 도로 2,000km에 대한 로드 레이아웃 구축을 완료했습니다. 자율주행에 필요한 도로 구조 정보(차선, 중앙선, 정지선, 좌회전 등의 노면표시)를 정밀한 벡터 데이터 형식으로 변환했습니다. 서울시만큼 큰 대도시 규모의 매핑이란 관점에서 보자면, 국내에서 유일한 기술입니다.(김형준|시스템 소프트웨어 개발) 하이브리드 HD 매핑의 자체 프로세스가 정립되면서, 예전과 비교해 최소한의 작업으로 원하는 지역의 HD맵을 생성할 수 있게 되었습니다. 무상 공개한 판교 및 상암 지역 HD맵도 이 결과물 중 하나죠.(이진한|PM/소프트웨어 개발) 상암/판교 지역의 HD맵 무상 배포를 DEVIEW에서 발표했을 때가 정말 보람되었던 것 같아요. 국내에서 자율주행을 연구하고 있는 많은 기관에서 데이터셋 신청을 해주셨어요. 저희의 솔루션으로 만든 HD맵이 국내 자율주행 기술 고도화에 도움이 될 수 있었으면 좋겠습니다.(전준호|비주얼 피처맵 개발) 네이버랩스의 HD맵은 도로 위의 정밀 위치 인식을 최종 목표로 하고 있습니다. 예를 들어 Visual Feature Map의 경우 위치 인식에 필요한 최소한의 시각 정보와 기하 정보를 Descriptor 형태로 경량화 했기 때문에, 대규모 도심 지역의 데이터도 용량이 아주 작습니다. 이러한 최적화를 계속할 계획이고요.미래 모빌리티 세상으로 한 걸음 더(김상진|하드웨어 설계) 매핑 시스템 고도화의 목표는 결국 신뢰성 높은 지도를 만드는 것에 있습니다. 하드웨어 시스템의 신뢰성/유연성/운용성을 빠르게 개선하고, 이를 더욱 저비용으로 구현할 수 있도록 개발을 지속하고 있어요. 이런 연구들의 결과가 모이고, 이러한 고정밀 데이터가 쌓이면, 우리가 상상하고 있는 미래 모빌리티 세상을 더욱 앞당길 수 있다고 생각합니다.
조회수 1077

[인터뷰] Clara의 인턴 직무 인터뷰 제3화 _iOS developer 민트를 만나다

안녕하세요:)인턴들의 하루하루를 전해드리는 클라라입니다오늘은 저번 시간에 말씀드렸던 Tech unit의  미녀 인턴과의 인터뷰를 진행했습니다!그녀의 이름은 상쾌한 Mint!본명에 '박하'가 들어가서 민트라는 이름을 지었다고 하네요~센스 만점이죠?이름처럼 상큼한 민트와의 인터뷰바로 만나보시죠!고고고☞Q. 안녕하세요 민트, 간단한 자기소개와 요즘 어떤 일을 하시는지 소개해주세요~M.네! 안녕하세요~ 저는 iOS 개발을 하고 있는 개발자입니다. 많은 분이 개발자가 코딩을 하고 이런 것들은 어렴풋이 알고 계실 텐데, 지금 저는 iOS 앱에서 개선할 부분을 조사하고 더 잘 구현하고자 열심히 개발하고 있습니다. 아직은 주로 UX/UI 의 개선에 집중하고 있고, 하는 일보다 배우는 일이 더 많은 것 같네요!M.네! 안녕하세요~ 저는 iOS 개발을 하고 있는 개발자입니다. 많은 분이 개발자가 코딩을 하고 이런 것들은 어렴풋이 알고 계실 텐데, 지금 저는 iOS 앱에서 개선할 부분을 조사하고 더 잘 구현하고자 열심히 개발하고 있습니다. 아직은 주로 UX/UI 의 개선에 집중하고 있고, 하는 일보다 배우는 일이 더 많은 것 같네요!Q. 개발자는 그 안에서도 하는 일이 다양하다고 들었어요. 요즘 민트의 주 업무에 대해 더 자세하게 설명해주실 수 있을까요?M.그럼요~지금 저는 아이폰의 OS인 iOS에 특화된 방식으로 개발하는 네이티브 방식을 활용하고 있어요. 네이티브 방식이란 안드로이드나 iOS와 같은 특정 OS에 최적화된 방식으로 앱을 개발하고 있다는 뜻입니다. 그렇지 않은 개발 방식도 있거든요! 모바일 웹페이지를 앱처럼 꾸며서 보여주는 등 여러 방식이 있습니다.M.그럼요~지금 저는 아이폰의 OS인 iOS에 특화된 방식으로 개발하는 네이티브 방식을 활용하고 있어요. 네이티브 방식이란 안드로이드나 iOS와 같은 특정 OS에 최적화된 방식으로 앱을 개발하고 있다는 뜻입니다. 그렇지 않은 개발 방식도 있거든요! 모바일 웹페이지를 앱처럼 꾸며서 보여주는 등 여러 방식이 있습니다.iOS개발은 안드로이드 앱 개발과 비교했을 때 제약 조건도 많고, 생소한 스타일의 개발 언어를 써야 하는 게 어려워요. 하지만 동시에 iOS 특유의 사용감과 안정성이 매력이에요. 그리고 아까 UX/UI라는 용어를 사용했는데 이는 User Experience와 User interface의 약자, 즉 사용자 경험을 의미합니다. 저희는 사용자 경험을 더욱 편리하게 하는 쪽으로 앱을 유지 보수하는 일을 하고 있는 거예요. 미미박스는 고객을 소중히 여기기 때문에 이런 UX/UI에 있어서도 많은 신경 쓰고 있습니다.Q. 그럼 개발자로서 미미박스는 어떤 장점을 가지고 있나요? 저희 회사 자랑 좀 해주세요!!!M. Q. 그럼 개발자로서 미미박스는 어떤 장점을 가지고 있나요? 저희 회사 자랑 좀 해주세요!!!M. 음, 저는 미미박스가 개발자의 의견을 듣고 반영하고자 하는 회사임을 가장 말씀드리고 싶어요! 미미박스 개발팀에서는 디자인팀+앱 개발팀+PM 팀, 세 팀이 모여서 정기적으로 회의를 하고 있습니다. 이 회의를 스크럼이라고 하는데, 프로젝트와 관련된 모든 사람들이 모여서 계획하고 피드백하는 것이죠.이걸 하면 좋은 이유는 개발을 담당하는 사람이 직접 기획에도 참여할 수 있다는 거예요. 보통 한국에서 개발 직무는 보통 상명하달식으로 이루어진다고 해요. 위에서 개발이라는 직무를 이해하지 않고 일방적으로 일정을 정해서 던져주는 거죠. 그런데 미미박스는 그렇지 않고 자신의 생각을 내고 반영할 수 있어서 좋아요.   Q. 오오오~ 그렇군요! 민트와 저는 자리가 멀잖아요. 업무적인 것과 별개로, Tech 유닛의 분위기는 어떤가요??? M.저희 유닛 분위기 완전 좋아요! 그리고 저는 사수 분들이 똑똑하셔서 배울 점이 많다는 생각으로 회사를 다니고 있어요. 서로 돕고 정보를 공유하는 분위기여서 무려 시니어 분들이 제게 본인의 코드를 다 오픈해주세요. 근데 그 코드가 다 샘플 코드의 수준이고요!(샘플 코드란 일종의 '교과서'같은 존재로, 코딩의 수준이 아주 높다는 뜻입니다.)iOS 직무는 신입의 진입장벽이 높거든요. 사전 지식 없이는 독학으로 따라잡을 수 없는 부분이 많기 때문에 코드와 그에 대한 설명을 들을 수 있다는 건 엄청난 거죠. 마치 최고의 영업사원이 자신의 영업 비밀을 공개해주는 그런 경우라고 할까요? 애플 워치의 코드까지 알려주는 회사, 흔치 않습니다! (엄지 척)  민트에게 몰려든 고양이들~Q. 와우! 애플 워치도 코딩을 하는 거군요. 제겐 너무나 신세계인데요...!  이제 마지막 질문입니다. 여성 개발자로서 강점은 무엇일까요?M.저는 사실 특정 산업 군이나 성별에 구애받지 않는 작업을 한다고 생각해요. 그럼에도 화장품을 온라인으로 사 본 개발자과 그렇지 않은 개발자는 차이가 있다고 생각해요. 여성이 주 고객층인 뷰티 쇼핑몰에 대한 경험이 쌓이면 새롭고 좋은 UX에 대한 아이디어도 더 잘 나오지 않을까 싶네요.  민트와의 인터뷰 어떠셨나요?저 클라라처럼 컴알못이거나개발자의 하루가 궁금하셨던 분들은 이번 인터뷰가 큰 도움이 되셨으면 좋겠습니다.민트를 마지막으로 인턴의 생활을 엿볼 수 있는 클라라의 인터뷰가 마무리 되는데요 :)미미박서의 일과 삶에 대해서 조금이나마 더 알아가셨다면,그래서 '미미박스에서 일해보고 싶다'는 마음이 스멀스멀 생기셨다면!클라라는 그것만으로도 보람찰 것 같습니다.그럼 또 미미박스의 소식으로 찾아올게요~

기업문화 엿볼 때, 더팀스

로그인

/