<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>로그프레소 랩</title>
    <description>로그프레소 연구소에서 운영하는 기술 블로그입니다.</description>
    <link>/</link>
    <atom:link href="/rss" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 14 Sep 2022 15:16:45 +0900</pubDate>
    <lastBuildDate>Wed, 14 Sep 2022 15:16:45 +0900</lastBuildDate>
    <generator>Jekyll v3.9.2</generator>
    
      <item>
        <title>GraalVM 으로 네이티브 이미지 만들기</title>
        <description>&lt;p&gt;GraalVM은 GraalVM 네이티브 이미지라는 AOT (ahead-of-time) 컴파일 기술을 제공합니다. 이는 자바 코드를 독립적으로 실행 가능한 네이티브 이미지로 컴파일해주는 기술입니다. GraalVM으로 컴파일된 실행 파일은 응용프로그램과 응용프로그램이 사용하는 라이브러리의 모든 클래스와 Substrate VM이라는 런타임을 내장합니다.&lt;/p&gt;

&lt;p&gt;즉, 생성된 실행 파일은 JVM으로 구동하는게 아니라 자체 VM을 내장하고 있어서, 메모리 관리나 스레드 스케줄링 등의 모든 기능을 수행합니다.&lt;/p&gt;

&lt;p&gt;이전 글&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://lab.logpresso.com/2020/05/10/graalvm&quot;&gt;GraalVM 소개&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 글에서는 공개 배포된 &lt;a href=&quot;https://github.com/logpresso/community&quot;&gt;로그프레소 미니&lt;/a&gt; 실행 파일을 GraalVM으로 어떻게 빌드했는지 소개합니다.&lt;/p&gt;

&lt;h3 id=&quot;윈도우-빌드-환경-세팅&quot;&gt;윈도우 빌드 환경 세팅&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;윈도우용 GraalVM 설치 파일 다운로드
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://github.com/graalvm/graalvm-ce-builds/releases&quot;&gt;GraalVM Community Edition Builds&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;시스템 환경변수 설정
    &lt;ul&gt;
      &lt;li&gt;JAVA_HOME: graalvm 배포 파일에 포함된 JDK로 경로를 지정합니다.&lt;/li&gt;
      &lt;li&gt;PATH: graalvm 경로의 bin 디렉터리가 포함되도록 변경합니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;native-image 설치
압축을 해제하면 bin 디렉터리에 gu.cmd 파일이 있습니다. 이를 아래와 같이 실행하여 native-image 패키지를 설치합니다.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; cmd&amp;gt; gu &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;native-image
 Downloading: Component catalog from www.graalvm.org
 Processing Component: Native Image
 Downloading: Component native-image: Native Image  from github.com
 Installing new component: Native Image &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;org.graalvm.native-image, version 21.0.0.2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Microsoft Visual C++ 준비&lt;br /&gt;
이 문서는 Visual Studio 2019 환경에서 작성되었지만, GraalVM은 아래의 윈도우 빌드 환경을 명시하고 있습니다.
    &lt;ul&gt;
      &lt;li&gt;JDK 8: MSVC 2010 SP1 버전 필요&lt;/li&gt;
      &lt;li&gt;JDK 11: MSVC 2017 15.5.5 이상의 버전 필요&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;리플렉션-설정&quot;&gt;리플렉션 설정&lt;/h3&gt;

&lt;p&gt;GraalVM 네이티브 이미지가 자바 바이트코드를 분석해서 의존성을 추출하긴 하지만, 응용 프로그램이 런타임에 동적으로 리플렉션을 호출하는 모든 경우의 수를 추적할 수 없기 때문에 리플렉션으로 호출되는 대상을 모두 설정으로 지정해야 합니다.&lt;/p&gt;

&lt;p&gt;예를 들면 아래와 같이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reflect-config.json&lt;/code&gt; 파일을 구성합니다:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;org.araqne.logdb.query.engine.QueryServiceImpl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allDeclaredConstructors&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allPublicConstructors&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allDeclaredFields&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allDeclaredMethods&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allPublicMethods&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;org.araqne.logdb.query.engine.QueryParserServiceImpl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allDeclaredConstructors&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allPublicConstructors&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allDeclaredFields&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allDeclaredMethods&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allPublicMethods&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 리플렉션 설정 추출 작업이 너무 힘들기 때문에 &lt;a href=&quot;https://docs.oracle.com/en/graalvm/enterprise/19/guide/reference/native-image/tracing-agent.html&quot;&gt;Tracing Agent&lt;/a&gt;를 사용하는 경우도 있으나, 런타임에 발견하지 못한 클래스가 누락되기 때문에 이 글에서는 설명하지 않습니다.&lt;/p&gt;

&lt;h3 id=&quot;이미지-빌드&quot;&gt;이미지 빌드&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x64 Native Tools Command Prompt&lt;/code&gt;를 실행하고, 해당 명령 프롬프트에서 아래의 명령을 실행합니다. 어차피 같은 명령줄 아닌가 해서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Developer Command Prompt&lt;/code&gt;에서 빌드하면 컴파일 중 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;guessArchitecture&lt;/code&gt;에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NullPointerException&lt;/code&gt;을 맞게 됩니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cmd&amp;gt; native-image &lt;span class=&quot;nt&quot;&gt;-jar&lt;/span&gt; logpresso-mini-1.0.0-package.jar logpresso &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt;:-CheckToolchain &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt;:ReflectionConfigurationFiles&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;reflect-config.json &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt;:IncludeResources&lt;span class=&quot;o&quot;&gt;=(&lt;/span&gt;.&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/.&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;EvtxMessages.json&lt;span class=&quot;s2&quot;&gt;$&quot;|&quot;&lt;/span&gt;.&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/.&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;properties&lt;span class=&quot;nv&quot;&gt;$)&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-fallback&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--enable-http&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--enable-https&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]    classlist:   2,356.89 ms,  0.96 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]        &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;cap&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:   2,857.85 ms,  0.96 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]        setup:   6,108.98 ms,  0.96 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]     &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;clinit&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:     723.32 ms,  3.69 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]   &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;typeflow&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:  15,988.98 ms,  3.69 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]    &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;objects&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:  14,367.36 ms,  3.69 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]   &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;features&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:   1,497.97 ms,  3.69 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]     analysis:  33,515.24 ms,  3.69 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]     universe:   1,438.35 ms,  3.69 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]      &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;parse&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:   6,594.25 ms,  4.34 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]     &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;inline&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:   4,539.15 ms,  6.09 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]    &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;compile&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:  22,801.97 ms,  6.40 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]      compile:  36,019.61 ms,  6.40 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]        image:   3,698.44 ms,  6.40 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]        write:   1,230.76 ms,  6.40 GB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;logpresso:38392]      &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;total]:  84,567.52 ms,  6.40 GB

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jar&lt;/code&gt; 옵션: AOT 컴파일 대상 JAR 파일을 지정합니다.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;H:-CheckToolchain&lt;/code&gt;: 툴 체인 검사를 생략합니다. 이 옵션을 넣지 않으면 아래와 같이 IA64 미지원 오류 메시지를 보게 됩니다.&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  Error: Native-image building on Windows currently only supports target architecture: AMD64 ((x64) unsupported)
  Error: To prevent native-toolchain checking provide command-line option -H:-CheckToolchain
  Error: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception
  Error: Image build request failed with exit status 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;H:ReflectionConfigurationFiles&lt;/code&gt;: 리플렉션 클래스 설정 파일을 지정합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;H:IncludeResources&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getResourceAsStream()&lt;/code&gt; 등으로 리소스를 읽어오는 경우, 생성되는 실행 파일에 리소스를 내장해야 합니다. 이를 위해 내장할 리소스 파일의 목록을 정규표현식으로 지정합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-enable-http&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--enable-https&lt;/code&gt;: 기본 빌드에서는 HTTP 통신 기능이 포함되지 않으므로, 별도로 옵션을 추가해야 합니다. (실행 파일 크기 약 13MB 증가)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;정리&quot;&gt;정리&lt;/h3&gt;

&lt;p&gt;GraalVM 네이티브 이미지 기술이 아직까지는 일부 불안정하게 보이는 부분도 있고, 빌드 오류 메시지가 친절하지는 않아서 JAR 버전 의존성이 불일치한다거나 하는 경우에 원인을 모르고 헤매게 되는 경우들이 있습니다.&lt;/p&gt;

&lt;p&gt;그렇지만 &lt;a href=&quot;https://github.com/logpresso/community&quot;&gt;로그프레소 미니&lt;/a&gt;처럼 자바 기반의 기존 프로젝트를 별도의 JVM 없이 단 하나의 작은 실행 파일로 단순화하여 배포할 수 있다는 점에서는 매력적인 기술이라 생각합니다.&lt;/p&gt;

&lt;p&gt;리눅스의 경우에는 상대적으로 손쉽게 빌드 환경을 구성할 수 있으니 자바 개발하신다면 한 번 네이티브 빌드를 시도해보세요. 데비안 계열을 쓰시는 경우에는 미리 빌드된 &lt;a href=&quot;https://github.com/dongjinleekr/graalvm-ce-deb/releases&quot;&gt;deb 패키지&lt;/a&gt;를 활용해보시면 좋습니다.&lt;/p&gt;

&lt;h3 id=&quot;레퍼런스&quot;&gt;레퍼런스&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.graalvm.org/reference-manual/native-image/&quot;&gt;GraalVM Native Image&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.graalvm.org/docs/getting-started/windows/#prerequisites-for-using-native-image-on-windows&quot;&gt;Prerequisites for Using Native Image on Windows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 27 May 2021 12:00:00 +0900</pubDate>
        <link>/2021/05/27/graalvm-native-image</link>
        <guid isPermaLink="true">/2021/05/27/graalvm-native-image</guid>
        
        
        <category>database</category>
        
      </item>
    
      <item>
        <title>TAXII 프로토콜의 이해</title>
        <description>&lt;p&gt;TAXII는 Trusted Automated Exchange of Intelligence Information의 약어로 HTTPS를 통해 사이버 위협 정보를 공유하는 프로토콜을 의미합니다. TAXII 프로토콜은 2.1 버전까지 나왔지만, 아직까지 개발자들이 참조할만한 국문 자료가 없어서 그런지 국내에서 구현체를 보기 힘들었습니다.&lt;/p&gt;

&lt;p&gt;TAXII 규격을 완전히 이해하려면 &lt;a href=&quot;https://oasis-open.github.io/cti-documentation/stix/intro&quot;&gt;STIX&lt;/a&gt;와 CybOX 규격(&lt;a href=&quot;http://docs.oasis-open.org/cti/stix/v2.0/stix-v2.0-part4-cyber-observable-objects.html&quot;&gt;STIX 2.0에 통합됨&lt;/a&gt;)을 함께 살펴봐야 하지만, 이 글에서는 한국정보보호산업협회(KISIA)를 통한 배포 사례가 있는 TAXII 2.0 버전 위주로 프로토콜을 설명하고, 2.1 버전과 2.0 버전의 차이에 대해 보완하여 설명합니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;참조-구현체&quot;&gt;참조 구현체&lt;/h2&gt;

&lt;p&gt;TAXII 2.1 서버의 참조 구현체로는 OASIS-OPEN이 공개한 medallion이 있습니다. 파이썬으로 구현되어 있으며 실제 어떤 식으로 TAXII 프로토콜이 동작하는지 간단히 확인할 수 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/oasis-open/cti-taxii-server&quot;&gt;Medallion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;정보-공유-모델&quot;&gt;정보 공유 모델&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.oasis-open.org/committees/cti/&quot;&gt;OASIS CTI TC&lt;/a&gt;에서 정의한 정보 공유 모델은 컬렉션과 채널이 있습니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/0006-understanding-taxii-protocol/taxii_diagram.png&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;정보 공유 모델&quot; /&gt;
&lt;/center&gt;

