Regular Motion

개발자가 상팔자

[Android] 악화가 양화를 구축한다.

‘악화가 양화를 구축한다’는 말은 그레샴이 멀리 500년 후를 내다보고 지금의 Android를 빚대어 한 말인 것 같다.

대다수의 안드로이드 개발자들은 표준을 준수하는 코드를 작성하고 싶어 하지만 삼성의 높은 시장 점유율과 반복되는 버그 리포트는 표준만 준수해서는 답이 없다는 뼈아픈 가르침과 인실좆을 반복적으로 알려준다.

삼성을, 정확히는 갤럭시를 지원하기 위한 코드들은 마치 표준인양 인터넷을 떠돌아다니고 표준은 설 곳을 잃는다.

Android Support Library의 눈부신 활약으로 요즘은 상황이 많이 좋아졌지만 카메라나 미디어 코덱과 같이 하드웨어와의 연동이 필요한 부분은 현재 진행형이다.

범용적이거나 호환성이 높은 제품을 만들 때 필요한 자질은 보이지 않는 단점들을 하나 하나 덮어 줄 수 있는 인내심과 따뜻한 마음 그리고 구글링 인 것 같다.

[AWS] Delivery Dynamic Content through CloudFront

회사에서 운영 중인 대부분의 서비스들의 웹서버가 AWS의 Elastic Beanstalk로 구성되어 있다. 기존에는 Beanstalk에 직접 DNS를 설정하여 운영중이었는데 WAF(Web Application Firewall) 구성을 위해 Beanstalk 앞에 CloudFront를 연동 한 뒤, TTL(Time to live)을 0으로 설정하여 매번 원본 저장소에서 콘텐츠가 전송되도록 설정했는데도 서비스가 빨라진 느낌적인 느낌을 받았다.

빨라진 느낌을 객관화하기 위해 CloudFront 연동 전/후 서비스의 페이지 로드 시간과 API Latency를 테스트 했는데 약 1.6배 정도 속도 향상이 있었다.  TTL을 0으로 설정했는데도 빨라진 이유는 ‘Edge 서버와 Origin 서버가 AWS 내부망으로 연결되어 있어 더 빠르겠지’ 하는 막연한 추측만 갖고 있었다.
* CloudFront 연동 전/후의 속도 차이는 테스트 환경과 Origin 서버의 지리적인 거리에 직접적인 영향을 받기 때문에 차이가 발생 할 수 있습니다. 저는 Ireland에 구축된 웹서버를 기준으로 테스트 했습니다.

나의 막연한 추측을 기술적으로 설명해주는 2개의 글을 읽고, 페이지 로드 시간이 빨라진 이유를 이해하게 됐다.

글에서 설명하는 이유를 정리하면 아래와 같다.

요청에 대한 응답 시간은 크게 4가지 요소의 합이다.
응답 시간 = DNS Lookup + TCP Connection + Time to First Byte + Content Download

  • CloudFront의 Edge 서버와 Origin 서버는 Keep Alive Connection을 통해 연결을 유지 및 재사용하기 때문에 TCP 3-way handshake 과정에서 SYN, SYN-ACK, ACK 과정을 생략 할 수 있는 경우가 많다.  지리적으로 거리가 떨어진 경우 높은 RTT(Round-Trip Time)로 인해 위의 SYN, SYN-ACK, ACK 과정의 생략을 통해 얻을 수 있는 속도 향상이 크다. Edge와 Origin과의 Keep Alive Connection을 통한 속도 향상은 TTFB(Time to First Byte) 시간의 감소로 확인 할 수 있다.
  • Gzip 압축을 통해 실제 전송되는 컨텐츠의 크기를 줄임으로써 Content Download에 필요한 시간을 줄일 수 있고, 비용도 절감 할 수 있다.
  • AWS Edge 서버와 Origin 서버 사이의 네트워크는 고성능 및 가용성을 유지함으로써 Content Download에 필요한 시간을 줄일 수 있다.
  • CloudFront의 최적의 라우팅 기술이 Route 53의 LBR(Latency Based Routing)과 통합되어 DNS Lookup 시간을 단축 할 수 있다.

 

결론

  • CloudFront의 Cache 기능을 사용하지 않는다고 하더라도 CloudFront 연동을 통해 1.6~1.8배 사이의 성능 향상을 기대 할 수 있다.
  • CloudFront에서 L3/L4 Flood Attack을 방어해주기 때문에 설정하는 것 만으로도 DDoS 방어 효과가 탁월하다.
  • CloudFront + WAF 구성을 통해 일반적인 웹 취약점 공격으로부터 보호하는 데 도움이 된다.
  • CloudFront의 gzip 옵션을 통해 전송되는 콘텐츠의 사이즈를 줄여 비용을 절감 할 수 있고, 콘텐츠 전송 속도를 줄일 수 있다.
  • GB당 컨텐츠 전송 비용은 설정 전/후 큰차이를 보이지 않는다. 다만 텍스트와 같이 gzip 옵션을 통해 높은 압축 효과를 기대 할 수 있는 콘텐츠의 경우는 비용 절감 효과도 기대 할 수 있다.
  • 속도와 보안 두마리 토끼를 잡을 수 있으니 CloudFront를 설정하지 않을 이유가 없다.

