async 처리되는 지 안되는지 확인하기위해서는 server코드도 중요하지만 request보내는 클라코드도 중요하다. 둘중 하나라도 잘못되면 테스트가 제대로 안되서 오해소지가 있다.

아래 코드로 python 3.5환경에서 requests library가 async로 잘 처리되는 것을 확인했다.


server

# packages

from gevent import monkey;monkey.patch_all(thread=False, subprocess=False)

import gevent

from flask import Flask, request, Response

from gevent.pywsgi import WSGIServer

from logging.handlers import RotatingFileHandler

import logging

import werkzeug.serving

import requests

import json

import resource

import hashlib

# local files

# limit gate process to use fd count less than 1024

resource.setrlimit(resource.RLIMIT_NOFILE, (1024, 1024))


app = Flask(__name__)

end_server = False

secret = None


@app.route("/do")

def check_ip():

    param = request.args.get("param", None)

    print("got {0}".format(param))

    resp = requests.get("https://snarky.ca/how-the-heck-does-async-await-work-in-python-3-5")

    # resp = requests.get("http://www.naver.com")

    print("done {0}".format(param))

    return resp.text



if __name__ == "__main__":

    http = WSGIServer(("0.0.0.0", 9999), app, log=app.logger)

    http.serve_forever()


    end_server = True

    app.logger.info("Server will be closed")

 


test client



from gevent import monkey;monkey.patch_all(thread=False)

import gevent

import requests

j = 0

host = "127.0.0.1:9999"

def test():

global j

try:

d = requests.get("http://127.0.0.1:9999/do?param="+str(j))

print(d.text+str(j))

except Exception as e:

print(e)

pass


pool = []


for i in range(0, 100):

pool.append(gevent.spawn(test))

j += 1

gevent.sleep(0.1)


gevent.joinall(pool)


 


'서버 교양' 카테고리의 다른 글

filebeat traceabck multiline config  (0) 2017.10.16
logstash conf example  (0) 2017.10.13
Logstash install  (0) 2017.03.17
[펌] 인증 암호화와 해쉬  (0) 2016.10.29
Docker overview  (0) 2015.06.13
블로그 이미지

시간을 거스르는자

,

If you use http request or something using socket in gevent spawn,
you should make a limit of file open count. use python resource. like this,

import resource
resource.setrlimit(resource.RLIMIT_NOFILE, (1024, 1024))

Otherwise, It will consume all your memory as much as it can by consuming all file count that it can consume as specified on limit.conf (/etc/security/limit.conf)

But requests still consumes a lot of memory.. I just decided to use tornado instead of flask+gevent+requests

'python' 카테고리의 다른 글

gevent monkey patch all, code location  (0) 2017.09.14
flask with gevent monkey patch all  (0) 2017.07.26
websocket with gunicorn  (0) 2017.03.03
gunicorn vs uwsgi  (0) 2017.01.20
flask async response  (0) 2017.01.04
블로그 이미지

시간을 거스르는자

,

aws api gate way

aws 2017. 3. 18. 01:14

삽질

- 허용된 request만 받고 싶을때 -> api key 이용 (Resources -> GET-> Method Request를 누르면 설정하는게 나온다)

https://www.gellock.com/2015/12/10/using-api-keys-with-aws-api-gateway/

그럼 여기나온데로 request 날릴때 해더에 x-api-key: apikey 를 보내야 허용된다.

'aws' 카테고리의 다른 글

AWS lambda 삽질 일기  (0) 2017.03.17
kinesis firehose 삽질일기  (0) 2017.03.16
How to EC2 disk and memory usage monitoring  (0) 2015.03.27
elasticache dump to file  (1) 2015.03.23
[ubuntu server instance] mytoon setting  (0) 2014.10.24
블로그 이미지

시간을 거스르는자

,

AWS lambda 삽질 일기

aws 2017. 3. 17. 21:08

#aws lambda python test


1. Lambda 에 올릴 zip 패키지 만들기

패키지를 모두 zip으로 해야하므로

로컬에서 directory를 하나만들고

directory/main.py python 파일을 만든다.

그리고 패키지는 이런식으로 폴더 아래 설치 되도록 한다.

"pip install module-name -t /absolute/path/to/directory"

그다음 lambda_handler function을 만들고 람다가 할일을 코딩한다. 그리고 나서 directory폴더 안에 있는 파일들을 모두 선택한다음 zip으로 만들고 lambda에 업로드한다.


2. main.py연결

