<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>A Pencil under the eraser</title>
    <link>https://lgb9811.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 6 Apr 2026 11:24:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>벨로그로 옮겼어요~</managingEditor>
    <item>
      <title>random 모듈, lambda, map, reduce, filter, related_name, related_query_name</title>
      <link>https://lgb9811.tistory.com/172</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;import random&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;random() : 0 이상 1 미만의 실수 난수 생성&lt;/li&gt;
&lt;li&gt;randrange(a, b, c) : a가 시작점, b가 끝점(포함 x), c는 간격(step). 간격은 필수 아님&lt;/li&gt;
&lt;li&gt;choice() : 하나 골라줌&lt;/li&gt;
&lt;li&gt;shuffle() : 시퀀스 객체를 셔플 시켜줌&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;lambda, map, reduce, filter&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# lambda 매개변수 : 표현식
def multi(x, y):
    return x * y

if multi(2, 4) == (lambda x, y: x * y)(2, 4):
    print('결과가 똑같아용')

# map(함수, 리스트)
print(list(map(lambda x: x ** 3, range(3))))  # [0, 1, 8] 출력

# reduce(함수, 순회 가능한 데이터[, 초기값]) -&amp;gt; 누적 집계
from functools import reduce

r = reduce(lambda x, y: x + y, range(5))
print(r)  # 10 출력

users = [{'mail': 'gregorythomas@gmail.com', 'name': 'Brett Holland', 'sex': 'M', 'age': 73},
         {'mail': 'hintoncynthia@hotmail.com',
             'name': 'Madison Martinez', 'sex': 'F', 'age': 29},
         {'mail': 'wwagner@gmail.com', 'name': 'Michael Jenkins', 'sex': 'M', 'age': 51},
         {'mail': 'daniel79@gmail.com',
             'name': 'Karen Rodriguez', 'sex': 'F', 'age': 32},
         {'mail': 'ujackson@gmail.com', 'name': 'Amber Rhodes', 'sex': 'F', 'age': 42}]

sum_age = reduce(lambda acc, cur: acc + cur[&quot;age&quot;], users, 0)
print(sum_age)

# filter(함수, 순회 가능한 데이터) -&amp;gt; 원소를 함수에 적용시켜 결과가 참인 값들을 걸러낸다.
f = filter(lambda x : x &amp;lt; 5, range(10))
print(list(f)) # [0, 1, 2, 3, 4] 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Django 복습 - 요새 기존에 알던 것도 공식 문서로 다시 공부 중입니당&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;verbose_name&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;verbose_name&amp;nbsp;is a human-readable name for the field.&lt;/li&gt;
&lt;li&gt;If the verbose name isn&amp;rsquo;t given, Django will automatically create it using the field&amp;rsquo;s attribute name, converting underscores to spaces.&lt;/li&gt;
&lt;li&gt;This attribute in general changes the field name in admin interface.&lt;/li&gt;
&lt;li&gt;요약 : 필드 이름을 인간이 읽기 쉽도록 바꿈. 안 쓰면 기본적으로 속성 이름 따라감(공백은 &amp;lsquo;_&amp;rsquo;로 치환)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;related_name &amp;rarr; &lt;a href=&quot;https://docs.djangoproject.com/en/4.1/topics/db/queries/#backwards-related-objects:~:text=Following%20relationships%20%E2%80%9Cbackward%E2%80%9D%C2%B6&quot;&gt;참고 docs&lt;/a&gt;&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모델이 외래키로 참조&amp;rsquo;되고&amp;rsquo; 있을 때, 해당 모델은 FOO_set을 통해 관련 모델의 필드를 반환하는 Manager에 접근할 수 있다.&lt;/li&gt;
&lt;li&gt;이때 FOO는 소스가 되는 모델의 소문자 이름이다.&lt;/li&gt;
&lt;li&gt;또는 FOO_set 대신 related_name으로 따로 이름을 지정해줄 수도 있다.&lt;/li&gt;
&lt;li&gt;해당 Manager는 QuerySets을 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;from datetime import date
from django.db import models

class Blog(models.Model) :
    name = models.CharField(max_length = 100)
    tagline = models.TextField()

    def __str__(self) :
        return self.name

class Entry(models.Model) :
    blog = models.ForeignKey(Blog, on_delete = models.CASCADE)
    headline = models.CharField(max_length=255)

b = Blog.objects.get(id=1)
b.entry_set.all() # b와 연관된 모든 Entry 객체를 들고 온다.
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 blog = models.ForeignKey(Blog, on_delete = models.CASCADE, related_name = 'entries')로 설정돼있을 경우 b.entries.all()로 가져올 수 있다.&lt;/li&gt;
&lt;li&gt;Django가 역방향 관계(Backwards relation)를 생성하지 않길 원한다면 related_name을&amp;nbsp;'+'로 설정하거나 '+&amp;nbsp;'+'로 끝내면 된다. (아래 예시)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;class Entry(models.Model) :
    blog = models.ForeignKey(Blog, on_delete = models.CASCADE, related_name = &quot;+&quot;, )
    # Blog 모델이 역방향 관계를 갖지 않도록 한다.
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;QuerySet의 kwarg로도 활용할 수 있다. 즉 reverse filter name으로 쓸 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;related_query_name&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타겟 모델의 reverse filter name으로 사용하는 이름&lt;/li&gt;
&lt;li&gt;if set 따로 지정하지 않을 경우 related_name이나 default_relaged_name과 동일하다(&amp;rarr;_set). otherwise 모델 이름으로 설정된다/&lt;/li&gt;
&lt;li&gt;related_name처럼 app label과 class interpolation을 지원한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;related_name과 related_query_name 사용 시 주의할 점 &amp;rarr; &lt;a href=&quot;https://docs.djangoproject.com/en/4.1/topics/db/models/#abstract-related-name:~:text=Meta&quot;&gt;참고 docs&lt;/a&gt;%3A%0A%20%20%20%20%20%20%20%20pass-,Be%20careful%20with%20related_name%20and%20related_query_name,-%C2%B6)&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추상 기본 클래스(abstract base classes)의 필드는 매번 속성값(attribute, related_name과 related_query_name 포함)을 똑같이 가지고 각각의 자식 클래스에 포함된다.&lt;/li&gt;
&lt;li&gt;따라서 외래키나 ManyToManyField를 가진 추상 기본 클래스(abstract base classes)를 상속받을 경우 항상 related_name&amp;nbsp;또는&amp;nbsp;related_query_name&amp;nbsp;속성값이 동일한 문제가 발생할 수 있다. (migrate할 때 에러가 나버릴지도~)&lt;/li&gt;
&lt;li&gt;그러므로 외래키나 ManyToManyField에서 related_name&amp;nbsp;또는&amp;nbsp;related_query_name&amp;nbsp;사용하는 경우, 필드의 고유한(unique) reverse name과 query name 필수로 지정해주어야 한다.&lt;/li&gt;
&lt;li&gt;이때 %(app_label)s과&amp;nbsp;%(class)s를 활용한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;%(class)s : 해당 필드가 사용되는 자식 클래스의 소문자(lower-cased) 이름.&lt;/li&gt;
&lt;li&gt;%(app_label)s : 자식 클래스가 포함돼있는 앱의 소문자(lower-cased) 이름. 이때 각 앱과 앱 내 모델 클래스의 이름이 모두 unique해야 이름이 다르게 나온다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;예시&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from django.db import models

