Category Archives: 허접프로그래머

[Linux] sar를 이용하여 서버의 현재 부하상태를 알아보기

사용자 삽입 이미지
서버가 부하가 가중되면 가장 먼저 알아내야 하는것이 원인을 파악하는 것일 겁니다. 하지만 그러기 어려운 상황이라면 가장 먼저 파악해야 하는것이 CPU에서 오는 부하인지 I/O에서 오는 부하인지를 알아내야 할 것입니다.

우선 기본적으로 부하상태(Load Average)를 알아내기 위해 top, w, uptime의 명령어를 활용할 수 있습니다.

top

top - 11:46:06 up 77 days,  1:16,  1 user,  load average: 0.06, 0.15, 0.11
Tasks:  87 total,   1 running,  86 sleeping,   0 stopped,   0 zombie
Cpu(s):  6.5%us,  0.5%sy,  0.0%ni, 92.7%id,  0.0%wa,  0.0%hi,  0.3%si,  0.0%st
Mem:   4033528k total,  1571260k used,  2462268k free,    26472k buffers
Swap:  3911816k total,      128k used,  3911688k free,   627956k cached

w

11:47:39 up 77 days,  1:17,  1 user,  load average: 0.08, 0.14, 0.11
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    121.133.79.177   11:13    0.00s  0.01s  0.00s w

uptime

11:47:56 up 77 days,  1:18,  1 user,  load average: 0.06, 0.13, 0.10

top > w > uptime 순으로 보여지는 정보의 양이 적어지는군요. top의 경우에는 실행중인 프로세스의 목록도 표시됩니다. 오늘 언급하려는것은 sar(System Activity Reporter)입니다. 매우 간단하게 부하를 분류하여 보여줍니다.

$ sar
Linux 2.6.18-238.19.1.el5 (Theeye)        09/29/11

16:20:10 CPU %user %nice %system %iowait %steal %idle
16:30:10 all 17.81 0.84  2.75    68.50   0.00   10.10
16:40:23 all 16.75 0.00  3.26    69.68   0.00   10.30
Average: all 17.28 0.41  3.01    69.10   0.00   10.20

위의 시스템은 IO대기가 차지하는 비율이 70%에 육박하는 상태입니다. IO문제가 분명하군요. 보통 DB 서버들이 부하가 걸릴때 위와 같은 모습을 보입니다. 이 경우 메모리를 증설하면 디스크에 읽고 써야 하는 데이터를 그만큼 메모리에 올릴 수 있어 디스크의 IO를 현저히 줄일 수 있습니다.

$ sar
Linux 2.6.18-238.19.1.el5 (Theeye)        09/29/11

14:30:01 CPU %user %nice %system %iowait %steal %idle
15:50:01 all 14.67 0.10  4.51    1.63    0.00   79.08
16:00:01 all 17.06 4.91  4.96    1.53    0.00   71.53
16:10:01 all 14.63 0.00  4.74    1.21    0.00   79.41
Average: all 13.04 2.18  3.98    8.36    0.00   72.45

메모리를 8G에서 16G로 증설한 후의 모습입니다. 정말 신기할 정도로 IO가 줄었네요. sar에서 자주 쓰이는 옵션으로는 다음과 같은 것이 있지 않을까 생각합니다.

-u : CPU 사용율 확인
-P : 특정 CPU의 사용율 확인 (sar -P 0)
-q : Load Average 확인
-r : 메모리 사용 현황 확인

sar는 sysstat 패키지에 포함되어있습니다. 다음과 같이 설치 가능합니다.

$ yum install sysstat

[Java/Android] AsyncTask를 사용하여 특정 작업 수행하기

기존에 글 [Thread를 이용한 특정 작업 수행하기]에서는 쓰레드를 이용하여 백그라운드에서 다른 작업을 수행하는 방법에 대해 설명을 하였습니다. 하지만 이방법은 안드로이드에서는 UI에 접근할 수 없는등 몇가지 예상치 못한 문제를 만날 수 있습니다.

