[백업][가리사니] 정직한 (!?) 조회수 기능을 만들어보자!
html

이 문서는 가리사니 개발자 포럼에 올렸던 글의 백업 파일입니다. 오래된 문서가 많아 현재 상황과 맞지 않을 수 있습니다.

조회수 업데이트 깨진링크 임시

예전 구-가리사니 시절부터 사이트에는 조회수를 표시하는 기능이 없었습니다. 몇몇 사용자분들께서 물어보셨는데 이유는 다음과 같습니다.

현재 가리사니는 두차례(새로 DB를 구축한걸 기준:리뉴얼 제외) 새로 만들어졌는데 구-가리사니 보다 앞선 사이트에선 조회수 기능이 있었고.. 애니편성표의 위력!? 으로 사이트에 많은 방문자가 생기면서 자연스럽게 자신의 조회수를 조작하는 사람들이 생기기 시작했습니다. (사이트의 사용자 유입을 위해 만들어졌지만… 사이트 전체가 애니화 되면서 결국 애니사이트를 따로만들어서 다른분께 인수인계 해드렸고…. 예상대로.. 새로 만든 가리사니는 접속자 수가 인기없는 블로그 수준이 되었습니다. 하하하하….. 여러분 자주 방문해주세요 ㅠㅠ) 따라서 조회수 조작을 방지할 목적으로 쿠키, 세션을 사용하다가 _근성있는 조작쟁이?_들 때문에 IP를 이용해 막는 방법밖에 없다고 생각했고.. IP로 막을 경우 소모되는 자원을 쓰느니 차라리 조회수를 없에버리는 것이 낫다고 생각하여… (당시엔 댓글이 잘 달려서 조회수가 없어도 댓글로나마 짐작할 수 있었습니다.) 조회수 기능이 빠지게 되었습니다. 하지만 이정도로 접속률이 낮은 사이트에 조회수 기능마저 없다면, 댓글이나 추천이 생기지 않는이상 자신의 글을 얼만큼 읽었는지 알길이 없다는 문의가 있었고.. 고민끝에… 조회수 기능을 넣기로 하였습니다.!!!

조회수 조작을 막아보자!

보통 조회수의 조작을 막기위해 사용하는 방법은 3가지가 있습니다. 쿠키, 세션, IP 자원절약 : »> 을 여러개 한것은.. 넘을 수 없는 벽이 있습니다. 하하.. 쿠키 »»» 세션 »»» IP 조작방지 IP »»»> 세션 >= 쿠키 실제 현업 사용도 : 현업에서 세션으로 거는 경우는 못봤습니다. 마찬가지로 IP로 거는 경우도 극소수입니다. 조작방지를하지않음 »> 쿠키 »»»»»» IP 쿠키, 세션, IP 에 대해서 살펴 보았지만.. 쿠키, 세션은 사실상 클라이언트에서 너무나도 쉽게 조작가능 하기 때문에 적당한 방법은 IP 밖에 없습니다. 쿠키나 세션만 막게된다면… 오히려 정상적인 사용자만 뷰가 덜 찍히게 되고… 비정상 적인 사용자가… 보다 많은 뷰를 얻을 수 있게됩니다…. 하하하;;;

IP로 조회수 조작을 막는 방법은 어떤 것이 있을까?

가장 쉽게 생각할 수 있는 방법은 모든 게시물이 IP를 기억하는 것이 되겠지만… 조회수가 많아지기 시작하면 배보다 배꼽이 더 커기게 됩니다. 정작 “안녕하세요.! 다들 잘지내고 계신가요?” 라는 글에.. IP로 몇 메가바이트!! 이상이 쌓이게 될 수 있기 때문입니다. 그래서 두번째로 생각한 것은 IP 테이블을 하나 만들고 하루에 한번씩 기록하게 하는 것 입니다. 즉, 한 IP에 한하여 한 게시물당 하루 1의 조회수를 올릴 수 있는 것 입니다.

