memcached increment always return false codeigniter.. 낫웤킹


배경 설명

문제상황

페이지 내에서 아주아주 크고 서비스내 여기저기서 빈번히 이용하며, 트랜잭션 걸려 사용하는 테이블을 매번 조회해서 보여주어야했다.

문제의 해결방법

선임이 매번 db에서 조회하는 것이 불필요하다했다. 그래도 매번 db 조회하는 것이 좋지 않다는 것은 알아 memcached를 사용하고 있었다. db를 조회한뒤 memcached에 60초동안 넣어두고, 또 60초 동안 넣어두니까 이정도면 괜찮지 않냐고 물었다. 

선임의 반응은 탐탁치 않았다. 캐싱을 이용하라 했다. 멤캐시로 겟하고, 늘어나는 것은 멤캐시 인크리먼트를 시켜서 불필요하게 db를 조회하는 일이 없도록 하는 것이 좋겠다고 하였다. 

(그 당시에는 항상 그냥 해왔던 부분이어서 음.. 꼭 해야하나? 라고 생각했는데 하고나니까 정말 필요했던 것 같다.)

그렇다면, 이제 구현해야할 나의 임무

  1. memcached로 get해서 보여주기
    1. memcached로 get했을때 없으면 초기 db에서 조회해서 memcached save 해주기
  2. 그 db에 insert가 생기는 순간에 memcached increment해주기.(매번 db를 조회하지 않을거기때문에) 

그래서 해결했나요?

해결하긴 해결했다. 하지만.. 껌이라고 생각했다 돌씹은 느낌이었다.. 코딱지를 파는 임무를 받았으나 너무 오래 많이파서 코피난 느낌이었다.. 

"memcache get쓰고있고,  save도 쓰고있으니까! increment하나 추가하는게 뭐 얼마나걸리겠어" 했지만 나는 또 삽질에 삽질을 했다. 어디서? increment에서..!


어떤 삽질을 하였나요?

우선 php.net의 memcached 사용법을 보았다. 그리고 memcached incrment 사용법을 보았다.
역시 깔끔깔끔했다.
<?php
$m 
= new Memcached();
$m->addServer('localhost'11211);

$m->set('counter'0);
$m->increment('counter');
$n $m->increment('counter'10);
var_dump($n);

$m->set('counter''abc');
$n $m->increment('counter');
// ^ will fail due to item value not being numeric
var_dump($n);
?>

The above example will output:

int(11)
bool(false)

음 increment는 당연하게 int만 되는 것이군. false 혹은 true를 반환하는 군! 했다.

예제와 똑같은 코드를 사용하고 싶다만, 우리 회사는 코드이그나이터의 캐싱드라이버를 사용하고 있다. 프레임워크가 도와주는데 굳이 직접 생성하여 쓸필요가 없지! 했다.


그럼 이제 내가 항상 쓰던 save를 해볼까 ^-^ 했다.

$this->cache->memcached->save('yujinee', 1, 0);

'yujinee'라는 키에 1이라는 값을 영구적(0)으로 넣고자 했다. 음 굿! 잘 된다.


그럼 이제 내가 항상 하던 get을 해볼까?

echo $this->cache->memcached->get('yujinee');

'yujinee'라는 키로 조회를 하면? 1이 나온다. 


그럼 이제 처음으로 써보는 increment 고고고~! 

$this->cache->memcached->increment('yujinee');
echo  $this->cache->memcached->get('yujinee');
내가 기대한 값은 increment에 키값만 넣은 경우 1이 늘어나기 때문에 yujinee에는 2가 되어있는 상황. 하지만.. 1이 나왔다.
var_dump($this->cache->memcached->increment('yujinee')); 로 찍어보니.. 
bool(false) 가 나왔다. 

