2017 어느 봄날

April 24, 2017

서울시계(市界) vs 서울까지

니가타 유자와(Niigata Yuzawa) 스키 여행

April 24, 2017

2017-01-09 naeba ski resort

생존본능을 발휘했던 최상급 코스;;

2017-01-09 八海山雪室

2017-01-09 hakkaisan warehouse

2017-01-10 yuzawa park hotel

2017-01-11 way back to niigata

나도 모르게 카메라 셔터를 누르고 있었다

과거와 현재가 공존하는 정선

May 22, 2016

20160518_1

 

20160518_2

 

2016-05-17 강원도 정선군

한라산

April 24, 2016

2016-04-17

2016-04-17 한라산

술래잡기 전봇대

April 5, 2016

 

2016-03-26

2016-03-26 종로구 익선동

わかやま城

January 9, 2016

2015-12-28

 

2015-12-28 和歌山城

Setup network streaming player (네트워크 스트리밍 플레이어)

October 14, 2014

배경

요즘 Audiophiler 들에게 각광받고 있는 기기는 단연 network stream player 이다. 마치 신개념을 무장한 기기로 보일 수도 있으나, 알맹이를 보면 기존 기기에 networking 기능을 더한 것이다. 네트워크 환경이 좋아지고, 편리한 부가기능들이 표준화 되면서 오디오 기기에 부가기능들이 추가되는 자연스런 행보라 하겠다. 하지만 역시나 오디오 기기에 그러한 기능들이 들어오면 가격이 무척 비싸 직딩에게는 그림의 떡일 뿐이다. 🙁

나는 바쁜 일상에서도 소중한 음악을 언제 어디에서나 쉽게 찾아 들고 싶었고, 네트워크 사운드 서버를 구성하여 집에있는 스피커를 최대한 활용해보고 싶었다. 지난 2년 동안 시행착오를 겪고 난 뒤 나름 만족할 만한 network streamer 를 구축하게 되었다. 그리하여 NAIM의 ND5 XS 처럼 멋있는 기기를 사용하고 싶지만,  자금이 넉넉지 않은 audiophiler 에게 기존 오디오 기기들을 100% 활용하면서 적은 비용으로 network stream player 를 구축하는데 도움이 되고자 포스팅을 시작한다.

naim_ND5_XS

NAIM ND5 XS

목적

  • streaming music server
    • 언제 어디에서나 음악을 들을 수 있어야 한다.
  • jukebox
    • 집에서는 고음질의 음악을 들을 수 있어야 한다. (a.k.a PC-FI)
  • network sound server
    • 쇼파위에서 맥북으로 youtube 볼 때, 스피커로 소리를 들을 수 있어야 한다.

Overview

구축 환경

  • Ubuntu Server 14.04.1 LTS (GNU/Linux 3.13.0-36-generic x86_64)
  • openjdk 7
  • nginx 1.4.6 (option)

Network sound server

여기서 pulseaudio 를 설치하는 가장 궁극적인 목적은 network sound server 를 구축하기 위함이다. pulseaudio 외에도 다른 방법이 존재하지만, 경험상 가장 간편하고 깔끔하였다. 엮으로 pulseaudio 가 작성된 이유이기도 하다. network sound server 기능이 필요 없다면 alsa 로 음악을 재생하는것이 음질면에서 더욱 유리하다.

1. install pulseaudio

2. configuration

대부분 alsa usb audio hotplug 로 DAC를 연결할 텐데,  hardware index 가 정상적으로 등록되어 있는지 확인해보자.

* /etc/asound.conf

* start pulseaudio

* speaker test

pulseaudio daemon 이 system mode 로 동작할 때에는 “pulse-access” group 에 속하지 않은 user 는 소리를 재생할 수 없다.

user를 pulse-access group 에 추가한다.

network를 통하여 sound를 재생하기 위해서는 pulseaudio에서 제공하는 module을 적재해야하며, ACL 추가가 필요하다.

* /etc/pulse/default.pa, /etc/pulse/system.pa

3. add client

soundflower (Mac 10.9.5)

pulseaudio 는 ESD 를 지원하여 외부에서 ESD protocol 로 송신만 해주면 pulseaudio 는 그 소리를 수신하여 재생시킬 수 있다. soundflower 라는 mac 용 프로그램을 이용하여 ESD protocol 로 pulseaudio 에 전달해보자.

soundflower 를 설치하고나면 sound preferences 에서 soundflower device 가 추가된 것을 볼 수 있다.  output device 에서 soundflower device 를 선택한다.

ss_soundflower1

이제 mac 의 모든 소리를 sound server 로 전송할 차례만 남았다. 간단한 shell script 하나 작성해두고 두고두고 사용하자.

* ~/bin/send_sound_to_esound_server.sh

Streaming music server

1. install subsonic

subsonic 공식페이지의 설치 가이드를 참고하여 설치한다.

2. configuration

* /etc/default/subsonic

* /etc/nginx/nginx.conf

nginx 에 연동하지 않고 직접 http://hostname:4040/subsonic 으로도 접근이 가능하다.

* start subsonic & restart nginx

* add audio file paths

http(s)://hostname/subsonic 에 접속하여 admin 권한을 가지는 계정을 생성한다.

그리고나서 admin 계정으로 로그인하여 “Settings > Media folders” tab 에서 audio files 이 있는 directory 를 추가한다.

