반응형

Janus의 official page에 있는 데모 페이지 소스코드를 읽어보다 official documentation에는 없는 내용이 있어서 기록함.

Send에 plugin으로부터 response가 왔을때 성공여부에 따른 callback을 호출할 수 있다.

데모 페이지 소스 코드의 일부:

    screentest.send({"message": create, success: function(result) {
        var event = result["videoroom"];
        Janus.debug("Event: " + event);
        if(event != undefined && event != null) {
            // Our own screen sharing session has been created, join it
            room = result["room"];
            Janus.log("Screen sharing session created: " + room);
            myusername = randomString(12);
            var register = { "request": "join", "room": room, "ptype": "publisher", "display": myusername };
            screentest.send({"message": register});
        }
    }});

screentest는 pluginHandler인데, send에서 저렇게 일반적으로 보내는 message말고도 success와 error 콜백함수를 보낼 수 있다.

아래는 janus.js안의 코드인데, send의 파라미터로 넘어온 객체 전체를 sendMessage라는 private method에 넘겨준다.

send : function(callbacks) { sendMessage(handleId, callbacks); },

그리고 sendMessage에서는:

callbacks.success = (typeof callbacks.success == "function") ? callbacks.success : Janus.noop;
callbacks.error = (typeof callbacks.error == "function") ? callbacks.error : Janus.noop;
var message = callbacks.message;

이런식으로 사용한다.

반응형
블로그 이미지

개발자_무형

,
반응형

이 글은 본인이 공부를 목적으로 공식문서를 읽으며 정리/번역한 글로서 오역이 있을 수 있을 수 있습니다. 또한 본인이 이미 알고 있거나 불필요하다 느끼는 내용들은 누락될 수 있습니다.




Class-based view는 view를 함수가 아닌 파이썬 객체로 구현할 수 있는 하나의 방법이다. Class-based view는 function-based view를 대체하지는 않지만 그와 비교하여 차이점과 장점이 있다.



- HTTP method(GET, POST, etc)에 따른 코드를 conditional branching(IF)를 하지않고 별도의 메소드로 분리 할 수 있다.

- 객체 지향 테크닉들이 사용될 수 있다.



Using class-based views

from django.http import HttpResponse

def my_view(request):
    if request.method == 'GET':
        # <view logic>
        return HttpResponse('result')


가 아래로 대체될 수 있다.

from django.http import HttpResponse
from django.views import View

class MyView(View):
    def get(self, request):
        # <view logic>
        return HttpResponse('result')


장고의 URL resolver는 request와 인자들을 클래스가 아닌 호출가능한 함수에 보내기 때문에 class-based view는 as_view()라는 클래스 메소드를 사용하여 request를 받는다. 이 함수는 클래스 인스턴스를 생성하고 setup()을 호출하여 attribute들을 initialize하고 dispatch()를 호출한다. dispatch()는 request를 확인하여 GET,POST 등 해당하는 메소드에 전달하여 준다.







반응형
블로그 이미지

개발자_무형

,
반응형

Apache

Apache는 MPM(Multi Processing Module)이라는 방식으로 처리를 하는데 대표적인 방식으로 Prefork와 Worker방식이 있다.

Prefork MPM: 실행중인 프로세스를 복제하여 처리한다. 각 프로세스는 한번에 한 연결만 처리하고 요청량이 많아질수록 프로세스는 증가한다. 하지만 프로세스를 복제하는 것이므로 메모리영역까지 복제되어 동작하기 때문에 메모리 공유가 없어 안정적이다.

Worker MPM: Prefork방식이 1개의 프로세스가 1개의 스레드로 처리가 되었다면 Worker 동작방식은 1개의 프로세스가 각각 여러 쓰레드를 사용하게 된다. 쓰레드간의 메모리를 공유하며 PreFork방식보다 메모리를 덜 사용하는 장점이 있다.





Apache vs Nginx