나의 삽질목록.

  1. 아 뭐야~ php.net참고해보니 int가 아닐때 false를 뱉던데.. save 할때 int로 값을 줘볼까? 
    1. $this->cache->memcached->save('yujinee', (int) 1, 0); 이렇게! 
    2. $this->cache->memcached->increment('yujinee', 10); 을 하면..1
    3. bool(false);
  2. 아 뭐지..^^;;; ? 다른 것들도 안되는게 있나? 다 찍어보자! 
    1.  $this->cache->memcached->is_supported() 된다. 
    2. $this->cache->memcached->get_metadata() 잘 된다. 심지어 data도 int로 들어가있는 것을 확인할 수 있었다.
    3. $this->cache->memcached->decrement() 안된다. 얘도 자꾸만 false이다.

Codeigniter cache driver
Codeigniter memcache always return false 다 검색해봤다. 

안나온다 나같은 상황이 ㅜ 그래서 직접 선언해서 사용해보았고, 그제서야 문제를 알수있었다. 


문제는 raw 정보! 잡았다 요놈!

$m = new Memcached();
$m->addServer('localhost', 11211);

$m->set('counter', 0);
$m->increment('counter');
$n = $m->increment('counter', 10);

어이없게도 위의 예제코드는 잘만돌아갔다. 그럼 뭐가 문제였던걸까? 문제는 세이브할때 raw를 true로 주지 않았기때문이었다. 
save($id, $data, $ttl = 60, $raw = FALSE) 
여기서 $raw가 false 였었고, 코드이그나이터에서 제공하는 드라이버로 get을 했을때는 int를 반환하지만, 실제로 memcache로 접근해서 찍어보니
array ^^로 구성되어있는 것을 확인할 수 있었다. 

그럼 이제 끝~

내가 항상 사용할때, 그리고 여러 예제들을 보았을때 raw에 대한 파라미터는 주로 생략되어있었어서 저게 문제일거라 생각도 하지 못했다.
코드이그나이터가 원망스럽기도했다. array였으면 array라고 알려주던가 왜 int라고 알려줘서 전혀 감이 오지 않았다. 
교훈은 그거였다. 내가 사용하는 함수가 어떻게 되어있는지를 먼저 확인해볼것! 파라미터를 확인해볼것! 괜히 이상한데를 삽질해서 많은 시간을 버렸다. 
그래도 결과물에 굉장히 만족한다. 오래걸리던 페이지가 디비에 접근하지 않으니 엄청빨라졌따. :> 다음에도 비슷한 조건이 있다면, 꼭 정확한 정보가 아니어도 되는데 너무 많은 db조회를 낭비하고 있따면 cache로 바꿔야겠따. 너무 오래 이걸 골머리를 앓아서 창피하다. 머리가 안돌아갔따.. ㅜㅜ누군가는 이걸봐서 덜 삽질했음 좋겠다.



0. 서론

사내에서 클린코드 스터디를 진행하고 있다. 스터디를 하면서 적용해보고 싶은 것들이 많지만 당장에 바로 적용하기에는 어려운 구석이 있었다. 가장 큰 이유는 부족한 나의 기본기일테지만 책에서 사용하는 언어(JAVA)의 차이점도 어느정도 이유가 되었던 것 같다. 

우연히 github을 둘러보던 도중 클린코드 PHP 버전(jupeter/clean-code-php)을 보게 되었다. 예시가 PHP로 쓰여있어서 조금 더 이해하기 쉬웠고 와닿았으며 코드를 지금보다는 깨끗하게 만들 수 있는 적용점이 보였다. 팀에게 공유하고 읽어보았다. 

영어 문서를 읽을 때마다 느끼는 건데, 그냥 온전히 이해하며 읽는 것이 아니라 느낌으로 해석하며 읽을 때가 있다. 아는 단어로 추론하면서 대~충 이런 느낌이겠거니. 하는 것. 분명히 지하철에서 오고가며 읽긴 다 읽은 것 같은데 머릿 속에 남은 것은 없다. 조금 더 내 머릿 속에 꼭꼭 잘 담아둘 수는 없을까. 

