2020년 1월 10일 금요일

산다는 건 뭘까...

 초등학교 6학년 때가 아마도 내 사춘기 시절이었던 것 같다.

내성적인 성격이라 크게 튄 건 아니지만 기억나는 장면이 있다.

당시 담임 선생님이 내가 벽에 쓴 낙서를 지우라고 했다.

낙서는 "나는 커서 뭐가 될까?"였다. 그때 당시에는 몰랐지만 중학교에서 사춘기에 대해 배우며 내가 썼던 낙서가 사춘기에 발생하는 일들 이란 걸 알았다.


 현재의 내가 만들어 진건 어찌 보면 아주 단순하다. 해커 영화를 보았고 해커가 멋있어 보였으며 해커를 양성한다는 학교를 갔다.

결과적으로 해커는 되지 못했지만 그 언저리쯤에는 있는 것 같다.

어떻게 보면 인생이란 이렇게 단순한 게 아닌 가 싶다. 그냥 막연하게 해커가 되고 싶었던 나는 프로그래머가 되었다.


그때는 막연하게나마 목표가 있었던 것 같다.

그런데 지금은 그런 목표조차도 없다. 꿈이 뭐냐는 질문이 가끔 들어오면 '평생 놀고먹는 것'이라고 대답하곤 했다. 이게 꿈이 될 수 있는지는 둘째 치고 목표가 흐리멍덩하다.

약간 풀어 본다면 평생 놀고먹으려면 경제적 자유로움이 당연히 있어야겠지. 그럼 역시 돈을 벌어야 하는 게 목표가 될 거다.

그래 내 목표는 돈을 버는 거다. 아주 많이. 놀고먹고살 수 있을 정도로.


...


정말 그걸로 될까... 음... 아마 될 것 같다. 그럼 어느 정도의 돈이 필요할 까. 정확히 계산해 보진 않았지만 검색해 본 결과로는 30억 정도 있으면 될 것 같다.


좀 더 풀어 보자. 왜 놀고먹고 싶은 가. 그것에 대한 답은 모든 사람들이 바라는 것. 행복해 지기 위해서다.

행복이란 이런 사전적 의미가 있다.


  생활에서 충분한 만족과 기쁨을 느끼어 흐뭇함또는 그러한 상태


많은 사람들의 목표 이기 때문에 역시 많은 연구들이 있다.

최근 본 유튜브에서는 행복해 지기 위한 방법들을 알려줬다. 생각나는 대로 적어보면 이렇다.


행복한 사람과 가까이 하라.

친구 나 가족과 시간을 가져라.

3개를 맞추고 싶은 데  2개밖에 기억이 안 난다.


돈과 사람. 어떻게 보면 뫼비우스의 띠.

돈을 벌려면 사람들과의  시간을 갖기 어렵고, 시간을 가지면 돈을 벌기 어렵다.


적당히 벌고 사람과의 시간을 많이 가지는 것도 나쁘지 않다.

하지만 그러면 노후가 걱정된다.


음... 길어진다...


마무리하자면

돈을 많이 벌기 위해 노력.

사람과의 관계를 위해 노력.

하자.

2019년 7월 10일 수요일

grep 사용 예제.

로그 데이터에서 필요한 부분만 추출하려고 하였다.
필요한 부분은 [f1]이라는 부분의 바로위 라인 이다.
처음에는 노트패드++에서 모든 파일을 열고 하나씩 복사 하려고 했는데, 데이터가 어마어마하게 많아서
grep 으로 처리 했다.
윈도우10에서 명령어 창을 열고 bash 라고 커맨드를 입력하면 linux 커맨드를 사용할 수가 있게 된다.


실제 데이터 샘플
...
2019-06-25 오후 1:14:53 [INTERFACE] [310166] [2201] [211.252.80.44:5614] Receive Reqeust ==================================================
2019-06-25 오후 1:14:53 [INTERFACE] [310166] [2201] [211.252.80.44:5614] [02 20 19 06 25 13 14 51 0A 84 02 33 31 30 31 36 36 32 32 30 31 66 31 00 B7 00 05 00 00 00 FF FF FF FF FE 00 00 28 DC 31 30 31 30 30 31 30 31 30 37 33 38 37 30 35 32 00 00 02 A2 01 16 27 00 00 00 00 00 02 20 19 06 25 11 57 53 13 23 45 00 00 07 04 BF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FE 7A 03 ]
2019-06-25 오후 1:14:53 [INTERFACE] [310166] [2201] Thread reqINS [f1]
...


조건
1. [f1]를 찾아서 한줄 위에 있는 부분을 가져온다.
2. 그 중 Send가 들어간 부분을 제외한다.
3. 시간 순서대로 sorting 해야 한다.



최종 명령어
grep -h -r -B1 '\[f1\]' ./  | grep -vE '\[f1\]'  | grep -v '\-\-' | grep -v 'Send' | sed 's/\ \([0-9]\)\:/\ 0\1\:/g' | sort  -k2 -k3.1,3.2 -k3.4,3.5 -k3.7,3.8  > sort_match.txt


--------설명--------
:: << 구분

