앱 서비스 장애편 #2 - 폰의 발열이 심해요 (CPU/GPU 편)

테크 이야기 2021년 4월 1일

앱의 체류 시간이 짧은 서비스라면 크게 중요하지 않을 수도 있으나, 사용자의 체류 시간이 긴 서비스라면 의외로 다가오는 복병이 바로 발열과 배터리 사용량입니다.

"이 앱을 실행하면 몇 분 안에 폰이 뜨거워져요.", "원인을 못 찾겠어요."라는 연락이 종종 옵니다. 크래시 리포트에 원인이라도 남으면 좋겠지만, 앱이 비정상 종료되기 이전까지는 어떠한 정보도 못 주기 때문에 원인을 찾기가 정말 어렵습니다. 그렇다면 원인을 어떻게 찾아야 할까요?

먼저 모바일 아키텍처에 대해 설명드리고, 장애가 난 사례들을 공유해 드리고자 합니다.


모바일 폰에서 CPU는 어떻게 동작하나?
학교에서 배운 컴퓨터 아키텍처와 모바일 아키텍처의 가장 큰 차이점 중 하나는 바로 쿨러 여부 입니다.

노트북이나 데스크탑은 쿨러를 가지고 있기에 CPU, GPU가 뜨거워지더라도 온도를 낮추면서 항상 일정하게 성능을 낼 수 있습니다. 하지만 폰은 다릅니다. 쿨러가 없다는 것이죠. 그렇기에 CPU, GPU 성능을 항상 최대로 사용할 수 없습니다.

ussagepercore

또한 상시 전원이 공급되지 않기에 배터리 사용량(전원 공급)도 아껴야 합니다. 그러니 딱 하는 일만큼 적절하게 전력을 공급해야 하죠. 또한 CPU의 성능이 몇 년 사이에 비약적으로 향상되면서, 제조사/모바일 운영체제 역시 똑똑해졌습니다. 발열 때문에 멀티 코어를 항상 다 사용하는 것이 아닌 일부 코어만 사용하다가, 시간이 지나면 다른 일부 코어를 사용하여 발열을 최소화하기 위한 전략들을 사용하고 있습니다.

cpu-z

실제 안드로이드 앱 중에 CPU-Z를 여러분의 폰에서 실행해 보면 모든 CPU가 다 균등하게 일을 하지 않는 것을 보실 수 있습니다.

CPU/GPU Governor의 정책

안드로이드 같은 경우 정말 다양한 CPU 정책을 가지고 있습니다. 그중에서 일반적으로 사용되는 것들을 정리했습니다.



Governor 정책 설명
OnDemand 현재 사용량에 따라 CPU 주파수 설정
OnDemandX 배터리 친화적인 OnDemand이며 I/O 스케줄러에 따라 성능이 좌우
Conservative 느린 OnDemand (가능한 최저 속도에서 동작하도록 구현)
Interactive OnDemand와 유사하나, 훨씬 빠르게 반응
Performance CPU를 최고 주파수로 설정
Powersave CPU를 최저 주파수로 설정 (Performance의 반대)
Userspace 테스트를 위해 사용 (CPU를 사용자가 지정한 주파수로 동작)


즉 CPU가 뜨거워지면 더 낮은 모드로, 남은 배터리 양이 적으면 천천히 돌아가게 Governor가 개입을 하게 됩니다. 우리가 잘 알고 있는 애플의 배터리 게이트도 이러한 상황 때문에 발생을 한 것입니다. 애플은 배터리 수명이 줄수록 오랫동안 폰을 사용하기 위해 인위적으로 CPU 성능을 제한해 왔던 것입니다. (선의로 행하였으나, 여러 게임회사로 부터 소송을 받음)

GPU 정책은 이곳을 참고하시길 바랍니다.

안드로이드 앱은 클라우드 VM처럼 자원을 공유해서 사용합니다

안드로이드의 앱은 클라우드 VM 처럼, 하나의 휴대폰에서 여러 앱이 자원을 공유해서 사용합니다. 하나의 앱이 많은 자원을 사용하면 당연히 다른 앱에 영향을 끼칠수 밖에 없는 구조입니다.

다행히 메모리는 안드로이드 5.0 미만에는 앱당 사용하는 메모리 사용량을 제한하는 정책으로 갔으나, 5.0 이후에는 작은 객체와 큰 객체의 저장공간을 분리하는 메모리 관리 정책 (ROS와 LOS) 도입 그리고 앱을 가볍게 하는 정책들이 도입되면서 메모리 이슈는 많이 사라졌습니다.