&lt;h3 id=&quot;컬렉션&quot;&gt;&lt;strong&gt;컬렉션&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;컬렉션은 CTI 객체를 관리하는 논리적 저장소입니다. TAXII 클라이언트와 서버가 요청, 응답 형태로 정보를 교환합니다.&lt;/p&gt;

&lt;h3 id=&quot;채널&quot;&gt;&lt;strong&gt;채널&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;채널은 구독을 걸어놓은 다수의 클라이언트가 서버에서 새로운 데이터를 받아갈 수 있도록 지원하는 통신 모델입니다. 그러나, TAXII 2.0, 2.1 모두 채널에 대한 명세를 정의하고 있지 않습니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;주요-개념&quot;&gt;주요 개념&lt;/h2&gt;
&lt;h3 id=&quot;디스커버리&quot;&gt;디스커버리&lt;/h3&gt;

&lt;p&gt;TAXII 디스커버리는 클라이언트가 네트워크에서 가용한 TAXII 서버가 존재하는지 검색해서 찾을 수 있는 방법을 제공합니다. 인터넷에 공개된 서버라면 &lt;strong&gt;DNS SRV 레코드 전달 방식&lt;/strong&gt;을 사용하고, 인가된 클라이언트만 접속하도록 허용한다면 &lt;strong&gt;디스커버리 엔드포인트&lt;/strong&gt;를 지정해야 합니다. 탐색 URL을 미리 설정해주어야 한다는 의미입니다.&lt;/p&gt;

&lt;h3 id=&quot;api-루트&quot;&gt;API 루트&lt;/h3&gt;

&lt;p&gt;API 루트는 TAXII 컬렉션 그룹을 제공합니다. 하나의 TAXII 서버는 여러 개의 API 루트를 지원할 수 있습니다. 이후 모든 요청은 API 루트 경로를 포함합니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;통신-헤더&quot;&gt;통신 헤더&lt;/h2&gt;

&lt;h3 id=&quot;클라이언트-헤더&quot;&gt;클라이언트 헤더&lt;/h3&gt;

&lt;p&gt;모든 TAXII 요청은 HTTP 헤더에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Accept&lt;/code&gt; 헤더를 포함해야 합니다:&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Accept: application/vnd.oasis.taxii+json; version=2.0&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;서버-헤더&quot;&gt;서버 헤더&lt;/h3&gt;

&lt;p&gt;모든 TAXII 응답은 HTTP 헤더에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; 헤더를 포함해야 합니다:&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type: application/vnd.oasis.taxii+json; version=2.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;주요-api&quot;&gt;주요 API&lt;/h2&gt;

&lt;p&gt;TAXII는 REST API 방식으로 정보를 주고 받습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Accept&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; 헤더에 기술된 것처럼, 모든 요청과 응답은 JSON 형식을 따릅니다.&lt;/p&gt;

&lt;h3 id=&quot;get-taxii&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /taxii&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;클라이언트가 TAXII 서비스의 디스커버리를 위해 사용합니다. 클라이언트가 서버를 찾는 과정이므로, API 루트까지 정확하게 알고 있다면 이 단계는 생략할 수 있습니다.&lt;/p&gt;

&lt;p&gt;서버는 요청을 받으면 아래 예시와 같이 응답합니다.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Some TAXII Server&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;This TAXII Server contains a listing of...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contact&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;string containing contact information&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;https://example.com/api1/&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;api_roots&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;https://example.com/api1/&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;https://example.com/api2/&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;https://example.net/trustgroup1/&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;(필수) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;: TAXII 서버 이름&lt;/li&gt;
  &lt;li&gt;(선택) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;description&lt;/code&gt;: TAXII 서버에 대한 설명&lt;/li&gt;
  &lt;li&gt;(선택) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;contact&lt;/code&gt;: 관리자 정보(이메일 주소 등)&lt;/li&gt;
  &lt;li&gt;(선택) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt;: 기본 API 루트. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api_roots&lt;/code&gt;에 존재하는 API 루트 URL 중 하나이어야 합니다.&lt;/li&gt;
  &lt;li&gt;(선택) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api_roots&lt;/code&gt;: 서버가 제공하는 API 루트 URL 목록. 서버는 클라이언트의 권한에 따라 이 목록을 필터링할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;get-api_root_name&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /[API_ROOT_NAME]&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;클라이언트가 API 루트를 조회할 때 사용합니다. 이 요청은 API 루트에 대한 메타데이터 조회이므로, 컬렉션 조회 시 이 과정은 생략할 수 있습니다.&lt;/p&gt;

&lt;p&gt;서버는 요청을 받으면 아래와 같이 응답합니다.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Malware Research Group&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;A trust group setup for malware researchers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;versions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;taxii-2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;max_content_length&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9765625&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;(필수) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;: API 루트 제목&lt;/li&gt;
  &lt;li&gt;(선택) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;description&lt;/code&gt;: API 루트에 대한 설명&lt;/li&gt;
  &lt;li&gt;(필수) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;versions&lt;/code&gt;: 이 API 루트가 지원하는 TAXII 프로토콜 버전을 나열합니다. 2.0 버전을 지원하면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taxii-2.0&lt;/code&gt;으로 명기합니다.&lt;/li&gt;
  &lt;li&gt;(필수) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max_content_length&lt;/code&gt;: HTTP 요청 시 전송 가능한 최대 바이트 수. 이 크기를 넘어가면 서버가 HTTP 상태 코드 413 (Request Entity Too Large)으로 응답할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;get-api_root_namecollections&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /[API_ROOT_NAME]/collections&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;서버가 지정된 API 루트에서 관리되는 컬렉션 목록을 조회할 떄 사용합니다. 조회 대상 컬렉션을 정확히 알고 있다면, 이 과정은 생략할 수 있습니다.&lt;/p&gt;

&lt;p&gt;서버는 요청을 받으면 아래와 같이 응답합니다.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;collections&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;91a7b528-80eb-42ed-a74d-c6fbd5a26116&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;High Value Indicator Collection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;This data collection is for collecting high value IOCs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;can_read&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;can_write&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;media_types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;application/vnd.oasis.stix+json; version=2.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;52892447-4d7e-4f70-b94d-d7f22742ff63&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Indicators from the past 24-hours&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;This data collection is for collecting current IOCs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;can_read&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;can_write&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;media_types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;application/vnd.oasis.stix+json; version=2.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;제공할 컬렉션이 하나도 없으면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;collections&lt;/code&gt; 키 자체가 생략되고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{}&lt;/code&gt;로 응답합니다. 각 컬렉션 정보의 속성은 아래와 같습니다:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;(필수) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt;: 컬렉션 식별자에 해당하는 GUID 값&lt;/li&gt;
  &lt;li&gt;(필수) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;: 컬렉션 제목&lt;/li&gt;
  &lt;li&gt;(선택) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;description&lt;/code&gt;: 컬렉션 설명&lt;/li&gt;
  &lt;li&gt;(필수) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;can_read&lt;/code&gt;: 읽기 가능 여부(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; 요청)에 대해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;로 표시&lt;/li&gt;
  &lt;li&gt;(필수) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;can_write&lt;/code&gt;: 쓰기 가능 여부(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; 요청)에 대해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;로 표시&lt;/li&gt;
  &lt;li&gt;(선택) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;media_types&lt;/code&gt;: 컬렉션에서 지원하는 객체 유형 목록. 생략하면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/vnd.oasis.stix+json&lt;/code&gt;로 간주합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;get-api_root_namecollectionsid&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /[API_ROOT_NAME]/collections/[ID]&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;클라이언트가 컬렉션에 저장된 위협 데이터를 검색하거나 목록을 조회할 때 사용합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[ID]&lt;/code&gt;에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /[API_ROOT_NAME]/collections/&lt;/code&gt;으로 확인한 컬렉션의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt;를 입력합니다. 전체 데이터 조회는 다음 예시와 같이 수행할 수 있습니다: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /default/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/objects/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;서버는 요청을 받으면 아래와 같이 응답합니다.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bundle--6773340e-59ad-4548-92b9-ad313f6bd61c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_collection_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;91a7b528-80eb-42ed-a74d-c6fbd5a26116&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-05-03T15:07:11.425Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;first_observed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-05-03T15:07:11.425123Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;observed-data--951af112-02e3-46cb-8852-d2f7dd34a673&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;labels&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;LOGPRESSO&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;last_observed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-05-03T15:07:11.425123Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;modified&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-05-03T15:07:11.425Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;observed-ipv4-10.10.10.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number_observed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ipv4-addr&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;27.72.56.98&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ipv4-addr&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;124.160.96.249&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;observed-data&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;spec_version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bundle&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;예시에서는 1개의 객체만 나오지만 실제로는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objects&lt;/code&gt; 키의 배열에 여러 개의 STIX 객체를 포함할 수 있습니다. STIX 도메인 객체는 공격 패턴 (Attack Pattern), 캠페인 (Campaign), 침해 지표 (Indicator), 관측 데이터 (Observed Data) 등으로 구성되고, 관측 데이터는 CybOX (Cyber Observable) 명세를 이용하여 표현됩니다. STIX에 대해서는 &lt;a href=&quot;https://tech.somma.kr/STIX2/&quot;&gt;쏘마 기술 블로그&lt;/a&gt;에 잘 정리된 내용이 있으니 이를 참조하시면 좋습니다.&lt;/p&gt;

&lt;p&gt;컬렉션 목록을 페이징하려면 요청 헤더에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Range&lt;/code&gt;를 포함시켜 보내면 됩니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GET .../collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/objects/ HTTP/1.1
Range: items 0-49
Accept: application/vnd.oasis.stix+json; version=2.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;인덱스는 0부터 시작하며, 끝 값까지 포함합니다. 즉, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0-49&lt;/code&gt;는 50개의 항목 조회를 의미합니다. 서버가 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Range&lt;/code&gt; 헤더를 포함한 요청을 받으면 아래와 같이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Range&lt;/code&gt; 헤더에 조회 범위와 전체 갯수를 포함하여 응답합니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;HTTP/1.1 206 Partial Content
Content-Range: items 0-49/500
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;특정 시점 이후 데이터를 수신하려면 데이터 목록 조회 시 쿼리 스트링에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;added_after&lt;/code&gt; 매개변수를 포함할 수 있습니다. 타임스탬프는 UTC (GMT+0) 기준입니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GET .../collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/objects/?added_after=2021-05-03T00:00:00.000Z HTTP/1.1
Accept: application/vnd.oasis.stix+json; version=2.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;get-api_root_namecollectionsidmanifest&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /[API_ROOT_NAME]/collections/[ID]/manifest/&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;컬렉션에 저장된 데이터를 조회하는 대신, 컬렉션에 대한 정보를 조회하여 추가 정보 수신 여부를 결정할 수 있습니다. 예를 들어, 클라이언트가 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /default/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/manifest/&lt;/code&gt; 요청을 보내면 아래와 같이 컬렉션의 메타데이터를 확인할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;indicator--29aba82c-5393-42a8-9edb-6a2cb1df070b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;date_added&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2016-11-01T03:04:05Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;versions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2016-11-03T12:30:59.000Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2016-12-03T12:30:59.000Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;media_types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;application/vnd.oasis.stix+json; version=2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;indicator--ef0b28e1-308c-4a30-8770-9b4851b260a5&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;date_added&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2016-11-01T10:29:05Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;versions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2016-11-03T12:30:59.000Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;media_types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;application/vnd.oasis.stix+json; version=2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;post-api_root_namecollectionsidobjects&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST /[API_ROOT_NAME]/collections/[ID]/objects/&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;이 요청은 서버에게 지정된 컬렉션에 데이터를 추가하도록 합니다. 참고로, TAXII 2.0에서 컬렉션 데이터를 추가 할 수 있지만 삭제는 지원하지 않습니다. 국내 구현체 중에는 커스텀 확장을 통해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;revoke&lt;/code&gt;를 지원하는 사례가 있습니다.&lt;/p&gt;