Nginx의 가장 유명한 특징이라면 Event Driven방식이다. 따라서 어떠한 요청이 들어오면 어떤 동작을 해야하는지만 알려주고 다른 요청을 처리한다. 그러다보니 프로세스를 fork하거나 쓰레드를 사용하는 Apache와는 달리 CPU에 관계없이 모든 I/O를 전부 Event Listener로 미루기 때문에 흐름이 끊기지 않고 응답이 빠르게 진행되어 1개의 프로세스로 더 빠른 작업이 가능하게 될 수 있다. 이때문에 메모리측면에서 Nginx가 System Resource를 적게 처리한다는 장점이 있다고 한다.



https://taetaetae.github.io/2018/06/27/apache-vs-nginx/">https://taetaetae.github.io/2018/06/27/apache-vs-nginx/



Nginx는 Webserver이자 Reverse Proxy이다.



Proxy: client가 요청한 정보를 여러개의 서버로부터 받은 뒤 client에 반환한다.



Forward Proxy: 

client를 위한 proxy로써 아무 server와 통신할 수 있도록 해준다.



Reverse Proxy: 

server를 위한 proxy로써 서버 어플리케이션의 취약점들을 보완해줌으로써 아무 client와 통신할 수 있도록 해준다. 예를 들자면 과도한 로드를 버틸 수 있게 해주며(buffer 역할), 다양한 request들(http, https 등)을 처리할 수 있게 해준다.



https://en.wikipedia.org/wiki/Reverse_proxy">https://en.wikipedia.org/wiki/Reverse_proxy








반응형
블로그 이미지

개발자_무형

,
반응형

웹서버의 기본적인 역할은 정적(static)인 파일을 그대로 보내주는 것입니다. 그 말인즉슨, 뭔가 별도의 처리를 거치지 않고 존재하는 파일을 그대로 보내주는 역할을 합니다.



CGI(Common Gateway Interface)

웹서버에서 어플리케이션을 작동시키기 위한 인터페이스로서, 정적인 웹서버를 동적으로 기능하게 하기 위해서 등장하였습니다. 기존에는 외부프로그램이 필요한 리퀘스트가 들어오면 CGI를 통해 따로 프로세스를 fork하고 외부프로그램을 실행시켜 처리하였지만, 요즘에는 웹서버에 인터프리터를 내장시켜 내부적으로 처리한다. CGI Programming이란, Perl, C/C++를 사용하여 웹서버가 실행할 수 있는 프로그램을 작성하는 것이다.



WAS(Web Application Server)

웹서버가 동적으로 기능하면 WAS이다. 즉, Web Server + CGI가 WAS이다.



WSGI Server(middleware)

Web server와 WSGI를 지원하는 Web Application사이에서 동작하며 아래와 같은 일을 한다

    - 환경변수가 바뀌면 타겟 URL에 따라서 리퀘스트 경로를 지정해줌

    - 같은 프로세스에서 여러 어플리케이션과 프레임워크가 실행됨

WSGI vs CGI

CGI는 리퀘스트가 들어오면 CGI 프로토콜에 따라서 스크립트를 실행시킵니다. 서브프로세스를 fork하여 서브프로세스가 response를 작성하고 이를 웹서버로 보내면 웹서버가 이 response를 브라우저로 보냅니다. 대부분 CGI는 모든 리퀘스트마다 서브프로세스를 fork합니다.



WSGI는CGI 디자인 패턴에 기반한 인터페이스입니다. 가장 큰 차이점은 WSGI는 모든 리퀘스트마다 fork를 통해 서브프로세스를 띄우지 않으므로 느리지 않습니다.



https://brownbears.tistory.com/350">https://brownbears.tistory.com/350




왜 WSGI가 중요한가?


전통적인 Web Server는 파이썬 어플리케이션들을 이해하거나 실행시킬 수가 없다. 그래서 처음 Apache와 함께 사용하기 위해 mod_python이라는 모듈이 개발되었지만, 시간이 지남에 따라 보안 이슈와 개발 지연등의 이유로 새로운 방법이 필요하게 되었다. 따라서 파이썬 커뮤니티는 WSGI라는 모듈과 컨테이너들이 도입할 수 있는 표준 인터페이스를 작성하게 되었다.