즉 공유 자원이며, 하나의 앱이 CPU를 50% 이상 사용한다면 다른 앱과 CPU 사용량을 나눠써야 하는 상황이 발생합니다. 예를 들어 백그라운드 앱으로 음악을 듣고, 앱을 동작할 경우 앱의 동작이 부자연스러운 상황이 발생하게 됩니다.

또한 안드로이드 진영에서 저가 폰일 경우 이러한 현상이 더 심화되는 상황이 발생합니다. 특히 여러분의 서비스가 동남아시아의 저가폰을 사용하는 유저가 많을 경우에는 최적화에 더 신경을 써야 합니다.

과도한 CPU/GPU 사용 사례

무거운 초기화가 단골 메뉴
앱을 시작하는 초기 시점에 너무나 많은 일을 하는 경우입니다.

--------------2_------01_2

--------------2_------02

위 같은 경우는 CPU를 앱에서만 51% 사용하는 경우입니다.
주요 원인은 다음과 같습니다.

  • 매우 복잡한 화면 구성(Linear Layout으로 복잡하게 중첩되어 화면 구성)
  • 네트워크로 데이터 가져오기
  • 비트맵 처리/GPU가 다 그릴 때까지 대기하기
  • 심지어 초기화 화면에서 DB 삽입, 업데이트까지 하는 경우도 있습니다.

무거운 화면 구성
화면 레이아웃의 계층화가 커질수록, 구성이 복잡해 질수록 이러한 상황은 종종 발생합니다.
CPU가 레이아웃을 구성하고, 레이아웃에 나오는 폰트나 이미지등은 GPU가 처리를 합니다. 즉 CPU와 GPU가 해야 하는 일을 적절히 분리해서 이점이 있게 화면을 구성해야 합니다.

위 영상에서는 한글 자막을 공식적으로 지원하니 화면구성에 대해서 확인해보시는 것을 추천합니다.

android4_5_diff

안드로이드 5.0 이상부터는 RenderThread의 도입(GPU의 사용)으로 CPU의 부하가 대폭 완화된 것을 볼 수 있습니다. (이 말의 의미는 Android 5.0 미만이거나 GPU가 없는 저가폰들은 CPU의 부하가 상대적으로 훨씬 크게 느껴진다고 이해하시면 됩니다.)

systrace

화면을 구성하는 작업이 레이아웃 구성에만 오랜 시간이 걸린다면 GPU의 도움을 받지 못하고, CPU에 부하가 커지는 이슈가 발생합니다. 실례로 위 프로파일러 화면에서 볽수 있듯이 화면 구성에 CPU(UI Thread)가 많은 시간을 쓴 것을 볼 수 있습니다.

이런 경우는 예를 들어 중첩된 레이아웃으로 구성되어 있고, 그중 한 레이아웃은 화면의 가로, 세로 사이즈를 계산해 원을 그리고, 원안의 색상을 일일이 계산해서 색칠하는 앱이라면 GPU의 도움을 많이 받지 못합니다. 그럼 내부적으로 어떠한 현상이 발생하는지 말씀 드리겠습니다.

  1. 열심히 중첩된 레이아웃으로 구조를 만든다. (OverDraw를 많이 만든다)
  2. 웹과 통신해 거대한 이미지를 받아 우리 화면 해상도에 맞게 다시 줄여서 그린다. (네트워크 지연 + 이미지 리사이징 작업 진행)
  3. 현재 윈도우의 화면의 가로, 세로 사이즈를 계산한다. (시스템 콜 호출)
  4. 그 윈도우 안에서도 원을 그리거나 색칠을 하는 부가적인 작업을 한다.

레이아웃 튜닝하기 - 참고 https://medium.com/@nicolasbridoux

이야기 한 것과 일치하지는 않지만 나름 비슷한 화면을 구했습니다. 보시면 왼쪽 화면에서 Frame Drop이 발생한 것을 확인하실 수 있습니다.

화면 구성 및 색상 구성에 대한 상세한 튜닝 방법에 도움이 될만한 글을 공유드립니다.