&lt;p&gt;예를 들어, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST /default/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/objects/&lt;/code&gt;을 통해 다음과 같은 데이터를 추가할 수 있습니다:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;observed-data&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;observed-data--951af112-02e3-46cb-8852-d2f7dd34a673&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-05-03T15:07:11.425Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;modified&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-05-03T15:07:11.425Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;labels&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;LOGPRESSO&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;first_observed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-05-03T15:07:11.425123Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;last_observed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-05-03T15:07:11.425123Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number_observed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ipv4-addr&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;27.72.56.98&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ipv4-addr&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;124.160.96.249&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h1 id=&quot;taxii-20과-21의-주요-차이&quot;&gt;TAXII 2.0과 2.1의 주요 차이&lt;/h1&gt;

&lt;p&gt;두 버전의 가장 큰 차이는 두 가지입니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;삭제 지원: 2.1은 &lt;a href=&quot;https://docs.oasis-open.org/cti/taxii/v2.1/cs01/taxii-v2.1-cs01.html#_Toc31107542&quot;&gt;DELETE 메소드를 통한 컬렉션 데이터의 삭제&lt;/a&gt;를 지원합니다.&lt;/li&gt;
  &lt;li&gt;item 단위의 페이징 제거: 새로 추가된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;limit&lt;/code&gt; 매개변수와 응답의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;more&lt;/code&gt; 속성을 이용하도록 바뀌었습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h1 id=&quot;로그프레소의-taxii-지원&quot;&gt;로그프레소의 TAXII 지원&lt;/h1&gt;

&lt;p&gt;로그프레소 소나 및 마에스트로에서는 아래의 쿼리 커맨드를 통해 TAXII 서버 연동을 지원합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taxii-discovery&lt;/code&gt;: TAXII 서버에서 API 루트를 포함한 일반 정보를 조회합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taxii-api-root&lt;/code&gt;: TAXII 서버에서 지정된 API 루트 정보를 조회합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taxii-collections&lt;/code&gt;: 지정된 TAXII 서버의 API 루트에서 컬렉션 목록을 조회합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taxii-objects&lt;/code&gt;: 지정된 TAXII 서버의 컬렉션에서 객체 목록을 조회합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taxii-add-observed-ip&lt;/code&gt;: 지정된 TAXII 서버의 컬렉션에 IP 주소 객체를 추가합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taxii-delete-object&lt;/code&gt;: 지정된 TAXII 서버의 컬렉션에서 객체를 삭제합니다(전용 확장 혹은 2.1 버전 대응).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h1 id=&quot;참고자료&quot;&gt;참고자료&lt;/h1&gt;

&lt;p&gt;완전한 TAXII 및 STIX 명세를 확인하시려면 아래 링크를 방문하세요.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://oasis-open.github.io/cti-documentation/taxii/intro.html&quot;&gt;Introduction to TAXII&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.oasis-open.org/cti/taxii/v2.0/taxii-v2.0.html&quot;&gt;OASIS TAXII Version 2.0&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.oasis-open.org/cti/taxii/v2.1/taxii-v2.1.html&quot;&gt;OASIS TAXII Version 2.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.oasis-open.org/cti/stix/v2.0/stix-v2.0-part2-stix-objects.html&quot;&gt;STIX Version 2.0. Part 2: STIX Objects&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.oasis-open.org/cti/stix/v2.0/stix-v2.0-part4-cyber-observable-objects.html&quot;&gt;STIX Version 2.0. Part 4: Cyber Observable Objects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 18 May 2021 09:00:00 +0900</pubDate>
        <link>/2021/05/18/understanding-taxii-protocol</link>
        <guid isPermaLink="true">/2021/05/18/understanding-taxii-protocol</guid>
        
        
        <category>database</category>
        
      </item>
    
      <item>
        <title>로그프레소 브랜드 디자인</title>
        <description>&lt;p&gt;지난 1편과 2편에서는 로그프레소 CI/BI에 담아야 할 것들을 점검하고 스토리텔링을 만들어 나가는 과정을 설명했습니다. 이 모든 내용을 본격적으로 구현한 최종 디자인 결과물을 보여드리려고 합니다.&lt;/p&gt;

&lt;p&gt;디자인 매뉴얼북, 가이드라인, 통합 브랜드 사용 규정 등을 제작할 때 어떤 것을 담으면 좋을지 고민하는 분들에게 로그프레소의 결과물이 참고가 되었으면 좋겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;브랜드-디자이너가-혼자-결정-구성원이-함께-결정&quot;&gt;브랜드 디자이너가 혼자 결정? 구성원이 함께 결정?&lt;/h2&gt;

&lt;p&gt;로그프레소는 ‘이디엄’의 제품명이었기 때문에 이전 로고가 존재하고 있던 상황이었습니다. 커피 잔을 위에서 내려다본 형상이 대문자 ‘O’가 들어갈 자리에 있었습니다.
저는 로그프레소가 지향하는 의사 결정 방식, 데이터 수집/분석과 데이터 시각화라는 제품의 특성, 지속적으로 기술 발전을 이어가는 회사의 비전을 로고에 담아야 한다고 생각했습니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/0005_logpresso-brand-new-ci-part-3/old_and_new.jpg&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;로그프레소 옛 로고(왼쪽)와 와 개편된 로고(오른쪽)&quot; alt=&quot;왼쪽엔 예전에 사용하던 로그프레소 로고, 오른쪽엔 새로 개편된 로고가 배치되어있다.&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;새로운 심벌의 기본 테마는 에스프레소 머신에서 커피가 추출되어 나오기 시작하는 그룹 헤드를 옆에서 본 모습을 사선 형태로 변형한 것입니다. 빠르게 데이터를 추출하는 로그프레소의 기술력을 형상화했습니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/0005_logpresso-brand-new-ci-part-3/layers.png&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;새 CI를 구성하는 레이어 세가지&quot; alt=&quot;테마를 겹쳐서 구성한 3개의 레이어&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;테마를 겹쳐서 구성한 3개의 레이어는 의사결정을 나타내는 벤 다이어그램의 교집합 모양과 데이터 사일로 모양을 동시에 표현합니다. 방사형 그래프(여러 항목을 한눈에 비교할 수 있는 시각화 그래프)의 육각형을 형상화해서 비정형/반정형 등 복잡한 형태의 데이터도 자동으로 시각화하는 기술을 표현했습니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/0005_logpresso-brand-new-ci-part-3/layers_abstract.jpg&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;새 CI의 3개 레이어&quot; alt=&quot;테마를 겹쳐서 구성한 3개의 레이어&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;지난 1편에서 CI/BI 개편의 전 과정을 투명하게 공유했다고 말씀드렸습니다. 브랜드 디자이너가 가진 디자인 영역의 전문성을 존중하되, 구성원들의 의견을 귀기울여 듣고 조율해가는 과정을 거쳤습니다. 특히 브랜드 응용 시스템 안에서 여러가지 작업물을 만들 때는 구성원들의 다양한 관점이 도움이 됩니다. 결과물을 받아볼 고객, 외부 공중과 자주 커뮤니케이션하는 구성원들이 고객 눈높이에서 점검해줄 수 있기 때문입니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/0005_logpresso-brand-new-ci-part-3/design_poll.jpg&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;사내 메신저를 통한 고객 기념품 패키지 디자인 투표&quot; alt=&quot;네스프레소 패키지 최종 버전을 사내 투표를 통해 선정하였습니다.&quot; /&gt;
&lt;/center&gt;

&lt;h2 id=&quot;브랜드-기본-시스템&quot;&gt;브랜드 기본 시스템&lt;/h2&gt;

&lt;p&gt;브랜드 아이덴티티 디자인은 크게 기본 시스템과 응용 시스템으로 나눌 수 있습니다. 
기본 시스템은 회사가 지향하는 가치를 도형화한 심벌, 회사 이름을 나타낸 로고 타입, 심벌과 로고 타입에 적용될 색상, 문서 등에 사용하는 서체 등 아이덴티티 디자인의 기초가 되는 요소를 말합니다. 앞서 로고와 심벌에 대한 내용을 말씀드렸고, 로그프레소의 기본 색상과 서체가 가지는 의미에 대해 설명 드리겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;색상-규정&quot;&gt;색상 규정&lt;/h3&gt;

&lt;p&gt;로그프레소 로고의 메인 색상은 빨강, 노랑, 오렌지색입니다. 고객의 소중한 데이터 자산을 기반으로 직관적인 의사 결정을 가져오는 솔루션을 강조하기 위해 오렌지색을 사용했습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Red	 → 추진력(신뢰)을 나타내며, 빠르게 추출하는 데이터 연상 [Confidence]&lt;/li&gt;
  &lt;li&gt;Yellow	 → 확고한 의사결정에 필요한 기분을 연상 [Logical]&lt;/li&gt;
  &lt;li&gt;Orange → 조화, 안전, 협조적, 중립(밸런스) [Freedom]&lt;/li&gt;
&lt;/ul&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/0005_logpresso-brand-new-ci-part-3/logpresso_color.png&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;로그프레소 색상 규정&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;로그프레소 색상 규정에 따라 지정된 색을 변형하여 다각화한 로그프레소 제품군별 색은 다음과 같습니다. 제품군에 지정한 색은 제품 및 관련 패키지 등에서 사용할 기본색이 됩니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/0005_logpresso-brand-new-ci-part-3/logpresso_BI_color.png&quot; style=&quot;width:100%;max-width: 800px;&quot; title=&quot;로그프레소 BI별 색상&quot; /&gt;
&lt;/center&gt;

&lt;h3 id=&quot;국영문-지정-서체&quot;&gt;국/영문 지정 서체&lt;/h3&gt;

&lt;p&gt;로그프레소의 국문 서체는 노토 산스(Noto Sans KR)입니다. 노토산스를 디자인 시스템 및 사내 업무용 서체로 선정했습니다. 노토 산스 서체는 차분하고, 깔끔한 느낌이 강한 고딕 폰트입니다. 가독성이 우수해서 웹 폰트부터 인쇄까지 다양한 분야에서 활용도가 높아 채택했습니다.&lt;/p&gt;

&lt;p&gt;로그프레소의 영문 서체는 고담(Gotham)입니다. 
고담 서체는 “혁신”과 “신뢰”를 상징합니다. 비즈니스 의사결정에 새로운 혁신을 제공하는 로그프레소를 나타내기 위한 최적의 서체라고 생각했습니다. 고담 서체의 우직하고 중립적인 느낌은 데이터의 수집/저장/분석/탐지/시각화를 자동화할 때 믿고 맡길 수 있는 로그프레소를 표현하기에 적합합니다.&lt;/p&gt;