WSGI의 목적

왜 Web server가 직접 application으로 포워딩하지 않고 WSGI를 거쳐야될까?

유연성

개발자는 웹서버를 바꿔도 웹 어플리케이션의 코드를 수정할 필요가 없다.

또, WSGI를 중간에 바꾸더라도 상관이 없다(Green Unicorn -> uWSGI)

즉, 사용자가 상황에 맞는 스택으로 쉽게 쉽게 바꿀 수 있다.

확장성

수천 건의 request를 처리하는 것은 framework의 역할이 아니라 WSGI server의 역할이다. WSGI 서버들은 request들을 어떻게 framework에 보낼지를 결정한다. 역할 분담은 확장성에 매우 중요하다.



https://www.fullstackpython.com/wsgi-servers.html">https://www.fullstackpython.com/wsgi-servers.html

반응형
블로그 이미지

개발자_무형

,
반응형

Ningx는 request가 가장 먼저 도착하는 곳이다.  Web application으로 보내져야만 하는 request들만을 보낸다.(필터링같은 느낌)



Gunicorn은 request를 웹 프레임워크가 이해하고 처리할 수 있는 형식으로 변환시켜 보낸다.





Nginx

Nginx는 Web server이자 Reverse Proxy이다. 아래는 Nginx가 잘하는 기능들 예시이다:

    - domain name routing

    - 정적 파일 보내기

    - 한번에 들어오는 많은 양의 request를 처리하기

    - 느린 client들 처리하기

    - 동적처리가 필요한 request들을 Gunicorn으로 보내기

    - SSL 끝내기

Nginx는 다음과 같은 일들은 할 수 없다:

    - Python web application 실행하기

    - request를 WSGI로 변역하기



Gunicorn

Gunicorn은 다음과 같은 일들에 특화되어 있다:

    - worker processes/threads 풀을 사용하여 코드 실행

    - Nginx가 보낸 request를 WSGI에 맞게 변환

    - 어플리케이션에서 보낸 WSGI response를 http response로 변환

    - request가 들어오면 실제로 파이썬 코드 실행하기

    - Gunicorn은 다양한 웹서버와 통신할 수 있음

다음과 같은 일은 할 수 없다:

    - 최전방에 나설 수 없다: DOS에 취약하다

    - SSL을 끝낼 수 없다(no https handling)




반응형
블로그 이미지

개발자_무형

,
반응형
1. Upstream Block
Upstream은 서버들의 묶음이다.
upstream backend {
    server 111.111.111:8000 weight=5;
    server 111.111.112:8000;
    server 111.111.113:8000;
}
위의 예시에서는 3개의 서버간에 load balancing이 되며 weight를 명시하게 되면 해당 서버에 더 많은 load를 배분할 수 있다. 위의 예시에서는 111.111.111서버가 다른 2서버에 비해 5배 많은 load를 할당받는다.

configuration 파일에서 server블럭에서는 ip주소로 호출하는 것이 아니라 upstream의 이름으로 호출한다. (예시에서 backend)

2. Server Block
Server Block은 하나의 가상 서버를 나타낸다. 따라서 여러개의 server block을 생성하게 되면 하나의 머신에서 여러개의 어플리케이션을 호스팅할 수 있다.

Nginx가 라우팅을 할때는 최우선 적으로 listen 옵션을 본다. listen 옵션은
    - address:port 숫자
    - ip주소 (포트80만 처리)
    - port 숫자 (해당 포트로 들어오는 모든 인터페이스)
    - unix socket 경로

Nginx는 오직 같은수준으로 명시된 listen이 여러개 있을 때만 server_name을 사용하여 비교한다.
server {
    listen 192.168.1.10;
    . . .
}
server {
    listen 80;
    server_name example.com;
    . . .
}
위의 예시에서 만약 example.com이 192.168.1.10의 80번 포트에 호스팅 되어 있다면, 항상 첫번째 블럭이 호출된다(Nginx는 불완전한 ip주소를 자동으로 채우므로 192.168.1.10:80으로 변환된다)