CREATE TABLE "아이피 확인 테이블"
(
	date date NOT NULL DEFAULT now(),
	ip inet NOT NULL, -- pg-sql의 IP 타입의 자료형입니다.
	jn bigint NOT NULL, -- 주제번호
	CONSTRAINT "인덱스 이름" PRIMARY KEY (date, ip, jn)
)
CREATE OR REPLACE FUNCTION "아이피 중복확인 후 조회수를 올려주는 함수"
(
	_jn bigint, -- 주제번호
	_ip inet -- 아이피
) RETURNS void AS $$
BEGIN

	IF (SELECT 1 FROM "아이피 확인 테이블" WHERE date = current_date AND ip = _ip AND _jn = jn LIMIT 1) IS NULL
	THEN
		INSERT INTO "아이피 확인 테이블" (ip, jn) VALUES ( _jn);
		-- 최대 hit수를 2000000000 으로 제한 (pg-sql에서 int는 4바이트 정수 (부호있음) 이다.)
		UPDATE "글테이블" SET hit = least(hit + 1, 2000000000) WHERE jn = _jn;
	END IF;

END;
$$ LANGUAGE 'plpgsql'

위처럼 처리하게 된다면 하루에 한번정도 계속해서 쌓여질 “아이피 확인 테이블”의 어제 이전 날짜 데이터를 비워주기만 하면 첫번째 생각했던 방법보단 가벼운 방법으로 조회수 조작을 처리할 수 있게 됩니다.

이 로직이 무거워질정도로 사용자가 많아질 경우 또 다른 방법은 없는 건가요?

필자가 알고있는 조회수 조작을 방지하는 유명한 서비스는 유튜브가 있습니다. 유튜브에서는 새로 동영상을 올렸을때 조회수 301에서 멈추게 되며 그뒤로는 여러 뷰 서버를 분석 후 통계를 내서 일괄적으로 업데이트 하는 방식을 쓰고있습니다. 유튜브의 조회수는 광고수입과 밀접한 관계가 있기 때문인데요. 자세한 사항은 아래 영상에서 확인 할 수 있습니다. @[Youtube oIkhgagvrjI] 유튜브가 어떤 로직을 사용하는지 정확히 알수는 없지만.. 아마 구글 애널리틱스같은 통계 시스템과 비슷한 방법을 쓸 것으로 추측하고 있습니다. 사이트의 통계 시스템의 경우 접속한 사용자를 여러가지 분류로 나누어 그래프 등의 다양한 형태로 보여줘야하는데.. 이 로직이 실시간으로 돌아가게 된다면 어마어마한 자원이 소모되고 속도 또한 극악으로 내려가게 됩니다. 때문에 보통 쓰는방법은 사용자가 접속할대 어떠한 테이블에 브라우저에어젠트를 포함한 여러가지 해더나 정보들을 무조건 insert 합니다. 몇시간 혹은 하루 주기로 도는 배치시스템이 위 insert 된 원본데이터를 통계에 적합한 형태로 가공하여 저장합니다. 이 방법을 쓰게되면 select로 중복등을 확인하는 로직이 필요없고 데이터를 삽입하는 테이블의 인덱스를 제거하여 삽입속도와 자원을 개선할 수 있습니다. 또한 아이피당 접속횟수라던지 통계에 더 유용한 기술들을 쓸 수 있게 됩니다. [ex) 비정상적으로 뷰가 많은 아이피는 통계에서 제거한다.] (어차피 몇시간에 한번씩 도는 배치는 정말 엄청나게 데이터가 많지 않은 이상.. 굳이 인덱스가 없어도 상관 없습니다. : 있어도 조금만 있으면됩니다.) 이 외에도 유튜브처럼 조회수가 수입과 밀접된다거나 이와 유사한 주요성 때문에 유사한 로직들이 많이 있지않을까 생각해봅니다.!

추신

제글은 항상 끝맺음이 이상한거 같습니다. 하하하하…