&lt;p&gt;고담 서체도 시인성/판독성이 우수한 폰트로 평가받고 있습니다. 로그프레소가 앞으로 데이터 비즈니스 분야에서 고객에게 가장 먼저 눈에 띄는 존재가 되고자 하는 의미를 담았습니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/0005_logpresso-brand-new-ci-part-3/font.png&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;로그프레소 BI별 색상&quot; /&gt;
&lt;/center&gt;

&lt;h2 id=&quot;브랜드-응용-시스템&quot;&gt;브랜드 응용 시스템&lt;/h2&gt;

&lt;p&gt;브랜드 응용 시스템은 기본 시스템에서 제작한 요소를 다양한 결과물로 만들어낸 것을 말합니다. 서식(명함, 봉투, 신분증 등), 사인 시스템(간판, 배너, 현수막 등), 홍보용 물품(고객 기념품, 머그컵, 텀블러 등) 등 다양합니다.&lt;/p&gt;

&lt;p&gt;기본 시스템에서 제작한 로고와 심벌을 활용해 제품 패키지 박스, 브로슈어, 스티커 뿐만 아니라 펜, 메모지, 물티슈같은 홍보용 물품을 제작했습니다. 에스프레소처럼 빠르고 강렬하게 데이터를 추출하는 솔루션을 잘 표현할 수 있는 기념품으로 캡슐 커피 패키지를 만들어 기존 기념품과 차별화된 시도를 했습니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/0005_logpresso-brand-new-ci-part-3/branding_product.png&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;로그프레소 BI별 색상&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;브랜드 응용 결과물은 계속 업데이트 될 예정입니다. 앞으로 홀로그램 등 보는 관점에 따라 달라 보이는 색 조합을 활용한다든지, 육각형 모양을 활용해 정교하고 튼튼하면서 상호 공존하는 브랜드 모티브를 제작하고 브랜딩에 적극 활용하려 합니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;로그프레소 CI/BI 개편 과정에서 가장 중점적으로 생각했던 가치는 ‘고객’입니다. 제품과 비즈니스의 본질은 고객이어야 합니다. 이번 개편 과정에서 로그프레소는 결국 ‘고객이 신뢰할 수 있는 회사’가 되기 위해 노력해 왔고, 앞으로도 신뢰 자산을 쌓기 위해 노력해야 한다는 것을 다시금 깨닫게 되었습니다. 로그프레소는 언제나 가장 빠르고 정확한 빅데이터 플랫폼을 제공하고, 자동화 시스템으로 비즈니스의 중요 의사 결정을 돕는 솔루션을 제공하겠습니다. 로그프레소의 제품이 궁금하시거나 협업하시길 원하는 분들은 언제든 연락 주시기 바랍니다. 어떠한 형태의 데이터 엔지니어링도 로그프레소는 가능합니다.&lt;/p&gt;

&lt;p&gt;글/정리 : 최고운, 로그프레소 보안기획팀&lt;/p&gt;
</description>
        <pubDate>Mon, 03 May 2021 09:00:00 +0900</pubDate>
        <link>/2021/05/03/logpresso-brand-new-ci-part-3</link>
        <guid isPermaLink="true">/2021/05/03/logpresso-brand-new-ci-part-3</guid>
        
        
        <category>database</category>
        
      </item>
    
      <item>
        <title>로그프레소 스토리</title>
        <description>&lt;p&gt;지난 1편에서는 로그프레소 CI/BI를 새롭게 논의하고 작업하는 과정을 공유했습니다. 새로운 사명과 브랜드를 개편하기에 앞서 비즈니스의 본질과 고객 가치를 점검하면서 얻은 것들을 말씀드렸는데요.&lt;/p&gt;

&lt;p&gt;이제 본격적으로 로그프레소의 스토리와 그 안에 담긴 저희의 고민을 나누고자 합니다. 브랜드의 스토리텔링을 고민하시는 분들에게 로그프레소의 작업 과정이 도움이 되었으면 합니다.&lt;/p&gt;

&lt;h2 id=&quot;브랜드의-스토리를-정의하기-위해-어떤-과정을-거쳤는가&quot;&gt;브랜드의 스토리를 정의하기 위해 어떤 과정을 거쳤는가?&lt;/h2&gt;

&lt;p&gt;새로운 브랜드의 스토리를 정의하기에 앞서 기존 BI와 CI를 재점검했습니다. 이 과정에서는 아무래도 창업자와 초기 멤버들의 인터뷰가 중요합니다. &lt;strong&gt;창업자가 당시 정의한 문제, 시장에 대한 예측, 브랜드 가치&lt;/strong&gt;를 명확하게 정리하면 좋습니다.&lt;/p&gt;

&lt;p&gt;로그프레소의 시작은 2008년으로 거슬러 올라갑니다. 당시 통합보안관제시스템은 하루에 10GB 수준의 로그를 다루는 것인데도 매우 느렸습니다. 지배적인 데이터 기술은 오라클, MS-SQL, MySQL과 같은 관계형 데이터베이스였습니다. 이는 트랜잭션이 포함된 OLTP(Online Transaction Processing) 기술이라 비정형/반정형 데이터를 다뤄야 하는 보안 로그에는 기능적으로 적합하지 않았습니다. 로그프레소 양봉열 대표는 이 문제를 반드시 해결해야 한다고 생각했습니다. 당시로써는 새로운 개념의 데이터베이스 기술을 만든다는, 어찌 보면 무모한 도전을 시작한 것이죠.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/2021-04-19-logpresso-brand-new-ci-part-2/co-founders.jpg&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;로그프레소 공동창업자 3인&quot; alt=&quot;왼쪽부터 황원근 상무, 양봉열 대표, 구동언 상무&quot; /&gt;
&lt;br /&gt;(로그프레소 창업주역 3인, 왼쪽부터 황원근 상무, 양봉열 대표, 구동언 상무.)
&lt;/center&gt;

&lt;p&gt;양 대표는 당시 구글과 같은 웹 검색엔진이 전세계적인 규모로 사용하는 역인덱스가 실마리가 되리라고 생각했고, IR(정보검색; Information Retrieval) 분야를 주로 연구했습니다. 로그 데이터, 특히 보안 로그는 위변조하거나 임의 삭제하면 안 됩니다. 데이터를 수정, 삭제하지 않기 때문에 엄청나게 많은 데이터가 쌓이므로 압축이 필수적입니다. 또한 압축이 실시간으로 이뤄져야 하므로 성능도 중요합니다. 이디엄의 전신인 엔초비는 2009년, 실시간 압축을 지원하는 스토리지 엔진을 구현했고, 2010년에는 실시간 인덱싱 기술을 개발하여 특허를 등록했습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;새로운 개념의 데이터베이스&lt;/li&gt;
  &lt;li&gt;로그&lt;/li&gt;
  &lt;li&gt;실시간 압축&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 세 가지가 초창기 로그프레소 기술의 중요한 키워드라고 볼 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;로그에스프레소--로그프레소&quot;&gt;로그+에스프레소 = 로그프레소&lt;/h2&gt;

&lt;p&gt;‘로그프레소(Logpresso)’는 log+presso의 합성어로, 에스프레소를 차용해 만든 이름입니다. 위에서 로그와 실시간 압축에 대해 말씀드렸습니다. 로그와 에스프레소에 대해 저희가 담고자 한 이야기는 다음과 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;로그(Log)&lt;/p&gt;

    &lt;p&gt;로그(log)는 운영 체제나 소프트웨어가 실행 중에 생기는 이벤트를 기록한 자동 생성 파일의 파일 확장명입니다. 쉽게 설명하면 항공기나 자동차의 운행 내역을 기록하는 블랙박스와 비슷한 역할을 합니다. 해킹 등의 사건이 발생했을 때, 로그 파일을 분석해 사건의 원인을 파악하기도 합니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;프레소(에스프레소)&lt;/p&gt;

    &lt;p&gt;에스프레소는 ‘빠르다(express)’라는 어원을 가진 이탈리아어입니다. 높은 압력으로 짧은 시간 동안 추출한 고농축 커피로, 한 잔(혹은 원샷)을 추출하는데 겨우 23~28초밖에 걸리지 않는다고 합니다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;에스프레소는 강한 압력으로 비수용성 성분까지도 추출하기 때문에 향미가 매우 강하고, 드립 커피와는 전혀 다른 농밀한 맛을 냅니다. 특유의 풍부하고 무게감 있는 맛이 개운한 느낌을 주기도 합니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/2021-04-19-logpresso-brand-new-ci-part-2/logpresso_nespresso.jpg&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;로그프레소 로고로 만든 네스프레소 패키지&quot; alt=&quot;패키지가 반쯤 열려있는 상태&quot; /&gt;
&lt;br /&gt;(브랜드 개편 결과물 중의 하나, 고객 기념품 에스프레소 커피 캡슐)
&lt;/center&gt;

&lt;p&gt;엄청나게 쌓이는 로그를 실시간으로 압축해서 만드는 일, 에스프레소를 내리는 것과 같다는 생각이 들었습니다. 로그와 프레소, 에스프레소를 통해 브랜드에 담고자 한 키워드는 다음과 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Log
    &lt;ul&gt;
      &lt;li&gt;자동화 / 데이터 / 축적 / 기록 / 자산&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Presso
    &lt;ul&gt;
      &lt;li&gt;고압 / 내리다 / 빠르다 / 강하게&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;브랜딩 이미지
    &lt;ul&gt;
      &lt;li&gt;에스프레소 / 커피 / 추출 / 진하다 / 신뢰 / 응축성 / 고객 지향성 / 데이터 추출&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;로그프레소-사람을-위한-데이터-분석&quot;&gt;로그프레소, 사람을 위한 데이터 분석&lt;/h2&gt;

&lt;p&gt;로그프레소는 방대한 머신 데이터로부터 비즈니스 의사결정에 필요한 인사이트를 에스프레소 머신처럼 빠르게 추출한다는 의미를 담고 있습니다.&lt;/p&gt;

&lt;p&gt;기존의 데이터베이스는 수집/처리/분석을 위해서 많은 사람들의 노력과 시간이 필요했습니다. 이제 로그프레소라는 분석 도구를 사용하면, 방대한 양의 데이터를 빠르게 분석하고 다양한 비즈니스 분야에서 성공적인 의사결정을 내릴 수 있습니다.&lt;/p&gt;

&lt;p&gt;로그프레소가 분석하고 관리하는 로그 데이터의 궁극적인 목적은 사람을 위한 데이터입니다. 인간 중심의 빅데이터, 고객의 디지털 혁신을 위해 더 큰 가치를 만들어 내는 분석을 위한 도구입니다.&lt;/p&gt;

&lt;p&gt;에스프레소는 다양한 커피의 베이스가 됩니다. 물+에스프레소=아메리카노, 우유+에스프레소=라떼가 되듯 로그프레소도 다양한 분야의 고객들이 데이터를 기반으로 한 자동화된 의사결정을 하실 수 있도록 돕겠습니다.&lt;/p&gt;

&lt;p&gt;다음 편에서는 CI, BI 개편의 최종 결과물에 대해 자세히 설명해 드리도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;글/정리 : 최고운, 로그프레소 보안기획팀&lt;/p&gt;
</description>
        <pubDate>Mon, 19 Apr 2021 09:00:00 +0900</pubDate>
        <link>/2021/04/19/logpresso-brand-new-ci-part-2</link>
        <guid isPermaLink="true">/2021/04/19/logpresso-brand-new-ci-part-2</guid>
        
        
        <category>database</category>
        
      </item>
    
      <item>
        <title>로그프레소 CI/BI 개편의 시작</title>
        <description>&lt;p&gt;‘이디엄’은 2013년부터 7년간 써온 사명을 ‘로그프레소’로 변경했습니다. 핵심 제품 브랜드인 ‘로그프레소’를 중심축으로 비즈니스 역량을 집중하고, 국내 빅데이터 플랫폼을 대표하는 브랜드로서의 정체성을 공고히 하기 위해서입니다.&lt;/p&gt;

