AWS람다를 찾아보면 서버리스(serverless) 라는 단어를 볼 수 있습니다.  처음 접했을 때 서버가 없는데 어떻게 요청을 받고 실행할 지 햇갈렸는데 여기서 서버리스는 내가 요청받고 처리하는 서버가 없는 것을 뜻합니다. 한 마디로 내 서버가 필요없이 AWS 서버가 알아서 처리해준다는 것입니다. 간략하게 람다를 사용하는 목적은 서버에 대한 걱정 없이 코드를 실행하고 사용한 컴퓨팅 시간에 대해서만 비용을 지불합니다. 아래에서 좀 더 자세하게 설명하겠습니다.

AWS Lambda 란? 

  • 서버를 프로비저닝하거나 관리할 필요 없이 코드를 실행
  • 모든 유형의 애플리케이션이나 백엔드 서비스에 대한 코드를 별도의 관리 없이 실행 가능
  • 코드를 업로드하면 Lambda에서 높은 가용성으로 코드를 실행 및 확장하는 데 필요한 부분을 처리함
  • 다른 AWS 서비스에서 코드를 자동으로 트리거하도록 설정하거나 웹 또는 모바일 앱에서 직접 코드를 호출할 수 있음

프로비저닝이란?

사용자의 요구에 맞게 시스템 자원을 할당, 배치, 배포해 두었다가 필요 시 시스템을 즉시 사용할 수 있는 상태로 미리 준비해 두는 것을 말합니다. 서버 자원 프로비저닝, OS 프로비저닝, 소프트웨어 프로비저닝, 스토리지 프로비저닝, 계정 프로비저닝 등이 있고 수동으로 처리하는 '수동 프로비저닝'과 자동화 툴을 이용해 처리하는 '자동 프로비저닝'이 있습니다.

Lambda 의 주요 장점

  • 인프라에 대한 걱정 없이 코드 실행 가능 -> NoOps 실현
  • 트리거를 이용해 애플리케이션을 자동으로 확장/축소 가능.
  • 코드가 병렬로 실행되고 각 트리거는 개별적으로 처리되어 정확히 워크로드 규모에 맞게 조정됨.
  • 100ms 단위로 코드가 실행되는 시간 및 코드가 트리거되는 회수를 측정하여 요금을 부과하고, 코드가 실행되지 않을 때는 요금이 부과되지 않음.

Lambda 사용 사례

람다를 AWS의 다른 서비스들과 조합하여 사용하면 더 큰 시너지를 낼 수 있다는 것이 람다의 또 다른 장점인 것 같은데요, 이런 방법으로 람다를 이용하면 어떤 것들을 구축할 수 있는지 사용 사례를 보겠습니다.

  • 실시간 파일 처리
    • Amazon S3를 사용하여 업로드하는 즉시 데이터를 처리하도록 AWS Lambda를 트리거할 수 있음. Lambda를 사용하여 실시간으로 이미지를 썸네일하고, 동영상을 트랜스코딩하고, 파일을 인덱싱하고, 로그를 처리하고, 콘텐츠를 검증하고, 데이터를 수집 및 필터링할 수 있음
  • 실시간 스트림 처리
    • AWS Lambda 및 Amazon Kinesis를 사용하여 애플리케이션 활동 추적, 트랜잭션 주문 처리, 클릭 스트림 분석, 데이터 정리, 지표 생성, 로그 필터링, 인덱싱, 소셜 미디어 분석, IoT 디바이스 데이터 텔레메트리 및 측정을 위한 실시간 스트리밍 데이터를 처리할 수 있음.
  • 추출, 변환, 로드
    • AWS Lambda를 사용하여 DynamoDB 테이블의 모든 데이터 변경에 대한 데이터 검증, 필터링, 정렬 또는 기타 변환 작업을 수행하고 변환된 데이터를 다른 데이터 스토어로 로드할 수 있음.
  • IoT 백엔드
    • AWS Lambda 및 Amazon Kinesis를 사용하여 사물 인터넷(IoT) 디바이스 데이터 텔레메트리 및 분석을 위한 백엔드를 구축할 수 있음.
  • 모바일 백엔드
    • AWS Lambda 및 Amazon API Gateway를 사용하여 API 요청을 인증 및 처리하도록 백엔드를 구축할 수 있음.
  • 웹 애플리케이션
    • AWS Lambda를 다른 AWS 서비스와 결합하면, 확장성, 백업 또는 여러 데이터 센터 중복에 필요한 별도의 관리 작업 없이 개발자가 자동으로 확장 및 축소되고 여러 데이터 센터에 걸쳐 가용성이 높은 구성에서 실행되는 강력한 웹 애플리케이션을 구축할 수 있음.