-h :: 파일이름 없이 출력
-r :: 하위 디렉토리
-B1 :: 검색된 위치 바로 위
'\[f1\]' :: 실제 검색 할 키워드, original keyword : [f1]
./ :: 검색 위치
grep -vE '\[f1\]' :: 바로 위 라인만 필요하고 실제 검색 된 위치는 필요없으므로 제외 시킴
grep -v  :: '\-\-' 검색 라인마다 추가되는 데, 옵션이 따로 있을 것 같지만 급해서 제외 시킴
grep -v 'Send' :: Send 는 제외
sed 's/\ \([0-9]\)\:/\ 0\1\:/g' :: sort 를 해야 하는 데, 데이터의 시간 일자가 '2019-06-25 오후 2:58:06' 이런식으로 시간이 02가 아닌 2이라서 sort가 안됨. 그래서 ' 2:'를 ' 02:'로 변경시킴
sort  -k2 -k3.1,3.2 -k3.4,3.5 -k3.7,3.8 :: '2019-06-25 오후 2:58:06' 의 형태를 sort 시킨다. 일자는 모두 같은 날이여서 포함 시키지 않았다.
k2 는 오전, 오후를 부분,
k3.1,k3.2 는 시(02),
k3.4,3.5는 분(58),
k3.7,3.8는 초(06)를 기준으로 sort 한다.

2019년 6월 20일 목요일

spring boot mybatis 에서 rollback 이 안되는 문제, 해결 한 결과


기본 base가 되는 table이 있고, 그 테이블에 대한 이력을 저장하는 history테이블이 있을 경우, base가 insert가 성공하고, history에서 에러가 발생할 경우 rollback이 되지 않는 문제가 있어서 여러가지 테스트를 해 본 결과이다.


1. 컨트롤러에서 base와 history 두개의 service를 가져와서 처리하는 경우 rollback이 되지 않는다.
서비스단에서 @Transactional 를 주고 처리를 해야 rollback이 된다.

2.Transactional 어노테이션은 클래스에 줘도 적용된다.


3. 이 부분 때문에 고생했다.
아래와 같이 강제로 익셉션을 발생시키면서 try catch로 잡으면 rollback이 안된다.
아래와 같이 메소드에서 throws Exception을 해 줘야 한다.
이 때 강제로 발생시키는 익셉션은 (rollbackFor = Exception.class) 옵션을 줘야 rollback이 된다.