class Base(models.Model):
    m2m = models.ManyToManyField(
        OtherModel,
        related_name=&quot;%(app_label)s_%(class)s_related&quot;,
        related_query_name=&quot;%(app_label)s_%(class)ss&quot;,
    )

    class Meta:
        abstract = True

class ChildA(Base):
    pass

class ChildB(Base):
    pass
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;The reverse name of the&amp;nbsp;&lt;b&gt;common.ChildA.m2m&lt;/b&gt;&amp;nbsp;field will be&amp;nbsp;&lt;b&gt;common_childa_related&lt;/b&gt;&amp;nbsp;and the reverse query name will be&amp;nbsp;&lt;b&gt;common_childas&lt;/b&gt;. (누가 내 블로그를 볼까 싶어서 굳이 한글로 해석하진 않았다../)&lt;/li&gt;
&lt;li&gt;The reverse name of the&amp;nbsp;&lt;b&gt;common.ChildB.m2m&lt;/b&gt;&amp;nbsp;field will be&amp;nbsp;&lt;b&gt;common_childb_related&lt;/b&gt;&amp;nbsp;and the reverse query name will be&amp;nbsp;&lt;b&gt;common_childbs&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;Finally, the reverse name of the&amp;nbsp;&lt;b&gt;rare.ChildB.m2m&lt;/b&gt;&amp;nbsp;field will be&amp;nbsp;&lt;b&gt;rare_childb_related&lt;/b&gt;&amp;nbsp;and the reverse query name will be&amp;nbsp;&lt;b&gt;rare_childbs&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;related_name&amp;amp;related_query_name요약&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;related_name은 일대다 관계에서 1인 모델 인스턴스가 관계된 多 모델의 객체를 가져올 때 사용한다.&lt;/li&gt;
&lt;li&gt;related_name은 모델 인스턴스의 속성처럼 활용 가능하고, 따로 related_query_name을 지정하지 않을 경우 QuerySet의 kwarg로도 사용 가능하다.&lt;/li&gt;
&lt;li&gt;만약 자식 클래스가 존재할 경우 %(app_label)s과&amp;nbsp;%(class)s를 활용해 고유한(unique) reverse name과 query name을 지정해 주어야 related_name&amp;nbsp;또는&amp;nbsp;related_query_name&amp;nbsp;속성값이 동일한 문제를 방지할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 기분 나쁜 일 있어서 뒤지게 공부만 했더니 스트레스가 좀 풀렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬픈 감정이든 빡침이든 부정적인 감정이 올라올 때는 일부러 나를 바쁘게 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 점에서 가끔은 짜잘하게 나쁜 일이 있는 것도 나쁘지 않아~~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덕분에 영어 공부랑 일본어 공부도 하고 코딩 공부까지 하루에 다 할 수 있었다.&lt;/p&gt;</description>
      <category>Programming/TIL and WIL</category>
      <author>벨로그로 옮겼어요~</author>
      <guid isPermaLink="true">https://lgb9811.tistory.com/172</guid>
      <comments>https://lgb9811.tistory.com/172#entry172comment</comments>
      <pubDate>Sun, 19 Feb 2023 20:47:08 +0900</pubDate>
    </item>
    <item>
      <title>float(&amp;rsquo;inf') : float 자료형의 무한대 상수</title>
      <link>https://lgb9811.tistory.com/171</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코딩 테스트 문제 등을 풀다 보면, 최솟값을 저장하는 변수에 아주 큰 값을 할당해야 할 때가 있다.&lt;/li&gt;
&lt;li&gt;inf는 어떤 숫자와 비교해도 무조건 크다고 판정된다.&lt;/li&gt;
&lt;li&gt;inf에는 음수 기호를 붙이는 것도 가능하다.&lt;/li&gt;
&lt;li&gt;정수형(int)에는 적용 불가능. 따라서 float에 적용한 inf에 int()도 사용할 수 없다.&lt;/li&gt;
&lt;li&gt;비교하는 상황에서 최솟값을 찾을 때 용이하다(useful for finding lowest values for sth).&lt;/li&gt;
&lt;li&gt;float 내장함수 말고 math 모듈을 사용해 표현할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;import math

max_float = math.inf
min_float = -math.inf
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;float(&amp;rsquo;-inf&amp;rsquo;)와 -math.inf는 음의 무한대. 무조건 작다고 판정된다.&lt;/li&gt;
&lt;li&gt;예시&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;min_val = 99999
min_val &amp;gt; 100000000 # ?
# 위 방법은 비교할 데이터가 아주 큰 경우, 정상 작동하지 않을 수 있다.

min_val = float('inf') # 무조건 크다고 판정된다.
min_val &amp;gt; 10000000000
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Programming/TIL and WIL</category>
      <author>벨로그로 옮겼어요~</author>
      <guid isPermaLink="true">https://lgb9811.tistory.com/171</guid>
      <comments>https://lgb9811.tistory.com/171#entry171comment</comments>
      <pubDate>Sat, 18 Feb 2023 23:41:57 +0900</pubDate>
    </item>
    <item>
      <title>Linux(리눅스) - 크론탭(Crontab)</title>
      <link>https://lgb9811.tistory.com/170</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정의 : 특정 시각이나 정기적인 시간대에 작업이 실행되게끔 할 수 있다. &amp;rarr; 작업 스케쥴링&lt;/li&gt;
&lt;li&gt;설치
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sudo apt install cron&lt;/li&gt;
&lt;li&gt;sudo service cron status : 크론탭이 실행 중인지 확인한다. 상태가 active면 그대로 두고, active가 아니면 아래 명령어 수행.&lt;/li&gt;
&lt;li&gt;pgrep cron을 입력했을 때 프로세스id의 출력 여부를 통해 확인할 수도 있다. (아무것도 출력하지 않으면 실행중이 아닌 것)&lt;/li&gt;
&lt;li&gt;sudo service cron start&lt;/li&gt;
&lt;li&gt;sudo service cron restart : 크론탭 재시작 (넘버링하긴 했지만 3 &amp;rarr; 4는 이상하다)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;기본적인 크론탭 명령어
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;crontab -e : 작업 할당 명령어. 첫 실행 시 nano와 vim 중 사용할 텍스트 편집기를 고르고, 이후에는 바로 편집기가 실행된다.&lt;/li&gt;
&lt;li&gt;만약 nano 에디터로 설정돼있을 경우 export VISUAL=vim이나 export EDITOR=vim 명령어를 통해 에디터를 vim으로 변경할 수 있다.&lt;/li&gt;
&lt;li&gt;crontab -l : 할당된 작업 리스트 확인&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;작업 할당 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;크론탭은 텍스트 입력을 통해 작업을 할당한다.&lt;/li&gt;
&lt;li&gt;*은 반복 주기를 의미한다.&lt;/li&gt;
&lt;li&gt;*은 순서대로 분(0-59), 시간(0-23), 일(1-31), 월(1-12), 요일(0-7) 설정에 해당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;crontab -e&lt;/li&gt;
&lt;li&gt;* * * * * + 실행할 명령 텍스트 ex) 30 16 * * * env &amp;gt; /tmp/env.output : 매일 오후 4시 30분에 환경변수를 tmp/env.output에 저장하는 배치 작업&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Programming/TIL and WIL</category>
      <author>벨로그로 옮겼어요~</author>
      <guid isPermaLink="true">https://lgb9811.tistory.com/170</guid>
      <comments>https://lgb9811.tistory.com/170#entry170comment</comments>
      <pubDate>Fri, 17 Feb 2023 23:56:56 +0900</pubDate>
    </item>
    <item>
      <title>인스턴스 메소드/클래스 메소드/스태틱 메소드, 알고리즘: 징검다리, ORM(lazy loading, eager loading, select_related, prefetch_related, n + 1, caching)</title>
      <link>https://lgb9811.tistory.com/169</link>
      <description>&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 메소드와 스태틱 메소드&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;'''
1. 인스턴스 메소드 : 첫 번째 매개변수로 객체를 받는다 -&amp;gt; self
2. 클래스 메소드 : 첫 번째 매개변수로 자기 클래스를 받는다 -&amp;gt; cls
3. 스태틱 메소드 : 일반 함수와 거의 비슷해 클래스와 연관성이 있음을 나타내는 정도로 쓰인다/
4. 클래스 메소드 vs. 스태틱 메소드
    - 공통점 : 클래스 변수에 접근 가능하지만 생성자를 포함한 인스턴스 메소드 변수에는 접근 불가능하다.
    - 스태틱 메소드 : 부모 클래스에서 정의된 스태틱 메소드는 자식 클래스에서 호출할 수 있다.
    - 클래스 메소드 : 부모 클래스에서 정의된 클래스 변수와 클래스 메소드는 자식 클래스에서도 선언이 가능하다.
    - 상속할 때 차이점 : 자식 클래스가 존재할 때, 스태틱 메소드는 부모 자식 어디서 선언하든 클래스 변수를 모두 바꾸지만, 클래스 메소드에서는 부모 클래스 객체에서 선언해야만 자식 클래스의 클래스 변수까지 모두 바꿀 수 있다. 자식 클래스에서 선언하면 자식 클래스의 클래스 변수만 바뀐다.
'''

