[개발] Node & Steem #9 - 스팀 노드 서비스 연결이 끓어질 때 해결방법 + 리스팀 목록 확인 명령 추가
#1 스팀 노드가 자꾸 죽는다구요?
최근 몇일정도 서비스를 켜두었더니 스팀노드 서비스가 일시적으로 멈추거나 끊기는 증상이 있었습니다. '아 이게 봇을 운영하시는 분들이 말씀하신 노드가 끊어지는 현상이었나봅니다.' streamBlock~의 api 시리즈들이 한번 연결이 끊어지니 에러가 발생하면서 다시 값을 받아오질 않았던 것이죠.
이 문제를 해결하는 과정을 담아보겠습니다. 아마 선대의 봇 운영자분들도 여러가지 방안으로 해결을 하셨을 것 같은데 같은 방식인지 다른 방식인지는 잘 모르겠습니다. 다른 좋은 방법이 있다면 공유해주시면 좋겠습니다.
1. 우선 문제 재현이 가능한지 확인
이 경우 스팀노드와 끊어지면서 다시 붙는 기능을 구현하지 않은 steem-js api 때문이라고 생각이 듭니다. 아쉬운 점이라면 자동으로 1,2초 뒤에 다시 스팀노드와 붙게 해서 값을 받아오도록 api 구현이 되어있었다면 이런 불편한 예외처리가 필요없었지 싶습니다.
많은 개발자분들이 문제 해결을 하기 위해 첫번째로 해야할 일은 테스트 환경에서 문제 재현이 가능한지 검토해봐야 한다는 것이겠죠. 스팀노드와 일시적으로 연결을 끊는 방식은 생각보다 간단합니다.
바...바로 랜선을 잠시 뽑으면 됩니다. 유레카! ㅋㅋㅋ재현이 가능하다면 해결하기도 쉽습니다. 재현을 하면서 코드를 수정 보완하면 되니까요. 저는 이렇게 뽑을 겁니다.
저기 '사용 안함'을 누르면 네트워크가 끊기면서 스팀 노드와도 끊기게 될겁니다. 그 상황에서 1초에 한번씩 다시 스팀노드에 붙도록 코딩하는게 1차 목표입니다.
2. 해결방안을 생각해보고 코딩으로 옮기자.
그러면 스팀노드가 뻗는다 해도 다시 살아나면 지가 1초에 한번씩 붙는 시도를 하다가 붙을 것입니다. 기존 소스로 이런 코딩을 하면 복잡하니 이 상황만을 개선하기 위한 테스트 파일을 만듭니다.
test_steem_api.js 라고 하나 파일을 만들었습니다. 그리고 여기에 지난번 wrkBot의 재귀처리를 이용한 방식으로 에러가 발생했을 때 다시 노드에 붙을 수 있도록 코딩을 해봤습니다. 이녀석의 이름은 blockBot입니다. block을 처리하는 넘이니까요.
// synchronize init!
var sync = require('synchronize');
var fiber = sync.fiber;
var await = sync.await;
var defer = sync.defer;
// synchronize init end!
var steem = require("steem")
steem.api.setOptions({url: 'https://api.steemit.com'});
var Fiber = require('fibers');
function sleep(ms) {
var fiber = Fiber.current;
setTimeout(function() {
fiber.run();
}, ms);
Fiber.yield();
}
var sleepTm = 1000;
function blockBot(){
var release = steem.api.streamBlockNumber('head',function(err, blockNumber){
fiber(function() {
if( err != null ){ // 에러가 나는 경우
console.error(blockNumber);
release(); // 반환하고
console.error("1초 쉬었다가...");
sleep(sleepTm);
console.error("다시 실행");
blockBot();
}else{
console.info(blockNumber);
}
}); // fiber end.
});
}
blockBot();
그리고 실행을 하고~ 아까 네트워크 연결을 끊어봅니다. 그리고 다시 붙여봅니다.
20033925
20033926
undefined
1초 쉬었다가... // 끊어졌을 때 쉬었다가 붙는 시도가 됨.
다시 실행
undefined
1초 쉬었다가...
다시 실행undefined
1초 쉬었다가...
다시 실행
20033932 // 다시 랜선을 꼽으니 노드에 붙음.
20033933
20033934
20033935
다시 연결이 잘 되는군요. 전에 wrkBot의 재귀처리 방식을 재 활용한거라 큰 공을 들이지 않고 활용했습니다. 여...역시 개발은 Ctrl + C, V가 진리
입니다.
3. 스팀잇에 공개된 여러 노드를 통해 페일오버 기능 구성
추가적으로 이 코드를 더 보완할 수 있는 방법이 있을 것 같습니다. 다른 방식은 steem-js의 api의 오류를 카운트 하고 일정시간, 일정횟수 이상이 되는 경우 노드 주소를 변경하는 것입니다. 이렇게 하면 스팀노드가 불안정하여 서비스 되지 않는 경우에 안정적인 노드로 붙을 테니 서비스가 훨씬 안정적이 되겠죠?
- 시간상으로 약 3초간 연결이 제대로 되지 않는다면 다른 노드로 붙이도록 코딩을 넣어봅시다.
이런걸 우리 전산에서는 페일오버(Fail Over) 기능이라고 말합니다. 대표적으로 오라클 디비에서는 rac( Active - Active ) , ha( Active - stand by)라고 부르죠. 아마 국내는 오라클 천국이니 많이들 들어보셨을거라 생각이 드네요. 액티브-액티브인 rac가 마니 비싸고, 액티브-스탠바이인 ha 는 상대적으로 저렴하니 회사의 주머니 사정이나 시스템 중요도에 따라 구성을 달리하게 되죵...
오늘 밤에 rac(또는 ha) 페일오버 테스트가 있어요.
라는 말을 듣는다면 오라클 DB 서버를 한대씩 껏다 켯다 하면서 페일오버 테스트를 하는구나 라고 생각하면 됩니다. 말이 샜으니 다시 스팀 노드로 넘어갑시다. ㅎㅎ
스팀 노드들이 머가 있는지 알아보던 차에 구글링을 열심히 한 결과 여기서 노드들의 리스트를 볼수가 있었습니다.
https://www.steem.center/index.php?title=Public_Websocket_Servers
제가 하나하나 노드에 붙어서 api가 돌아가는것만 리스트를 추려봤습니다. 이 중에 현재 시점으로 노드가 외부에서 접근이 가능한 리스트는 아래와 같습니다. 안되는 곳이 생각보다 많더군요.
https://api.steemit.com
https://steemd-int.steemit.com
https://steemd.steemitstage.com
https://api.steemitstage.com
https://steemd.pevo.science
@ludorum님께서 steemkr 노드도 알려주셔서 그것도 포함시켰습니다. 감사합니다.
steem-js 에서 노드를 여러개 설정하는 방법은 상당히 많은 구글링을 했지만 찾지 못했습니다. steem-js의 config 구조로 봤을 때도 힘들어보여서 에러를 캡처하여 카운트 하다가 일정 갯수가 넘어가면 노드를 변경하는 식으로 소스를 구성해봤습니다.
steem-js의 config 구조
config:
Config {
transport: 'ws',
websocket: 'wss://steemd.steemit.com',
websocketdev: 'wss://steemd.steemitdev.com',
uri: 'https://steemd.steemit.com',
url: 'https://api.steemit.com',
dev_uri: 'https://steemd.steemitdev.com',
stage_uri: 'https://steemd.steemitstage.com',
address_prefix: 'STM',
chain_id: '0000000000000000000000000000000000000000000000000000000000000000' },
그리고 수일간 노드가 끊기는 증상을 모니터링해본 결과 'HTTP 504: Gateway Time-out' 에러와 함께 stream api가 끝나버리는 것도 확인했습니다.
13:36:47 - error: Error: HTTP 504: Gateway Time-out
노드를 전환시켜주는 함수를 하나 만들고 저기 에러난 곳에서 호출하는 코드만 추가하면 제가 원하는 페일오버 기능은 완성되는 것 같습니다.
var cntNodeErr = 0;
var stnrNodeErr = 3;
function rotateNode(){
if( cntNodeErr >= stnrNodeErr ){
if( arrNode.length == idxNode+1){
idxNode = 0;
}else{
idxNode++;
}
steem.api.setOptions({url: arrNode[idxNode] });
cntNodeErr = 0;
}
}
function blockBot(){
---생략---
if(err){
cntNodeErr++; // 에러인 경우 카운트 증가
}
---생략---
}
이제 왠만하면 봇이 꺼지지 않고 돌아가리라 생각합니다. 이렇게 페일오버의 기능을 흉내낸 스크립트까지 추가했고 그 방법을 소개해봤습니다.
#2 리스팀 목록 확인 명령 기능 추가
그리고 하루 이틀 기능을 쓰다보니 이녀석이 너무 댓글을 많이 다는 문제가 있다는 생각이 들었습니다. 이...인기도 없고요. ㅠㅠ 그래서 댓글 하나에 리스팀한 유저들의 리스트를 보여주는 것으로 수정하기로 마음 먹었습니다. 그리고 원할 때에만 1회용으로 명령으로 리스팀한 유저들을 볼 수 있도록 기능을 추가했습니다. 아무 포스팅에 하시면 리스팀한 분들의 전체 리스트를 보실 수 있습니다. 심지어 본인 것이 아니더라도 가능.
이녀석은 댓글의 댓글의 댓글에도 무한 반복 반응하리라는 생각이 듭니다. 상세 코드는 제 github에서 언제든 확인 가능합니다. 읽어주셔서 감사합니다.
Node & Steem - 지난 회차 살펴보기
1편 - nodejs 개발환경을 구성해보자. 윈도우 개발 + Github 저장소 + 리눅스 운영
2편 - 콜백 지옥을 탈출해보자. - synchronize.js 편
3편 - 로깅 처리와 DB(mysql)설치 및 설정
4편 - DB 설정과 운영서버까지 설정 마무으리!
5편 리스팀 알림 봇을 만들어볼까? #1
6편 리스팀 알림 봇을 만들어볼까? #2 whitelist 데이터 수집
7편 리스팀 댓글 알림 봇 #3 시범오픈과 구현 마무으리!
8편 - 간단한 서버 관리 다섯가지 팁 - 쉘 접속과 alias 지정 등
Cheer Up!
오오 매우 고오급 정보이군요~ 써먹어야지~~!! ㅋㅋ 리스팀해놔야겠네용 ㅋㅋ
오우... 리스팀은 사랑입니당 ㅋㅋㅋ
좋은 정보 감사드립니다. 나중에 사용해야겠네요.. 노드 하나 구축해볼까 하다 사양 얘기 듣고 좌절했었던 ^^;;
@eversloth님께서 이 포스팅에 많은 관심을 가지고 있어요. 리스팀을 해주셨군요~!
@리스팀 리스트
이 글을 리스팀 해주신 소중한 분들입니다.
@멘션 등록
멘션 댓글 안내 서비스가 등록되었습니다.
후.....멋있으십니다 저는 바보가 된 기분이네요 ㅎㅎㅎㅎㅎㅎ
역시 하나도 모르겠는데 멋있어~!! 근데 궁금한게 있는데 마지막 거는 지금 여기서도 사용 가능한 건가요~?저는 그냥 스팀잇 공식 홈페이지에서 하고 있는데??!
@리스팀 목록
이 글을 리스팀 해주신 소중한 분들입니다.
대단스!!
들렸다갑니다.
나름 꼼꼼히 읽었는데도 뭐가 뭔지 잘 모르겠네요. 이 어려운걸 아무렇지 않아 하며 올리시다니 대박이십니다 ㄷㄷ 저는 아직 봇을 돌리지는 않지만 나중에 반드시 필요 할 거 같아 리스팀 해갑니다. 완전 감사합니다!!
저도 작성하면서 이렇게 이기적인 포스팅이 있을까도 싶습니다. ㅎㅎㅎ 시리즈물이다보니 전의 것을 보지 않으면 이해하기도 어렵고 많은분들이 보시긴 힘드니 ㅜㅜ . 그래도 감사합니다 ^^
이런글은 더 이기적이어도 좋습니다 ㅎㅎ 막상 처리가 쉽지 않은데 진짜 꼼꼼히 하셨네요. 나중에 진심으로 도움될거 같습니다. 다시 한 번 감사드립니다. 짱짱!!!
@segyepark님께서 이 포스팅에 많은 관심을 가지고 있어요. 리스팀을 해주셨군요~!
@nhj12311
@nhj12311