반응형
블로그 이미지

개발자_무형

,
반응형
1. links vs depends_on:
links와 depends_on 둘 다 dependency와 container의 생성순서를 정해준다.
하지만 links는 위의 기능과 link된 container의 이름을 내부코드에서 사용하여 접근할 수 있다.
예시:
web:
  image: example/my_web_app:latest
  links:
    - db
    - cache

db:
  image: postgres:latest

cache:
  image: redis:latest
위의 예시에서 links를 사용한다면 web 내부에서 db:5432 로 접근할 수 있지만 depends_on을 사용한다면 접근할 수 없다.

https://stackoverflow.com/questions/35832095/difference-between-links-and-depends-on-in-docker-compose-yml

또, links와 depends_on은 생성순서는 지정해주지만, 먼저 시작된 컨테이너가 실제로 '사용가능'한 상태인지는 확인하지 않는다고한다. 예를 들자면 데이터베이스 컨테이너를 먼저 시작은 하지만 이 데이터베이스 컨테이너가 현재 연결가능하지 않을수도 있다는 것이다.

2. Volumes:
Volume의 역할인 로컬에 있는 파일을 도커 컨테이너로 마운트하는 역할을 한다. 크게 2가지로 나눌 수 있다.
    - 그냥 마운트: 그냥 그대로 파일/디렉토리를 복사하여 넣는 것이다.
       (예: temp_volume: /app/static/ <- 로컬의 /app/static/을 마운트하고 temp_volume으로 명명)
    - 연결: 데이터베이스가 실행중인 컨테이너를 종료와 함께 삭제하면, 컨테이너가 실행된 시간동안 저장된 데이터가 모두 날아가게 된다. 이를 방지하기 위해 로컬의 폴더와 연결하면 컨테이너의 정보가 날아가더라도 남아있게 된다.
       (예: ./docker/data:/var/lib/mysql/data <- 컨테이너의 /var/lib/mysql/data를 로컬의 ./docker/data와 연결)










반응형
블로그 이미지

개발자_무형

,
반응형
Viewset을 사용하면 관련된 view들을 하나의 클래스로 묶을 수 있다.

class UserViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing or retrieving users.
    """
    def list(self, request):
        queryset = User.objects.all()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = User.objects.all()
        user = get_object_or_404(queryset, pk=pk)
        serializer = UserSerializer(user)
        return Response(serializer.data)
from rest_framework import routers

router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = router.urls
위의 예시는 아래의 URL 패턴을 만든다
  • URL pattern: ^users/$ Name: 'user-list'
  • URL pattern: ^users/{pk}/$ Name: 'user-detail'
  • URL pattern: ^accounts/$ Name: 'account-list'
  • URL pattern: ^accounts/{pk}/$ Name: 'account-detail'

Viewset에서 사용하는 self.action은 router가 자동으로 변환한 것이다.
URL StyleHTTP MethodActionURL Name
{prefix}/GETlist{basename}-list
POSTcreate
{prefix}/{url_path}/GET, or as specified by `methods` argument`@action(detail=False)` decorated method{basename}-{url_name}
{prefix}/{lookup}/GETretrieve{basename}-detail
PUTupdate
PATCHpartial_update
DELETEdestroy
{prefix}/{lookup}/{url_path}/GET, or as specified by `methods` argument`@action(detail=True)` decorated method{basename}-{url_name}
위에 표는 URL Style + HTTP Method가 어떻게 Action으로 변환되는지를 보여준다.
만약 POST users/라고 쿼리를 보내면 {prefix}/ + POST로 action은 list가 된다.
만약 GET users/123라고 쿼리를 보내면 {prefix}/{lookup}/ + GET으로 action은 retrieve가 된다.

perform_create()는 create()가 호출된 과정에서 serializer를 사용하여 serializer.save()를 하기 위해 호출된다.
perform_create()와 create()를 구분해서 사용하는법
추가1
추가2

serializer.save()는 객체가 이미 존재하면 update를, 없다면 create를 해준다





반응형
블로그 이미지

개발자_무형

,