class Parent:
    name = 'Geumbin Lee'
    
    @staticmethod
    def change_name_with_static(new_name) :
        Parent.name = new_name
        
    @classmethod
    def change_name_with_class(cls, new_name) :
        cls.name = new_name
    
class Child(Parent) :
    pass

parent = Parent()
child = Child()

print('&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; 스태틱 메소드에 대해 배워봅시당 &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;')
parent.change_name_with_static('Robin Lee')
print(f'부모 클래스에서 선언 : {parent.name}, {child.name}') # Robin Lee, Robin Lee
child.change_name_with_static('Katy Lee')
print(f'자식 클래스에서 선언할 때 : {parent.name}, {child.name}') # Katy Lee, Katy Lee

print('-'*50)
print('&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; 클래스 메소드에 대해 배워봅시당 &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;')
parent.change_name_with_class('Robin Lee')
print(f'부모 클래스에서 선언 : {parent.name}, {child.name}') # Robin Lee, Robin Lee
child.change_name_with_class('Katy Lee')
print(f'자식 클래스에서 선언할 때 : {parent.name}, {child.name}') # Robin Lee, Katy Lee
&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그래머스 - 이분 탐색: 징검다리&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;def solution(distance, rocks, n):
    answer = 0
    rocks.sort()
    start, end = 0, distance
    
    while start &amp;lt;= end: 
        mid = (start + end) // 2
        del_rock = 0 # 제거 횟수 카운트
        stone = 0 # 기준점
        for rock in rocks:
            if rock - stone &amp;lt;  mid: # 거리가 mid보다 작으면 제거한다.
                del_rock += 1 
            else: # 돌 사이 거리가 mid보다 크면 기준을 바꾼다.
                stone = rock
             
            if del_rock &amp;gt; n: #제거된 돌이 문제 조건 보다 크면 for문을 나온다
                break
        
        if del_rock &amp;gt; n: # 제거할 바위 수(n)보다 많은 바위를 제거했을 시 범위를 줄인다.
            end = mid - 1
        else: # 그게 아니면 큰 쪽으로 줄인다.
            answer = mid
            start = mid + 1
        print(f&quot;start : {start}, end : {end}, mid : {mid}, del_rock : {del_rock}, answer :{answer}&quot;)
            
    return answer