&lt;p&gt;사명을 변경하는 것은 쉬운 일이 아닙니다. 사명을 바꾸는 목표가 분명해야 하고, 모든 과정의 중심에는 고객이 있어야 합니다.&lt;/p&gt;

&lt;p&gt;로그프레소는 CI(Corporate Identity)를 개편하는 과정에서 많은 고민과 논의를 거쳤습니다. 제품과 비즈니스의 본질, 기업의 가치관과 비전의 정수를 담기 위해 노력했으며, 고객이 로그프레소를 통해 얻고자 하는 것에 집중했습니다.&lt;/p&gt;

&lt;p&gt;로그프레소 CI/BI를 새롭게 논의하고 작업하는 과정, 새로운 CI/BI에 담긴 이야기와 결과물을 공유하려 합니다. 새로운 사명과 브랜드를 고민하시는 분들에게 조금이나마 도움이 되었으면 좋겠습니다.&lt;/p&gt;

&lt;p&gt;로그프레소에 관심을 갖게 되신 분들에게는 저희의 일하는 방식과 비즈니스에 대한 이해를 돕는 글이길 바랍니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/2021-04-12-logpresso-brand-new-ci-part-1/ci.png&quot; style=&quot;width:100%;max-width: 600px;&quot; title=&quot;로그프레소의 새로운 CI&quot; alt=&quot;CI를 아크릴 간판으로 만들어 부착한 사진&quot; /&gt;
&lt;/center&gt;

&lt;h2 id=&quot;새로운-사명에-담아야-할-비즈니스의-본질은-무엇인가&quot;&gt;새로운 사명에 담아야 할 비즈니스의 본질은 무엇인가?&lt;/h2&gt;

&lt;p&gt;‘데이터 기반 의사결정’이라는 말을 들어보신 적 있을 것입니다. 현장 인력의 감에 의존하던 방식을 탈피하고, 데이터에 기반해 전략적인 비즈니스 의사결정을 내리는 회사가 늘고 있습니다. 그런데 이 데이터를 다루는 일이 결코 쉽지 않습니다.&lt;/p&gt;

&lt;p&gt;1980년대 킬로바이트(KB) 단위로 다뤄지던 데이터가 어느 순간 페타바이트(PB)급으로 폭발적으로 증가했습니다. 데이터가 1,000,000,000,000,000배 증가했다는 의미입니다. 향후 20년도 비슷한 속도로 데이터가 증가할 것으로 예상됩니다. 2019년 5G 시대로 진입했고 IoT 센서가 곳곳에 깔리기 시작했습니다. 수많은 단말에서 데이터가 실시간으로 쏟아지게 될 것입니다.&lt;/p&gt;

&lt;p&gt;이렇게 쏟아지는 데이터의 90%는 비정형, 반정형 데이터입니다. 센서나 네트워크 장비, 제조 설비 등 기계에 의해 자동으로 생성되는 머신 데이터는 생성 속도가 매우 빠르지만 정형적이지 않습니다.&lt;/p&gt;

&lt;p&gt;기존의 데이터베이스는 정형적 데이터를 대상으로 합니다. 데이터베이스 연구자들도 정형적 데이터를 수집하고 분석합니다. 전체 데이터의 10%만 다뤄지고 있는 것이죠.&lt;/p&gt;

&lt;p&gt;로그프레소는 90%의 비정형 데이터에 집중합니다. 데이터베이스 연구자들에게서 잊혀진 90%를 분석할 수 있어야 제대로 된 데이터 관리라고 볼 수 있습니다. 비정형 데이터를 수집/가공/저장/분석/탐지/시각화할 수 있는 대안을 만드는 것이 로그프레소의 목표입니다.&lt;/p&gt;

&lt;p&gt;로그프레소는 20년 뒤를 초연결 시대로 봅니다. 초연결시대에 가장 빠르고 정확한 빅데이터 플랫폼을 제공하고, 자동화 시스템으로 비즈니스의 중요 의사 결정을 돕는 솔루션을 제공하는 것이 로그프레소의 큰 그림입니다.&lt;/p&gt;

&lt;p&gt;고객의 모든 선택과 행위가 실시간 데이터로 입수되고, 시스템은 기업에서 가용한 데이터를 외부/내부를 가리지 않고 자동 취합함과 동시에 업무를 이해하며 비즈니스 성과를 극대화하는 정책을 자동으로 제안할 것입니다.&lt;/p&gt;

&lt;h2 id=&quot;고객은-로그프레소를-통해서-무엇을-얻고자-하는가&quot;&gt;고객은 로그프레소를 통해서 무엇을 얻고자 하는가?&lt;/h2&gt;

&lt;p&gt;로그프레소는 사이버 보안, IT 운영관리, 이상거래탐지, 제조공정 최적화, 실시간 마케팅 캠페인 등 다양한 분야에 솔루션을 제공하고 있습니다.&lt;/p&gt;

&lt;p&gt;로그프레소는 로그를 수집한 뒤, 위변조가 불가능하게 보관하고, 다수의 장비를 통합 관리할 수 있도록 분석 기능을 제공합니다. 수백 대의 보안장비를 통합 관제 및 운영하는데 필요한 로그 수집/저장/분석/탐지/시각화 기능을 제공하고, 서비스 품질 모니터링과 장애 원인 검색 분석도 지원합니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/2021-04-12-logpresso-brand-new-ci-part-1/wordcloud.png&quot; style=&quot;width:100%;max-width: 700px;&quot; title=&quot;로그프레소 관련 단어 구름&quot; alt=&quot;단어 구름을 표현한 사진&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;이러한 기능을 요구하는 고객은 무엇보다도 &lt;strong&gt;‘신뢰할 수 있는 회사’&lt;/strong&gt;를 찾습니다. 어마어마한 규모의 데이터 엔지니어링을 안정적으로 수행해야 하고, 어떠한 문제가 발생하더라도 빠르고 안정적으로 해결할 수 있어야 합니다.&lt;/p&gt;

&lt;p&gt;로그프레소는 ‘신뢰할 수 있는 회사’를 수치로 증명할 수 있습니다. 고객사의 LTE 트래픽 데이터를 처리하기 위해 기존에는 하둡 10대로 3일이 걸렸지만, 로그프레소는 4대로 10분 내에 완료할 수 있었습니다.&lt;/p&gt;

&lt;p&gt;로그프레소는 오픈소스 조립이 아닌 자체 기술로 빅데이터 플랫폼의 모든 요소를 개발합니다. 100개가 넘는 고객사에서 저장된 모든 데이터의 호환성을 유지하며 지금까지 엔진의 기능과 성능을 향상시켜 왔습니다. 고객이 원하는 데이터 엔지니어링, 고객의 디지털 비전을 장기적으로 반영할 수 있는 기술력을 갖춘 제조사입니다.&lt;/p&gt;

&lt;h2 id=&quot;논의-및-작업-과정은-어떻게-이뤄졌는가&quot;&gt;논의 및 작업 과정은 어떻게 이뤄졌는가?&lt;/h2&gt;

&lt;p&gt;비즈니스의 본질을 다시 점검하고, 고객이 로그프레소를 통해 얻고자 하는 바를 정리하는 것은 새로운 CI, BI를 제작할 때, 반드시 선행되어야 하는 일입니다. 단순히 이름을 바꾸는 일이 아니라, 기업의 과거와 미래를 잇는 아이덴티티를 만들고 지속적으로 커뮤니케이션해야 하기 때문입니다.&lt;/p&gt;

&lt;p&gt;고객과 소통하는 외부 커뮤니케이션도 중요하지만, 내부 구성원의 공감대 형성도 중요했습니다. 그래서 로그프레소는 &lt;strong&gt;논의와 작업 과정 자체를 투명하게&lt;/strong&gt; 하는 것과 &lt;strong&gt;문서화로 지속적 축적&lt;/strong&gt;이 가능하게 하는 것에 중점을 뒀습니다.&lt;/p&gt;

&lt;p&gt;투명한 커뮤니케이션은 온라인과 오프라인을 넘나들며 진행되었습니다. 사내 메신저의 투표 기능을 활용하기도 하고, 사소한 의견이라도 귀기울여 듣고 조율해 나가는 것을 중요하게 생각했습니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/2021-04-12-logpresso-brand-new-ci-part-1/poll.png&quot; style=&quot;width:100%;max-width: 800px;&quot; title=&quot;사내 메신저 투표 기능을 활용하여 BI 시안 투표&quot; alt=&quot;담당자가 사내 메신저에 BI 시안과 설명을 올리는 모습&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;소통 과정과 구성원의 생각을 담은 내용은 모든 구성원이 편집에 참여할 수 있는 문서로 공유되었습니다. 사내에서 구글 문서도구를 사용하고 있기 때문에, 덧붙여진 내용이나 편집 히스토리 또한 누구나 볼 수 있습니다.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/img/2021-04-12-logpresso-brand-new-ci-part-1/design_team.jpg&quot; style=&quot;width:100%;max-width: 800px;&quot; title=&quot;BI 개편 관련 아이디어 회의중인 모습&quot; alt=&quot;담당자들이 화이트보드에 BI 시안을 그려가며 아이디어를 나누는 모습&quot; /&gt;
&lt;/center&gt;
&lt;p&gt;이번 편에서는 CI/BI 개편을 시작하면서 논의하고 고민했던 과정을 보여드렸습니다.
다음 편에서는 로그프레소에 담긴 이야기와 심볼에 대해 좀 더 자세히 말씀드리도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;글/정리 : 최고운, 로그프레소 보안기획팀&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Apr 2021 09:00:00 +0900</pubDate>
        <link>/2021/04/12/logpresso-brand-new-ci-part-1</link>
        <guid isPermaLink="true">/2021/04/12/logpresso-brand-new-ci-part-1</guid>
        
        
        <category>database</category>
        
      </item>
    
      <item>
        <title>쿼리는 어떤 과정을 거쳐서 실행되는가</title>
        <description>&lt;p&gt;쿼리는 사용자와 데이터베이스를 매개하는 역할을 수행합니다. 응용프로그램을 개발할 때 파일 입출력을 직접 다루는 대신 데이터베이스를 사용하는 이유는 의도하는 데이터 처리 결과를 간단하게 얻을 수 있기 때문인데요. 쿼리를 사용하면 프로그램 코드를 작성하는 것에 비해 같은 작업을 훨씬 짧게 표현할 수 있습니다.&lt;/p&gt;