@Transactional(rollbackFor = Exception.class)
public class CompanyRoleService extends GenericService<CompanyRole, CompanyRoleRequest> {

...
    public int saveWithHistory(CompanyRole object) throws Exception {
        AddBaseEntity.addCreatedBy(object);
        object.setUseYn("Y");
        object.setDeleteYn("N");
        int baseSuccessCount = baseMapper.insert(object);
        if(baseSuccessCount>0){
            throw new Exception("test");
        }
...


2019.07.26 추가.
4. try catch로 롤백 하는 방법
https://stackoverflow.com/questions/25738883/spring-transactional-annotation-when-using-try-catch-block


메소드에 선언.
@Transactional(rollbackFor={MyException1.class, MyException2.class, ....})
public Result doStuff(){
   ...
}

or

프로그램 방식으로 rollback
public Result doStuff(){
  try {
    // business logic...
  } catch (Exception ex) {
    // trigger rollback programmatically
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  }
}


2019년 6월 19일 수요일

queryDsl로 groupBy having 사용시 에러 발생.

queryDsl로 groupBy having을 사용할 때 아래와 같은 에러가 발생한다.
nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: having near line 3, column 1 [select count(distinct multiLangInfo.languageCode)\nfrom com.charzin.cems.api.model.multiLang.MultiLangInfo multiLangInfo\nhaving multiLangInfo.languageType = ?1]


문제의 원인은  fetchCount()라는 전체 개수를 가져오는 함수를 사용하는 데, 이 함수가 만들어 주는 sql 쿼리문이 잘못 되었다. 위에 오류내용에 나와 있듯이 그냥 groupby를 없애버리는 쿼리를 만든다.

할 수 없이 전체 개수를 구해오는 쿼리를 따로 만들었다.

보통 group by 카운트를 가져오는 from 절 subquery는 queryDsl에서 지원하지 않는다.
여기서 확인.

할 수 없이 네이티브를 사용했다.

2019년 5월 27일 월요일

spring mongodb Sort시 에러.

spring mongodb Sort시에 아래와 같은 에러가 발생한다.

Query failed with error code 96 and error message 'Executor error during find command :: caused by :: Sort operation used more than the maximum 33554432 bytes of RAM. Add an index, or specify a smaller limit.' on server localhost:27017

조회하려는 테이블이 log성 테이블이라 백만건이 넘어간다.
Sort 하려는 필드는 lastUpdated 이다. 해당 필드를 index에 추가 해서 해결했다.
index 추가하는 건 compass로 접속 해서 collection 선택하면 나오는 index 탭에서 쉽게 할 수 있다.

근데, compass에서는 index 설정을 안해도 잘 된다. 어떻게 되는 건지 모르겠다.

2019년 4월 17일 수요일

mysql federated 트래픽 증가 문제.

어느 날 갑자기 트래픽이 약 2배이상 증가한 것을 확인 해 보니 nethogs 로 확인 해 보니
 mysql 프로세스가 문제 였다.

federated 를 사용하여 간단한 상태체크를 하는 테이블을 하나 만들어 사용중이였는 데, 이게 문제 였다.

원인은 federated 테이블을 select 해 올 때 index를 타지 않으면 모든 데이터를 가져온 후 처리 하는 방식이였다.

약 22,000건 정도의 데이터를 가져오는 데, 약 1.5M 정도의 데이터를 사용하고 있었다.


         SELECT
        *
       FROM CHARGER_STATUS
       WHERE send = 'N'
       AND createdAt > @intervalTime

createdAt(timestamp)에 index를 설정하고 실행 하니 2K정도로 줄어든 것을 확인 할 수 있었다.

2019년 4월 15일 월요일

mysql http post json 전송 트리거

mysql http post json 전송 트리거


테이블에 값이 insert 되면 trigger를 이용하여 http post를 전송하도록 한다.
mysql 자체적으로는 해당 기능을 지원하지 않는다.

검색해 보니 mysql의 UDF(user define function)를 이용하여 만들어진 mysql-udf-httpmysql-udf-http lib가 있다.


근데 최근 업데이트 2013년이다. 찜찜한 면이 있지만, 소스를 살펴보니 별 거 없다.
libcurl을 이용하여 http 전송해 주는 c로 짠 플러그인이다.



소스를 서버에 받은 후 압출을 풀고 컴파일 하면 된다.
문서상으로 되어 있는 설치가이드는 mysql을 소스 설치 했을 때 상황으로 보인다.
yum을 이용하여 설치 하였기 때문에 config 설정이 조금 다르다.
config 시 mysql_config 명령어를 사용하는 데, mariadb-devel를 설치해야 한다.


sudo yum install mariadb-devel -y

sudo wget https://github.com/y-ken/mysql-udf-http/archive/master.zip

unzip master.zip


or
(git 명령어가 있으면)
git clone https://github.com/y-ken/mysql-udf-http.git


여기서 소스를 조금 수정 해야 된다.
실제 테스트 해보면, http_post로 json 전송하면 받는 server에서 json 타입으로 인식을 하지 못한다.
json으로 post 전송하기 때문에 header에 "Content-Type: application/json"이 필요하지만 그런 설정 부분이 없다.
워낙 소스가 간단해서 http_post function을 복사해서 http_post_json을 하나 만들고
해더만 아래처럼 추가 했다.
...
  if (curl)
  {
    struct curl_slist *hs=NULL;
hs = curl_slist_append(hs, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs);
...

소스 수정 파일


재컴파일 후 mysql 재시작 후 function 등록.
create function http_post_json returns string soname 'mysql-udf-http.so';

테스트 해보면 정상적으로 인식 된다.



cd mysql-udf-http-master/

sudo CPPFLAGS="-I/usr/include/mysql" sh ./configure --with-mysql=/etc/my.cnf   --enable-shared --libdir=/usr/lib64/mysql/plugin && sudo make && sudo make install



설치가 정상적으로 완료 되었으면 /usr/lib64/mysql/plugin 디렉토리에 mysql-udf-http.* 파일들이 생긴다.
동적으로 인식이 되기 때문에 mysql 재시작은 안해도 된다. (*** 같은 이름으로 다시 넣으면 인식 안된다. 그럴 때는 재시작하자)

mysql console 상에서 function을 등록해 준다.

create function http_get returns string soname 'mysql-udf-http.so';
create function http_post returns string soname 'mysql-udf-http.so';
create function http_put returns string soname 'mysql-udf-http.so';
create function http_delete returns string soname 'mysql-udf-http.so';


사용법
SELECT http_get('<url>');
SELECT http_post('<url>', '<data>');
SELECT http_put('<url>', '<data>');
SELECT http_delete('<url>');

테스트로 가져오면 잘 가져온다.
select http_get('http://example.com/');



lib_mysqludf_json을 설치해서 json 타입을 리턴 받을 수 있다.


소스를 다운받은 후 so 파일로 만들어 주면 된다.
이건 make를 지원하지 않아 다른 방식으로 만들어야 된다.
같이 다운받아지는 so 파일을 사용하려고 봤는데, 32bit이다.
[root@VM1554776686489 lib_mysqludf_json]# file lib_mysqludf_json.so
lib_mysqludf_json.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped

삭제 하자.

git clone https://github.com/mysqludf/lib_mysqludf_json.git

cd lib_mysqludf_json/

gcc -fPIC -shared -o lib_mysqludf_json.so -I/usr/include/mysql/  lib_mysqludf_json.c


만들어진 lib_mysqludf_json.so 파일을 plugin 폴더로 넣자.
mv lib_mysqludf_json.so /usr/lib64/mysql/plugin/

.sql 파일을 보면 function 만드는 법이 나온다. 복사해서 쓰자.


mariadb 기반으로 설치 하였다.


https://github.com/y-ken/mysql-udf-http
https://github.com/mysqludf/lib_mysqludf_json