solution(25, [2, 14, 11, 21, 17], 2)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ORM
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정의 : 객체와 관계형 데이터베이스의 데이터를 자동으로 매핑(연결)해준다.&lt;/li&gt;
&lt;li&gt;SQL로 변환해서 들어가기 때문에 sql문을 잘 몰라도 작성할 수 있다. where를 filter로 가져오는 식&lt;/li&gt;
&lt;li&gt;특징
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Lazy Loading
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;말 그대로 게을러서 실제로 데이터를 조작하는 순간에 DB를 hit한다.&lt;/li&gt;
&lt;li&gt;필요할 때마다, 필요한 횟수만큼만 db를 건드린다.&lt;/li&gt;
&lt;li&gt;n + 1 문제를 발생시킬 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;n + 1 문제
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;N건의 데이터를 가져오고(쿼리 +1), 특정 데이터를 위해 N건의 데이터를 순회(쿼리 +N)하는 문제&lt;/li&gt;
&lt;li&gt;ORM은 필요할 때마다 쿼리문을 수행하기 때문에 조회할 데이터가 개수가 증가할수록 쿼리문 수행 개수도 증가한다 &amp;rarr; 서버 부하 UP &amp;rarr; 속도 DOWN&lt;/li&gt;
&lt;li&gt;해결책 : Eager Loading&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Eager Loading
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;말 그대로 굉장히 열심(eager)이다. 지금 당장 안 필요한 데이터도 가져온다. &amp;rarr; select_realted와 prefetch_related&lt;/li&gt;
&lt;li&gt;select_realted
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL의 JOIN을 사용하는 방법 &amp;rarr; 외래키로 종속된 테이블의 데이터를 함께 들고 온다 (부지런하다)&lt;/li&gt;
&lt;li&gt;One 객체를 참조하는 경우(one-to-one, many-to-one), 정참조 관계일 때(many-to-one(many에서 one 참조)) 사용 가능&lt;/li&gt;
&lt;li&gt;정참조와 역참조 모두 사용 가능한 prefetch_realted에 비해 &lt;b&gt;범용성은 떨어지지만&lt;/b&gt;, 대개 &lt;b&gt;성능이 더 좋기 때문에&lt;/b&gt; 가능한 상황에서는 select_related를 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;prefetch_related
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공식 문서에서 &amp;lsquo;joining&amp;rsquo;이라고는 하나, 그 JOIN이 아니고, 테이블을 각각 불러들인 후 ORM 처리 단계에서 결합하는 방식&lt;/li&gt;
&lt;li&gt;따라서 항상 추가 쿼리가 발생한다. 그래서 대개 select_realted에 비해 성능이 떨어진다. (항상은 X)&lt;/li&gt;
&lt;li&gt;정참조 역참조 모두 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Caching
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캐싱을 활용해 이미 가져온 데이터를 쿼리문을 또 날리지 않고 그대로 재사용할 수 있다.&lt;/li&gt;
&lt;li&gt;핵심은 그대로!!! 가져온 데이터에 무언가 가공을 가하지 않은 상태여야 캐싱을 활용할 수 있다. ex) 슬라이싱이나 인덱싱하면 안됨&lt;/li&gt;
&lt;li&gt;당연히 많이 활용할수록 속도가 개선된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Programming/TIL and WIL</category>
      <author>벨로그로 옮겼어요~</author>
      <guid isPermaLink="true">https://lgb9811.tistory.com/169</guid>
      <comments>https://lgb9811.tistory.com/169#entry169comment</comments>
      <pubDate>Thu, 16 Feb 2023 21:38:38 +0900</pubDate>
    </item>
    <item>
      <title>230215: 시퀀스 자료형</title>
      <link>https://lgb9811.tistory.com/168</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;어제 공부했는데 갑자기 까무룩 잠들어서 til만 못 썼다.. 오늘은 그래서 두 개가 올라간다.&lt;/p&gt;
&lt;pre id=&quot;code_1676523228808&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# rnage(시작, 끝, 간격)
range_tuple = tuple(range(10, 0, -2))
print(range_tuple)

# 튜플은 리스트처럼 요소를 일렬로 저장하지만, 안에 저장된 요소를 변경, 추가, 삭제할 수 없다. (튜플은 불변 객체라 아무래도...)
# 간단하게 읽기 전용 리스트라고 생각할 수 있다.
a = 'a', # 이렇게 튜플 맏들어도 됨
b = 'b', 'c', 
print(type(a), type(b))
print(a)
print(b)
'''
&amp;lt; 시퀀스 자료형 &amp;gt;
- list, tuple, range, string 등
- 공통점 : 값이 연속적(sequential)으로 이어져 있다.
- in/not in 사용 가능 -&amp;gt; True or False
- + 연산자 활용 가능
- * 연산자 활용 가능. 단, 0 또는 음수를 곱하면 빈 객체가 나오며 실수는 곱할 수 없다.
- range는 +/* 연산자로 객체 연결 불가능 -&amp;gt; list나 tuple로 만들어 연결/반복하면 됨
- str도 시퀀스 자료형이니까 len(사용 가능
- 시퀀스 객체의 요소는 순서가 정해져 있으므로 인덱스로 접근 가능하다.
- tuple은 요소 변경이 불가능하기 때문에 인덱스를 통한 요소 변경/삭제/추가가 불가능하다. str, range도 마찬가지
- 슬라이싱은 모두 활용 가능, 다만 불변 객체는 객체를 새로 만드는 방식
- 시퀀스 객체 중에서도 불변 객체는 슬라이싱을 활용해도 요소를 할당할 수 없다.
'''

print(len(range(0, 10, 2))) # 5
print(len('hello, world')) # 띄어쓰기도 카운트함

r = range(1, 11)
print(r[:7:2]) # range(1, 8, 2)라고 요소가 모두 표시되지 않고 생성 범위만 표시됨
print(list(r[:7:2])) # [1, 3, 5, 7] 리스트로 표시해주면 해결

# 슬라이싱을 활용해 리스트에 새로운 요소를 할당할 때, 할당할 요소의 개수가 슬라이싱된 요소의 개수보다 적으면 그만큼 리ㅡ트의 요소 개수도 줄어든다.
a = list(range(0, 10))
a[2:5] = ['2~4'] 
print(a) # [0, 1, '2~4', 5, 6, 7, 8, 9]

# 반대로 할당할 용소의 개수가 슬라이싱된 요소의 개수보다 많으면 그만큼 리스트의 요소 개수도 늘어난다.
a[2:5] = [2, 3, 4, 5, 6]
print(a) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 인덱스의 증가폭을 활용해 슬라이싱을 통한 재할당을 할 때는, 슬라이싱 범위 내 요소의 개수와 할당할 요소의 개수가 일치해야 한다.
b = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
b[2:8:2] = ['a', 'b', 'c'] # 개수 안 맞추면 ValueError 발생
print(b)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Programming/TIL and WIL</category>
      <author>벨로그로 옮겼어요~</author>
      <guid isPermaLink="true">https://lgb9811.tistory.com/168</guid>
      <comments>https://lgb9811.tistory.com/168#entry168comment</comments>
      <pubDate>Thu, 16 Feb 2023 13:53:54 +0900</pubDate>
    </item>
    <item>
      <title>CORS(Cross-Origin Resource Sharing)</title>
      <link>https://lgb9811.tistory.com/167</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추가 HTTP를 사용해 다른 출처에 있는 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Protocol + Host + Port&lt;/b&gt; 3가지가 같으면 동일 출처(Origin)라고 한다. 하나라도 다르면 교차 출처[다른 출처].&lt;/li&gt;
&lt;li&gt;요청하는 클라이언트와 요청받는 서버가&amp;nbsp;&lt;b&gt;같은 출처에 있으면 동일 출처&lt;/b&gt;,&amp;nbsp;&lt;b&gt;서로 다른 서버에 있으면 다른 출처 요청&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;동일 출처 정책 (Same-origin policy)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 출처로부터 조회된 자원들의 읽기 접근을 막아 다른 출처 공격을 예방한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다른 출처 요청 정책 3가지 &amp;rarr; &lt;a href=&quot;https://escapefromcoding.tistory.com/724#:~:text=Origin%20Policy&quot;&gt;참고자료&lt;/a&gt;(이 분께서 잘 정리해 주셨다.)
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순 요청 (Simple Request)&lt;/li&gt;
&lt;li&gt;프리 플라이트 (Preflight Request)&lt;/li&gt;
&lt;li&gt;신용 요청 (Credentialed Request)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Programming/TIL and WIL</category>
      <author>벨로그로 옮겼어요~</author>
      <guid isPermaLink="true">https://lgb9811.tistory.com/167</guid>
      <comments>https://lgb9811.tistory.com/167#entry167comment</comments>
      <pubDate>Tue, 14 Feb 2023 22:51:55 +0900</pubDate>
    </item>
    <item>
      <title>HTTPS의 개념과 원리</title>
      <link>https://lgb9811.tistory.com/166</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;면접 직전에 굉장히 압축해서 적은 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 내용은 구글링하면 굉장히 잘 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블로그에 내용 정리한 거 올리면서 답변용으로 요약을 한 번 더 한다고 했는데, 이 정도 분량으로 압축하는 편이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자잘한 건 꼬리질문이 나왔을 때 대답할 수 있을 정도로만 걍 이해하고 넘어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP는 암호화 과정이 없어 보안에 취약하다.&lt;/li&gt;