Lambda configuration에 보면 Handler가 있는데 이부분을 main.lambda_handler 라고 써주면된다. "파일명.함수명" 이다.

3. Test

만들어진 람다 function을 보면 테스트 시그널을 줘서 실행해볼수 있는데 실행하면 끝날줄 모른다. 알고보면 이미 끝나있을거니 그 실행로그는 cloudWatch에가서 보면된다. 

4. 삽질

- 람다에서 커넥션 안되면 에러를 튕기기보다 설정된 타임아웃시간까지 hang이 걸린다. 따라서 스텝이 안넘어가면 뭔가 네트웤 이슈가 있구나 라고 생각하면된다.

- 일단 람다란 녀석은 만들어진 vpc내의 통신만 되기 때문에 외부 DB나 s3의 서비스 연결은 기본적으로 불가하다 -ㅅ-ㅋ 그래서 s3같은경우는 VPC -> endpoints 를 하나 만들어줘야 접근이 가능하다. 그리고 다른 vpc에 있는 DB같은경우는 Peering을 만들어서 하면되는데 그냥 peering만 만들면 접근이 안되고, 람다가 속한 vpc의 route table에 peering 접근설정을 해줘야한다.
예) destination: 10.0.0.0/28, target: pcx-c37bdsfsa(peering)(http://docs.aws.amazon.com/AmazonVPC/latest/PeeringGuide/vpc-peering-routing.html)

람다가 속한 vpc내 resource만 사용할경우 vpc만 설정해주면되고
람다가 그냥 퍼블릭 주소에 접근하는 경우만 있을경우는 vpc를 설정 안해주면된다.

하지만 이 둘을 모두 사용할땐 NAT gateway가 필요하다.. 이건 또 따로 돈나가고.. 이 두가지 모두 해당되면 람다는 좀 아닌것 같다.


*참고

http://docs.aws.amazon.com/lambda/latest/dg/python-programming-model-handler-types.html

http://docs.aws.amazon.com/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html

http://blog.hde.co.jp/entry/2016/05/19/102706


'aws' 카테고리의 다른 글

aws api gate way  (0) 2017.03.18
kinesis firehose 삽질일기  (0) 2017.03.16
How to EC2 disk and memory usage monitoring  (0) 2015.03.27
elasticache dump to file  (1) 2015.03.23
[ubuntu server instance] mytoon setting  (0) 2014.10.24
블로그 이미지

시간을 거스르는자

,

Logstash install

서버 교양 2017. 3. 17. 15:16


Prerequisite


1. java 8

yum update

wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u45-b14/jdk-8u45-linux-x64.rpm"

rpm -ivh jdk-8u45-linux-x64.rpm



Install Log stash


1. rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch


2. Add the following in your /etc/yum.repos.d/ directory in a file with a .repo suffix, for example logstash.repo

[logstash-5.x]

name=Elastic repository for 5.x packages

baseurl=https://artifacts.elastic.co/packages/5.x/yum

gpgcheck=1

gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch

enabled=1

autorefresh=1

type=rpm-md 


3. yum install logstash


4. info

 - /etc/logstash/logstash.yml


5. configurations for input (filebeat in my case)

vim /etc/logstash/conf.d/input-beat.conf

 input {

beats {

port => 5044

}

}


filter {

grok {

match => { 

"message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{DATA:log_level}\] %{DATA:path} %{GREEDYDATA:tail}"

} // this log format is for flask+ gevent wsgi server log

}


if "_grokparsefailure" not in [tags] {

json {

source => "tail" // json will decode target source and add all field to output json. so tail field is not needed anymore

}


mutate {

remove_field => [ "tail", "message"] //will remove specific field
gsub => ["timestamp", ",[0-9]+", ""] // replace (target field, regex, newStr) 

}

}

}



6. configurations for output (s3, elasticsearch)

(if you are using aws-es, you should add your instance public ip on the es policy)

vim /etc/logstash/conf.d/output.conf

 output {

if "_grokparsefailure" not in [tags] { // well parsed

   s3 {

     access_key_id => "crazy_key"
     secret_access_key => "monkey_access_key"
     region => "us-east-1" (US Standard)

     bucket => "your_bucket"
     size_file => 2048 (optional)
     time_file => 5    (optional) - Minutes

     codec => "json" (or "plain")

(optional. Options are "private", "public_read", "public_read_write", "authenticated_read". Defaults to "private" )

   }

}

// all logs

elasticsearch {

    hosts => ["localhost:9200"]

  }

}


7. run

systemctl start logstash


8. check log

/var/log/logstash/


Reference

1. https://www.elastic.co/guide/en/logstash/current/installing-logstash.html

2. https://alexandreesl.com/tag/logstash/

'서버 교양' 카테고리의 다른 글

logstash conf example  (0) 2017.10.13
python 3.5 flask gevent async requests test  (0) 2017.04.07
[펌] 인증 암호화와 해쉬  (0) 2016.10.29
Docker overview  (0) 2015.06.13
SSL 인증서 발급  (0) 2015.03.04
블로그 이미지

시간을 거스르는자

,

kinesis firehose 삽질일기

aws 2017. 3. 16. 20:09

kinesis 에 보면

streams랑 firehose가 있는데 

stream은 그냥 진짜 stream만 받는것이고

firehose는 stream을 받아서 s3나 elastic search(es)로 보내는 역할을 하는녀석이다.

차이 설명: DemystifyingAmazonKinesis_infographic.pdf

목적지가 s3와 es, redshift정도라면 firehose만 쓰면된다.


시작하기전에 한가지 알아두어야할 사실은 "그림에 속았다" 이다.

kinesis를 보면 마치 firehose하나로 s3, redshift, es에 동시에 보낼수 있을것 같이 보인다. 

하지만 설정에 들어가보면 3개중 하나를 고르라고한다.. 잉? 그리고는 백업용으로 s3를 선택할수는 있다. 그럼 redshift랑 es에는 동시에 못하나?

https://stackoverflow.com/questions/44595655/multiple-destinations-for-kinesis

같은 생각을 갖고있는 사람들이 역시 있다. 좀 가시나무들이 있지만 방법은 있단다.. firehose에 람다 트리거를 붙여서 람다가 es에 쓰도록 하는것..


아무튼, file tailing을 이용한 firehose에 로그보내기를 

aws-kinesis-agent를 설치하고 테스트해보았다.


1. config

-> /etc/aws-kinesis/agent.json

이렇게 테스트함.

{

  "cloudwatch.emitMetrics": false,

  "firehose.endpoint": "",

  "log.level": "DEBUG", 

  "flows": [

    {

      "filePattern": "/test/debug2.log",

      "deliveryStream": "test",

      "maxBufferAgeMillis": 1000,

      "minTimeBetweenFilePollsMillis": 1,

      "dataProcessingOptions": [

                {

                    "optionName": "LOGTOJSON",

                    "logFormat": "SYSLOG",

                    "customFieldNames": ["@timestamp", "host", "filename", "lineno", "msg"]

                }

            ]

    }

  ]

}


2. kinesis log

-> /var/log/aws-kinesis-agent/aws-kinesis-agent.log

먼가 안뜨거나 모니터링 할때 용이함.


3. 삽질

- firehose는 deliveryStream으로 써야한다는것

- aws key는 json파일말고 /etc/sysconfig/aws-kinesis-agent 여기에 설정해줘야 한다는것 (IAM role에서 AmazonKinesisFirehoseFullAccess 권한을 준 계정을 만들어 사용한다.)

- 로그가 오해의 소지가 있을수있다는 것. 로그는 파일 append에 상관없이 일정시간동안 찍는데 나오는 값은 agent가 실행된순간부터 지금까지의 토탈이다.

- 저 위에 dataProcessingOptions는 그야말로 옵션인데, 기본 파일에 남는 로그가 json string이 아니면 es에서 먹지 않고 에러만 남는다. (s3엔 상관없이 잘써짐) 그런데 여기서 가능한 logFormat이 4개가 있는데 이중에서 젤 만만한 녀석이 SYSLOG라 이거로 골랐다. 어떻게든 

Mar 16 10:46:49 앞에 이 타임 형식만 잘 찍어주면 뒤에는 없는 부분은 - 로 써서 넘기면 된다.

예) Mar 16 10:46:49 - main.py[123]: message