'AWS' 카테고리의 다른 글

[AWS] 람다 레이어(Lambda Layer)란?  (0) 2019.01.27
[AWS] 람다(Lambda)란?  (0) 2019.01.27
[AWS-EC2] 리눅스, 맥 터미널로 EC2 Instance 접속하기  (0) 2016.09.23

고스트 프로토콜(GHOST Protocol)은 비트코인의 성능 향상과 보안성 향상을 위해 나온 알고리즘입니다. 이더리움은 고스트 프로토콜을 수정하여 적용한 결과, 빠른 블록 생성 속도를 가지면서 보안성도 높이는 결과를 얻었습니다. 비트코인은 블록 생성 속도가 느리기 때문에 stale 블록의 생성확률이 낮고 보안성이 높습니다. 반면, 이더리움은 블록 생성 속도가 빠르기 때문에 stale 블록의 생성확률이 높고 보안성이 낮습니다. 이러한 문제를 보안하기 위해 이더리움은 고스트 프로토콜을 적용하여 stale 블록을 잘 처리하고 보안성도 높였습니다.

고스트 프로토콜은 stale 블록의 처리에 대한 알고리즘이라고 볼 수 있습니다. 고스트 프로토콜은 bitcoin을 위해 생성됬습니다. 비트코인은 블록생성시간이 약 10분으로 느리기 때문에 stale 블록의 생성확률이 매우 낮습니다. 만약, stale 블록이 발생하면 가장 긴 블록을 메인 블록체인(Canonical Blockchain)에 연결하고 나머지 stale 블록은 버립니다. 하지만 이를 위해 10분을 기다리므로 비트코인은 매우 느립니다. 이를 보완하기 위해 이더리움은 블록생성 시간을 약 12초 정도로 매우 빠르게 만들었습니다. 그러나 블록이 빠르게 생성되면 그만큼 stale 블록이 생성될 확률이 높아지므로 안정성이 떨어집니다. 이를 보완하기 위해 이더리움은 수정된 고스트 프로토콜을 적용한 이유입니다.

상관관계

블록 크기, 블록 생성 시간, 트랜잭션 처리 성능, fork 수, 보안성은 서로 상관관계를 갖고 있습니다. 

블록 사이즈와 블록생성속도가 커지면 트랜잭션 처리율이 올라가고 fork되는 블록의 수가 늘어납니다. 결과적으로 블록체인 네트워크의 보안성이 떨어집니다.

비트코인의 경우 블록생성속도는 약 10분으로 느립니다. 느린 블록생성속도 때문에 트랜잭션 처리 성능도 낮아지는 대신 fork되는 블록의 수는 줄어듭니다. fork의 수가 줄어들기 떄문에 stale 블록이 발생하는 빈도 또한 줄어서 자연스럽게 보안성이 늘어납니다. 하지만 블록생성속도가 매우 느리다는 치명적인 단점을 갖고 있습니다. 이더리움에서는 이것을 개선하여 블록생성속도를 약 12초 정도로 매우 빠르게 유지합니다. 하지만 블록생성속도를 올리면 상관관계에 의해 fork의 수가 늘어납니다. 즉 늘어난 fork의 수 때문에 네트워크의 보안성을 낮춥니다. 이를 해결하기 위해 이더리움은 수정된 고스트 프로토콜을 사용합니다. stale 블록에 대해 보상을 주고 가장 긴 것이 아닌 가장 무거운 것을 사용합니다. 수정된 고스트 프로토콜을 적용함으로써 네트워크의 보안성을 올리고 트랜잭션 처리율을 유지하면서 블록생성속도도 빠르게 할 수 있는 것입니다.