&lt;li&gt;HTTPS는 HTTP를 SSL 프로토콜 위에서 돌아가도록 해 클라이언트와 서버 간 텍스트를 암호화하는 방식으로 구현합니다.&lt;/li&gt;
&lt;li&gt;즉 HTTPS는 HTTP 프로토콜 + SSL 프로토콜&lt;/li&gt;
&lt;li&gt;SSL 프로토콜 동작 원리 : &lt;b&gt;SSL/TLS handshake&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트가 서버에 접속하면 서버는 클라이언트에게 SSL 인증서를 전달합니다.&lt;/li&gt;
&lt;li&gt;브라우저는 대부분의 검증된 민간 기업의 공개키를 보유하고 있으므로, 이를 통해 인증서를 복호화 합니다.&lt;/li&gt;
&lt;li&gt;복호화를 통해 인증서의 신뢰성을 확인했으면 클라이언트는 해당 공개키를 활용해 서버와 소통하며 대칭키인 &amp;lsquo;세션키&amp;rsquo;를 생성하고 이를 활용해 통신을 진행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Programming/TIL and WIL</category>
      <author>벨로그로 옮겼어요~</author>
      <guid isPermaLink="true">https://lgb9811.tistory.com/166</guid>
      <comments>https://lgb9811.tistory.com/166#entry166comment</comments>
      <pubDate>Sat, 11 Feb 2023 23:25:33 +0900</pubDate>
    </item>
    <item>
      <title>웹 서버와 웹 어플리케이션, CGI, WSGI, ASGI</title>
      <link>https://lgb9811.tistory.com/165</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3줄 요약
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만들어놓은 것 그대로 제공하는 리소스를 정적 리소스라 하고, 데이터 처리에 따라 값이 다를 수 있는 리소스를 동적 리소스라 한다.&lt;/li&gt;
&lt;li&gt;웹 서버는 정적 리소스 처리를 담당하기 때문에 동적 리소스를 처리하기 위해 웹 어플리케이션을 사용한다.&lt;/li&gt;
&lt;li&gt;CGI는 웹 서버와 웹 어플리케이션 서버 간 통신을 위한 공통의 인터페이스이고, 매 요청 때마다 프로세스를 생성해야 한다는 CGI의 단점을 보완한 게 WSGI, 비동기에 취약하다는 WSGI의 단점을 보완한 게 ASGI이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;정적 리소스 (Static Resource) vs. 동적 리소스 (Dynamic Resource)
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 리소스 (Static Resource)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만들어놓은 것 그대로 제공하는 리소스&lt;/li&gt;
&lt;li&gt;ex) 파일이나 이미지, HTML 페이지 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;동적 리소스 (Dynamic Resource)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상호작용을 통한 데이터 처리가 필요한 리소스&lt;/li&gt;
&lt;li&gt;값이 그때그때 다를 수 있는 리소스&lt;/li&gt;
&lt;li&gt;대표적으로 데이터베이스의 처리가 필요한 경우 &amp;lsquo;동적&amp;rsquo;이라는 말이 붙는다.&lt;/li&gt;
&lt;li&gt;&amp;rarr; 서버가 사용자의 '요청(Request)'에 따라 데이터를 가공처리한 뒤에 생성되어진 웹 페이지를 보여주게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;웹 서버(Web Server) vs 웹 어플리케이션 서버(Web Application Server)
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Web Server 웹 서버
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적인 리소스 요청을 처리하는 프로그램으로, 웹 서버의 종류에는 아파치(Apach)와 Nginx 등이 있다.&lt;/li&gt;
&lt;li&gt;동적 컨텐츠를 처리하기 위해 데이터 베이스 쿼리문 처리와 같은 동적 요청이 들어오면 웹 어플리케이션에 요청을 넣는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Web Application 웹 어플리케이션 &amp;rarr; 보통 WAS라고 부른다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 서버로부터 오는 동적인 요청을 처리하는 서버로, 로직을 수행한 뒤 웹 서버에 결과를 돌려준다.&lt;/li&gt;
&lt;li&gt;기능
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램 실행 환경과 데이터베이스 접속 기능을 제공&lt;/li&gt;
&lt;li&gt;여러 개의 트랜잭션을 관리&lt;/li&gt;
&lt;li&gt;업무를 처리하는 비즈니스 로직 수행&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;종류에는 아파치 톰캣, 제우스, 제티(Jetty), 레진(Resin) 등이 있다.&lt;/li&gt;
&lt;li&gt;예시 : nginx가 웹 서버가 django가 백엔드에서 돌린 웹애플리케이션 서버에 해당한다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt; &amp;nbsp;Web Server 는 다소 광범위한 용어라서 Hardware 로서의 의미와 Software 로서의 의미를 함께 가지고 있어 여기에서는 &lt;b&gt;Software 로서의 의미에 집중&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;CGI / WSGi / ASGI 개념 &amp;rarr; &lt;a href=&quot;https://kangbk0120.github.io/articles/2022-02/cgi-wcgi-asgi&quot;&gt;참고자료&lt;/a&gt;&lt;a href=&quot;https://kangbk0120.github.io/articles/2022-02/cgi-wcgi-asgi&quot;&gt;https://kangbk0120.github.io/articles/2022-02/cgi-wcgi-asgi&lt;/a&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CGI (Common Gateway Interface)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 서버가 동적인 리소스를 처리하기 위해 웹 어플리케이션과 소통할 때 서버 간, 그리고 언어 간 요청을 공통의 형태로(&amp;rarr;&lt;b&gt;Common&lt;/b&gt; Gateway &lt;b&gt;Interface&lt;/b&gt;) 처리하기 위해 만들어진 인터페이스&lt;/li&gt;
&lt;li&gt;&amp;rarr; 즉 한마디로 웹 서버와 웹 어플리케이션이 소통할 수 있는 인터페이스&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청이 들어올 때마다 애플리케이션 프로세스를 다시 생성해 실행해야 한다.&lt;/li&gt;
&lt;li&gt;C와 같은 컴파일 언어보다 파이썬과 같은 스크립트 언어에서 실행에 더 많은 시간이 필요하기 때문에 더욱 단점이 두드러진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;동작 원리
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Web Server 가 Client 로 부터 HTTP Request 를 받는다.&lt;/li&gt;
&lt;li&gt;Web Server 는 Request 에 대한 정보(Method, Url, Parameters, ...)를 환 경숭수오와 tanad rddIIut 을 통해 전달하면서 Script 를 실행한다.&lt;/li&gt;
&lt;li&gt;Script 는 비즈니스 로직을 수행하고 Standard Output 으로 결과를 Web Server 에게 전달한다.&lt;/li&gt;
&lt;li&gt;Web Server 는 이를 다시 Client 에게 전달한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;WSGI (Web Server Gateway Interface)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이름과 달리 범용적이라기보다는 파이썬에서 사용되는 개념&lt;/li&gt;
&lt;li&gt;CGI의 단점을 보완하기 위해 고안되었다.&lt;/li&gt;
&lt;li&gt;CGI가 환경 변수나 STDIN 등으로 처리했지만 WSGI에서는 웹 서버가 요청에 대한 정보를 어플리케이션에 전달할 때 Callable object(호출 가능한 객체), 즉 함수나 객체로 처리한다.&lt;/li&gt;
&lt;li&gt;&amp;rarr; 서버에서 Callable object를 통해서 요청에 대한 정보와 Callback 함수를 전달하면 애플리케이션은 이 요청을 처리하고 Callback 함수를 실행한다.&lt;/li&gt;
&lt;li&gt;하나의 동기적인 callable이 요청을 받아 응답을 리턴하는 방식으로, 비동기 요청 처리에 취약하다.&lt;/li&gt;
&lt;li&gt;WSGI compatible하다 : 앞서 설명한 인터페이스를 구현하는 서버나 어플리케이션을 설명하는 용어&lt;/li&gt;
&lt;li&gt;WSGI application : WSGi 어플리케이션 지칭&lt;/li&gt;
&lt;li&gt;WSGI Middleware : 중간에서 인증이나 쿠키 등을 관리하는 역할을 하며, WSGI application의 일종으로, gunicorn을 포함한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;WSGI Middleware
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인증, 라우팅, 세션, 쿠키, 에러 페이지 보여주기 등 공통적으로 필요한 기능들을 웹 어플리케이션 실행 전후에 추가해주는 역할을 하는 WSGI 어플리케이션의 일종.&lt;/li&gt;
&lt;li&gt;gunicorn이 WSGI Middleware 기능을 가진 라이브러리 중 하나이다.&lt;/li&gt;
&lt;li&gt;gunicorn은 WSGI Middleware의 기능 뿐 아니라 그 자체로도 웹 서버의 역할을 할 수도 있다. 그래서 WSGI Server 나 Stand alone WSGI Container 라고 불리기도 한다.&lt;/li&gt;
&lt;li&gt;Nginx 는 주로 Buffering, Reverse Proxying, Load Balancing 등의 기능을 위해 Gunicorn 앞단에 배치하고, Gunicorn 은 Django 로 작성한 Web Application 에 HTTP 요청을 전달해주는 역할의 WSGI HTTP Server 로서 사용하는 것이다.&lt;/li&gt;
&lt;li&gt;Gunicorn 을 사용할 땐 worker process 의 개수와 worker class(async 방식인 Gevent, Tornado, ...)를 설정하여 요청 처리 성능을 높일 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ASGI
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비동기에 취약한 WSGi를 보완하기 위해 고안되었다. &amp;rArr; WSGI + 비동기&lt;/li&gt;
&lt;li&gt;&amp;rarr; WSGI는 하나의 동기적인 callable이 요청을 받아 응답을 리턴하는 방식으로, 길게 유지돼야 하는 연결(ex. long-poll HTTP나 Websocket)에는 적합 X&lt;/li&gt;
&lt;li&gt;WSGI에 대한 호환성은 유지하면서 비동기적인 요청까지 처리할 수 있는 인터페이스&lt;/li&gt;
&lt;li&gt;ASGI 서버로는 주로 uvicorn 등을 많이 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sgc109.github.io/2020/08/15/python-wsgi/&quot;&gt;참고자료&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Programming/TIL and WIL</category>
      <author>벨로그로 옮겼어요~</author>
      <guid isPermaLink="true">https://lgb9811.tistory.com/165</guid>
      <comments>https://lgb9811.tistory.com/165#entry165comment</comments>
      <pubDate>Fri, 10 Feb 2023 23:54:07 +0900</pubDate>
    </item>
    <item>
      <title>프록시 - 포워드 프록시, 리버스 프록시</title>
      <link>https://lgb9811.tistory.com/164</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프록시 서버(proxy server)란
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프록시 서버(proxy server)란 클라이언트와 네트워크 서비스 사이에서 통신을 받아 중계해주는 서버입니다.&lt;/li&gt;
&lt;li&gt;프록시 서버를 사용하면 보안성, 성능, 안정성을 향상 시킬 수 있습니다.&lt;/li&gt;
&lt;li&gt;크게 포워드 프록시 서버(forward proxy server)와 리버스 프록시 서버(reverse proxy server)로 나눠집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;포워드 프록시 서버(forward proxy server)란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;흔히 말하는 &amp;lsquo;프록시 서버&amp;rsquo;란 포워드 포록시 서버를 의미합니다.&lt;/li&gt;
&lt;li&gt;프록시 서버는 아래 그림처럼 클라이언트 앞에 놓여 있습니다.&lt;/li&gt;
&lt;li&gt;클라이언트가 웹 서버에 요청을 보내면 중간에서 그 요청을 가로채 웹 서버로 보내고, 웹 서버에게 받은 응답을 다시 클라이언트에게 전달한다.&lt;/li&gt;
&lt;li&gt;활용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 기관에 속한 사람들이 그들이 방문하고자 하는 웹사이트에 직접적으로(directly) 방문하는 것을 방지한다.&lt;/li&gt;
&lt;li&gt;즉 기관에 속한 유저가 특정 컨텐츠에 접근하는 것을 방지하는데 사용됩니다.&lt;/li&gt;
&lt;li&gt;예를 들어, 포워드 프록시 서버에 룰을 추가해서 특정 사이트에 접속하는 것을 막을 수 있습니다.&lt;/li&gt;
&lt;li&gt;포워드 프록시 서버를 사용하면 IP 주소를 역추적해도 프록시 서버만 보이기 때문에 유저의 정체를 숨겨주는 데 용이합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리버스 프록시 서버(reverse proxy server)란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포워드 프록시 서버는 클라이언트 앞에 놓여져 있는 반면, 리버스 프록시 서버는 아래 그림처럼 웹서버 앞에 놓여 있습니다.&lt;/li&gt;
&lt;li&gt;리버스 프록시 서버는 로드 밸런싱(load balancing)에 사용됩니다.&lt;/li&gt;
&lt;li&gt;&amp;rarr; 싱글 서버는 대량의 트래픽을 감당하기 어렵지만, 리버스 프록시 서버를 여러개의 서버 앞에 두면 특정 서버가 과부화 되지 않게 로드밸런싱이 가능합니다.&lt;/li&gt;
&lt;li&gt;리버스 프록시를 사용하면 보안에 좋습니다. 본래 서버의 IP 주소를 노출시킬 필요가 없어 DDoS 공격과 같은 공격을 막는데 유용합니다.&lt;/li&gt;
&lt;li&gt;대신 CDN과 같은 리버스 프록시 서버가 공격의 타겟이 될수는 있습니다.&lt;/li&gt;
&lt;li&gt;리버스 프록시 서버는 성능 향상을 위해 캐시 데이터를 저장할 수 있습니다. 그리고 캐싱되어 있는 데이터를 사용함으로써 더 빠른 성능을 보여줄 수 있다.&lt;/li&gt;
&lt;li&gt;마지막으로 SSL 암호화에 좋습니다. 원래는 비용이 많이 들지만, 리버스 프록시를 사용하면 들어오는 요청을 모두 복호화하고 나가는 응답을 암호화해주므로 클라이언트와 안전한 통신을 할수 있으며 본래 서버의 부담을 줄여줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;포워드 프록시 vs 리버스 프록시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포워드 프록시 서버는 클라이언트 앞에 놓여져 있는 반면, 리버스 프록시 서버는 웹서버 앞에 놓여 있습니다.&lt;/li&gt;
&lt;li&gt;따라서 포워드 프록시 서버를 사용하면 클라이언트와 직접 통신하는 웹서버가 없습니다.&lt;/li&gt;
&lt;li&gt;반면 리버스 프록시 서버를 사용하면 웹서버와 직접 통신하는 클라이언트가 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프록시 서버(proxy server)란
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프록시 서버(proxy server)란 클라이언트와 네트워크 서비스 사이에서 통신을 받아 중계해주는 서버입니다.&lt;/li&gt;
&lt;li&gt;프록시 서버를 사용하면 보안성, 성능, 안정성을 향상 시킬 수 있습니다.&lt;/li&gt;
&lt;li&gt;크게 포워드 프록시 서버(forward proxy server)와 리버스 프록시 서버(reverse proxy server)로 나눠집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;포워드 프록시 서버(forward proxy server)란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;흔히 말하는 &amp;lsquo;프록시 서버&amp;rsquo;란 포워드 포록시 서버를 의미합니다.&lt;/li&gt;
&lt;li&gt;프록시 서버는 아래 그림처럼 클라이언트 앞에 놓여 있습니다.&lt;/li&gt;
&lt;li&gt;클라이언트가 웹 서버에 요청을 보내면 중간에서 그 요청을 가로채 웹 서버로 보내고, 웹 서버에게 받은 응답을 다시 클라이언트에게 전달한다.&lt;/li&gt;
&lt;li&gt;활용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 기관에 속한 사람들이 그들이 방문하고자 하는 웹사이트에 직접적으로(directly) 방문하는 것을 방지한다.&lt;/li&gt;
&lt;li&gt;즉 기관에 속한 유저가 특정 컨텐츠에 접근하는 것을 방지하는데 사용됩니다.&lt;/li&gt;
&lt;li&gt;예를 들어, 포워드 프록시 서버에 룰을 추가해서 특정 사이트에 접속하는 것을 막을 수 있습니다.&lt;/li&gt;
&lt;li&gt;포워드 프록시 서버를 사용하면 IP 주소를 역추적해도 프록시 서버만 보이기 때문에 유저의 정체를 숨겨주는 데 용이합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리버스 프록시 서버(reverse proxy server)란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포워드 프록시 서버는 클라이언트 앞에 놓여져 있는 반면, 리버스 프록시 서버는 아래 그림처럼 웹서버 앞에 놓여 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;img id=&quot;img_1676382809154_1&quot; src=&quot;https://s3-us-west-2.amazonaws.com/secure.notion-static.com/8ba6f0bc-0e6b-461c-a3e4-74c1f2456559/Untitled.png&quot; /&gt;&lt;/li&gt;
&lt;li&gt;리버스 프록시 서버는 로드 밸런싱(load balancing)에 사용됩니다.&lt;/li&gt;
&lt;li&gt;&amp;rarr; 싱글 서버는 대량의 트래픽을 감당하기 어렵지만, 리버스 프록시 서버를 여러개의 서버 앞에 두면 특정 서버가 과부화 되지 않게 로드밸런싱이 가능합니다.&lt;/li&gt;
&lt;li&gt;리버스 프록시를 사용하면 보안에 좋습니다. 본래 서버의 IP 주소를 노출시킬 필요가 없어 DDoS 공격과 같은 공격을 막는데 유용합니다.&lt;/li&gt;
&lt;li&gt;대신 CDN과 같은 리버스 프록시 서버가 공격의 타겟이 될수는 있습니다.&lt;/li&gt;
&lt;li&gt;리버스 프록시 서버는 성능 향상을 위해 캐시 데이터를 저장할 수 있습니다. 그리고 캐싱되어 있는 데이터를 사용함으로써 더 빠른 성능을 보여줄 수 있다.&lt;/li&gt;
&lt;li&gt;마지막으로 SSL 암호화에 좋습니다. 원래는 비용이 많이 들지만, 리버스 프록시를 사용하면 들어오는 요청을 모두 복호화하고 나가는 응답을 암호화해주므로 클라이언트와 안전한 통신을 할수 있으며 본래 서버의 부담을 줄여줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;포워드 프록시 vs 리버스 프록시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포워드 프록시 서버는 클라이언트 앞에 놓여져 있는 반면, 리버스 프록시 서버는 웹서버 앞에 놓여 있습니다.&lt;/li&gt;
&lt;li&gt;따라서 포워드 프록시 서버를 사용하면 클라이언트와 직접 통신하는 웹서버가 없습니다.&lt;/li&gt;
&lt;li&gt;반면 리버스 프록시 서버를 사용하면 웹서버와 직접 통신하는 클라이언트가 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Programming/TIL and WIL</category>
      <author>벨로그로 옮겼어요~</author>
      <guid isPermaLink="true">https://lgb9811.tistory.com/164</guid>
      <comments>https://lgb9811.tistory.com/164#entry164comment</comments>
      <pubDate>Thu, 9 Feb 2023 22:25:53 +0900</pubDate>
    </item>
    <item>
      <title>스키마, 인덱스, 수직적 확장과 수평적 확장</title>
      <link>https://lgb9811.tistory.com/163</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 푼 알고리즘 문제는 답이 틀려서&amp;hellip;ㅜㅜㅜ 낼 다시 풀어야 된다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 소설 퇴고하고 포폴 만든다고 새벽에 잠을 못 잤다.. 피곤&amp;hellip; 저녁에 결국 자버렷구~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RDBMS랑 NoSQL도 공부했는데 아직 지식들이 머리에 산재해있는 느낌!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내일 한 번 더 공부해서 요약 정리하고 올려야겠다 싶더라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약은 총 두 번 한다. 공부용 요약 하나, 대답용 요약 하나&amp;hellip; 그리고 막상 면젖ㅂ 보면 머리가 새하얘져서 대답을 못하지&amp;hellip;^^&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스키마&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정의 : 데이터베이스에서 자료의 구조, 자료의 표현 방법, 자료 간의 관계를 형식 언어로 정의한 구조로, 데이터베이스의 구조와 제약조건에 관해 전반적인 명세를 기술한다.&lt;/li&gt;