- 진짜 최강삽질은 es에 기록이 된다음부터인데, 키바나에서 일단 시작하려면 index pattern에서 add New를 해줘야하는데 이때 Time-field name이 뜨질 않는다. Advanced Settings에 가면, dateFormat:scaled라고 해서 타입을 정해줄수있는데 IOS8601 기준밖에 안된다. 그러나 Mar 16 10:46:49 이 타임형식은 rfc3164라는것!! 그래서 여기서 막혔다....


참고:

http://docs.aws.amazon.com/firehose/latest/dev/writing-with-agents.html

https://www.sumologic.com/aws/demystifying-kinesis-streams-firehose-infographic/

'aws' 카테고리의 다른 글

aws api gate way  (0) 2017.03.18
AWS lambda 삽질 일기  (0) 2017.03.17
How to EC2 disk and memory usage monitoring  (0) 2015.03.27
elasticache dump to file  (1) 2015.03.23
[ubuntu server instance] mytoon setting  (0) 2014.10.24
블로그 이미지

시간을 거스르는자

,

websocket with gunicorn

python 2017. 3. 3. 04:13

reference: http://d.hatena.ne.jp/Malan/20121007

flask + gevent websocket + gunicorn

실행 방법은

gunicorn --bind 0.0.0.0:yourwebsocketport -w 2 -k "geventwebsocket.gunicorn.workers.GeventWebSocketWorker" yourappfilename:app

