<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>chocopie_jjeong.log</title>
        <link>https://velog.io/</link>
        <description>개발 커리어 저장소</description>
        <lastBuildDate>Wed, 09 Jun 2021 05:13:36 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>chocopie_jjeong.log</title>
            <url>https://images.velog.io/images/chocopie_jjeong/profile/c9acb454-1dbb-422b-b80d-78e93fee90b9/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. chocopie_jjeong.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/chocopie_jjeong" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Kotlin] Enumerate]]></title>
            <link>https://velog.io/@chocopie_jjeong/Kotlin-Enumerate</link>
            <guid>https://velog.io/@chocopie_jjeong/Kotlin-Enumerate</guid>
            <pubDate>Wed, 09 Jun 2021 05:13:36 GMT</pubDate>
            <description><![CDATA[<p>Python에서는 반복문을 돌 때, index도 함께 받을 수 있는 enumerate() 함수를 제공한다</p>
<pre><code class="language-python">
family_names = [&quot;park&quot;, &quot;kim&quot;, &quot;choi&quot;]
for idx, f_name in enumerate(family_names):
    print(str(idx+1), &quot;번째 성:&quot;, f_name)</code></pre>
<p>출력 시,</p>
<pre><code>1 번째 성: park
2 번째 성: kim
3 번째 성: choi</code></pre><p>Kotlin 에서는 이와 같은 기능을 어떻게 제공하는지 찾아보았다.</p>
<ul>
<li>Iterable의 withIndex()</li>
</ul>
<pre><code class="language-kotlin">val family_names = arrayListOf(&quot;park&quot;, &quot;kim&quot;, &quot;choi) 
for ((index, f_name) in family_names.withIndex()) { 
    println(&quot;index: ${index+1}, name: $f_name&quot;) 
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] NIO]]></title>
            <link>https://velog.io/@chocopie_jjeong/JAVA-NIO</link>
            <guid>https://velog.io/@chocopie_jjeong/JAVA-NIO</guid>
            <pubDate>Sun, 30 May 2021 11:03:38 GMT</pubDate>
            <description><![CDATA[<h3 id="nio">NIO</h3>
<ul>
<li>Non-blocking I/O, New I/O</li>
<li>Channel이 양방향 buffer를 통해 외부 데이터와 통신</li>
<li>읽기/쓰기를 하나의 통로로 해결</li>
</ul>
<h4 id="특징">특징</h4>
<ul>
<li>Non-blocking<ul>
<li>I/O 작업이 진행되는 동안 유저 프로세스의 작업을 중단시키지 않는 방식</li>
</ul>
</li>
<li>비동기<ul>
<li>I/O 작업이 진행되는 동안 유저 프로세스에는 관심이 없음. 그저 자신의 일을 하다가 이벤트 핸들러에 의해 알림이 오면 처리하는 방식</li>
</ul>
</li>
<li>Buffer, Channel, Selector 이용하여 성능 향상<ul>
<li>Buffer: 커널에 의해 관리되는 시스템 메모리를 직접 사용할 수 있는 Buffer Class<ul>
<li>Channel: 읽기, 쓰기 둘 다 가능한 양방향 입출력 클래스(cf) Stream: 읽기, 쓰기 하나씩 쓸 수 있는 단방향 입출력 클래스</li>
</ul>
</li>
<li>Selector: 네트워크 프로그래밍 효율을 높임. 클라이언트 하나당 스레드 하나를 생성해서 처리하는 방식은 스레드 생성 수가 늘어날수록 급격한 성능 저하를 가져오므로, 이를 개선한 Reactor 패턴의 구현체</li>
</ul>
</li>
</ul>
<p><img src="https://images.velog.io/images/chocopie_jjeong/post/7e3ecd64-25dd-4675-963d-2ce5c91f4293/image.png" alt=""></p>
<p><a href="https://junshock5.tistory.com/149">참고</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[네트워크] TCP 3way-Handshake]]></title>
            <link>https://velog.io/@chocopie_jjeong/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-TCP-3way-Handshake</link>
            <guid>https://velog.io/@chocopie_jjeong/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-TCP-3way-Handshake</guid>
            <pubDate>Wed, 26 May 2021 13:16:47 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p><strong>네트워크</strong>