[Android] SecurityException when Notification is being registered with Vibration

안드로이드 개발을 하다보면 재현이 되지 않는 버그들이 참 많다.  어떤 버그들은 특정 기기에서만 발생하고, 또 어떤 버그는 특정 OS 버전에서만 발생하기도 한다.  따라서 상용 서비스는 반드시 CrashliticsSplunk Mint와 같은 버그 리포트 서비스를 연동 후 배포하기를 권장한다.

실 사용자가 10만명 정도되는 앱에 버그 리포트 서비스를 연동해보면 별 회개망칙한 버그들을 다 볼 수 있다.

오늘 수정한 버그는 앱에서 Notification을 등록 할 때 발생하는 Vibrate로 인해 SecurityException이 발생 할 수 있는 버그다.

앱에서 Notification을 등록 할 때, setVibrate() 함수 또는 setDefaults() 함수로 진동을 줄 수 있는데 이때 사용자 기기의 OS 버전이 4.2.1 미만이고 AndroidManifest.xml에  Vibrate 권한을 설정하지 않았다면 SecurityException이 발생 할 수 있다. (‘발생한다’가 아니라 ‘발생 할 수 있다’고 표현하는 이유는 테스트 결과 일부 기기는 4.2 미만에서도 SecurityException이 발생하지 않는다.)

Android 4.2.1에 이 문제와 관련해서 패치가 있었다. 읽어보면 기기가 진동모드여서 진동이 불가피한 경우거나 setDefaults()의 인자로 Vibrate를 설정하는 경우는 더 이상 AndroidManifest.xml에 Vibrate 권한을 추가 할 필요가 없다. 다만 setVibrate() 함수를 통해 Custom Vibration pattern을 등록하는 경우는 여전히 권한 추가가 필요하다.

따라서 우리는 AndroidManifest.xml에 아래와 같이 권한을 추가하여 꼭 필요한 기기에 한해서만 권한을 요청하도록 설정 할 수 있다.

 

아마 내부 테스트 중에는 Vibrate와 관련한 권한 문제가 없었는데, 버그 리포트로 처음 접한다면 위에서 언급한 문제일 확률이 매우 높다.

 

[Android] Doubt till your Bug Tracking tool.

AndroidStudio의 Monitors로 memory monitoring 중 기이한 현상을 발견했다.

앱에서 다운로드를 시작하면 장판처럼 고요하던 메모리가 요동을 치기 시작하는 것이다.

실제로 3~5MB 정도의 메모리가 매우 빠른 속도로 할당/해제를 반복한다. 저사양 단말에서 파일 다운로드시 앱이 굉장히 느려지는 현상도 왠지 요동치는 그래프와 깊은 관련이 있을 것 같다.

다운로드 중 Monitors 툴에 나타나는 그래프는 아래와 같다.

요동치는 메모리

17초부터 다운로드가 시작됐고, 이후 요동치는 메모리를 보시라. 길에서 탕웨이를 우연히 만나면 내 심장도 저렇게 요동 치겠지.

처음에는 다운로드 중 Notification과 View를  갱신하기 때문에 메모리가 요동치는 줄 알았는데, 해당 작업을 주석처리 후 테스트 해봤지만 요동치는 메모리는 돌아오지 않았다.

범인을 잡기 위해, Allocation Tracking을 해보니 용의선상에 없던 놈이 범인이었다. 범인은 앱에서 사용하던 버그 트래킹 툴(Splunk Mint)인데,  툴에서 Network IO를 Monitoring 하는 로직이 BufferedInputStream의 read시마다 실행되도록 구현되어 있어 속도가 빠른 네트워크를 통해 대용량 파일을 다운로드 할 때 해당 로직이 매우 빈번하게 실행된다.

15초간 Allocation Tracking한 결과는 아래와 같다. 눈을 크게 뜨고 보시라.

절대 현혹되지 마라

 

다행히 Network Monitoring을 비활성화 할 수 있도록 SDK가 구현되어 있어 비활성화 후 테스트하니 메모리는 다시 고요해졌다.

이렇게…

백투장판

 

 

금일의 교훈

  1. 몸에 좋은 약도 알고 먹자.
  2. Android Studio의 Monitoring을 통해 Profiling을 가끔해보자. 버그 같지 않은 버그를 잡을 수 있다.

From Audio To Text