으로 실행하면 아주 잘 되야한다.


그러나 쟁점은 gunicorn 실행시

if __name__ == "__main__" 에 걸리지 않는다는것이다.

걸리게 하려면 yourappfilename을 __main__대신 넣어주면 된다.


if __name__ == "yourappfilename"

그리고 실행하면 Address already in use를 만날수 있다.

그렇다면 살며시 이부분을 주석처리해준다.

# server = pywsgi.WSGIServer((myIP, config.NOTI_WS_PORT), app, handler_class=WebSocketHandler)
# server.serve_forever()


'python' 카테고리의 다른 글

flask with gevent monkey patch all  (0) 2017.07.26
flask gevent spawn use a lot of memory  (0) 2017.04.05
gunicorn vs uwsgi  (0) 2017.01.20
flask async response  (0) 2017.01.04
functools.wraps에 대해  (0) 2015.04.15
블로그 이미지

시간을 거스르는자

,


Reference: https://devcenter.heroku.com/articles/getting-started-with-go#deploy-the-app


0. Prepare your github project containing go app

this is mine: https://github.com/ytkang/golang_chat_bot

for newbee, important thing is your folder is going to be under src folder. so, there is no src or pkg folder in  github (related go structure).


if you already have $GOPATH just skip #1, 2 

1. Make some folder whatever you named, I named it "go"

$mkdir go
$cd go


2. Set gopath

go>$export GOROOT=/usr/local/go
go>$export GOPATH=`pwd`
go>$export PATH=$PATH:$GOPATH/bin


3. Login to heroku

you should install this first. 
https://devcenter.heroku.com/articles/getting-started-with-go#set-up

go>$heroku login


4. Get your project into this folder

go>$go get github.com/ytkang/golang_chat_bot

then, whatever there is an error or not,
"go/src/github.com/ytkang/golang_chat_bot" folder is created.

if you got an import like error when you "go get" then, It will be something occurred from your own module.

you should change your import path to solve this.

if you have folder and files like this,

github.com/ytkang/golang_chat_bot/chat.go
github.com/ytkang/golang_chat_bot/jarvis/jarvis.go

and if chat.go imports jarvis.go, then it should be like this

import github.com/ytkang/jarvis O
import ./jarvis X


4. Deploy to heroku!

go/src/github.com/ytkang/golang_chat_bot>$heroku create
go/src/github.com/ytkang/golang_chat_bot>$git push heroku master

if you got "reject" error something like "failed to detect set buildpack" then you should add "godep"


How to godep

$go get -u github.com/tools/godep   // install

go/src/github.com/ytkang/golang_chat_bot>$godep save  // make godep after this you got Godep folder

go/src/github.com/ytkang/golang_chat_bot>$git add -A; git commit -am "godep added" // important! you should apply this to your github

(after this, retry git push heroku master command. It should work!)


last command

go/src/github.com/ytkang/golang_chat_bot>$heroku open









'Go' 카테고리의 다른 글

Goroutine context switching 시점  (0) 2018.04.20
LITE IDE setup  (0) 2015.01.28
cannot download, $GOPATH not set  (0) 2015.01.28
블로그 이미지

시간을 거스르는자

,


std::move가 단지 캐스팅일 뿐이라니?

일단, move 구현을 보자

template<typename _Tp> inline typename std::remove_reference<_Tp>::type&& move(_Tp&& __t) { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }

move가 무엇을 하는지 자세히 보니,

static_cast<typename std::remove_reference<_Tp>::type&&>(__t);

진짜 캐스팅뿐이다. 그렇다. source object가 없어지거나 그런거 아니다.