&lt;p&gt;예를 들어 웹 로그에서 클라이언트 IP별 다운로드 트래픽 총량을 계산하려면 아래와 같은 과정을 거쳐야 합니다. 웹 로그는 아래와 같은 형식으로 기록됩니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;110.70.47.162 - - [23/May/2020:13:24:22 +0900] &quot;GET /static/images/favicon.png HTTP/1.1&quot; 200 57692 &quot;-&quot; &quot;Mozilla/5.0 (iPhone; CPU iPhone OS 13_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/81.0.4044.124 Mobile/15E148 Safari/604.1&quot; 849
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;웹 로그 파일을 연다.&lt;/li&gt;
  &lt;li&gt;IP와 정수로 구성된 해시테이블을 초기화한다.&lt;/li&gt;
  &lt;li&gt;웹 로그 파일을 개행 문자로 분리해서 행 단위로 읽어들인다.
    &lt;ol&gt;
      &lt;li&gt;웹 로그에서 클라이언트 IP와 전송량에 해당되는 문자열을 추출한다.&lt;/li&gt;
      &lt;li&gt;전송량 문자열을 정수로 변환한다.&lt;/li&gt;
      &lt;li&gt;해시테이블에서 클라이언트 IP를 조회한다.&lt;/li&gt;
      &lt;li&gt;기존 누적값과 현재 전송량을 합산하여 클라이언트 IP와 전송량의 쌍을 다시 해시테이블에 넣는다.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;파일 끝을 만나면 해시테이블의 모든 클라이언트 IP 키를 순회하면서 결과를 출력한다.&lt;/li&gt;
  &lt;li&gt;웹 로그 파일을 닫는다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;프로그래밍 언어에 따라 다르지만 파이썬으로는 몇 줄, 자바로는 수십 줄 정도 구현이 필요할 것이고, 클라이언트 IP가 엄청나게 많아서 메모리에 다 올릴 수 없는 상황은 고려하지 않고 있습니다.&lt;/p&gt;

&lt;p&gt;만약 일반적인 데이터베이스 테이블에 웹 로그가 파싱되어 저장되어 있는 상태라면 일반적으로 SQL을 이용해서 간단하게 1줄로 쿼리할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;SELECT client_ip, SUM(bytes) FROM weblog GROUP BY client_ip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;weblog 테이블에 데이터가 정규화된 형태로 존재한다면 로그프레소 쿼리는 아래와 같이 표현합니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;table weblog | stats sum(bytes) by client_ip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;일반 데이터베이스는 테이블에 적재되지 않은 데이터를 처리하지 못하지만, 로그프레소는 아래와 같이 추출과 형 변환을 포함하여 모든 데이터 처리를 한 줄로 표현할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;textfile access_log | rex field=line &quot;^(?&amp;lt;client_ip&amp;gt;\S+).* (?&amp;lt;bytes&amp;gt;\S+)$&quot; | eval bytes=long(bytes) | stats sum(bytes) by client_ip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;쿼리-실행-단계&quot;&gt;쿼리 실행 단계&lt;/h2&gt;

&lt;p&gt;데이터베이스는 위와 같이 기술한 쿼리 문장을 실제 실행 가능한 코드로 변환해야 합니다. 이 과정은 크게 쿼리 파싱, 최적화, 실행으로 구분합니다.&lt;/p&gt;

&lt;h3 id=&quot;쿼리-파싱&quot;&gt;쿼리 파싱&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/2020-05-25-query-execution/operator_tree.png&quot; style=&quot;max-width: 600px;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;쿼리는 한 줄로 간단하게 표현하였지만 프로그램 코드를 직접 작성한 것과 동일하게 동작하려면 각 기능 단위가 사용자의 의도에 맞게 배치되어야 합니다. 데이터베이스는 이러한 기능 단위를 쿼리 연산자 (Query Operator) 라고 부릅니다. 각 쿼리 연산자는 레코드를 입력 받아서 고유의 데이터 처리를 수행한 후 출력하며, 다음 연산자는 이전 연산자의 출력을 입력으로 받아들입니다.&lt;/p&gt;

&lt;p&gt;위의 그림에서 실행 흐름은 아래에서 위로 올라가는 방향으로 표현되어 있는데 이것이 약간 부자연스럽게 느껴질 수 있습니다. 하지만 조인 연산이 포함되는 경우에 하단이 늘어나면서 넓게 배치되고 결과는 하나로 모이게 되므로 트리 형태로 표현하는 것이 유리하고, 그에 맞춰서 실행 흐름은 아래에서 위로 표시하는 것입니다.&lt;/p&gt;

&lt;h3 id=&quot;최적화&quot;&gt;최적화&lt;/h3&gt;

&lt;p&gt;데이터베이스는 쿼리를 파싱하여 트리 형태로 만들고 난 후에 이를 논리적, 물리적으로 최적화하는 과정을 수행합니다. 예를 들어, 위의 경우에 집계를 수행하므로 테이블 혹은 파일의 레코드 순서는 중요하지 않습니다.  따라서 병렬화된 테이블 스캔 혹은 파일 스캔으로 변환할 수 있습니다. 이 외에도 타입 추론, 비용 계산, 조인 순서, 필터링 위치 결정은 쿼리 최적화에서 중요한 주제인데 이는 나중에 다시 다루도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/2020-05-25-query-execution/query_optimizer.png&quot; style=&quot;max-width: 560px;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;실행&quot;&gt;실행&lt;/h3&gt;

&lt;p&gt;최적화를 거치고 나면 최종적으로 쿼리 실행 계획 (Query Plan) 이 완성됩니다. 데이터베이스는 이 쿼리를 실행하는데 어느 정도의 CPU, 메모리, 디스크 자원을 사용할지 결정해야 합니다. 가장 단순하게는 프로그램을 직접 구현해서 실행하듯이 단일 프로세스가 쿼리를 실행할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;프로세스 모델&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL처럼 역사가 오래된 데이터베이스는 프로세스 모델 기반으로 동작합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/2020-05-25-query-execution/process_model.png&quot; style=&quot;max-width: 800px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;프로세스 모델은 클라이언트가 접속하면 새로운 프로세스를 생성해서 할당합니다. 유닉스 프로그래밍 스타일의 오랜 전통이기도 하지만, 공유 메모리를 기반으로 프로세스를 분리하는 이런 실행 모델은 프로그램 오류로 크래시가 발생하더라도 해당 프로세스만 영향을 받기 때문에 상대적으로 장애에 견고합니다. 프로세스가 재시작하더라도 디스크에서 다시 읽어들일 필요 없이 공유 메모리 영역이 그대로 유지되는 장점도 있습니다. IBM DB2, Oracle (11g 이하 버전) 데이터베이스는 이러한 아키텍처로 설계되어 있습니다.&lt;/p&gt;

&lt;p&gt;그러나 프로세스를 fork 하는 방식은 상당히 무거운 편입니다. 프로세스 풀링을 통해 어느 정도 단점을 희석시키기는 하지만, 운영체제에 실행을 맡기므로 스케줄링을 세밀하게 관리하기 어렵고 CPU 캐시 활용도 비효율적입니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;스레드 모델&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;로그프레소 쿼리 엔진은 스레드 모델 기반으로 동작합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/2020-05-25-query-execution/thread_model.png&quot; style=&quot;max-width: 800px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;로그프레소는 쿼리마다 하나의 쿼리 스케줄러 스레드를 실행합니다. 쿼리 스케줄러는 쿼리 실행 계획에서 의존성이 해소된 실행 가능한 태스크를 선별하여 쿼리 태스크를 병렬적으로 실행합니다. 스캔이나 정렬과 같이 실행 성능에 큰 영향을 미치는 요소는 별도의 스레드 풀이 할당되어 있어서, CPU를 최대한 활용하여 빅데이터 쿼리를 실행합니다. 로그프레소 쿼리 엔진은 푸시 모델로 구성되어 있기 때문에, 스캔 스레드의 병렬화가 전체 쿼리의 수행 성능을 좌우합니다. 메모리에 캐시된 페이지를 처리하는 경우 이러한 병렬화는 수 배 이상의 성능 차이를 낼 수 있습니다.&lt;/p&gt;

&lt;p&gt;다음 편에서는 Pull 모델과 Push 모델의 장단점을 알아보도록 하겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;레퍼런스&quot;&gt;레퍼런스&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/docs/12/tutorial-arch.html&quot;&gt;PostgreSQL 12 Documentation: 1.2. Architectural Fundamentals&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/18/cncpt/process-architecture.html#GUID-4B460E97-18A0-4F5A-A62F-9608FFD43664&quot;&gt;Oracle 18c Database Concepts: 15 Process Architecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 25 May 2020 12:56:56 +0900</pubDate>
        <link>/2020/05/25/query-execution</link>
        <guid isPermaLink="true">/2020/05/25/query-execution</guid>
        
        
        <category>database</category>
        
      </item>
    
      <item>
        <title>GraalVM 소개</title>
        <description>&lt;p&gt;로그프레소 빅데이터 플랫폼은 복잡한 사용자 분석 기능 확장을 지원하기 위하여 2014년 이래 그루비, 자바스크립트 엔진을 내장하여 지원하고 있습니다. 지금까지는 자바스크립트를 구동하는데 Nashorn 엔진을 사용했는데요. 자바 11이 출시되면서 Nashorn은 제거 예정 상태로 변경되었고 GraalVM으로 대체를 권고하고 있습니다. 이번 글에서는 GraalVM에 대한 전반적인 개요를 소개합니다.&lt;/p&gt;

&lt;h2 id=&quot;graalvm-개발-배경&quot;&gt;GraalVM 개발 배경&lt;/h2&gt;

&lt;p&gt;GraalVM은 2005년에 썬 마이크로시스템즈에서 Maxine 가상머신 프로젝트로 시작되었습니다. 자바 가상머신(JVM)은 C++ 언어로 구현되어 있는데, 이 프로젝트의 목표는 자바 가상머신 전체를 자바 언어로 다시 작성하는 것이었습니다. 그러나 모든 코드를 한 번에 다 갈아엎는다는 것이 현실적으로 매우 달성하기 어렵기 때문에, 기존 핫스팟 런타임을 최대한 재사용하면서 플러그인으로 JIT 컴파일러를 끼워넣는 방향으로 선회하여 오늘에 이르렀습니다.&lt;/p&gt;

&lt;h2 id=&quot;graalvm-구성&quot;&gt;GraalVM 구성&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/2020-05-10-graalvm/graal-arch.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;GraalVM JIT 컴파일러는 자바 9 버전에 추가된 JVMCI (JVM 컴파일러 인터페이스)를 이용하여 기존 핫스팟 런타임에 플러그인 되는 구조로 동작합니다. 자바나 스칼라 같은 JVM 기반 언어는 GraalVM JIT 컴파일러의 최적화를 통해 성능 향상을 기대할 수 있습니다. 그 위에 Truffle 프레임워크가 올라가는데, 이는 자바스크립트, R, 파이썬, 루비 등 JVM 기반이 아닌 기존 언어의 새로운 구현을 지원합니다.&lt;/p&gt;

&lt;h2 id=&quot;graalvm-활용-분야&quot;&gt;GraalVM 활용 분야&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;기존 자바 응용 프로그램의 성능 향상
    &lt;ul&gt;
      &lt;li&gt;트위터의 경우 GraalVM을 적용해서 기존 Scala 코드에 대해 약 20%의 성능 향상 달성&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;다양한 언어 확장
    &lt;ul&gt;
      &lt;li&gt;자바 코드에서 자바스크립트, R, 파이썬, LLVM IR, 웹 어셈블리 실행 가능&lt;/li&gt;
      &lt;li&gt;각 언어별 라이브러리 활용 가능 (예: R이나 파이썬에서 데이터 분석 후 자바스크립트로 출력)&lt;/li&gt;
      &lt;li&gt;고성능이 필요한 모듈을 C/C++로 구현&lt;/li&gt;
      &lt;li&gt;호스트 접근 필터링 기능으로 스크립트 실행 시 보안성 향상&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;네이티브 이미지 생성
    &lt;ul&gt;
      &lt;li&gt;AOT 컴파일을 통해 부팅 시간 단축, 이미지 크기 최소화&lt;/li&gt;
      &lt;li&gt;특히 최근의 컨테이너 기반 마이크로서비스 아키텍처에 활용성 높음&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;기존 언어의 대량 메모리 사용 지원
    &lt;ul&gt;
      &lt;li&gt;자바 가상머신은 수십 년간 GC를 개선하여 테라바이트 단위의 힙 메모리까지 지원 가능&lt;/li&gt;
      &lt;li&gt;GraalVM 기반으로 구현된 기존 언어는 대량 메모리 사용 시나리오도 지원할 수 있음&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;graalvm-구동-방법&quot;&gt;GraalVM 구동 방법&lt;/h2&gt;

&lt;p&gt;OpenJDK 11 버전 이상을 사용하고 있다면 아래와 같이 부팅 스위치를 추가하여 GraalVM JIT을 활성화 할 수 있습니다. 아래 구성은 Graal JIT만 사용하는 최소 구성입니다:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI --module-path=graalvm --upgrade-module-path=graalvm/compiler.jar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;아래 3개의 파일이 graalvm 위치에 있어야 합니다. (20.0.0 버전 기준으로 약 21MB)&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://repo1.maven.org/maven2/org/graalvm/compiler/compiler/20.0.0/compiler-20.0.0.jar&quot;&gt;compiler.jar&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://repo1.maven.org/maven2/org/graalvm/sdk/graal-sdk/20.0.0/graal-sdk-20.0.0.jar&quot;&gt;graal-sdk.jar&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://repo1.maven.org/maven2/org/graalvm/truffle/truffle-api/20.0.0/truffle-api-20.0.0.jar&quot;&gt;truffle-api.jar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;시스템 프로퍼티에 아래 속성들이 추가되면 정상적으로 GraalVM이 핫스팟 런타임에 플러그인 된 것입니다.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;jdk.internal.vm.ci.enabled=true
jdk.module.path=graalvm
jdk.module.upgrade.path=graalvm/compiler.jar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;다음 글에서는 자바스크립트, 파이썬 코드를 실제 구동하는 방법에 대해 알아보겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;레퍼런스&quot;&gt;레퍼런스&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Maxine_Virtual_Machine&quot;&gt;Maxine Virtual Machine&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/graalvm/graal-js-jdk11-maven-demo&quot;&gt;Running GraalJS on stock JDK11&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://chrisseaton.com/truffleruby/jokerconf17/&quot;&gt;Understanding How Graal Works - a Java JIT Compiler Written in Java&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sun, 10 May 2020 16:03:03 +0900</pubDate>
        <link>/2020/05/10/graalvm</link>
        <guid isPermaLink="true">/2020/05/10/graalvm</guid>
        
        
        <category>java</category>
        
      </item>
    
      <item>
        <title>스레드 스택 덤프를 내장하는 방법</title>
        <description>&lt;p&gt;자바 응용프로그램의 장애는 크게 2가지로 분류됩니다. 첫번째는 과도한 힙 메모리 사용에 따른 잦은 GC 발생이고, 두번째는 I/O로 인한 블록 혹은 잠금으로 인한 스레드 대기 혹은 교착 문제입니다. 개발 환경에서는 디버거를 통해서 쉽게 WAS나 자바 애플리케이션의 내부 동작을 확인할 수 있지만, 운영 환경에서는 보안 문제로 터미널 접속조차 쉽지 않은 경우가 많습니다.&lt;/p&gt;

&lt;p&gt;운영 환경에 JRE 대신 JDK를 설치한 경우라면, 잘 알려진대로 jstack 도구를 사용할 수 있습니다. 다음과 같이 현재 동작 중인 JVM 프로세스 PID를 매개변수로 넘겨서 실행합니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ jstack &amp;lt;PID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;그러면 아래와 같은 형식으로 스레드 스택이 출력됩니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2017-02-01 23:01:35
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.51-b03 mixed mode):