ss_subsonic_media_folders

3. add client

subsonic 은 많은 device 를 지원한다. 자신의 device 에 맞는 app 을 설치하고나서 subsonic server 를 추가하면 audio files 를 재생할 수 있다.

* iSub (iphone app)

iSub 는 cache (pre downloading) 기능이 있어, off line mode 에서도 음악을 들을 수 있다.

ss_isub

Jukebox

1. install mpd

2. configuration

* /etc/mpd.conf

* pulseaudio-access group 에 mpd 추가

* start mpd

3. add client

mpd 도 많은 device 를 지원한다. mpd clients 를 보고 자신의 구미에 맞는 것을 고르자.

* MPoD (iphone app)

ss_mpod

 

어둠속 기다림

October 11, 2014

DSC00244

京都夜

September 2, 2014

DSC00059

Implementation of java.util.Map 의 보이지 않는 위험

December 12, 2011

a pit of infinite loopeness

배경

Server scale-up 이후부터 Web Application을 배포하고 나면 몇시간 이내에 특정 서버의 CPU 사용률이 100%에 이르는 사태가 발생하였다. thread dump를 확인해 봐도 특별한 이상 징후는 발견되지 않았다. 단지 아래와 같이 여러 Thread 들이 java.util.WeakHashMap.get(WeakHashMap.java:355) 에 걸려있었으나, Thread.State가 RUNNABLE 이기 때문에 주의깊게 보지 않았다. 왜냐하면 지금까지 Java core package에서 문제가 발생한 적은 한 번도 없거니와, Java core package를 의심하게 되면 밑도끝도 없이 모든것을 의심해야 하는 불상사가 발생하기 때문이다. 난 적어도 절친은 믿고 세상을 살아간다. 훗날 내 뒤통수를 칠 지언정…

문제가 된 web application에서 사용하는 XStream의 version이 1.3인데, 혹시나 하는 마음에 공식 XStream site에 들어가서 change history를 보다가 XSTR-584: Race condition in XmlFriendlyReplacer issue를 발견했다. Issue description 에는 내가 겪은 증상과 동일했고, 문제의 원인은 not synchronized java.util.WeakHashMap 을 사용했기 때문이라고 간단히 쓰여 있었다.

com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer makes use of 2 WeakHashmaps to hold string.
Those maps are accessed multi-threaded, but are not synchronized.

This can lead to access on those maps occupying all CPU-resources, which can only get solved by restarting the VM.
This happens under rare heavily multi-threaded circumstances, nevertheless the impact is critical.

Implementation of java.util.Map이 가진 잠재적 문제점

구글링을 해보니 Multi-threaded situation(under high concurrency) 에서 Implementation of java.util.Map 의 get() 호출 시 method 내부에서 infinite loop에 빠질 수 있다고 한다. 해당 되는 Implementation of java.util.Map 는 API Document에 아래와 같이 설명된 Class 들이다.

Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be “wrapped” using the Collections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map:

Map m = Collections.synchronizedMap(new HashMap(…));

  • java.util.HashMap
  • java.util.LinkedHashMap
  • java.util.TreeMap
  • java.util.WeakHashMap

더욱이 문제는 대부분의 개발자들은 concurrency로 인한 data corruption 을 염두해두고 위 Class들을 자주 사용한다는 점이다. 즉 개발자가 Java Document의 “Note that this implementation is not synchronized” 의 의미를 race condition 에 의한 data corruption 까지만 이해하고 위 Class들을 자주 사용할수록, infinite loop에 빠질 확률이 더 높아진다.

그 결과 JVM hanging 뿐만 아니라 해당 서버에서 제공하는 서비스들(i.e daemon)까지도 CPU 자원을 사용할 수 없기 때문에 문제는 더욱 커진다. 이렇게 불시에 찾아와 CPU 자원을 모두 고갈시키는 불청객의 위험이 우리 주위에 도사리고 있다.

어느 CS 전공자가 위 Note만 보고 JVM이 hanging 될꺼라 예상할 수 있을까? 5년 넘게 Java language 의 API들을 많이 사용해 왔지만, 위 처럼 황당한 경우는 처음이다. 최소한 infinite loop 에 대한 경고는 해야 하지 않았을까? Synchronization에 따른 deadlock은 들어 봤어도, not synchronization에 따른 infinite loop는 들어 본 적이 없다.

언제 infinite loop가 발생하는가?

기가 막히게 제목을 잘 지은 “A Beautiful Race Condition” article 에서 infinite loop가 언제 발생할 수 있는지에 대해 설명이 잘 되어 있다.

java.util.HashMap.transfer() 를 호출하고 난 뒤 Entry[] table의 상태를 그려보았다.

    • normal case

    • abnormal case

    1. 2개 이상의 thread가 Map에 동시에 write할 때 rehash의 조건이 true 이면
    2. Map의 어느 bucket의 Entry.next 가 서로를 가리킨다. infinite loop 생성
    3. infinite loop Entry가 있는 bucket 을 read 할 때 해당 thread는 hanging

대응 방법

  1. java.util.concurrent.ConcurrentHashMap 사용
  2. Collections.synchronizedMap method 사용하여 wrapping
  3. mutator method 에 접근 할 때 synchronized 처리
 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org