새해 목표중에 영어 공부를 하자! 근데 나의 직함은 개발자라고 하니 조금 더 실용적으로 영어 공부를 해보자! 영어 블로그를 번역해보자! 라는 목표가 있었다.  PHP 버전 클린코드가 조금 더 많은 사람에게 쉽게 읽혔으면 좋겠단 생각이 들었다. 근데, 마침 수많은 translation 중 korean은 없어서 내가 비벼(?) 볼수 있겠단 생각이 들었다. 깃헙 계정은 있으나 이전회사에서 업무하기 위해 사용했을 뿐이었다. 자발적으로 생성한 프로젝트도 없고(깃헙에는.. ㅎㅎ) 남의 코드를 fork 해서 뭔가를 해본 적은 없었다. 개발자로 일하고 나서부터 막연하게 멋지다고 생각했던 것은 남의 소스를 fork해서 PR을 날리고 무언가의 기여를 하는 것이었다. 그냥 막연하게 멋있었다. 용기있고 멋진 행동이라고 생각했다.

정리하자면 내가 번역을 진행한 이유는 다음과 같다.

1. PHP에서 적용할 수 있는 클린 코드를 꼭꼭 머릿속에 잘 담아 두고 싶다.

2. 새해 목표인 실용적인 영어 공부를 해보자.

3. 더 많은 사람에게 이 내용이 읽히고 공유되었으면 좋겠다. 

4. 나도 fork하고 기여해보자. 왜냐하면 그게 멋있어 보였으니까. 키키..


여튼 그래 빠르게 번역을 시도해보았다. 번역작업이 뭐 어렵겠어 했는데 생각보다 발걸음을 내딛는 것 부터 어려웠다. 

이 글에서는 번역작업 진행 과정과 느낀점을 작성해보려 한다. 혹 나같은 초보 개발자가 같은 걸 시도할 때 도움이 되었으면 해서 그리고 시도하는 사람이 많이 늘었음 해서.. 


1. 번역작업 진행 과정

1. fork하기!

우선 번역작업을 하기 위해서는 번역하고자 하는 프로젝트를 fork한다. 화면의 맨 오른편 Fork를 누른다


fork를 누르면 나의 repository에 프로젝트가 생긴다.



2. clone하여 작업 환경 만들기

그냥 바로 master에서 번역을 할 수 있으나 나는 브랜치를 새로 따서 진행을 했다. 번역작업은 readme.md 파일을 수정하는 것이어서 굳이 clone하지 않고 readme.md파일을 클릭한뒤 연필 아이콘을 눌러 edit할 수 있다.  작업하면서 바로바로 preview changes를 볼 수 있는 점이 좋은 것 같다. 


나는 clone을 떠서 내 개인 PC에서 작업하였다. 


여기서 clone or download를 클릭한뒤 클립보드에 복사하여 terminal 에서 git clone (복붙)을 해도 되고 sourcetree같은 툴에서 새 프로젝트를 만들기를 한 담에 복붙을 해도 되고 zip을 받아도 되고 그렇다. 나는 sourcetree로 작업하였다. 보다가 맘에 안드는 번역은 제외해서 commit하고 추가적으로 진행하고 싶어서…


3. 번역을 합니다.


 번역을 한다. (영어사전과 파파고 구글 이것저것을 다 켜놓고) commit을 하고 push하고를 반복하다보면 어느새 번역이 끝나있다. 나의 경우에는 master-translation-ko라는 이름으로 브랜치를 새로 땄기 때문에 나의 master에 머지리퀘스트를 날리고 합치는 작업을 했다. 그렇게 하니 이제 yujinee/clean-code-php에는 깨끗한 한글판만 남게 되었다.


4. 이제 한글판을 추가했다고 Pull request를 날려본다. 

다음과 같은 한줄을 추가한다. 나는 patch-1이라는 브랜치가 있길래 거기에다가 했다. korean flag를 찾아서 달때에는 괜히 뿌듯했다. 


이제 내가 fork한 원본 프로젝트로 들어가 master에 pull request를 날려준다. 

그럼 이렇게 나의 요청이 생성된 것을 볼 수 있다.

5. 듀근듀근 MERGE 해주기를 기다린다.

괜히 두근두근 했다. 이틀 정도를 기다렸다. 


6. MERGE 완료!

나의 PR이 merge 된 것을 볼 수 있다. 또한, README 파일에도 KOREAN이 추가되어있는 것을 볼 수 있었다. 