&quot;[iPOJO] pool-5-thread-1&quot; #53 prio=5 os_prio=0 tid=0x000000000428a000 nid=0x7dcd waiting on condition [0x00007f3b2cf74000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  &amp;lt;0x0000000080c04348&amp;gt; (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)

&quot;FelixStartLevel&quot; #36 daemon prio=5 os_prio=0 tid=0x000000000263d000 nid=0x7dbc in Object.wait() [0x00007f3b2d67b000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:283)
        - locked &amp;lt;0x0000000080f65660&amp;gt; (a java.util.ArrayList)
        at java.lang.Thread.run(Thread.java:745)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;jstack 덤프는 스레드 이름, 스택, 동작 상태 뿐 아니라, 현재 각 스레드가 소유하고 있는 잠금 인스턴스, 대기하고 있는 인스턴스 정보까지 포함합니다. 이를 확인하면 현재 어떤 이유로 스레드가 대기하고 있는지 진단할 수 있습니다.&lt;/p&gt;

&lt;p&gt;그러나 보안 문제로 운영 환경에서 jstack 도구를 실행하기 어렵거나, 진단 정보를 자동으로 수집하려는 경우에는 &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/lang/management/ThreadMXBean.html&quot; target=&quot;_blank&quot; style=&quot;color:darkblue&quot;&gt;ThreadMXBean&lt;/a&gt;을 사용해서 애플리케이션 자체에 잠금 상태를 포함한 스택 덤프 기능을 내장할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/logpresso/c7928aefac3f094bef5905c5284eb9cb &quot; target=&quot;_blank&quot; style=&quot;color:darkblue&quot;&gt;JstackHelper.java 전체 코드 보기&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;ThreadMXBean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bean&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ManagementFactory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getThreadMXBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tids&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAllThreadIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Thread dump (total=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tids&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;)&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;LF&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;------------------------------------------&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;LF&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ThreadInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getThreadInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tids&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\&quot;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getThreadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;\&quot; tid=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;: (state = &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getThreadState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;)&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;LF&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mergeStackTrace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LF&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;그런데 스레드 풀을 활용하는 경우 보통 스레드 풀을 대표하는 이름만 부여되기 때문에 스택 덤프를 봐도 현재 실행 중인 작업의 맥락을 쉽게 식별하기 어려운 경우가 종종 있습니다. 많은 개발자들이 스레드 이름은 스레드를 생성할 때만 설정할 수 있다고 생각하지만 실제로는 실행 중에 스레드 이름을 임의로 변경할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setName-java.lang.String-&quot; target=&quot;_blank&quot; style=&quot;color:darkblue&quot;&gt;Thread.setName(String name)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;따라서 Runnable 혹은 Callable을 구현할 때, 시작 부분에 현재 컨텍스트에 해당하는 문자열을 스레드 이름으로 설정하고, finally 블록으로 원래 스레드 이름을 복구하도록 코딩하면 현장에서 빠르게 장애를 진단하고 대응할 수 있습니다.&lt;/p&gt;

&lt;p&gt;로그프레소는 system threads 쿼리를 통해서 스레드 실행 상태를 진단할 수 있는 기능을 제공하며, 외부 시스템이 흔히 연동되는 스트림 엔진에서는 실행 중인 스트림 쿼리 이름을 스레드 이름으로 설정함으로써 필드 엔지니어의 장애 진단을 지원합니다.&lt;/p&gt;

&lt;p&gt;예를 들어 인덱스되지 않은 외부 데이터베이스의 테이블을 dblookup 커맨드로 참조하는 경우 낮은 SQL 조회 성능으로 인해 스트림이 JDBC 드라이버 스택에서 소켓 수신을 대기하고 있는 모습을 쉽게 확인할 수 있고, 해당 스트림 쿼리에 설정된 SQL 쿼리를 확인한 후 즉시 대응할 수 있습니다.&lt;/p&gt;
</description>
        <pubDate>Thu, 02 Feb 2017 11:30:00 +0900</pubDate>
        <link>/2017/02/02/embedding-jstack</link>
        <guid isPermaLink="true">/2017/02/02/embedding-jstack</guid>
        
        
        <category>java</category>
        
      </item>
    
      <item>
        <title>JMH로 알아보는 오토 박싱의 부하</title>
        <description>&lt;p&gt;쉽게 쓰여진 자바 코드에서는 일반적으로 정수 값의 목록을 List 클래스로 관리합니다. 자바 컬렉션 프레임워크는 구조적으로 잘 설계된 편이지만, 자바 언어의 한계로 프리미티브 타입을 자바 컬렉션으로 관리하는 경우 성능 상 많은 불이익을 받게 됩니다. 이는 자바 컬렉션이 설계적으로 Object 타입만 받아들일 수 있고, 프리미티브는 Object를 상속하지 않기 때문에 자동으로 객체 변환(Boxing)을 수행하기 때문입니다.&lt;/p&gt;

&lt;p&gt;64비트 시스템에서 int 프리미티브는 8바이트를 차지하는 반면, Integer 객체는 포인터 8바이트, 객체 헤더 16바이트, 데이터 8바이트로 총 32바이트를 소모하므로 메모리량을 많이 차지할 뿐더러, GC 작업에 있어서도 하나의 프리미티브 배열에 비해 개별 Integer 객체를 모두 추적해야 하므로 많은 비용이 들어갑니다.&lt;/p&gt;

&lt;p&gt;자바 컬렉션으로 인한 성능 페널티는 계산량이 많은 응용프로그램일수록 더욱 두드러지는데, 수십-수백 테라바이트의 역인덱스 포스팅 리스트를 스캔해야 하는 검색엔진이나, 대량의 연산을 수행해야 하는 데이터베이스에서도 마찬가지로 큰 성능 저하를 유발합니다.&lt;/p&gt;

&lt;p&gt;오래된 예이지만, 루씬 3.5 시절의 아래 이슈는 객체 참조로 인한 메모리 사용량을 줄이고 프리미티브 배열로 처리하는게 어느 정도의 성능 향상 효과를 가져올 수 있는지 잘 보여줍니다:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://issues.apache.org/jira/browse/LUCENE-2205&quot; style=&quot;color: darkblue&quot; target=&quot;_blank&quot;&gt;[LUCENE-2205] Rework of the TermInfosReader class to remove the Terms[], TermInfos[], and the index pointer long[] and create a more memory efficient data structure&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;&lt;span style=&quot;font-size: 1.4em; font-weight: bold; line-height: 3em&quot;&gt;JMH: Java Microbenchmark Harness&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;이제 오토박싱으로 인한 부하를 실제 측정해보기에 앞서, JMH를 소개하도록 하겠습니다. JMH는 JDK에서 공식적으로 제공하는 마이크로 벤치마크 프레임워크입니다. JMH를 기반으로 벤치마크 테스트를 작성하는 것을 권장하는 이유는, 조심스럽게 테스트 코드를 작성하지 않으면 JVM에서 제공하는 다양한 최적화 기법 때문에 벤치마크 테스트가 의도한대로 동작하지 않고 왜곡된 결과를 내놓을 수 있기 때문입니다.&lt;/p&gt;