왜 빠른 블록생성이 좋지만은 않을까?

현재 블록체인의 빠른 승인 시간은 높은 stale 생성 비율로 인해 보안성이 낮아진다는 문제가 있습니다. 왜냐하면 블록이 네트워크를 통해 전파되기 위해서는 일정 시간이 필요하기 때문입니다. 예를 들어, 마이너 A가 블록을 채굴하고, 이 블록이 전파되기 전에 마이너 B가 블록을 채굴한 경우, 마이너 B의 블록은 버려지고(stale) 이는 네트워크의 안정성에 기여하지 못합니다. 또한 중앙화 이슈가 있는데, 만약 마이너 A가 마이닝 풀이며 30%의 해시 파워를 가지고 있고 마이너 B가 10%의 해시 파워를 가진다면, A는 전체 시간 중 70%의 시간에서 stale 블록을 생성할 가능성이 있지만 (30%로 자신이 생성한 블록은 즉시 전파될 것이므로) B는 90%의 시간동안 리스크를 가지게 됩니다.

그러므로 블록 인터벌이 높은 stale 생성 비율을 가지게 될 만큼 짧다면 A는 실질적으로 단순히 그 규모로 인해 훨씬 효율적이 될 수 있습니다. 이런 이유로 블록을 빠르게 생성하는 블록체인은 많은 해시 파워를 가진 한 마이닝 풀이 마이닝 프로세스에 있어서 실질적인 통제력을 가지게 될 수 있습니다.

고스트 프로토콜이란?

고스트 프로토콜은 Greedy Heaviest Object subTree의 약자로 '가장 큰 무게를 가진 subtree'를 선택하는 알고리즘입니다. 비트코인의 경우, fork가 발생했을 때 길이가 더 길게 연결된 블록을 메인 블록체인으로 하고 stale블록은 버립니다. 이더리움의 경우, fork가 발생했을 때 더 무거운 쪽을 선택하게 됩니다. 이더리움은 비트코인의 고스트 프로토콜을 살짝 수정하여 사용하고 있습니다.

이더리움의 고스트 프로토콜 알고리즘을 간단하게 설명하면 '제네시스 블록에서 출발하여 각 subtree들이 얼마나 블록을 포함하고 있고, 그 블록들의 개수가 많은 체인을 메인체인의 블록으로 선택하겠다' 입니다.

예시


이더리움 고스트 프로토콜을 위 그림으로 다시 예시를 들어보면 시작은 제네시스 블록인 0에서 시작합니다. 0를 부모로 가지는 노드는 1B와 1A입니다. 1B를 루트로 한 subtree의 노드 개수는 12개이고 1A는 6개입니다. 따라서 메인체인에 붙게 되는 것은 1B입니다. 다음으로 1B를 부모로 가지는 노드는 2D, 2C, 2B입니다. subtree의 노드개수는 각각 4개, 5개, 2개이므로 메인에 붙게 되는 노드는 2C입니다. 이러한 방식을 subtree에 전부 적용하면 선택되는 메인체인은 0-1B-2C-3D-4B 입니다. 비트코인의 경우, 위 그림에서 동그라미로 표시되어 있는 것을 메인체인으로 선택합니다.