이 소스에 contributors를 클릭해보면 여기에도 내가 추가된 것을 볼 수 있당.. 히힣...


3. 번역을 하면서 내가 배운 것과 느낀 것

  1. 깃헙 마크다운을 배웠다.
    1. 편하다는데 뭐가 편하다는 건지 몰랐는데 마크다운 문법에 익숙해지니 아 이래서 편하다는 구나 하고 깨달았다. 이제 회사에서 git 올릴때 에디터 클릭하지 않고 예쁘게 작성할 수 있을 것 같아서 기분이 좋았다. 링크를 다는 것, 목차를 만드는 것, 두꺼운 글씨를 쓰는 것, 헤더를 쓰는 법 등을 배웠다. 
  2. 일단 한번 해보자가 중요한 것 같다.
    1. 시도하겠다고 맘만 먹고 질질끌기만 했었다. 한 단락만 번역해보자는 마음으로 막상 시작해보니 재미있었고 후딱 끝낼 수 있었다.
  3. 그냥 읽는 것보다 내용을 조금 더 이해하게 되었다.
    1. 그냥 영어로 쭉 봤을 때 이해했다고 생각했는데 문장으로 그걸 바꿔보려고 시도해보니, 이해하지 못하고 있었다는 것을 알게되었다. 
  4. 무엇보다, 뿌듯하다.
    1. 첨으로 생판 남의 소스를 fork하고 PR을 날려보고 contributor가 되어보았는데, 생각보다 기분이 좋고 뿌듯하다.
    2. 다른 사람들에게는 중요하지 않겠지만 나에게는 가장 중요하다. 내가 느꼈다는 것이 중요하다. 적어도 다음에는 더 편하고 재밌는 마음으로 같은 작업에 참여할 수 있고 시도해볼 수 있을 것 같다.
  5. 오역과 의역이 많은 같다
    1. 다른 사람이 많이 많이 오역과 의역을 발견해주고 커밋해주고 PR 날려주었음 좋겠다. 진심으로..



4. 그냥 드는 생각

뭐 별거 한것도 없으면서 나너무 에바쌈바오바꽁치참치인가하는 생각이 들기도 했지만.. 그냥 내 첫 발걸음이 기분이 좋고 뿌듯한걸 어찌해야하나 싶다. 키키.. 결과보다는 시도와 노력에 가치를 두는 사람이 되고 싶다. 

평생 개발자를 할 것인지 그리고 정말 개발자가 될 수 있을련지는 아직 잘 모르겠다. 하지만 나는 어제보다는 더 개발을 좋아하게 된 것 만 같은 느낌이 든다. 조금씩 차근차근 나가다 보면 나도 개발자라고 스스로를 뿌듯해할 수 있는 날이 오지 않을까 싶다. 

개발을 미친듯이 잘하기보다는 계속해서 탐구하기를, 그리고 다른사람에게 좋은 영향을, 도움이 되는 사람이 되었으면 좋겠다는 생각이 든다. 또 번역할 만한 거리가 없을지 찾아봐야겠다. 혹은 이번에는 readme말고 코드에 기여를 해보면 어떨까? 큰 기여가 아니더라도 작은 기여부터 차근차근히 해가다 보면 더 큰 기여를 할 수 있겠지! 라는 생각이 드는 날이다 :D 

번역한 클린코드 링크는 다음과 같다. https://github.com/yujineeee/clean-code-php


'개발개발 > PHP' 카테고리의 다른 글

memcached increment always return false codeigniter  (0) 2018.07.19
메일건 트랙킹  (0) 2016.12.08
암호화한 코드 링크 유의사항  (0) 2016.10.28
공유하기 썸네일 및 url문제  (0) 2016.10.19

메일건 트래킹하기 위해서는

CNAME을 설정해 두어야 한다. 



암호화를 하게 되면

= + / 와 같은 문자가 들어갈 떄가 있는데 (왜)


링크로 이런 코드를 get으로 보내야 할 때가 있다. 

그 때 이런 문자가 들어가게 되면 링크가 잘리는 불상사가 발생한다. 


$code = str_replace('=', '', $code);

$code = str_replace('+', 'plus', $code);