&lt;p&gt;아래와 같이 몇 가지 잘못된 예를 생각해볼 수 있습니다:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;JIT 컴파일 여부: 핫스팟 컴파일러는 일정 횟수 이상 실행되는 메소드를 컴파일하는데, 만약 웜업 단계를 생략하게 되면 결과에 왜곡이 발생하게 됩니다.&lt;/li&gt;&lt;li&gt;데드코드 제거: 벤치마크 작성 시 성능 측정 대상 코드만 간단히 루프에 넣어 돌리는 경우가 흔한데, 핫스팟 컴파일러는 참조되지 않는 무의미한 코드를 자동으로 삭제하기 때문에 왜곡된 결과를 얻을 수 있습니다.&lt;/li&gt;&lt;li&gt;버추얼테이블 최적화: 인터페이스 구현체가 1개인 경우에는 실행 시 분기할 필요가 없기 때문에 네이티브 코드가 최적화됩니다. 그러나 코드 실행에 따라 동일 인터페이스를 구현하는 클래스가 추가로 로드되는 경우, 이전 실행과 달리 왜곡된 결과를 얻을 수 있습니다.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;&lt;span style=&quot;font-size: 1.4em; font-weight: bold; line-height: 3em&quot;&gt;JMH 벤치마크 프로젝트 만들기&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Maven을 이용해서 새 JMH 프로젝트를 생성합니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mvn&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;archetype:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DinteractiveMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; 
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DarchetypeGroupId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;openjdk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;jmh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DarchetypeArtifactId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jmh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;java&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;archetype&lt;/span&gt; 
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DgroupId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;logpresso&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DartifactId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchmark&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Dversion&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;그러면 아래와 같이 샘플 코드가 생성됩니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.logpresso&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.openjdk.jmh.annotations.Benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyBenchmark&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Benchmark&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;testMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// This is a demo/sample template for building your JMH benchmarks. Edit as needed.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Put your benchmark code here.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;아래와 같이 두 개의 벤치마크 테스트 코드를 작성합니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.logpresso&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.openjdk.jmh.annotations.Benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.openjdk.jmh.runner.Runner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.openjdk.jmh.runner.RunnerException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.openjdk.jmh.runner.options.Options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.openjdk.jmh.runner.options.OptionsBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyBenchmark&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MAX_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;nd&quot;&gt;@Benchmark&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;testPrimitive&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MAX_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MAX_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;nd&quot;&gt;@Benchmark&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;textBoxing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nc&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MAX_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MAX_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;컴파일 후 아래와 같이 실행합니다:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mvn clean package
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;java &lt;span class=&quot;nt&quot;&gt;-jar&lt;/span&gt; target/benchmark-1.0.jar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 실행하면 아래와 같은 결과를 볼 수 있습니다:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Run complete. Total time: 00:14:20&lt;/span&gt;

Benchmark                   Mode  Cnt    Score   Error  Units
MyBenchmark.testPrimitive  thrpt  200  166.054 ± 1.265  ops/s
MyBenchmark.textBoxing     thrpt  200   32.191 ± 0.484  ops/s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;프리미티브 배열의 처리량이 객체 배열에 비해 약 5배 정도 높은 것을 확인할 수 있습니다. 전체 실행 결과는 &lt;a href=&quot;https://gist.github.com/xeraph/06cedd1054ad0ff3e9536e2b7115a537&quot; style=&quot;color:darkblue&quot; target=&quot;_blank&quot;&gt;이 링크&lt;/a&gt;에서 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;JMH 프레임워크에서 적용할 수 있는 옵션은 여러가지인데, 이번 글에서는 가장 간단한 테스트 구성만 알아보았습니다. 자세한 내용은 &lt;a href=&quot;http://openjdk.java.net/projects/code-tools/jmh/&quot; style=&quot;color:darkblue&quot; target=&quot;_blank&quot;&gt;OpenJDK: JMH&lt;/a&gt; 페이지를 참고하시기 바랍니다.&lt;/p&gt;
</description>
        <pubDate>Thu, 12 Jan 2017 11:30:00 +0900</pubDate>
        <link>/2017/01/12/auto-boxing-penalty</link>
        <guid isPermaLink="true">/2017/01/12/auto-boxing-penalty</guid>
        
        
        <category>java</category>
        
      </item>
    
      <item>
        <title>GC를 회피하는 메모리 관리 기술</title>
        <description>&lt;p&gt;자바는 프로그래머가 메모리 관리를 직접 하지 않도록 설계된 언어입니다. 가비지 컬렉션 기술(이하 GC)은 이전 세대의 프로그램에서 있었던 많은 메모리 참조 오류들을 원천적으로 해결하여 크래시나 메모리 오염으로부터 프로그래머들을 해방시켰습니다.&lt;/p&gt;

&lt;p&gt;그러나 이러한 특성은 웹 애플리케이션 서버처럼 상태가 별로 없는 프로그램의 동작에는 적합하나, 데이터베이스처럼 대량의 상태를 유지관리해야 하는 프로그램에는 근본적인 한계를 가지고 있습니다. 메모리에 많은 개체들이 유지될수록, GC를 수행하는데 더 많은 시간이 소요됩니다. 단순히 사용되지 않는 쓰레기 개체를 찾는 것 뿐만 아니라, 단편화를 해결하기 위해 메모리 재배치를 수행하면서 많은 메모리 복사를 유발하기 때문입니다.&lt;/p&gt;

&lt;p&gt;많은 웹 서비스들이 수천만 건 이상의 세션 정보나 데이터들을 자체 캐싱하는 대신 C로 구현된 memcached나 redis 같은 외부 데몬에 캐싱하는 것은 이런 이유도 깔려있습니다.&lt;/p&gt;

&lt;p&gt;그렇다면 아예 방법이 없는 것인가? 그렇지 않습니다. 바로 오프힙 메모리입니다.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;font-size: 1.4em; font-weight: bold; line-height: 3em&quot;&gt;다이렉트 버퍼의 유래&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;DirectByteBuffer는 자바 1.4 시절 NIO 기술과 함께 등장했습니다. JNI로 직접 C 라이브러리를 자바에 링크시켜 본 경험이 있다면 쉽게 이해하겠지만, 자바 월드에서 네이티브 월드로 넘어갈 때는 메모리 복사가 일어납니다. 자바 코드에서 참조하는 배열의 메모리는 &lt;a href=&quot;http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html#wp1265&quot; style=&quot;color: darkblue&quot;&gt;불연속적이거나 네이티브 콜을 한 직후에 GC로 삭제될 수도 있기 때문에&lt;/a&gt;, 자바가상머신은 시스템 콜 호출 시 별도의 메모리 공간에 입력 데이터를 복사해서 사용합니다.&lt;/p&gt;

&lt;p&gt;초기 버전의 자바는 디스크나 네트워크 등 I/O를 수행하면서 빈번한 메모리 복사가 발생하므로 많은 성능 저하가 있을 수 밖에 없었고, 자바 1.4부터 I/O 시 반복적으로 복사를 하지 않도록 다이렉트 버퍼를 제공하기 시작했습니다. 다이렉트 버퍼는 불필요한 복사를 회피할 수 있는 대신, 연속적인 메모리 공간 할당, 참조 정보 관리로 인해 자바 힙 메모리에 비해 할당과 접근 모두 상대적으로 느립니다.&lt;/p&gt;

&lt;p&gt;그러나 여기서 중요한 특징은 &lt;a href=&quot;http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html&quot; style=&quot;color: darkblue&quot;&gt;GC 범위의 바깥&lt;/a&gt;에 있다는 사실입니다. 다이렉트 버퍼는 GC의 영향에서 벗어날 수 있으므로, 메모리 재배치로 인한 수십 초 단위의 GC 수행을 회피할 수 있습니다.&lt;/p&gt;
&lt;blockquote style=&quot;margin: 0.5em 2em; font-family: Consolas,'Bitstream Vera Sans Mono',Monaco,monospace; font-size: 14px;&quot;&gt;The buffers returned by this method typically have somewhat higher allocation and deallocation costs than non-direct buffers. &lt;i&gt;The contents of direct buffers may reside outside of the normal garbage-collected heap&lt;/i&gt;, and so their impact upon the memory footprint of an application might not be obvious.&lt;/blockquote&gt;

&lt;p&gt;&lt;span style=&quot;font-size: 1.4em; font-weight: bold; line-height: 3em&quot;&gt;다이렉트 버퍼의 생명주기 제어&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;위의 인용문구에서 보이듯이, 다이렉트 메모리의 사용량은 단순 힙 사용량으로는 관측되지 않습니다. 이러한 특성은 GC 자체에도 영향을 주는데, 예를 들어 다이렉트 메모리를 더 이상 어디에서도 참조하지 않는데도 불구하고 즉시 GC로 제거되지 않는 현상이 발생합니다. 실제로는 가용 메모리가 있는데도 불구하고 아래와 같이 다이렉트 메모리 할당에 실패할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java.lang.OutOfMemoryError: Direct buffer memory
        at java.nio.Bits.reserveMemory(Bits.java:658)
        at java.nio.DirectByteBuffer.&amp;lt;init&amp;gt;(DirectByteBuffer.java:123)
        at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;강제로 System.gc()를 호출하지 않는 이상, 다이렉트 바이트버퍼를 해제하려면 다른 방법을 고안해야 합니다. 이 이슈 때문에 다이렉트 메모리를 응용하는 애플리케이션들은 흔히 문서화되지 않은 아래 방법을 사용합니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;ByteBuffer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ByteBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;allocateDirect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleanerMethod&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cleaner&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cleanerMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAccessible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleaner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleanerMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleanMethod&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleaner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;clean&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cleanMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAccessible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cleanMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cleaner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;본래는 Finalizer에 의해 호출될 다이렉트 바이트버퍼의 내부 Cleaner 메소드를 리플렉션을 이용해서 직접 호출하는 것입니다. 그러나 이제 문제는 새로운 차원으로 옮겨가게 됩니다.&lt;/p&gt;

&lt;p&gt;다이렉트 바이트버퍼의 메모리를 직접 할당하고 해제한다는 것은, 기존의 C/C++와 같은 언어에서 직접 메모리를 할당하고 해제했던 것처럼 메모리에 대한 모든 생명주기를 직접 책임져야 한다는 의미입니다. 특히, 멀티스레드 환경에서는 개체의 참조를 정확하게 계산하도록 레퍼런스 카운터 등을 이용해야 합니다.&lt;/p&gt;

&lt;p&gt;만약, 이미 해제해버린 메모리를 대상으로 데이터를 쓰거나 읽으려고 시도한다면, 크래시를 피할 수 없습니다. 예를 들어 아래의 코드는 아주 쉽게 크래시를 유도합니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nc&quot;&gt;ByteBuffer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ByteBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;allocateDirect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleanerMethod&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cleaner&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;cleanerMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAccessible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleaner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleanerMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleanMethod&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleaner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;clean&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;cleanMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAccessible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;cleanMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cleaner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;윈도우 환경의 크래시 발생 예&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007fff1c899f58, pid=10756, tid=16228
#
# JRE version: Java(TM) SE Runtime Environment (8.0_60-b27) (build 1.8.0_60-b27)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.60-b23 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  [ntdll.dll+0x39f58]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# hs_err_pid10756.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이 뿐만 아니라, 오프힙 메모리는 바이트 배열에 불과하기 때문에 반드시 바이트 직렬화 과정을 거쳐야 합니다. 예를 들어, 16909060라는 정수 값이 있다면, 01 02 03 04로 인코딩해야 합니다. 여기에 더해서 다이렉트 바이트버퍼의 할당과 해제는 상대적으로 훨씬 느리기 때문에, 오프힙 메모리의 응용에는 버퍼 풀링을 포함한 정교한 아키텍처 설계가 필요합니다.&lt;/p&gt;

&lt;p&gt;로그프레소는 오프힙 메모리 기술을 통해 GC 문제를 회피하고 수백 기가에 이르는 데이터를 압축된 상태로 캐싱하며 쿼리 실행을 가속합니다.&lt;/p&gt;
</description>
        <pubDate>Tue, 03 Jan 2017 11:30:00 +0900</pubDate>
        <link>/2017/01/03/java-offheap</link>
        <guid isPermaLink="true">/2017/01/03/java-offheap</guid>
        
        
        <category>java</category>
        
      </item>
    
  </channel>
</rss>