이경우 AsyncTask를 사용하시면 이러한 문제를 해결할 수 있습니다. 간단하게 만들어본 예제를 보여드리겠습니다.

private Button mButton;
private ProgressBar mProgress;
private AsyncTask<Void, Integer, Void> mTask;

@Override
public void onCreate(Bundle savedInstanceState)
{
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  mButton = (Button) findViewById(R.id.button);
  mProgress = (ProgressBar) findViewById(R.id.progress);

  mButton.setOnClickListener(this);
}

@Override
public void onClick(View v)
{
  // 시작 버튼
  if(mButton.getText().equals("start"))
  {
    // AsyncTask는 재활용할 수 없습니다. 매번 새롭게 생성
    mTask = new AsyncTask<Void, Integer, Void>()
    {
      // 작업 취소시 사용하기 위한 플래그
      private boolean isCanceled = false;

      // 작업을 시작하기 직전에 호출되는 메서드
      @Override
      protected void onPreExecute()
      {
        publishProgress(0);
        isCanceled = false;
      }

      // 백그라운드에서 작업
      @Override
      protected Void doInBackground(Void... params)
      {
        // 0.1초마다 100단계로 구성된 프로그래스바를 1씩 증가시킵니다.
        for(int i = 1 ; i <= 100 && ! isCanceled ; i++)
        {
          try
          {
            publishProgress(i);
            Thread.sleep(100);
          }
          catch(InterruptedException e)
          {
            e.printStackTrace();
          }
        }

        return null;
      }

      // publishProgress() 메서드를 통해 호출됩니다. 진행사항을 표시하는데에 쓰입니다.
      @Override
      protected void onProgressUpdate(Integer... progress)
      {
        mProgress.setProgress(progress[0]);
      }

      // 작업 완료 직후에 호출되는 메소드
      @Override
      protected void onPostExecute(Void result)
      {
        Toast.makeText(AsyncTaskExampleActivity.this, "완료됨", Toast.LENGTH_SHORT).show();
        mButton.setText("start");
      }

      // 외부에서 강제로 취소할때 호출되는 메소드
      @Override
      protected void onCancelled()
      {
        isCanceled = true;
        publishProgress(0);
        Toast.makeText(AsyncTaskExampleActivity.this, "취소됨", Toast.LENGTH_SHORT).show();
      }
    };

    // 작업 시작
    mTask.execute();
    mButton.setText("cancel");
  }
  // 취소 버튼
  else if(mButton.getText().equals("cancel"))
  {
    mTask.cancel(false);
    mButton.setText("start");
  }
}

위에서 관심있게 이야기 해볼것은 new AsyncTask를 선언할때에 나오는 3개의 Generic 인자입니다.

첫번째 인자execute()시에 넘겨 받을 인자를 정의합니다. doInBackground()에서 호출될때 값이 넘어가게 되며 여러개의 값을 넘겨받을 수 있도록 되어있습니다. 다수의 값을 처리하도록 할 수 있습니다.

두번째 인자onProgressUpdate()가 호출될때 넘겨받을 인자를 뜻합니다. 마찬가지로 publishProgress()를 통해 넘겨줄 인자이기도 합니다. 마찬가지로 다수의 인자를 넘겨받을수도 있으며 위의 예제에서는 단순히 ProgressBar를 증가시키는것밖에 안하기 때문에 1개의 Integer형만을 받도록 하였습니다.

세번째 인자onPostExecute()가 호출될때 넘겨받을 인자를 뜻합니다. 작업이 끝날때 어떤작업이 끝났는지를 알려주고 싶다거나 하면 그 작업 이름을 넘겨주면 되겠죠. 이와 같이 작업이 끝났을때 무언가 처리를 하고 싶은데 이것을 작업 수행 시점에 넘겨주고 싶다면 이 세번째 인자를 사용하시면 됩니다.

사용자 삽입 이미지[샘플코드 다운로드]