$code = str_replace('/', 'slash', $code);


한번더 변환해준다음에 링크에 포함하고,

그 다음에 다시 또 각 + /  등으로 바꿔준다


= 는 '' 다


서론. 


우리 사이트 내 다음 5가지의 공유 기능이 붙어야 했다. 

  1. 카카오톡
  2. 카카오스토리
  3. 페이스북
  4. 트위터
  5. 네이버


모든 기능은 각 api의 개발 문서를 참고해서 스크립트만으로 쉽게 만들 수 있다.

쉽게 만들 수 있지만, (항상 그렇듯이) 내가 하려던 것이 되지 않아 애를 먹었다.


그거슨 바로 5. 네이버 공유하기 기능.


네이버 공유하기 기능에 대한 개발 문서는 다음에서 찾아볼 수 있다. 

https://developers.naver.com/docs/share/navershare   



첫번째 당황. 하란대로 했는데요..?


넘나 간단하고 명료한 예시에서는 다음과 같이 하면 된다고 하는데... 8ㅅ8 거짓부렁이다.


인코딩 : UTF-8
요청방식 : GET방식
http://share.naver.com/web/shareView.nhn?url=인코딩한URL값&title=인코딩한title값


#파라미터설명
1url문자열인코딩한 공유할 웹 URL
2title문자열 (optional)인코딩한 제목 문자열



음...  title이 optional이라고 되어있는데, title을 넣어주지 않으면

"url 또는 title 정보가 없습니다." 라는 alert이 뜨면서 안된다. 


url과 title모두 인코딩해서 넘겨주어야 에러가 나지 않는다 :) 


스크립트로는 다음과 같이 작성해주면 된다.


<button type='button' id='naver_share'>네이버 공유 버튼</button>


<script>

$("#naver_share").click(function(e) {     

var share_url = '공유할 url주소';

var title = '포스팅/글의 제목';

  var url = 'http://share.naver.com/web/shareView.nhn?url='+encodeURIComponent(share_url)+'&title='+encodeURIComponent(title);

  window.open(url);

   });

</script>



두번째 애먹음. 썸네일 왜 그래요.. url.. 왜 나한테 그래요...


우리사이트 내에서 공유할 주소에는 각 사용자의 추천코드가 함께 붙어있다. 즉, 공유된 블로그/카페의 포스팅을 타고 들어오면, 추천코드가 함께 붙어있어야 하는데....

네이버 공유하기 api로 포스팅 된 것에는 썸네일과 링크가 마음대로 붙어버렸다.


이를 테면, 내가 공유하려던 url이

http://prosaist0131.tistory.com/8 이라면,

링크가 자꾸 http://prosaist0131.tistory.com으로만 붙어버렸다. 썸네일도 마음대로 되지 않았다. 


애를 먹다가, 네이버 개발자 포럼을 확인하다 다음의 질문 글을 발견하였다.

http://forum.developers.naver.com/t/topic/1133


글을 읽어보니, 네이버는 http://ogcrawler.blog.naver.com/crawler.json 를 통해서, 링크의 정보를 가지고 오는 것 같다는 거였다.

해당 crawler.json에 내가 공유하려던 url을 확인해보았다. 


썸네일과 링크가 내가 공유하려는 페이지의 메타 태그에 있는 것으로 연결이 되고 있었다. 

그래서 다음과 같이 간단히(?) 해결했다.


내가 공유하려고 했던 페이지 url을 메타태그로 가진 페이지를  만들어서 그 페이지를 공유하도록 했다. 

예를 들면 다음과 같다. 


<!DOCTYPE html>

<html>

<head>

<title>페이지 이름</title>

<!-- meta info -->

<meta name="keywords" content="키워드들">

<meta name="description" content="설명">

<meta property="og:title" content="페이지제목 "/>

<meta property="og:image" content="원래 공유하려고 했던 썸네일 이미지"/>

<meta property="og:url" content="원래 공유하려고 했던 페이지 URL"/>

<meta property="og:description" content="구체설명"/>


<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />

<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>

<meta charset="utf-8">

(생략).




해결~ 끄읏...

+ Recent posts