회사에서 종이책을 전자책으로 변환하는 중, Chapter 별로 녹음된 오디오 파일을 페이지 별로 컷팅 할 필요가 생겼다.

사실 내가 하는건 아니고, 책을 변환하시는 분들이 컷팅을 하는데 작업하는걸 옆에서 보니 약간만 도움을 드리면 일주일째 야근하는 저분도 칼퇴 할 수 있을 것 같아 방법을 찾아봤다.

기존의 작업 방식은 약 15분~1시간짜리 오디오 파일을 Seek 해가며 페이지의 마지막 문장이 끝나는 시점을 찾아 Timestamp를 기록 한 뒤, Timestamp 별로 오디오 파일을 컷팅했다. 이때 오디오를 Seek 해가며 각 페이지의 마지막 문장이 끝나는 시점을 찾는게 상당히 시간을 잡아먹는 작업이었다.

만약, 오디오 파일에서 자막 파일과 비슷하게 각 문장별 시작시간과 종료시간을 자동으로 추출 할 수 있다면, 페이지의 마지막 문장을 자막 파일에서 찾은 뒤 문장의 종료시간을 바로 찾을 수 있으니 퇴근을 못하고 파일을 컷팅하시는 분의 소중한 시간을 매우 절약 할 수 있을 것 같았다.

다행히 오디오 파일은 소음과 배경음이 없는 환경에서 원어민이 깔끔하게 녹음한 파일이라 괜찮은 Speech Recognize Engine만 있으면 자막에 준하는 파일을 자동으로 생성 할 수 있을 것 같았다.

이제 문제를 간단하게 요약 할 수 있을 것 같다.

mp3 -> smi

 

구글링을 30분 정도 해보니 괜찮은 Speech Recognizer가 3가지 정도 있는 것 같다.

  1. Google Speech  API : 2016년 06월 현재 Limited Preview라 신청 후 승인까지 시간이 소요되고, 승인이 안되서 그런건지 API Document를 찾기 어렵다.
  2. Nuance Naturally Speaking : 왠지 될 것 같은데 구매를 하지 않아 정확히는 모르겠다.
  3. CMUSphinx : 카네기멜론에서 공개한 Open Source Speech Recognition Engine. 설치와 설정이 약간 번거롭지만 무료고 명령어 기반으로 처리되기 때문에 Batch 작업 돌리기에 적합하다.

위의 3가지 옵션을 약 30분 가량 고민하다. 제일 Geek하고 Batch processing에 용이해보이는 3번으로 진행하기로 결정했다.

MP3 -> SMI 작업에는 ffmpeg과 cmu-sphinxbase, cmu-pocketsphinx이 필요하며 설치 과정은 아래와 같다.

  1. ffmpeg을 피씨 또는 서버에 추가한다. Package를 다운로드 후 bin에 추가하여 사용하시면 편합니다!
    (ffmpeg을 설치하는 이유는 CMUSphinx가 Input File로 wav파일만 받기 때문에 mp3 파일을 wav 파일로 변환해야 한다)
  2. cmu-sphinxbase를 설치한다.  (OSX 사용자 기준)
  3. cmu-pocketsphinx를 설치한다.  (OSX 사용자 기준)

* cmu-sphinxbase와 cmu-pocketsphinx의 stable 버전은 0.8인데 OSX 사용자는 HEAD revision을 설치하기를 권장합니다. 자세한 이유와 설치 방법은 https://github.com/watsonbox/homebrew-cmu-sphinx 포스팅 참고.

 

필요한 프로그램이 설치됐으면 필요한 기능들이 제대로 동작하는지 확인해보자

ffmpeg을 이용해 MP3 파일을 WAV로 변환하는 명령어 (ar: Sample Rate,  ac: Channel)

WAV 파일로 변환된 오디오에서 텍스트를 추출하는 명령어

 

위의 2가지 명령어 + 편한 Script 언어를 조합하여 오디오 파일에서 텍스트를 추출할 수 있다.

한가지 아쉬운 점은 CMUSphinx에 미국 발음 Recognizer만 기본으로 내장하고 있어 영국 발음으로 녹음된 파일의 경우 인식률이 조금 떨어진다는 점이다.

테스트 결과 미국 발음으로 녹음된 음원은 80~85%, 영국 발음은 60~65% 정도의 인식률이 나온다.

 

아래는 PHP로 작성된 MP3 -> SMI

* PHP 뉴비라 인터넷에서 몸에 좋다는 코드들 덕지 덕지 붙여서 만들었습니다;

* 고백하자면 이해를 돕기위해 자막/SMI 라는 표현을 차용했을 뿐 정확히 SMI 포맷을 생성하기 위해서는 약간의 수정이 필요합니다.

 

« Older posts

© 2016 Regular Motion

Theme by Anders NorenUp ↑