뭐 값을 대입시킬 객체에는 rvalue reference를 넘겨서 메모리주소를 그대로 전달한다고 치고,


이시점에서 궁금한건 오로지하나,

"뭐지? 그럼 기존 객체는 어떻게 없어지는거야?"

알고보니, 그 답은 rvalue reference 생성자와 대입연산자에 있었다.

rvalue reference 생성자와 대입연산자에서는 source object의 메모리 주소를 dest object에 주고

source object는 nullptr처리하거나 하는것이다.

대표적인 예가 std::string 이다.

assign(basic_string&& __str) { this->swap(__str); return *this; }

보면, source와 dest를 swap하고 있다. 따라서 string을 move시켜보면 move당한 놈은 "" 빈스트링을 갖게된다.

그럼 한번 테스트해볼까? 내가 만든 클레스를 move시킨면 어떻게되는지?

repl.it: https://repl.it/FbVT/0

code:

#include <iostream>
#include <stdlib.h>

class TestMe {

public:
TestMe(){ i = nullptr; }
void set(int& k){ i = &k; }
int get(){ return *i; }
void plus(){ (*i)++; }

private:
int* i;
};

int main()
{
        int test1 = 1;
        TestMe t1;
        t1.set(test1);

TestMe t2(std::move(t1));

t2.plus();
std::cout << "t1: " << t1.get() << std::endl;
std::cout << "t2: " << t2.get() << std::endl;

t1.plus();
std::cout << "t1: " << t1.get() << std::endl;
std::cout << "t2: " << t2.get() << std::endl;   

   return 0;

result:

 t1: 2
 t2: 2
 t1: 3
 t2: 3

아마도 이 결과로부터 유추할수있는건, 

std string처럼 swap같은건 없고 메모리는 일단 복사가되었는데 source object에 대한 후처리는 없다는 것이다. 

따라서 default move constructor가 어떻게 작동하는지 이해하고, 맘에 안든다면 직접 구현해야한다.



References

1) std::string source

2) std::remove_reference

3) What are rvalues, lvalues, xvalues, glvalues, and prvalues?


블로그 이미지

시간을 거스르는자

,

gunicorn vs uwsgi

python 2017. 1. 20. 19:29

- 보통 퍼포먼스를 보면 아무래도 pure C기반의 uwsgi가 pure python인 gunicorn보다 빨라보입니다. 간혹 uwsgi가 느리다는 비교가있는데 이는 gunicorn은 워커를 gevent로 하면 몽키패치를 지가 app서버에 해버리는데 반해 uwsgi는 app서버 코드에 몽키패치를 해줘야함을 모르고 테스트할 결과로 보여지네요.

- 사용성 측면에서 uwsgi가 좀더 복잡하고 코어 갯수에 따라 configure를 잘못하면 오히려 성능저하가될 우려가 보이네요.

- 도큐먼트는 gunicorn이 훨깔끔


*참고로 gunicorn, uwsgi모두 앞단에 nginx를 쓰는케이스가 많이 있습니다. 이는
DDos 공격방지, static file전송 효율성등때문이라고 합니다. 그리고 gunicorn document에서도 말하고 있는 nginx buffering기능때문입니다. 

nginx에도 설명이 잘나와있지만 nginx buffering에 대해 좀더 설명하자면,

client - nginx - app servers

이 구조에서 client에 response를 전송하는데 nginx buffer가 없고 클라이언트가 response 패킷을 천천히 받으면 그 영향이 app server한테까지 끼쳐서 그 process는 블락이되어 다른 패킷을 처리 못하게 됩니다. 

하지만 nginx buffer가 있다면 nginx는 app server에게 response패킷을 모두 받을때까지 client에게 응답하지 않고 app server에게 다 받은후 client에게 응답을 보냅니다. 따라서 slow client를 만나더라도 app server는 블락이 되지않을 수 있는것이죠.


*추가로 볼만한것

- Backend Architechtures(https://gist.github.com/ngocphamm/5849994)

- ELB+nginx+appservers(http://amazonwebservices21.blogspot.kr/2015/07/system-architecture-to-deploy-django.html)

'python' 카테고리의 다른 글

flask gevent spawn use a lot of memory  (0) 2017.04.05
websocket with gunicorn  (0) 2017.03.03
flask async response  (0) 2017.01.04
functools.wraps에 대해  (0) 2015.04.15
Apple Push Notification Service(APNs) python modules  (0) 2015.04.07
블로그 이미지

시간을 거스르는자

,