데이터를 교환하기 위해 전송 매체를 매개로 서로 연결되어 있는 것</p>
</li>
<li><p><strong>인터넷</strong>
전세계 컴퓨터들이 서로 연결되어 있는 거대한 네트워크</p>
</li>
<li><p><strong>프로토콜</strong>
네트워크 상에서 데이터를 주고받기 위한 일종의 규약</p>
</li>
</ul>
<ul>
<li><strong>OSI 7계층, TCP/IP 4계층</strong>
<img src="https://images.velog.io/images/chocopie_jjeong/post/5b22b4df-4e83-4100-8558-8f6026ac2ddd/image.png" alt=""></li>
</ul>
<p>네트워크 상에서 정보를 주고받기 위해서는 여러 계층별 프로토콜이 필요하다. 따라서, 상호 독립적이면서 유기적인 관계를 가진 계층 구조를 바탕으로 데이터가 교환될 수 있다. </p>
<p>여기서는, 전송계층을 다루겠다. </p>
<p>전송계층 (Transport Layer)
: 전송계층의 프로토콜은 크게 TCP와 UDP로 나뉜다. </p>
<ul>
<li><p>TCP</p>
<ul>
<li>연결지향적</li>
<li>데이터를 전송하는 측과 데이터를 전송받는 측에서 전용의 데이터 전송 선로(Session)을 만들어 통신함</li>
<li>데이터 전송 성공/실패에 대한 신뢰도가 중요하다고 판단될 때 사용</li>
</ul>
</li>
<li><p>UDP</p>
<ul>
<li>비연결지향</li>
<li>최소한의 오류제어 기능만 수행<ul>
<li>단순히 데이터를 받거나, 보내기만 하는 프로토콜</li>
</ul>
</li>
<li>실시간 멀티미디어 정보를 처리하기 위해 주로 사용됨</li>
</ul>
</li>
</ul>
<p>TCP가 연결지향적 특성을 갖게 해주는 방법이 바로 3way-handshake!</p>
<ul>
<li><strong>3way-Handshake</strong>란?
전송 제어 프로토콜(TCP)에서 통신을 하는 장치 사이에 서로 연결되어 있는지 확인하는 방법</li>
</ul>
<ul>
<li><strong>3way-Handshake</strong> 과정</li>
</ul>
<p><img src="https://images.velog.io/images/chocopie_jjeong/post/c42f1d9a-87dd-4956-80fc-d26cc03e80db/image.png" alt=""></p>
<p>SYN: Synchronize sequence numbers
ACK: Acknowledgements</p>
<p>[Step1]
클라이언트1은 A서버에 접속을 요청하는 SYN 패킷을 보낸다.
이때, 클라이언트1은 요청한 서버로부터 SYN/ACK 응답을 기다리는 SYN_SENT 상태가 된다.</p>
<p>[Step2]
A서버는 Listen 상태로 포트 서비스가 가능한 상태여야한다. 
닫힌 상태였던 A서버는 SYN요청을 받고 Listen 상태가 되며, 클라이언트1에게 요청을 수락한다는 ACK요청과 SYN flag가 설정된 패킷을 발송한다.
그리고 클라이언트1이 다시 ACK를 보내기를 기다린다. 
이때, A서버는 SYN_RECEIVED 상태가 된다. </p>
<p>[Step3]
클라이언트1은 A서버에게 ACK을 보내고 이후로부터는 두 매체 간의 연결이 이루어진다. 
이때의 A서버 상태가 ESTABILISHED 이다. </p>
<p><img src="https://images.velog.io/images/chocopie_jjeong/post/d15e7a85-d3dd-4083-9cda-963b2003869d/image.png" alt=""></p>
<ul>
<li>실제 과정
<img src="https://images.velog.io/images/chocopie_jjeong/post/b728bd24-54ae-42f5-90f9-b9c3a7ed1866/image.png" alt=""></li>
</ul>
<p>3way-Handshake 과정에서, 두 매체는 서로 랜덤한 숫자를 보내고 이를 잘 받았다는 ACK로 1을 더해주는 방식을 사용한다. </p>
<p>이처럼, TCP는 연결지향적인 특성과 자체적으로 오류를 처리하며 순서가 뒤바뀐 패킷을 교정해주는 기능을 제공한다. 데이터 전송의 신뢰도가 중요하다고 판단될 때 쓰이는 방식이지만, 데이터 전송 속도가 중요시되는 경우면 제한적인 방법이다.
UDP는 위와 같은 과정없이 단순히 데이터만 전송하기 때문에 속도는 빠르다. 
스트리밍 서비스의 경우에는 데이터의 손실은 있더라도 끊기지 않은 데이터 전송이 중요하므로 UDP 방식이 더 사용하기 적합하다. </p>
<ul>
<li>참고
<a href="https://mindnet.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%89%BD%EA%B2%8C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-22%ED%8E%B8-TCP-3-WayHandshake-4-WayHandshake">참고 링크 1</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Triton] 빌드]]></title>
            <link>https://velog.io/@chocopie_jjeong/Triton-%EB%B9%8C%EB%93%9C</link>
            <guid>https://velog.io/@chocopie_jjeong/Triton-%EB%B9%8C%EB%93%9C</guid>
            <pubDate>Wed, 26 May 2021 08:42:22 GMT</pubDate>
            <description><![CDATA[<p>Trtion Inference Server 공식 github으로부터 받은 빌드 스크립트를 활용해서
단계적으로 도커 이미지를 빌드해가는 과정에서, 아래에 해당하는 Dockerfile이 생성되었다.
하지만, 여기에 우리가 필요한 Kobert를 설치해야하며, 그와 더불어 필요한 의존 라이브러리들을 설치해야했다. 
따라서, 이 Dockerfile로 최종 Tritonserver 이미지가 구축되기 때문에
필요한 명령어들을 추가로 넣어서 이미지를 최종 빌드했다. </p>
<pre><code class="language-Dockerfile">#
# Multistage build.
#
ARG TRITON_VERSION=2.9.0
ARG TRITON_CONTAINER_VERSION=21.04

ARG BASE_IMAGE=nvcr.io/nvidia/tritonserver:21.04-py3-min
ARG BUILD_IMAGE=tritonserver_build

############################################################################
##  Build image
############################################################################
FROM ${BUILD_IMAGE} AS tritonserver_build

############################################################################
##  Production stage: Create container with just inference server executable
############################################################################
FROM ${BASE_IMAGE}

ARG TRITON_VERSION
ARG TRITON_CONTAINER_VERSION

ENV TRITON_SERVER_VERSION ${TRITON_VERSION}
ENV NVIDIA_TRITON_SERVER_VERSION ${TRITON_CONTAINER_VERSION}
ENV TRITON_SERVER_VERSION ${TRITON_VERSION}
ENV NVIDIA_TRITON_SERVER_VERSION ${TRITON_CONTAINER_VERSION}
LABEL com.nvidia.tritonserver.version=&quot;${TRITON_SERVER_VERSION}&quot;

ENV PATH /opt/tritonserver/bin:${PATH}

ENV TF_ADJUST_HUE_FUSED         1
ENV TF_ADJUST_SATURATION_FUSED  1
ENV TF_ENABLE_WINOGRAD_NONFUSED 1
ENV TF_AUTOTUNE_THRESHOLD       2

# Create a user that can be used to run triton as
# non-root. Make sure that this user to given ID 1000. All server
# artifacts copied below are assign to this user.
ENV TRITON_SERVER_USER=triton-server
RUN userdel tensorrt-server &gt; /dev/null 2&gt;&amp;1 || true &amp;&amp;     if ! id -u $TRITON_SERVER_USER &gt; /dev/null 2&gt;&amp;1 ; then         useradd $TRITON_SERVER_USER;     fi &amp;&amp;     [ `id -u $TRITON_SERVER_USER` -eq 1000 ] &amp;&amp;     [ `id -g $TRITON_SERVER_USER` -eq 1000 ]

# Ensure apt-get won&#39;t prompt for selecting options
ENV DEBIAN_FRONTEND=noninteractive

# Common dependencies. FIXME (can any of these be conditional? For
# example libcurl only needed for GCS?)
RUN apt-get update &amp;&amp;     apt-get install -y --no-install-recommends          libb64-0d          libcurl4-openssl-dev          libre2-5 &amp;&amp;     rm -rf /var/lib/apt/lists/*

# python3, python3-pip and some pip installs required for the python backend
RUN apt-get update &amp;&amp;     apt-get install -y --no-install-recommends          python3          python3-pip &amp;&amp;     pip3 install --upgrade pip &amp;&amp;     pip3 install --upgrade wheel setuptools &amp;&amp;     pip3 install --upgrade grpcio-tools grpcio-channelz numpy &amp;&amp;     rm -rf /var/lib/apt/lists/*

WORKDIR /opt/tritonserver
RUN rm -fr /opt/tritonserver/*
COPY --chown=1000:1000 LICENSE .
COPY --chown=1000:1000 TRITON_VERSION .
COPY --chown=1000:1000 --from=tritonserver_build /tmp/tritonbuild/install/bin/tritonserver bin/
COPY --chown=1000:1000 --from=tritonserver_build /tmp/tritonbuild/install/lib/libtritonserver.so lib/
COPY --chown=1000:1000 --from=tritonserver_build /tmp/tritonbuild/install/include/triton/core include/triton/core

COPY --chown=1000:1000 --from=tritonserver_build /tmp/tritonbuild/install/backends backend

# Extra defensive wiring for CUDA Compat lib
RUN ln -sf ${_CUDA_COMPAT_PATH}/lib.real ${_CUDA_COMPAT_PATH}/lib  &amp;&amp; echo ${_CUDA_COMPAT_PATH}/lib &gt; /etc/ld.so.conf.d/00-cuda-compat.conf  &amp;&amp; ldconfig  &amp;&amp; rm -f ${_CUDA_COMPAT_PATH}/lib

COPY --chown=1000:1000 NVIDIA_Deep_Learning_Container_License.pdf /opt/tritonserver
COPY --chown=1000:1000 nvidia_entrypoint.sh /opt/tritonserver

##########################추가한 부분#####################################
COPY --chown=1000:1000 requirements.txt .
COPY --chown=1000:1000 kobert_install.sh .

RUN apt-get update &amp;&amp; apt-get install -y python3-dev
RUN pip3 install -r requirements.txt
RUN chmod a+x kobert_install.sh

RUN ./kobert_install.sh

ENV LANGUAGE=en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
RUN apt-get clean &amp;&amp; apt-get update &amp;&amp; apt-get install -y locales
RUN locale-gen en_US.UTF-8
##########################추가한 부분#####################################

ENTRYPOINT [&quot;/opt/tritonserver/nvidia_entrypoint.sh&quot;]

ENV NVIDIA_BUILD_ID &lt;unknown&gt;
LABEL com.nvidia.build.id=&lt;unknown&gt;
LABEL com.nvidia.build.ref=

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AI] Gluonnlp 설치 에러]]></title>
            <link>https://velog.io/@chocopie_jjeong/AI-Gluonnlp-%EC%84%A4%EC%B9%98-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@chocopie_jjeong/AI-Gluonnlp-%EC%84%A4%EC%B9%98-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Wed, 26 May 2021 08:37:55 GMT</pubDate>
            <description><![CDATA[<p>BERT 모델을 활용하는 AI 모델의 추론 서버를 구축하는 과정에서
의존 라이브러리를 일괄 설치하는 도중에, 
&quot;glounnlp&quot;라는 라이브러리 설치 에러가 발생했다. 
아래와 같은 에러 메시지가 출력되었다. </p>
<pre><code class="language-shell">...(생략)
src/gluonnlp/data/fast_bert_tokenizer.c:14:10: fatal error: Python.h: No such file or directory
       14 | #include &quot;Python.h&quot;
          |          ^~~~~~~~~~
    compilation terminated.
    error: command &#39;x86_64-linux-gnu-gcc&#39; failed with exit status 1
    ----------------------------------------
ERROR: Command errored out with exit status 1: /usr/bin/python3 -u -c &#39;import io, os, sys, setuptools, tokenize; sys.argv[0] = &#39;&quot;&#39;&quot;&#39;/tmp/pip-install-ynu4t8bt/gluonnlp_c9b89e59f39b4d0fb4b8ea2323a4d980/setup.py&#39;&quot;&#39;&quot;&#39;; __file__=&#39;&quot;&#39;&quot;&#39;/tmp/pip-install-ynu4t8bt/gluonnlp_c9b89e59f39b4d0fb4b8ea2323a4d980/setup.py&#39;&quot;&#39;&quot;&#39;;f = getattr(tokenize, &#39;&quot;&#39;&quot;&#39;open&#39;&quot;&#39;&quot;&#39;, open)(__file__) if os.path.exists(__file__) else io.StringIO(&#39;&quot;&#39;&quot;&#39;from setuptools import setup; setup()&#39;&quot;&#39;&quot;&#39;);code = f.read().replace(&#39;&quot;&#39;&quot;&#39;\r\n&#39;&quot;&#39;&quot;&#39;, &#39;&quot;&#39;&quot;&#39;\n&#39;&quot;&#39;&quot;&#39;);f.close();exec(compile(code, __file__, &#39;&quot;&#39;&quot;&#39;exec&#39;&quot;&#39;&quot;&#39;))&#39; install --record /tmp/pip-record-np4sy9qk/install-record.txt --single-version-externally-managed --compile --install-headers /usr/local/include/python3.8/gluonnlp Check the logs for full command output.
</code></pre>
<p>이는 &quot;python3-dev&quot;가 설치되어있지 않아서 발생한 문제였고,</p>
<pre><code class="language-shell">$ apt-get install -y python3-dev</code></pre>
<p>로 해결하였다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Linux] chown 명령어]]></title>
            <link>https://velog.io/@chocopie_jjeong/Linux-chown-%EB%AA%85%EB%A0%B9%EC%96%B4</link>
            <guid>https://velog.io/@chocopie_jjeong/Linux-chown-%EB%AA%85%EB%A0%B9%EC%96%B4</guid>
            <pubDate>Wed, 26 May 2021 08:32:59 GMT</pubDate>
            <description><![CDATA[<p>리눅스 상에서 파일은 Owner과 Group에 속해있다.
&quot;chown&quot; 명령어는 이를 변경하는 명령어이다. </p>
<pre><code class="language-shell">$ chown [OPTION] USER[:GROUP] file(s)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Docker] 이미지 저장 및 불러오기]]></title>
            <link>https://velog.io/@chocopie_jjeong/Docker-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%A0%80%EC%9E%A5-%EB%B0%8F-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0</link>
            <guid>https://velog.io/@chocopie_jjeong/Docker-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%A0%80%EC%9E%A5-%EB%B0%8F-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0</guid>
            <pubDate>Wed, 26 May 2021 04:48:20 GMT</pubDate>
            <description><![CDATA[<p>다른 서버에 있는 docker image를 파일로 압축해서 가지고 올 필요가 생겼다.</p>
<ul>
<li>Docker Image 저장<pre><code class="language-shell">$ docker save -o {이미지 압축파일명}.tar {타깃 이미지명 혹은 이미지ID}</code></pre>
해당 경로상에 &quot;{이미지 압축파일명}.tar&quot;이 생성되는 것을 확인한다.</li>
</ul>
<p>이후, 내 서버에 해당 압축파일을 옮겨온 뒤, 다시 docker image로 로드한다.</p>
<ul>
<li><p>Docker Image 로드</p>
<pre><code class="language-shell">$ docker load -i {이미지 압축파일명}.tar
$ docker images</code></pre>
</li>
<li><p>원하는 이미지 이름으로 변경</p>
<pre><code>$ docker tag {바꾸고싶은 이미지ID} {원하는 이미지명:tag}</code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 프로젝트 패키지 구조]]></title>
            <link>https://velog.io/@chocopie_jjeong/Spring-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8C%A8%ED%82%A4%EC%A7%80-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@chocopie_jjeong/Spring-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8C%A8%ED%82%A4%EC%A7%80-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Tue, 25 May 2021 14:37:03 GMT</pubDate>
            <description><![CDATA[<p>Spring boot 프로젝트를 시작할 때, 
WAS를 구성하는 각 요소들을 어떤 패키지로 묶으며, 
그 하위 패키지는 어떻게 구성할지,
인터페이스와 그를 구현한 구체 클래스들의 패키지는 어떤 식으로 가져갈지,
등등...
경험이 부족한 나의 프로젝트 내부 구조는 뒤죽박죽으로 되어있다.</p>
<p>따라서,</p>
<p>하나의 서버를 구성하는 프로젝트의 하위 패키지 구조 설계에 도움이 되는 Github을 바탕으로 정리해본다.</p>
<blockquote>
<p>참고한 Github 주소
<a href="https://github.com/osopromadze/Spring-Boot-Blog-REST-API/tree/master/src">https://github.com/osopromadze/Spring-Boot-Blog-REST-API/tree/master/src</a></p>
</blockquote>
<ul>
<li>프로젝트 구조
코드가 시작하는 부분부터 패키지 구조를 그려본 것</li>
</ul>
<p>| config </p>
<pre><code>      |___ AConfig.java
      |___ BConfig.java
      ...</code></pre><p>| controller</p>
<pre><code>      |___ AController.java
      |___ BController.java 
      ...</code></pre><p>| exception</p>
<pre><code>      |___ AException.java
      |___ BException.java 
      ...</code></pre><p>| model</p>
<pre><code>      |___ AModel

              |___ AEntity.java
            ...

      |___ BModel
      ...</code></pre><p>| payload</p>
<pre><code>      |___ request

              |___ ARequest.java
      |___ response
      ...</code></pre><p>| repository</p>
<pre><code>      |___ ARepository.java
      |___ BRepository.java 
      ...</code></pre><p>| security</p>
<pre><code>      |___ ATokenProvider.java
      ...</code></pre><p>| service</p>
<pre><code>      |___ Impl

              |___ AServiceImpl.java
            ...

      |___ AService.java 
      |___ BService.java
      ...</code></pre><p>| utils</p>
<pre><code>      |___ ServiceConstant.java
      |___ ServiceUtils.java 
      ...</code></pre><p>| Application.java</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Redis] Docker로 실행]]></title>
            <link>https://velog.io/@chocopie_jjeong/Redis-Docker%EB%A1%9C-%EC%8B%A4%ED%96%89</link>
            <guid>https://velog.io/@chocopie_jjeong/Redis-Docker%EB%A1%9C-%EC%8B%A4%ED%96%89</guid>
            <pubDate>Tue, 25 May 2021 05:40:11 GMT</pubDate>
            <description><![CDATA[<p>먼저, Redis 서버를 docker network 내에서 실행시키기 위해
네트워크를 먼저 생성한다.</p>
<pre><code class="language-shell">$ docker network create redis-net</code></pre>
<p>이제 Redis 서버를 실행시킨다.</p>
<pre><code class="language-shell">$ docker run --name redis\
         -p 6379:6379 \
             --network redis-net \
             -v my/folder:/data -d redis:latest redis-server \
             --appendonly yes</code></pre>
<p>redis-cli로 해당 redis server에 접속해본다.</p>
<pre><code class="language-shell">$ docker run -it --network redis-net --rm redis:latest redis-cli -h redis</code></pre>
<p>참고</p>
<blockquote>
<p>--rm: 실행할 때, 컨테이너 id가 존재하면 삭제 후 run</p>
</blockquote>
<p>Redis server의 docker network ip를 확인한다.</p>
<pre><code class="language-shell">$ docker network inspect redis-net</code></pre>
<p>&quot;Containers&quot;의 &quot;redis&quot;이름에 해당하는 부분에서 IPv4 주소를 확인하면 된다.</p>
<p>redis:latest 이미지를 ash 쉘로 실행하여 redis-cli 접속해본다.</p>
<pre><code>$ docker run -it --network redis-net --rm redis:latest ash</code></pre><p>쉘에 접속하면, 아래와 같이 redis server의 컨테이너명을 호스트로 해도 되고, ip를 입력해도 된다.</p>
<pre><code>/data # redis-cli -h redis</code></pre><ul>
<li>참고한 블로그
<a href="https://emflant.tistory.com/235">https://emflant.tistory.com/235</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] String format]]></title>
            <link>https://velog.io/@chocopie_jjeong/JAVA-String-format</link>
            <guid>https://velog.io/@chocopie_jjeong/JAVA-String-format</guid>
            <pubDate>Sun, 23 May 2021 14:30:46 GMT</pubDate>
            <description><![CDATA[<p>2021.05.23의 개발 기록</p>
<p>MySQL의 like 구문을 활용할 때, % 자체를 사용해야하는데
이를 동적으로 받은 특정 값에 대해서 적용하여 쿼리 string으로 넘길 때,
String.format()을 활용해야 했음</p>
<p>근데, String.format의 포멧 string에는 %와 conversion의 조합으로 구성하여 들어가는데,
이때 % 자체를 활용하려면 %%로 두번 입력해줘야 함</p>
<p>예를 들어, projectId를 인자로 받아서 해당 값으로 시작하는 모든 컬럼 값들을 가져오는 쿼리를 작성할 때, 아래의 함수처럼 작성하여 활용함</p>
<pre><code class="language-java">public String getProjectIdFormat(long projectId){
    return String.format(&quot;%d_%%&quot;, projectId);
} // return 값 예시: &quot;1_%&quot; -&gt; 1_로 시작하는 컬럼값들을 가져올 때 활용
</code></pre>
]]></description>
        </item>
    </channel>
</rss>