수정된 GHOST Protocol의 내용은 다음과 같습니다.

  • 하나의 블록은 반드시 하나의 부모 블록을 지정하며, 0 또는 그 이상의 엉클 블록을 지정. 현재 2개까지 지원하고 있다.
  • 블록 A의 K번째 조상의 직접적인 자손이어야 한다.
  • 블록 A의 조상이어서는 안된다.
  • 엉클블록 마이너 보상은 블록 생성 시에 받는 보상의 93.75%를 보상으로 받고, 엉클 블록이 포함된 정상블록의 마이너는 엉클블록 1개당 3.125%의 추가 보상을 받게 됩니다.


요약

블록생성속도를 올리는 것은 블록체인 네트워크 전체의 처리율과 비례관계를 갖지만 보안성과는 반비례 관계를 갖습니다. 고스트 프로토콜을 이용하여 이를 보완할 수 있습니다. 따라서 이더리움의 고스트 프로토콜은 전체 성능과 보안에 아주 중요한 역할을 한다고 할 수 있습니다.



합칠 대상의 결과가 2개 이상인 경우

union()

union()를 사용해서 1개로 합칠 수 있습니다. union()의 2번째 인자는 중복을 허용할지에 대한 여부인데 기본값은 False로 중복을 허용하지 않습니다. (중복데이터일 경우 중복제거)

result = a.union(b, all=True)

결과가 쿼리셋 리스트 타입이기 때문에 ORM 형식을 그대로 사용할 수 있습니다.

| 연산자

| 연산자를 사용하여 손쉽게 쿼리셋 타입 리스트를 합칠 수 있습니다.

result = a | b

결과가 쿼리셋 리스트 타입이기 때문에 ORM 형식을 그대로 사용할 수 있습니다.

+ 연산자

+ 연산자를 사용하기 위해선 각 쿼리셋 리스트 타입을 일반 리스트 타입으로 변경한 후 합칩니다.

a = list(a)
b = list(b)
result = a + b

합칠 대상이 단일일 경우

합칠 대상이 2개 이상이 아닌 1개만 존재하는 경우, 위의 방법을 전부 사용하지 못합니다.

chain()

chain() 함수를 사용하면 대상이 단일 건이거나 복수개여도 언제든지 합칠 수 있습니다.

from itertools import chain
result = list(chain(a, b))

list 변환 후 병합

쿼리셋 리스트 타입을 리스트로 변환 후, 단일건을 해당 리스트에 추가하는 형식입니다.

a = list(a)
a.append(b)

limit이 걸려있는 쿼리셋 리스트일 경우

limit이 걸려있는 경우에는 | 연산자 방식을 제외하고 전부 사용할 수 있습니다.

결론

병합에는 여러 방법이 있지만 가장 좋은 방법은 ORM에서 제공하는 union()과 chain() 입니다. 쿼리 결과를 병합하는 것을 지양해야 하지만 어쩔 수 없이 사용해야 한다면 union()과 chain()을 상황에 맞게 사용하면 됩니다.

Django model ORM로 Where절에 or 문을 추가하고 싶다면 Q() 를 사용해야 합니다. 사용법은 아래와 같습니다.

사용하기

OR

from django.db.models import Q