최악의 경우 - 다른 앱과의 자원 경합
백그라운드 동작하는 다른 앱이 과도한 자원을 사용하여 나의 앱에 자원을 주지 못하는 경우입니다. 이러한 일은 종종 발생하는 일로, 예를 들어 백그라운드에서 네트워크 스트리밍으로 음악을 들으면서, 우리가 만든 앱을 실행을 하는 상황으로 이해하시면 됩니다.

app-high-cpu-usage

위 데이터를 보면 운영체제 전체적으로는 83%의 CPU를 사용하였고, APP에서는 53%의 CPU를 사용했습니다. 하지만 데이터를 보니 IO 대기에 20%, Steal Time에 20%를 사용하였습니다. 즉 다른 앱에 영향을 받은 비율(Steal)이 20%, IO 속도가 나지 않아 20%를 대기한 것이죠.

이런 경우를 대비하기 위해서는 우리가 만든 앱이 처음부터 적은 자원을 쓰도록 설계하는 것 밖에 없습니다. 저희는 앱의 CPU 사용량이 50%가 넘지 않게 하도록 가이드하고 있습니다.

끊임없는 네트워크 통신
무선  통신 상태 시스템 - 안드로이드 개발자 사이트

무선 통신을 하는 것은 배터리를 많이 소모합니다. 네트워크 통신을 하다가 5초 동안 idle 상태로 가면 네트워크 라디오 센서가 저전력으로 바뀌고, 여기서 12초 이상 idle이면 대기 상태로 바뀝니다. 즉 끊임없이 통신을 하는 앱은 많은 배터리를 소모한다는 것입니다.

예를 들어 18초의 주기로 1초마다 계속 통신을 한다면 영구적으로 배터리는 활성 상태를 유지하며, 대기 상태로 전환되지 않아서 많은 배터리를 소모합니다. 만약 주기를 5초 미만으로 데이터를 주고받는다면 고전력을 소비하는 상태로 데이터를 주고받는다는 것을 의미합니다. 즉 데이터를 주고받을 때, 한꺼번에 데이터를 모아서 받는 것이 훨씬 배터리 소모가 적게 듭니다.

관련 상세 내용은 효율적인 네트워크 접근을 위한 다운로드 최적화 를 참고하시길 바랍니다.

제조사의 버그
폰이 출시된 지 얼마 되지 않아, 1~2시간 이상 화면을 끄지 않고, 계속해서 앱을 사용하는 경우 화면이 멈추는 현상들이 특정 단말에서 종종 나옵니다. 예를 들어 영화를 2시간 정도 보고, 앱을 실행했을 때를 의미합니다. 보통 데드라인에 맞추어 신규 출시된 폰에서 종종 발생하며, 이후 폰 펌웨어 업데이트를 통해 안정화되는 경우가 종종 목격되었습니다. 결국 폰이 뜨거워지면 평상시에 1/3 수준으로 밖에 CPU를 사용할 수밖에 없어서 성능이 늦어지는 상황이 발생할 수밖에 없습니다.

정리하며
이 외에도 여러 가지 문제들이 숨겨져 있습니다. 단지 크래시 리포트에서는 보이지 않을 뿐이죠. IMQA는 크래시를 넘어서 ANR이 발생하지 않더라도 화면 로딩 속도 지연 및 병목 구간을 찾아내는 솔루션입니다.

현재 IMQA의 레퍼런스로는 아모레퍼시픽, 하이닉스, 보험앱, 건강앱, 배달앱, 마사회 등이 있으며, 대규모 서비스에 적용 및 컨설팅 도구로 사용되었습니다.

B2B 솔루션 임에도 불구하고, 고객의 불편함을 최소화하려는 금융권, 유통에 먼저 적용되었으니 궁금한 점이 있으면 언제든지 연락 주시기 바랍니다.

좀 더 쉽게 볼 수 있는 서비스에 대한 설명은 IMQA 활용 가이드_개발자편 을 참고하시면 될듯합니다.

또한 화면 로딩 속도 이슈의 원인과 해결 방안을 다룬 '앱 서비스 장애편 #1 - 화면 로딩 속도'편도 함께 확인해보시기 바랍니다!

모바일 앱의 장애나 별점 테러를 받고 계시다면 연락 주시길 부탁드립니다.

태그

좋아요! 성공적으로 구독하셨어요.
좋아요! 이제 결제를 끝내고 모든 컨텐츠를 활성화하세요.
또 봐서 반가워요! 성공적으로 로그인 했습니다.
성공입니다! 이제 계정이 완전히 활성화되어 모든 컨텐츠에 접근 가능합니다.