&lt;li&gt;잘 설계된 스키마는 데이터 중복을 최소화하고, 테이블이 되지 않는 것을 방지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인덱스&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추가적인 쓰기 작업과 저장 공간을 활용해 데이터베이스 테이블에 대한 검색 속도를 높여주는 자료 구조&lt;/li&gt;
&lt;li&gt;데이터와 데이터의 위치를 포함한 자료구조를 생성해 데이터를 빠르게 조회할 수 있다.&lt;/li&gt;
&lt;li&gt;데이터들에게 인덱스를 지정하면 지정한 인덱스 번호로 빠르게 데이터를 찾을 수 있도록 되어 있다.&lt;/li&gt;
&lt;li&gt;인덱스를 활용하면 데이터를 조회하는 SELECT 외에도 UPDATE나 DELETE의 성능이 함께 향상된다. &amp;larr; 수정이나 삭제를 하려면 먼저 조회를 해야 하니까.&lt;/li&gt;
&lt;li&gt;관리
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;INSERT : 새로운 데이터에 대한 인덱스를 추가&lt;/li&gt;
&lt;li&gt;DELETE: 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업을 진행&lt;/li&gt;
&lt;li&gt;UPDATE: 기존의 인덱스를 사용안함 처리하고, 갱신된 데이터에 대해 인덱스를 추가&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;장점
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블을 조회하는 속도와 그에 따른 성능 향상&lt;/li&gt;
&lt;li&gt;전반적인 시스템 부하 감소&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인덱스 관리를 위해 DB의 약 10%에 해당하는 저장공간 필요&lt;/li&gt;
&lt;li&gt;인덱스를 관리하기 위해 추가 작업 필요&lt;/li&gt;
&lt;li&gt;잘못 사용할 경우 오히려 성능 저하&lt;/li&gt;
&lt;li&gt;&amp;rarr; CREATE, DELETE, UPDATE가 빈번한 속성에 인덱스를 걸게 되면 인덱스의 크기가 비대해져서 성능이 오히려 저하되는 역효과가 발생할 수 있다. UPDATE와 DELETE는 기존의 인덱스를 삭제하지 않고 '사용하지 않음' 처리를 해준다고 하였다. 만약 어떤 테이블에 UPDATE와 DELETE가 빈번하게 발생된다면 실제 데이터는 10만건이지만 인덱스는 100만 건이 넘어가게 되어, SQL문 처리 시 비대해진 인덱스에 의해 오히려 성능이 떨어지게 될 것이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;모든 요소에 인덱스를 걸지 않는 이유&lt;/li&gt;
&lt;li&gt;&amp;rarr; 인덱스 테이블이 생성되므로 메모리를 많이 소모하게 되고 Select를 제외한 Insert, Update, Delete에 대한 성능 저하 가능성이 있기 때문에 PK같은 컬럼들을 인덱싱 하도록 하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;수직적 확장과 수평적 확장&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;I/O란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력(Input)/출력(Output)의 약자로, 컴퓨터 및 주변장치에 대하여 데이터를 전송하는 프로그램, 운영 혹은 장치를 일컫는 말&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;데이터베이스에 데이터 요청시 문제점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 RAM 메모리에 데이터를 요청할 때 RAM에 적재되어 있는&amp;nbsp;데이터를 가져올 경우 I/O가 발생하지 않지만 하드디스크에서 데이터를 가져와야할 경우 &lt;b&gt;I/O가 발생&lt;/b&gt;한다. 이를 페이지 교체가 일어난다고 하는데 &lt;b&gt;속도가 현저히 떨어진다&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;해결방법 : 수직적 확장과 수평적 확장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;수직적 확장 : 서버 성능 향상
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 컴퓨터에서 데이터를 관리하기 때문에 데이터 쓰기(추가, 수정, 삭제)를 할 때 한번에 할 수 있다.&lt;/li&gt;
&lt;li&gt;컴퓨터가 분산되어 있지 않아 동기화가 필요없어 데이터의 일관성이 유지된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 컴퓨터에서 데이터를 관리하게 되면 RAM의 공간에 한계가 있으므로 결국에는 하드웨어에서 데이터를 가져오게 되는데 이 과정에서 I/O가 일어나기 때문에 데이터 읽기에서 성능이 떨어질 수 밖에 없다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;활용
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 테이블이 서로 연계되어 있어 데이터 쓰기를 할 때 한번에 할 수 있는 RDB 방식의 데이터 모델에 적합하다.&lt;/li&gt;
&lt;li&gt;주로 데이터 쓰기가 자주 일어나고 데이터의 정확성이 요구되는 정형화된 프로그램에서 도입된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;수평적 확장 : 서버 분산
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분산이란 데이터를 나누어 가지는 것이 아니라 같은 데이터를 복제하는 것을 의미한다.&lt;/li&gt;
&lt;li&gt;라우터에서는 각각의 레플리카의 가동 상태를 확인하여 최소한의 시간으로 데이터를 요청받을 수 있는 곳으로 보낸다.&lt;/li&gt;
&lt;li&gt;단점 : 은 데이터를 공유하고 있는 레플리카에서 데이터 쓰기가 일어날 경우 레플리카 간의 동기화로 데이터를 업데이트하는데 이는 동기화하는 과정에서 여러번 쓰기를 해야하고 동기화되는 시점에 따라 딜레이가 생겨 일관성이 유지되기 어려워진다.&lt;/li&gt;
&lt;li&gt;장점 : 하지만 동일한 데이터를 각각의 레플리카가 가지고 있기 때문에 읽기 속도는 매우 빨라진다.&lt;/li&gt;
&lt;li&gt;활용
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 테이블이 서로 연계되어 있는 RDB에서는 적합하지 않지만 컬렉션 사이의 관계가 없고 중복된 데이터를 가질 수 있는 NoSQL 방식의 데이터 모델에 적합하다.&lt;/li&gt;
&lt;li&gt;주로 데이터의 정확성 보다 읽기 속도가 요구되고 쓰기보다 읽기가 자주 읽어나는 소셜 네트워크 서비스(SNS) 등에 도입된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Programming/TIL and WIL</category>
      <author>벨로그로 옮겼어요~</author>
      <guid isPermaLink="true">https://lgb9811.tistory.com/163</guid>
      <comments>https://lgb9811.tistory.com/163#entry163comment</comments>
      <pubDate>Wed, 8 Feb 2023 23:42:39 +0900</pubDate>
    </item>
  </channel>
</rss>