AWS SDK for C++/Go and S3 upload time check
AWS S3에 Object Upload를 테스트 하는 업무가 있다.
이를 위해 RESTful API, C++ SDK, Go SDK를 사용하여 테스트를 진행하였다.
각각의 SDK는 결국 RESTful API를 wrapping해서 사용하는 것이었다.
내부 코드를 보면 s3 manager 혹은 s3 client 객체를 생성하여 진행한다.
Object를 업로드할때 일정 이상의 용량일때는 multipart 업로드가 유리하다.
다음은 multipart upload에 대한 AWS의 공식 문서와 이를 해 잘 설명한 블로그다.
멀티파트 업로드 개요 - AWS
Amazon S3 Parallel MultiPart File Upload - BLOG(java)
개인적으로 잘 사용하는 C++과 Go lang용 SDK는 다음의 링크에서 확인할 수 있다
AWS SDK C++ - download(github)
AWS SDK GO - download(github)
다음의 링크는 C++ SDK의 통합 테스트코드로 상세하고 다양한 코드샘플을 찾을 수 있다.
https://github.com/aws/aws-sdk-cpp/blob/master/aws-cpp-sdk-s3-integration-tests/BucketAndObjectOperationTest.cpp
C++ SDK에는 putobject와 multipart upload가 별도로 구분되어 있다.
위의 테스트 코드에서 PutObjectRequest 를 검색하면 기본 업로드 코드를, CreateMultipartUploadRequest 를 검색하면 multipart upload 코드를 찾을 수 있다.
아래 주소에 가면 cpp, go, .net, java, javascript, php, python, ruby의 예제 코드를 확인할 수 있다.
환경 설정이 잘 되어 있으면 즉각 컴파일과 실행이 가능하다.
GO Lang SDK의 sample 코드는 오픈소스라 더 쉽게 내용을 확인할 수 있다.
패키지 s3manager의 Upload를 확인하면 Upload() 함수가 있다.
이 함수를 사용하면 uploader의 PartSize가 s3manager.MinUploadPartSize인 5Mbytes보다 작으면 에러를 발생시킨다.
이후 PartSize 단위로 읽어들여 하나 이하의 chunk가 발생하면 single part upload를 진행한다.
chunk가 둘 이상이면 mulpartuploader 객체를 통해 업로드를 진행한다.
위의 SDK를 실행하려면 기본 환경설정을 해야 한다.
AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY 를 설정해야한다.
AWS_SESSION_TOKEN 의 경우 옵션이다.
SDK Configuration - GO Lang
CPP SDK의 경우 CMake를 활용하며 c++ version이 최소 C++11를 지원해야 한다.
SDK 설치시 C++11 혹은 C++14를 지정할 수 있다.
이와 함께 CMake를 사용한다.
사용하는 linux의 기존 CMake는 버전이 낮아 호환되지 않았다.
yum을 통해 cmake3를 설치하여 사용하였다.
Configuring the SDK - CPP
위의 링크들의 문서와 예제 코드를 사용하면 SDK를 활용하여 AWS를 사용하는 것이 크게 어렵지 않을 것이다.
위의 과정들을 통해 파일 업로드 속도를 간단히 체크한 결과이다.
테스트는 IDC의 linux 서버에서 진행하였으며 multipart upload의 경우 사무실의 개발PC에서 실행하여 체크한 시간이다.
S3 File upload time check - linux server, AWS CLI | |||
시작(ms) | 종료(ms) | 시간차(ms) | |
1회 | 1494548006096 | 1494548043927 | 37831 |
2회 | 1494548050272 | 1494548072718 | 22446 |
3회 | 1494548094591 | 1494548148717 | 54126 |
4회 | 1494548161326 | 1494548217320 | 55994 |
5회 | 1494548227645 | 1494548275162 | 47517 |
6회 | 1494548306828 | 1494548329881 | 23053 |
7회 | 1494548352251 | 1494548364362 | 12111 |
8회 | 1494548382826 | 1494548395007 | 12181 |
9회 | 1494548401111 | 1494548453868 | 52757 |
10회 | 1494548459801 | 1494548475682 | 15881 |
합산 | 333897 | ||
평균 | 33389.7 |
S3 File upload time check - linux server, c++ sdk, putobject(single), file size:25826362 | ||
소요시간(seconds) - 1회 | 소요시간(seconds) - 2회 | |
1회 | 8.70795 | 18.9716 |
2회 | 21.2515 | 12.0308 |
3회 | 34.9919 | 13.7737 |
4회 | 29.1713 | 6.39977 |
5회 | 9.98919 | 7.33901 |
6회 | 15.6894 | 16.913 |
7회 | 29.9045 | 20.028 |
8회 | 53.3282 | 25.8403 |
9회 | 32.0113 | 42.0073 |
10회 | 10.8376 | 33.4675 |
합산 | 245.883 | 196.771 |
평균 | 24.5883 | 19.6771 |
S3 File upload time check - linux server, go sdk, Upload(auto multiparts), file size:26189716 | ||
소요시간(seconds) - 1회 | 소요시간(seconds) - 2회 | |
1회 | 4.6583578 | 4.6088254 |
2회 | 3.9769095 | 4.1344735 |
3회 | 4.0830212 | 4.2095661 |
4회 | 4.7418807 | 4.1589274 |
5회 | 4.1057907 | 4.6452324 |
6회 | 4.2522046 | 4.0686392 |
7회 | 4.5779243 | 4.0981387 |
8회 | 4.6437622 | 5.8632637 |
9회 | 4.2051021 | 6.0630964 |
10회 | 4.1674061 | 6.753556 |
합산 | 43.412359 | 48.60372 |
평균 | 4.3412359 | 4.860372 |
'프로그래밍??? > AWS' 카테고리의 다른 글
AWS 기반의 마이크로 서비스 아키텍쳐 구현 방안 (0) | 2017.09.28 |
---|---|
고급 클라우드 아키텍처 방법론- 양승도 솔루션즈 아키텍트:: AWS Cloud Track 2 Advanced (0) | 2017.09.27 |
AWS EC2를 다른 리전으로 이전하기 (0) | 2017.08.29 |
Amazon S3 REST API (0) | 2017.05.11 |
시작~~~ (0) | 2017.04.21 |
POCO Library link 이슈 - GCC 5.4.0 업버전 후 생긴 문제
현재 운영중인 시스템에서 poco library의 log시스템을 사용한다.
c++14를 사용하기 위해 최근 GCC를 5.4버전으로 올렸다.
그 과정의 수많은 삽질이 있었다. Linux를 잘아는 천과장이 아니었으면 지금도 미궁을 헤메고 있었을듯... :(
우쨋거나 GCC 5.4 업버전 이후 또 다른 문제에 봉착했다.
poco library가 정상 작동을 하지 않았다.
혹시 하는 생각에 poco-1.7.4로 업버전 하여 컴파일하여 install 하였다.
여전히 안된다.
configure를 살펴봐도 gcc 관련 내용은 없다.
여기저기 뒤져보다가 make file을 살펴보니 다름과 같은 라인이 보인다.
include $(POCO_BASE)/build/config/$(POCO_CONFIG)
시스템상 관련 파일은 ./build/config/Linux 이다
해당 부분에서 현재의 gcc5.4의 관련 부분으로 수정하여 컴파일 했더니 문제 없이 넘어가게 되었다.
# # $Id: //poco/1.4/build/config/Linux#2 $ # # Linux # # Make settings for Linux 2.6/gcc 3.3 # # # # General Settings # LINKMODE ?= SHARED # # Define Tools # #CC = ${CROSS_COMPILE}gcc #CXX = ${CROSS_COMPILE}g++ CC = /opt/rh/gcc-5.4.0/bin/gcc CXX = /opt/rh/gcc-5.4.0/bin/g++
원래 나던 링크 에러 문제...
ubirloader.cpp:(.text+0x20a): undefined reference to `Poco::FileChannel::setProperty(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::char_traits<char>, std::allocator<char> > const&)' collect2: error: ld returned 1 exit status
'프로그래밍??? > C/C++' 카테고리의 다른 글
GCC 5.4.0 Install on CentOS 및 작업중 기타 삽질 시리즈... (0) | 2016.09.22 |
---|---|
Dual ABI 이슈 - GCC5 (0) | 2016.08.05 |
기존에 제작했던 pcqueue 샘플 코드 (0) | 2016.07.13 |
Bad cast exception on poco-library when I tried to cast Int64 (0) | 2015.07.30 |
Boost를 활용해 공유 메모리에 STL Container 사용하는 방법 (0) | 2015.07.10 |
기존에 제작했던 pcqueue 샘플 코드
//--------------------------------------------------------------------------------------------------------------------- // pcqueue.hpp // // Asker's product consumer queue //--------------------------------------------------------------------------------------------------------------------- #pragma once #include <iostream> #include <vector> #include <pthread.h> #include "errno.h" #include "common.hpp" using namespace std; //--------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------- template <class T> class CPCQueue { private: pthread_mutex_t ProducerLock; pthread_mutex_t ConsumerLock; vector<T*> ProducerQueue; vector<T*> ConsumerQueue; private: bool LockProducer() { int _nError = pthread_mutex_lock( &ProducerLock ); if ( _nError ) { cout << "error in lock producer. return : " << _nError << ", err :" << strerror(errno) << endl; formatlog( LOG_CRIT, "error in lock producer. return(%d) ErrNo(%d) ErrMsg(%s)", _nError, errno, strerror(errno)); return false; } return true; } bool UnlockProducer() { int _nError = pthread_mutex_unlock( &ProducerLock ); if ( _nError ) { cout << "error in unlock producer. return : " << _nError << ", err :" << strerror(errno) << endl; formatlog( LOG_CRIT, "error in unlock producer. return(%d) ErrNo(%d) ErrMsg(%s)", _nError, errno, strerror(errno)); return false; } return true; } bool LockConsumer() { int _nError = pthread_mutex_lock( &ConsumerLock ); if ( _nError ) { cout << "error in lock consumer. return : " << _nError << ", err :" << strerror(errno) << endl; formatlog( LOG_CRIT, "error in lock consumer. return(%d) ErrNo(%d) ErrMsg(%s)", _nError, errno, strerror(errno)); return false; } return true; } bool UnlockConsumer() { int _nError = pthread_mutex_unlock( &ConsumerLock ); if ( _nError ) { cout << "error in unlock consumer. return : " << _nError << ", err :" << strerror(errno) << endl; formatlog( LOG_CRIT, "error in unlock consumer. return(%d) ErrNo(%d) ErrMsg(%s)", _nError, errno, strerror(errno)); return false; } return true; } public: CPCQueue(){} virtual ~CPCQueue() { for ( class vector<T*>::iterator _iter = ProducerQueue.begin(); _iter != ProducerQueue.end(); _iter++) delete *_iter; for ( class vector<T*>::iterator _iter = ConsumerQueue.begin(); _iter != ConsumerQueue.end(); _iter++) delete *_iter; ProducerQueue.clear(); ConsumerQueue.clear(); } bool Init() { int _ErrorNo = pthread_mutex_init( &ProducerLock, NULL); if (_ErrorNo) return false; _ErrorNo = pthread_mutex_init( &ConsumerLock, NULL); if (_ErrorNo) return false; return true; } // Product에 하나를 추가한다 bool AddProduct( T* _Job ) { if ( false == LockProducer()) { // lock 실패 formatlog( LOG_CRIT, "CPCQueue::%s(%d) Lock Fail. fatal issue.", __func__, __LINE__); return false; } ProducerQueue.push_back(_Job); if ( false == UnlockProducer()) { // unlock 실패 formatlog( LOG_CRIT, "CPCQueue::%s(%d) Unlock Fail. fatal issue.", __func__, __LINE__); return false; } return true; } // Consumer 쪽에서 하나씩 빼낸다. bool PopFromConsumer(T** _Value) { *_Value = NULL; if ( false == LockConsumer()) { // lock 실패 formatlog( LOG_CRIT, "CPCQueue::%s(%d) Lock Fail. fatal issue.", __func__, __LINE__); return false; } if (!ConsumerQueue.empty()) { *_Value = ConsumerQueue.front(); ConsumerQueue.erase(ConsumerQueue.begin()); } if ( false == UnlockConsumer()) { // unlock 실패 formatlog( LOG_CRIT, "CPCQueue::%s(%d) Unlock Fail. fatal issue.", __func__, __LINE__); return false; } return true; } // 합할 것이 하나도 없는 경우 false를 반환한다 bool MoveProducerToConsumer(int& _MoveCount) { if ( false == LockConsumer()) { // lock 실패 formatlog( LOG_CRIT, "CPCQueue::%s(%d) Lock Fail. fatal issue.", __func__, __LINE__); return false; } if ( false == LockProducer()) { // lock 실패 formatlog( LOG_CRIT, "CPCQueue::%s(%d) Lock Fail. fatal issue.", __func__, __LINE__); return false; } _MoveCount = ProducerQueue.size(); if (!ProducerQueue.empty()) { for ( class vector<T*>::const_iterator _iter = ProducerQueue.begin(); _iter != ProducerQueue.end(); _iter++) ConsumerQueue.push_back(*_iter); ProducerQueue.clear(); } if ( false == UnlockProducer()) { // unlock 실패 formatlog( LOG_CRIT, "CPCQueue::%s(%d) Unlock Fail. fatal issue.", __func__, __LINE__); return false; } if ( false == UnlockConsumer()) { // unlock 실패 formatlog( LOG_CRIT, "CPCQueue::%s(%d) Unlock Fail. fatal issue.", __func__, __LINE__); return false; } return true; } int GetConsumerSize() const { return ConsumerQueue.size(); } }; //---------------------------------------------------------------------------------------------------------------------
class CDataThread: public CUbiThread { private: CPCQueue<COnePacket> PCQueue; int ThreadIndex; CURL* ctx; public: bool Terminated; public: CDataThread(); virtual ~CDataThread(); bool init(); void SetIndex(int _Index); bool AddProduct( COnePacket* _OnePacket); virtual void Run(); private: bool DoPacketProcess(COnePacket* _OnePacket); CUbiParser* MakeParser(COnePacket* _OnePacket); } //--------------------------------------------------------------------------------------------------------------------- CDataThread::CDataThread() { } //--------------------------------------------------------------------------------------------------------------------- CDataThread::~CDataThread() { } //--------------------------------------------------------------------------------------------------------------------- bool CDataThread::init() { return PCQueue.Init(); } //--------------------------------------------------------------------------------------------------------------------- void CDataThread::SetIndex(int _Index) { ThreadIndex = _Index; } //--------------------------------------------------------------------------------------------------------------------- bool CDataThread::AddProduct( COnePacket* _OnePacket ) { return PCQueue.AddProduct(_OnePacket); } //--------------------------------------------------------------------------------------------------------------------- void CDataThread::Run() { int _Count = 0; int _JobCount = 0; int _SleepMicro; COnePacket* _OnePacket = NULL; Terminated = false; while(!Terminated) { try { // Customer Queue에 Producer Queue의 내용을 가져오게 한다 if (!PCQueue.MoveProducerToConsumer(_Count)) formatlog( LOG_FATAL, "CDataThread::%s(%d) %10d Thread Error in Move PCQueue data", __func__, __LINE__, ThreadIndex); //, typeid(T).name()); else formatlog( LOG_INFO, "CDataThread::%s(%d) %10d Thread %2d %3d remain.", __func__, __LINE__, ThreadIndex, _Count, PCQueue.GetConsumerSize()); } catch(exception &_innerException) { formatlog( LOG_CRIT, "Exception on CDataThread::%s(%d). %2d Thread what(%s)", __func__, __LINE__, ThreadIndex, _innerException.what()); } // Customer Queue를 비울때 까지 작업을 처리 한다 _JobCount = 0; while(true) { _OnePacket = NULL; // 처리 간격에 일정 시간을 둔다 if (!PCQueue.PopFromConsumer(&_OnePacket)) { formatlog( LOG_FATAL, "CDataThread::%s(%d). %2d Thread Error in Get Data From PCQueue", __func__, __LINE__, ThreadIndex); break; } if ( NULL == _OnePacket) break; //1 실질적인 패킷 처리!! DoPacketProcess(_OnePacket); _JobCount++; delete _OnePacket; } usleep(500000 ); } }
'프로그래밍??? > C/C++' 카테고리의 다른 글
Dual ABI 이슈 - GCC5 (0) | 2016.08.05 |
---|---|
POCO Library link 이슈 - GCC 5.4.0 업버전 후 생긴 문제 (0) | 2016.08.04 |
Bad cast exception on poco-library when I tried to cast Int64 (0) | 2015.07.30 |
Boost를 활용해 공유 메모리에 STL Container 사용하는 방법 (0) | 2015.07.10 |
Creating STL Containers in Shared Memory (0) | 2015.07.10 |
C++11 STL 프로그래밍
최근 Effective Modern C++이란 책을 구매해서 봤다.
결국 중간에 접었다.
어려웠다.
다시 이전 단계로 갔다.
C++11 STL 프로그래밍...
문법 보다는 사용예를 위주로 책을 구성하였다.
일주일도 안되는 시간에 몇몇 예제를 돌려보며 책을 다 보았다.
일관된 방식으로 빠르게 볼 수 있게 구성된 것이 장점이다.
그러나 개정2판임에도 몇몇의 오자와 함께 예제가 통채로 뒤바뀐 경우도 있고
대소문자가 다르게 나온 경우도 있다.
그럼에도 불구하고 빠른 시간내에 C++11에 대해 접하기에는 나쁘지 않다는 생각이다.
이 예제 테스트를 위해 VC++ 2015(Professrional)를 깔았다.
예전과 다르게 MS 홈페이지에서 직접 다운로드 하여 깔 수 있다.
(혼자 공부하는 것이니 아마도 라이센스에 걸리지는 않을 듯하다)
예전 디지털방송쪽 일을 할때 보면 문서가 두벌이 세트이다.
규격과 Guide...
이번에 C++11을 보면서도 그 지점을 느꼈다...
C++11 STL 프로그래밍은 "규격"을 보여준다면 Effective Modern C++은 Guide를 제공한다.
규격이 훌륭하더라도 그 제약점과 한계를 모르면 일을 할 수 없다.
여기서 좀 더 발전하면 How를 제공하는 패턴과 같은 쪽으로 갈 수 있을 것이다.
일단 읽은 기념으로 표지라도 붙인다.
'책' 카테고리의 다른 글
난 정말 JAVA를 공부한 적이 없다구요. (0) | 2016.12.07 |
---|---|
7가지 동시성 모델 (0) | 2016.09.22 |
Pro Oracle Spatial for Oracle Database 11g (0) | 2011.11.15 |
오라클SQL튜닝(쿼리의 본질과 성능 튜닝에 대한 37가지 이슈) (0) | 2011.11.15 |
Head First PMP (0) | 2010.03.06 |