Base.objects.filter(
    Q(name='qwer') | Q(no=152124)
# 동일한 결과
# SELECT * FROM base WHERE no=152124 OR name='qwer'

Q() 조건 연결

from django.db.models import Q



q = Q()

q.add(Q(no=12121), q.OR)
q.add(Q(name=lee)|Q(name=kim), q.AND)
q.add(Q(142411), q.OR)

Base.objects.filter(q)
# 동일한 결과
# SELECT * FROM base WHERE (no=12121 AND (name='lee' OR name='kim')) OR no=142411

NOT 구문 표현하기

from django.db.models import Q


q = Q()
q.add(Q(no=12121), q.OR)
q.add(Q(name=lee) & ~Q(name=kim), q.AND)
Base.objects.filter(q)
# 동일한 결과
# SELECT & FROM base WHERE no=12121 AND name='lee' AND NOT (name='kim')

주의사항

Q()를 사용할 때 조심할 점은 첫 Q() 선언 이후 .add()로 추가할 때, 2번째 인자값은 어떤 쿼리로 연결할지를 나타내는데 여기에 선언된 값으로 앞의 조건과 연결이 됩니다.

q = Q(no=1)
q.add(name='lee', q.OR)
# no=1 or name='lee'


Q를 선언한 이후, 해당 인스턴스에서 .OR이나 .AND.connector를 볼 수 있습니다. 여기서 OR나 AND는 조건문과 동일한 연결문입니다. .connector는 바로 이전에 사용한 연결문을 뜻합니다. 아무것도 선언되지 않았을 때, 기본 값은 AND 입니다.

OR 나 AND는 클래스 변수로 선언되어 있기 때문에 q = Q(); q.AND 나 Q.AND나 동일합니다.

q = Q(item_no=123123123)
print(q.connector)
q.add(Q(gs_item_no=0), q.OR)
print(q.connector)
# AND
# OR


Selenium은 웹앱을 테스트 하는데 주로 사용하는 프레임워크입니다. webdriver API를 통해 브라우저를 제어하게 할 수 있습니다. JavaScript를 이용해 비동기적으로 컨텐츠를 호출할 수 있으므로 브라우저에서 보이는 컨텐츠라면 전부 가져올 수 있다는 것을 의미합니다. 한마디로 Selenium은 실제 웹 브라우저가 동작하기 때문에 JS로 렌더링이 완료된 후의 DOM 결과물에 대한 접근이 가능합니다.

설치

파이썬

브라우저의 업데이트 마다 새로운 드라이버를 잡기 때문에 최신버전을 유지하는 것이 좋습니다.

pip3 install selenium

webdriver

아래에서는 chrome을 설치하여 사용합니다.

https://sites.google.com/a/chromium.org/chromedriver/downloads 에서 가장 최신인 드라이버 버전을 선택한 후, OS에 맞는 드라이버를 다운받습니다. 



설치 받은 압축파일을 해제하면 chromedriver 파일이 나오는데 해당 파일을 향후 사용하기 쉬운 장소로 변경합니다.

PhantomJS webdriver

PhantomJS는 화면이 존재하지 않은 브라우저입니다. CLI서버 환경에서 테스트를 진행할 예정이면 PhantomJS를 사용하는 것이 좋습니다. PhantomJS에 대한 설명은 https://brownbears.tistory.com/363 에서 확인할 수 있습니다.

http://phantomjs.org/download.html 에서 현재 OS 환경에 맞는 압축파일을 받은 후 압축을 풀어줍니다. 향후 사용할 파일의 위치는 bin폴더의 phantomjs 파일 입니다.

현재 PhantomJS는 개발이 진행되고 있지 않기 때문에 현재 브라우저가 최신이라면 크롬의 headless 모드를 사용하는 것이 좋습니다.

사용하기

아래와 같이 위에서 설치한 파일 위치를 입력합니다.

from selenium import webdriver


chrome_driver = webdriver.Chrome('chromedriver 파일 위치')
phantom_driver = webdriver.phantomjs('phantomjs 파일 위치')


selenium은 실행하기 위한 자원들이 전부 로드될 때까지 기다려 줍니다. 만약 이 시간을 지정하고 싶다면 implicitly_wait(초) 를 작성합니다. 아래는 implicitly_wait()을 사용하고 https://naver.com을 호출하는 예제입니다.

from selenium import webdriver


chrome_driver = webdriver.Chrome('/Users/user/Documents/chromedriver')

# 로드를 위해 5초 대기
chrome_driver.implicitly_wait(5)

chrome_driver.get('https://naver.com')


만약 정상적으로 호출이 되었다면 새로운 chrome 브라우저에 네이버가 떠 있는 것을 볼 수 있습니다.

예시

위 https://naver.com에서 로그인을 시도해 봅니다.

  1. 먼저 네이버의 로그인 화면 url인 https://nid.naver.com/nidlogin.login 를 입력합니다.
  2. 네이버 로그인의 화면에서 아이디 입력 태그의 id명은 id, 비밀번호 입력태그의 id명은 pw로 되어 있으므로 아래처럼 해당 태그에 값을 세팅합니다.
  3. 로그인 버튼을 클릭합니다.
from selenium import webdriver


chrome_driver = webdriver.Chrome('/Users/user/Documents/chromedriver')

# 로드를 위해 5초 대기
chrome_driver.implicitly_wait(5)

# 네이버 로그인페이지
chrome_driver.get('https://nid.naver.com/nidlogin.login')

# 아이디 비밀번호 입력
chrome_driver.find_element_by_id('id').send_keys('naver')
chrome_driver.find_element_by_id('pw').send_keys('naver')

# 로그인 버튼 클릭
chrome_driver.find_element_by_xpath('//*[@id="frmNIDLogin"]/fieldset/input').click()


계정정보가 올바르다면 정상적으로 로그인이 되는 것을 확인할 수 있습니다.


로그인이 필요한 페이지의 경우 로그인을 한 다음, 호출하고자 하는 페이지를 다시 불러와 사용할 수 있습니다. 아래는 로그인 후, BeautifulSoup을 함께 사용한 예시입니다.

from selenium import webdriver
from bs4 import BeautifulSoup


chrome_driver = webdriver.Chrome('/Users/user/Documents/chromedriver')

# 로드를 위해 5초 대기
chrome_driver.implicitly_wait(5)

# 네이버 로그인페이지
chrome_driver.get('https://nid.naver.com/nidlogin.login')

# 아이디 비밀번호 입력
chrome_driver.find_element_by_id('id').send_keys('id')
chrome_driver.find_element_by_id('pw').send_keys('password')

# 로그인 버튼 클릭
chrome_driver.find_element_by_xpath('//*[@id="frmNIDLogin"]/fieldset/input').click()


# 네이버 내정보
chrome_driver.get('https://nid.naver.com/user2/help/myInfo.nhn')
# html 로드
html = chrome_driver.page_source
bs = BeautifulSoup(html, 'html.parser')
notices = bs.find_all('div', class_='form')



테스트를 진행할 때, 네이버는 적절하지 않을 수 있습니다. 그놈의 자동입력방지문자

node와 npm 버전을 최신으로 전부 올렸다가 기존 프로젝트가 실행되지 않아 노드 버전을 다시 내려야 하는 상황이 왔습니다. 1시간 삽질 덕에 아래와 같이 정리합니다.

Node 버전 확인

$ node -v

Cache 삭제

$ sudo npm cache clean --force

n 플러그인 설치

n은 node의 버전을 관리해주는 플러그인입니다. 해당 플러그인이 있으면 노드 버전을 변경할 때, 해당 노드 삭제가 아닌 사용할 버전선택이라는 간편함이 있으니 설치해줍니다.

$ sudo npm install -g n

최신 버전 설치

$ n latest

stable 버전 설치

$ n stable

LTS 버전 설치

$ n lts

특정 버전 설치

n 다음 특정 버전을 입력하여 설치하여 줍니다.

$ n 5.6.0
$ n 8.11.1
$ n 11.4.0

node 버전 변경하기

node의 버전이 여러개일 경우, 간단하게 n 을 입력하고 사용할 버전을 선택한 후, 엔터를 입력하면 됩니다.

$ n
  o node/5.6.0
    node/8.11.1
    node/11.4.0

버전 특정 버전 삭제 / 현재 버전 외 전체 버전 삭제

아래 명령어를 통해 특정 버전 또는 현재 선택된 버전 외 모든 버전을 삭제할 수 있습니다.

-- 특정 버전 삭제
$ n rm 0.9.4 v0.10.0
$ n - 0.9.4
-- 현재 선택된 버전 외 전체 버전 삭제
$ n prone


  1. 2019.05.29 10:56

    비밀댓글입니다

    • 2019.06.27 13:59

      비밀댓글입니다

+ Random Posts