The era of “Know-Right”

The paradigm of knowledge keeps changing. In the beginning, it was the era of know-how. An individual’s experience and mastery were the greatest assets, passed down only within a person’s head or a limited part of an organization. The central question in that era was naturally “How do we implement this?” Anyone who could answer that how well was considered a valuable talent and central to work.

Then time passed through the eras of know-what and know-where. As information became easier to find and more high-quality content was created, developers could get a lot of work done simply by searching Google, Stack Overflow, and other sources. Still, the core was know-how — because the quality of information was high enough that finding it generally meant it was reliable.

But now that period is becoming the era of “Know-Right.” (I’m not sure if this term really exists or is correct — I’m using it for my own thinking…) Information can be composed easily (I think “composed” is more accurate than “searched”), but now we must verify the reliability of that information. (I’m using AI assistance to write this, so you should verify this text’s reliability too.)

Here is a simple summary in a table:

CategoryKnow-howKnow-whatKnow-whereKnow-Right
Focus Era1990s ~ mid-2000slate 2000s ~ mid-2010slate 2010s ~ early 2020smid-2020s ~ (AI era)
Core QuestionHow do I implement this?What should I use?Where is the answer?Is this answer really correct?
Location of KnowledgePersonal experience, internal docsOfficial docs, patterns, best practicesSearch engines, GitHub, Q&AContext, constraints, system understanding
Developer StrengthSkilled hands-on abilityCorrect selection abilityFast searching abilityJudgment, validation, reasoning ability
Learning MethodRepetition, trial-and-errorCase study, comparative learningOptimized search, reference tracingDeep understanding + cross-validation
Cause of FailureLack of experienceWrong choicesCopy-paste lacking contextAccepting without verification
Role of AIAlmost noneReference toolPowerful searcherBoth a subject of judgment and a tool

So how does this change the way we think? For example, think about a simple Redis failure problem:

EraDeveloper Reaction
Know-how“We tuned it this way before and fixed it.”
Know-what“This issue is caused by KEYS; use SCAN instead.”
Know-where“There’s a solution in the official docs and on GitHub.”
Know-Right“For this workload, SCAN is also risky, and the real problem is the data model.”

When ChatGPT first came out, things weren’t this extreme, but the pace of change keeps increasing and the importance of verification is growing. Now the question arises: So how should people prepare for this? Does it necessarily mean that humans must verify everything?

Some people say that, just as we don’t verify every line of machine code the compiler generates and managers don’t review every result a team member produces, we should accept a certain level of mistakes. That perspective isn’t wrong. But still, a single mistake can cause a huge problem — and while humans can sometimes understand their own mistakes, AI mistakes might be unknowable. (There is no definitive answer here — in a few years this discussion itself might be meaningless.)

One technique to improve LLM reliability is test-time scaling: using a smaller model to evaluate what the larger model generates and filtering out responses below a reliability threshold — effectively enhancing performance by throwing out low-confidence results. This resembles using other models (or smaller ones) to verify output, and it shows why evaluating trustworthiness of results is becoming more crucial for people who use this information.

So my question becomes: How should “people” be educated in this era? …I’ll leave that discussion for another time (maybe — I’m still thinking about it).

[책 리뷰] AI 자율학습 밑바닥부터 배우는 AI 에이전트

“해당 도서는 길벗출판사의 협찬으로 출판사에서 도서를 제공받았습니다.”

AI 관련 일을 하게 되었지만, 사실 AI 자체는 잘 모르는 상태이다보니, AI에 학습이 필요한
상황이었는데, AI를 이용하는 기본적인 방법은 OpenAI와 같은 LLM api를 호출하는 것이지만,
현재는 좀 더 복잡한 작업을 위해서 AI 에이전트를 이용하는 것이 일반적이다. 그러기 위해서
아예 쉽게 할 수 있는 n8n 부터, 좀 더 다양하게 구성이 가능하고(코딩도 필요한) LangChain이나
LangGraph 를 이용하기도 합니다.

그런데 이런 내용을 처음부터 보면, 좀 더 어렵습니다. 좀 더 쉽게 내용을 이해하는 방법이 없을까?
하고 고민을 하게 되는데, 이 책은 이해를 목적으로 이런 프레임워크를 사용하지 않고 AI 에이전트
를 만드는 방법에 대해서 설명하고 있습니다.(원리를 설명한다가 더 좋을듯 하네요.)

그래서 따라하기 형식이기도 하고 내용 자체는 처음에 이해하기 쉽게 되어 있습니다. 프롬프트 체이닝
부터 시작해서 LLM 라우팅에 대한 설명, 각각의 작업을 조율해서 결과를 내는 오케스트레이션-워커 개념
그리고 최종적인 평가까지 전체를 가볍게 다루고 있습니다.(그래서 실제로 LangChain이나 LangGraph에
대해서 더 알고 싶으신 분은 해당 기술을 다루는 책을 보시는게 좋습니다.)

다만 이런 개념을 이해하고 프레임워크를 사용하면, 어떤 개념이 들어가는지, 그게 안된다면 어떻게
적용할 수 있는지에 대해서 더 쉽게 적용할 수 있게 됩니다. AI 에이전트가 복잡하다고 생각하시면
가볍게 기본적인 컨셉을 이해하고 더 복잡한 내용에 도전하시기에 좋은 책입니다.

The era of “Know-Right”

지식의 패러다임은 계속 바뀌고 있다. 초기에는 know-how 의 시대였다. 개인의 경험과 숙련이 가장 큰 자산이고, 이런 것들이 사람의 머릿속이나 일부 조직내에서만 전수되는 그런 시대였다. 그래서 know-how의 시대의 핵심 질문은 “어떻게” 였다. 당연하지만 이 어떻게를 잘 하는 사람이 인재로써 중요한 가치를 가지고, 일의 중점에 있게 되었다.

그런 시기가 점점 know-what, know-where의 시대를 거쳐오게 되지만, 예전보다 정보를 찾기가 쉬워지고, 많은 퀄리티 있는 정보가 생성되면서, 개발자들은 구글, 스택오버플로우드등을 검색해서 많은 일을 처리할 수 있었다. 그래도 그 안의 핵심은 know-how 였다. 정보들의 퀄리티가 높았기 때문에, 찾기만 하면 어느정도의 신뢰도가 보장이 되던 시기.

그런데 그 시기가 이제 “Know-Right” 의 시대가 되고 있다.(Know-Right 라는 단어가 있는지, 맞는지는 잘 모르겠지만, 일단 나는 내 마음대로 생각해서 쓰고 있는…) 정보는 쉽게 구성이 되지만(찾는다고 하지 않고 구성된다라는 용어를 쓰는게 맞다고 생각한다.) 그 정보의 신뢰도를 검증해야 하는 시기이다.(이 글을 쓰는데도 AI의 도움을 얻고 있으니, 신뢰도를 검증하셔야 한다.)

일단 간단히 표로 정리하면 다음과 같다.

구분Know-howKnow-whatKnow-whereKnow-right
중심 시기1990s ~ 2000s 중반2000s 후반 ~ 2010s 중반2010s 후반 ~ 2020s 초2020s 중반 ~ (AI 시대)
핵심 질문어떻게 구현하지?무엇을 쓰는 게 맞지?답이 어디에 있지?이 답이 정말 맞나?
지식의 위치개인 경험, 내부 문서공식 문서, 패턴, 베스트 프랙티스검색 엔진, GitHub, Q&A맥락·제약·시스템 이해
개발자 경쟁력숙련된 손기술올바른 선택 능력빠른 탐색 능력판단·검증·추론 능력
학습 방식반복 경험, 시행착오사례 학습, 비교 학습검색 최적화, 레퍼런스 추적깊이 있는 이해 + 교차 검증
실패의 원인경험 부족잘못된 선택맥락 없는 복붙검증 없는 수용
AI의 역할거의 없음참고 도구강력한 탐색기판단 대상이자 도구

그렇다면 사고 방식은 어떻게 바뀌고 있을까? 예를 들어 간단히 Redis의 장애문제를 생각해보자.

시대개발자의 반응
Know-how“예전에 이렇게 튜닝해서 해결했어”
Know-what“이 문제는 KEYS가 원인이고 SCAN을 써야 해”
Know-where“공식 문서랑 이 GitHub 이슈에 해결책 있어”
Know-right“이 워크로드에선 SCAN도 위험하고, 데이터 모델이 문제야”

ChatGPT가 나온 초기만 해도 이 정도는 아니었다고 생각하지만, 그 변경 속도는 점점 더 바뀌면서 검증의 중요성이 점점 더 커지고 있다. 그런데 여기서 드는 고민은 이것이다. 그렇다면 사람은 어떻게 이를 대비해야 하는가? 꼭 사람이 검증할 필요는 있을까?

일부에서 어떤 분들은, 어차피 우리가 컴파일러가 만드는 기계어를 검증하지 않는 것처럼, 팀에서 매니저가, 팀원의 모든 결과를 직접 다 검토하지 않는 것처럼, 어느 정도의 실수는 용납할 수 있어야 한다라는 의견도 있다. 물론 이것도 틀린 의견이 아니다. 그렇지만 여전히 실수 하나가 굉장히 큰 문제를 만들 수 있고, 사람의 실수는 그 문제를 어느정도 파악하고 있지만, AI의 문제는 그럴 수 없지 않냐라는 의견도 있다.(여기서 답은 없다. 몇년만 지나도 이런 논쟁 조차도 의미가 없을 수 가 있기 때문에…)

LLM의 성능을 높이는 기법주엥 test-time scaling 이라는 방법이 있다. LLM이 생성하는 내용을 더 성능이 작은 SLM으로 평가해서 어느 정도 점수 이하인 것은 버림으로써 도리어 성능을 높일 수 있다는 방법인데, 어느정도 가드레일을 주거나, 나온 결과의 신뢰성을 평가하기 위해서 다른 LLM(혹은 SLM)을 쓰는 것과 유사한데… 신뢰도가 낮은 결과는 버림으로써, 신뢰를 확보한다는 것인데… 이런 정보를 써야 하는 입장에서는 이런 부분을 더더욱 중요하게 봐야 하는 시대가 온 것다.

그래서 생기는 나의 고민은 그렇다면 이런 시기에 “사람”의 교육은 어떻게 되어야 하냐인데… 이 이야기는 다음 기회에… 해보기로 하자.(안할수도 있다. 현재 고민만 하고 있어서…)

[DATA] S3에서 데이터 파티션 하는 법의 진실…

인터넷에서의 위의 링크의 글을 읽게되었다. 데이터 엔지니어링에서 오래 업무를 본 사람들은 습관적으로 아래 이미지와 같은 형태로 데이터를 파티셔닝 하는 경우가 많다. 크게 버컷에 데이터 종류에 따라 나누고 s3://bucket/data 부분 그뒤에 데이터의 생성 날짜에 따라 year=YYYY/month=MM/day=DD 형태로 나누는 것이다.

이렇게 나누면 뭐가 좋을까? 특정 데이터의 날짜로 읽거나 month로 읽거나 year 단위로 읽을 때 다른 데이터를 읽을 필요가 없다. 즉, 필요하지 않은 데이터를 자동으로 제거(pruning)이 가능해진다.

s3://bucket/data/year=2025/month=01/day=01/events.parquet

그런데 위의 방법이 나쁘니, 새로운 방식을 제안한다. 아래와 같이 그냥 하나에 쓰는 방식이다.

s3://bucket/data/dt=2025-01-01/events.parquet

여기서 장점으로 든 예제는 다음과 같은 것이다. 2024년 1월 1일 부터 2025년 2월 10일까지의 데이터가 필요하면 어떻게 표현해야 하는가? 먼저 후자의 방식은 단순히 아래와 같이 간단히 기술이 된다.

WHERE dt >= ‘2025-01-01’ AND dt <= ‘2025-02-10’

그런데 전자의 방식은 좀 더 복잡해진다. 개별 DAY, MONTH, YEAR 단위는 쉽지만, 개별적으로 쪼개기는 쉽지 않기 때문에 코드는 아래와 같이 복잡해진다.

WHERE (year = ‘2024’ AND month = ‘01’ AND day = ‘01’)
   OR (year = ‘2024’ AND month = ‘01’ AND day = ‘02’)
   OR ...
   OR (year = ‘2025’ AND month = ‘02’ AND day = ‘10’)

단순히 보면 누가봐도 후자가 전자보다 좋아보인다. 그리고 현재로는 후자가 더 좋은 방법이다. 그러면 여기에 핵심은 왜 전자의 방식이 유행했나이다. 당연히 좋은 방식을 두고 왜 안좋은 전자를 많이 선택했을까? 데이터 엔지니어들이 혹시나 멍청했던 것일까?

S3는 초기에 나왔던 버전과 현재의 버전의 기능과 성능이 많이 다르다. 실제로 Hive나 Spark 을 s3와 연결하는 것은 굉장한 도전이었던 시기도 있었다. 일단 이 문제의 특징을 몇 가지 살펴보면, 초기의 s3는 hot paritition 이슈가 있어서 prefix별로 shard 데이터를 저장하다 보니, 한 버킷이나 연결된 prefix안에 많은 파일이 있는 것이 좋지 않은 구조였습니다.

이 경우에 전자의 방식도 좋은 방식은 아니지만, 후자는 더 성능 이슈를 일으킬 수 있습니다. 이 시기에 AWS의 권장 사항을 보면 아래와 같은 방법을 제시합니다.

비추천(비추천이지만 전자와 유사한…)

/images-to-process/2024/09/11/184502_5579cb0b97c990f7.jpeg
/images-to-process/2024/09/11/184502_5cd386a19afce9af.jpeg
/images-to-process/2024/09/11/184502_a900fdd2064e3073.jpeg
/images-to-process/2024/09/11/184502_acbe3954657842dd.jpeg

추천(그러나 데이터 쪽에서는 아래 방식을 바로 적용하기는 어렵습니다.)

/images-to-process/5579cb0b97c990f7/2024/09/11/184502_5579cb0b97c990f7.jpeg
/images-to-process/5cd386a19afce9af/2024/09/11/184502_5cd386a19afce9af.jpeg
/images-to-process/a900fdd2064e3073/2024/09/11/184502_a900fdd2064e3073.jpeg
/images-to-process/acbe3954657842dd/2024/09/11/184502_acbe3954657842dd.jpeg

이런 사항에서 하나의 bucket 에 적절히 나눈 위치에 데이터를 넣을려고 하던 나름의 고심이 전자인 것입니다.

그리고 2020년 겨울쯤에 s3에서 list 오퍼레이션에 대한 strong consistency 기능을 제공했습니다. 이게 얼마나 중요햐 하면, hive, spark에서는 s3의 폴더의 내용을 list로 읽어오는데, 이게 특정 시점에 서로 다를 수 있었습니다. 즉 내가 특정 잡이 끝나고, 저장을 했는데, 다른 곳에서는 안 보이거나, 내가 지웠는데, 누가 읽어가서 참조하는 엄청난 이슈죠. 이것도 꼼수를 통해서 변경해야 했는데, 굉장히 힘들었던 기억이 있네요.

다시 한번 정리하자면, 결론은 후자가 더 좋다입니다. 그런데 왜 그랬는지도 한번 정리해 보면 좋을꺼 같습니다.

[책 리뷰] 러스트 클린 코드

해당 도서는 제이펍 출판사의 리뷰 이벤트로 증정받았습니다.

저는 2015년에 러스트를 처음 접했습니다. 하지만 당시에는 샘플 코드만 조금 들여다보다가 “참 어렵다”는 생각만 하고 제대로 익히지 못했습니다. 그래서 지금은 거의 기억이 나지 않는 수준입니다.

새로운 기술이 어렵게 느껴지는 이유는 두 가지가 있습니다. 하나는 관련 배경 지식이 부족해서이고, 다른 하나는 그 기술 자체의 문법과 관습이 익숙하지 않아서입니다. 저 같은 경우는 후자에 가까웠습니다. 이럴 때 좋은 방법은 바로 그 언어의 관습을 이해하는 것이라고 생각합니다.

예를 들어, “좋은 소스를 많이 보라”는 말은 단순히 알고리즘을 배우라는 의미만이 아니라, 많은 개발자들이 공감하는 관습적이고 효과적인 기법을 몸에 익히라는 뜻이기도 합니다. 우리는 이를 종종 디자인 패턴이라 부르죠. 러스트의 경우에도 전통적인 GOF 패턴이 아니라, “러스트다운” 코드 스타일이 자연스럽게 하나의 패턴으로 자리 잡고 있습니다. 이 책은 그런 점에서 기본부터 고급 주제까지 체계적으로 다루며 러스트의 특징을 잘 보여줍니다.

러스트는 여전히 쉽지 않은 언어입니다. 하지만 리눅스 커널이나 Git 같은 핵심 프로젝트에도 점점 도입될 만큼 중요성이 커지고 있습니다. 이 책은 그런 러스트의 난해함을 풀어내면서도 특징을 잘 설명하고 있습니다. 당장 쉽게 이해되지는 않더라도 곁에 두고 읽으면 분명 도움이 될 것입니다.

이번 추석 연휴에 개발방에 한 권 놓아두면, 좋은 동료가 되어줄 것 같습니다.

[책 리뷰] 밑바닥부터 만들면서 배우는 LLM

해당 도서는 길벗 출판사의 리뷰이벤트로 증정받았습니다.

OpenAI에서 GPT가 나온이후로, 수 많은 LLM(Large Language Model)이 나오게 되었습니다. llama나 deepseek, qwen과 같은 sLM 까지 포함하면

굉장히 빠르게 발전하고 있는 분야가 이 부분입니다. 현재 AI 프로젝트라고 하면 대부분 이런 LLM이나 sLM을 이용한 결과를 내는 것이 대부분입니다.

그렇다면 모두가 LLM을 정확히 이해해야 하는가라고 물어보면 사실 그런건 아닙니다. 그런데, LLM을 사용하기 위해서 기본적인 내용은 이해하고 있는 것이 중요합니다.

그리고 어떤 흐름으로 LLM이 발전하는가에 대한 이해도 필요합니다. LLM이 나올수록 이런 내부구조를 아는 사람이 더 LLM을 적절히 이용할 수 있기 때문입니다.

(물론 LLM 마다 구조가 다르지만, 모델의 특징에 대해서 이해하면, 좀 더 정확한 답변을 요구하기 쉬워집니다.)

사실 밑바닥부터 만들면서 배우는 LLM은 ChatGPT 같은 LLM을 기초부터 만드는 책이기 때문에, 내가 이런 수준까지 알 필요가 있을가라고 생각할 수 있습니다.

그런데 1,2,3장을 읽어보면, 생각보다 굉장히 쉽게, 어떤식으로 LLM을 학습시키는지, 그 과정에 대한 지식을 얻을 수가 있습니다. 특히 예전에는 word2vec 이라고

부르는 그런 벡터화 방식부터, 실제로 벡터 임베딩이 어떻게 진행되는지에 대한 지식을 쉽게 얻을 수 있습니다. 이 책의 장점이 여기에 있는데, 일단 자세히는 아니고

어느정도 대략적인 내용만 알고 싶다면, 그냥 가볍게 읽으면, 깊은 이해는 못하지만, 대략적으로 이런식으로 진행되는가에 대한 지식을 얻게 됩니다. 그런데 만약 내가

실제로 만들어보고 싶다면(사실 여기서부터는 지식뿐만 아니라 그래픽카드라는 돈의 문제가 발생하지만) 좀, 더 자세히 책을 볼 필요가 있습니다. 재미난 점은 책 자체는

번역도 읽는 사람에게 쉽게 번역이 되어있습니다. 그런데, 이원래 이 쪽 분야의 내용자체가 어렵다보니, 천천히 책을 제대로 읽어야만 실제로 적용할 수 있는 지식이

이해가 될 것입니다.

책 자체가 400페이지가 조금 넘어가지만, 130페이 분량의 워크북이 있어서, 이걸로 한번 더 내용을 생각할 수 있게 도와줍니다. 어떤 지식이든 책을 읽는다고 해서

바로 이해되어 적용할 수는 없습니다. 특히 LLM의 내부구조 자체가 쉬운 내용은 아닙니다. 그러나 이 책은 그 과정 자체를 최대한 쉽게 풀어서, 이해를 도와줍니다.

저는 벡터 임베딩 과정부터 살짝 잘못 알고 있던 부분을 이 책을 보면서 좀 더 제대로 이해할 수 있었습니다. 그래서 LLM을 직접 만들어보려는 분이나

(다시 한번 말하지만, 제대로 할려면 돈이 많으딥니다.) 그렇지 않더라도 저처럼 LLM을 좀 이해해보고 싶은 사람에게 강력히 도움이 될 것입니다.

Redis 와 Valkey 무엇을 선택해야 할까?

2024년에 Redis 7.2.4 부터 라이센스 이슈로 Valkey 가 fork 되면서 많은 사람들이 Redis와 Valkey 중에 무엇을 사용해야 하는가? 그럼 어떤 차이가 있는지에 대한 질문이 꽤 많습니다. 그래서 거기에 대한 간단한 의견(답정너) 를 소개하려고 합니다.

일반적으로 클라우드 기반에서 사용하던 분들 특히 AWS의 ElastiCache 를 쓰는 분들은 그냥 Redis 쓰는 것보다 Valkey로 가셔도 전혀 문제가 없습니다.(비용이 더 싸진다는 장점만 있다고 보시면 됩니다.) 왜냐하면 클라우드에서 쓸 수 있는 Redis 버전은 기본적으로 7.2.4 의 이전 버전들이라, 그 시점은 Valkey가 Fork 되면서 그대로 이전했기 때문입니다. 즉, 기존 Redis 를 제공하는 클라우드의 내부 버전이 다르더라도 그냥 제품명만 Redis -> Valkey로 바꿔서 그대로 제공이 됩니다. 그냥 바꾸면 변경이 되는 수준입니다.

그럼, 실제로 문제가 되는 것은 어떤 상황일까요? 현재 우리가 Redis를 자체적으로 운영하고 있는데, Valkey로 바꾸어야 되는가 입니다. 이 이야기를 하기 전에 Redis와 Valkey가 이제 차이가 나는가? 라는 주제 부터 얘기를 해야 합니다. Redis 8과 Valkey 8이 2025년에 나오면서 조금씩 큰 차이가 벌어지고 있습니다.

Redis Module 이야 대부분이 원래 RSAL 라이센스라, 클라우드에서 제공이 안되었지만, Redis 는 사용자의 편의성 기능과 AI쪽에 좀 더 집중하고 있는 모습입니다.

Redis는 7 버전 이후에 Hash 에 서브 Key를 Expire 하는 기능이 들어갔지만, Valkey에는 들어가지 않았습니다.(포크가 되는 시점에, 개발되고 있다가, 포크되고 반영된…) Redis 8에는 VectorSet 이나 AutoComplete 등 AI 지원 기능이나 편의성 기능이 이번에 많이 추가 되었습니다.(내부적으로 콜렉션등에 성능개선도 있었다고…)

Valkey 는 8 버전부터, CPU Cache Line을 맞추거나, 포인터 접근 횟수를 줄여서, 좀더 메모리를 아끼거나, 성능을 높이는 쪽으로 가고 있습니다. 그래서 8부터는 명령이나 이런 부분에서 어느정도 차이가 나고 있습니다.(다만 아직 기본 명령 보다는, 모듈쪽에서 차이가 나는거 같습니다.)

그럼 발전성은 어떨까요? Redis 8이 AGPLv3가 추가되면서 기업에서 뭔가 사용하기가 어려워졌지만, 여전히 Redis(회사) 가 많은 지원을 하고 있고, 가장 많은 컨트리뷰션을 하고 있습니다. 반대로 Valkey는 리눅스 파운데이션과 AWS, 알리바바 등 지원이 있지만, Redis 보다는 조금 덜 활성화 된걸로 보입니다.

결국 선택의 우리의 몫입니다. 다만 정말 특별한 기능을 사용하지 않고, 기존 흐름을 따르는 형태에서는 뭘 선택해도 당장은 큰 문제는 없어보입니다. 하지만, 새로운 Redis 기능을 써야 한다면, 이제 좀 고민을 하셔야 될듯 합니다.

Redis 8 에서의 AGPLv3 추가의 의미(오픈소스로의 리턴?)

지금부터의 의견은 100% 내 개인적인 의견이다.

2024년 Redis 생태계에서 아주 충격적인 일이 일어났다. Redis 7.2.4 부터 Redis 의 오픈소스 라이센스가 기존의 BSDv3 에서 Redis Source Available License v2 (RSALv2) 와 Server Side Public License v1 (SSPLv1) 로 바꿔버린 것이다. 그러면서 Valkey 라는 Redis Fork 프로젝트가 새롭게 생겨나게 된 계기가 되었다.

먼저 RSALv2 와 SSPLv1 라이센스에 대해서 먼저 알아보자. 이 두 해당 라이센스는 공식적인 오픈소스 라이센스로 인정받지 못한다. 즉 기본적으로 Redis는 더 이상 오픈소스로 인정 되지 않는다는 얘기였다.(그래서 각 종 리눅스 배포판에서 빠지게 되었다.)

일단 각 라이센스 부터 정리하면. 아래와 같다.

라이센스비고
RSALv2비상업적 또는 자체 내부 서비스 용도로는 사용 가능.
SaaS(서비스형 소프트웨어) 형태로 Redis를 제공하는 것은 금지.
예: AWS, GCP 같은 클라우드 벤더가 Redis를 서비스로 제공하는 것 제한.
수정 및 배포는 가능하지만, 상업적 Redis-as-a-Service 제공은 불허.
SSPLv1기본적으로 GPLv3 기반이지만, 클라우드 제공자에게 훨씬 더 엄격함.
Redis를 서비스로 제공하고 싶다면, 해당 서비스 전체의 소스코드를 공개해야 함.
예: Redis와 함께 사용하는 관리 도구, 오케스트레이션 시스템 등도 모두 공개해야 함.
사실상 대기업의 SaaS 제공을 어렵게 만드는 라이선스입니다.

딱 살펴보면 알겠지만, Redis를 그냥 사용하는 것은 되지만, Redis As a Service 를 못하게 하는 라이센스라고 보면 된다. 여기서 타겟이 되는 것은 AWS Elasticach 나 GCP 같은 클라우드 업체이며, 더 이상 Redis 를 서비스 할 수 없게 된다.(정확히는 Redis 7.2.4 부터이고 그 이전까지는 여전히 BSDv3 이므로 상관없다.)

Redis(회사) 에서 말하는 것은 오픈소스 레디스에 우리는 이렇게 투자를 많이하는데, 클라우드 업체에서는 과실만 따먹고, 여기에 대한 투자를 하지 않는다라는 것이다.(물론, 알리바바 클라우드나 AWS에서도 꽤 공헌이 있었다.)

여기서 재미있는 것은 Redis(회사) 의 엔터프라이즈 버전이나, AWS의 Elasticash 같은 경우 Open Source Redis의 엄청난 개조버전이라는 것이다.(여기서, Redis 엔터프라이즈 버전은 오픈소스 Redis를 앞에서 Redis(회사)에서 만든 Proxy가 붙어서 다른 형태로 동작하게 하는 걸로 알고 있다.) 즉, 이렇게 수정한 버전을 서비스를 할려면, 소스를 공개하라는 뜻이다.

그런데 몇일전에, Redis 8을 릴리즈하면서 이제 AGPLv3 를 라이센스에 추가했다. 관련 글에는 고객들이 오픈소스 라이센스일때 더 적용하기 쉽다고 해서, AGPLv3를 추가했다는 것이다. 그리고 AGPLv3는 인정 받는 오픈소스 라이센스가 맞다.

그럼 AGPLv3는 어떤 특징이 있을까?

가장 “자유로운” 라이선스처럼 보일 수 있으나, 기업 입장에서는 부담이 큼.

  • 네트워크 상에서 Redis를 서비스 형태로 제공할 경우, 소스코드 전체를 공개해야 함.
  • Redis를 커스터마이징하거나 변경한 버전을 서비스로 제공하면, 해당 서비스 전체 소스도 공개해야 함.

살펴보면 SSPLv1 과 유사하다는 것을 알 수 있다. 즉, 결국 Redis 오픈 소스 버전을 쓰고 싶다면, 결과물을 공개하라는 의지가 계속 들어가 있는 것이다.

당연히 오픈소스 Redis 로 다시 돌아왔지만, 그 목적이 예전처럼 더 자유로웠던 BSDv3가 아닌 것은, 그 목적이 어느 정도 명확해서라고 생각한다.

AWS 에서 Amazon Linux Nginx TCP Stream Proxy 설정

  • 아마존 리눅스에서 nginx 설치
    • sudo amazon-linux-extras install nginx1
  • tcp stream 모듈은 Default 설치가 아니라서 추가 설치 필요
    • sudo yum install nginx-mod-stream

stream 설정

stream {
    # target
    upstream upstream_pass {
        server 10.20.30.40:10001;
    }

    # tcp
    server {
        listen 10001;
        proxy_pass upstream_pass;
        proxy_connect_timeout 1s;
    }
}

이때 기본적으로 ngx_stream_module.so 이 load 가 되어 있지 않기 때문에 load_module 로 해당 모듈을 등록해줘야만 stream 키워드가 사용가능하다. 이때 위에 yum 으로 설치한 경로와 기본 경로가 다를 수 있으므로 해당 경로에 링크를 걸어주거나 아래와 같이 절대 경로를 적어줘야 한다.

load_module /usr/lib64/nginx/modules/ngx_stream_module.so;

[입 개발] Kotlin으로 Google Sheet 열어보기

Java/Kotlin 으로 Google Sheet 에 접속하는 예제는 사실 구글에 아주 잘 나와있다. https://developers.google.com/sheets/api/quickstart/java?hl=ko 를 보면 샘플이 있는데, 이걸 돌려보면 되는 사람도 있고 잘 되지 않는 경우도 있을 텐데… 그 이유에 대해서 살짝 적어볼려고 한다.

구글 인증 방식은 두 가지(OAuth 클라이언트ID, ServiceAccount)

위의 링크를 잘 읽어보면 인증 정보 만들기에서 OAuth 클라이언트 ID로 만들어진 경우이다. 그런데, python 등에서 사용하다보면 보통 ServiceAccount 를 이용하는 형태를 스게 되는데, 이 두가지가 서로 달라서 위의 샘플로 ServiceAccount 형태의 인증을 요청하면 InvalidArgumentException을 만나게 된다.

위의 링크에서 전자(OAuth 클라이언트ID)의 방식을 잘 설명하고 있으므로 여기서는 후자만 다룬다.

접속 방법

간단한 접속 코드는 다음과 같다. (GoogleCredential 이 그런데 deprecated 되는 건 함정)

import com.google.api.client.auth.oauth2.Credential
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport
import com.google.api.client.json.gson.GsonFactory
import com.google.api.services.sheets.v4.Sheets
import com.google.api.services.sheets.v4.SheetsScopes
import org.springframework.context.annotation.Configuration
import java.io.IOException
import java.security.GeneralSecurityException
import java.util.*

@Configuration
class GoogleAuthorizationConfig {
    private val applicationName: String = "test-api"

    private val credentialsFilePath: String = "/credentials.json"

    private val tokensDirectoryPath: String = "tokens"
    @Throws(IOException::class, GeneralSecurityException::class)
    private fun authorize(): Credential {
        val inputStream = GoogleAuthorizationConfig::class.java.getResourceAsStream(credentialsFilePath)
        val googleCredential = GoogleCredential.fromStream(inputStream)
            .createScoped(Collections.singleton(SheetsScopes.SPREADSHEETS_READONLY))
        return googleCredential
    }

    @get:Throws(IOException::class, GeneralSecurityException::class)
    val sheetsService: Sheets
        get() {
            val credential: Credential = authorize()
            return Sheets.Builder(
                GoogleNetHttpTransport.newTrustedTransport(),
                JSON_FACTORY, credential
            )
                .setApplicationName(applicationName)
                .build()
        }

    companion object {
        private val JSON_FACTORY: com.google.api.client.json.JsonFactory = GsonFactory.getDefaultInstance();
    }
}

그리고 이제 각 sheet 정보와 각각의 데이터를 가져오는 걸 알아보자.

    fun getSpreadSheets(page: String) {
        val sheetsService = googleAuthorizationConfig.sheetsService
        val sheets = sheetsService.spreadsheets().get(page).execute()

        sheets.sheets.map {
            println(it.properties.title)
            val sheet = sheetsService.spreadsheets().values().get(page, it.properties.title).execute()
            val values = sheet.getValues()

            values.map { //row 별로 가져오는 코드
                it.map { // 각 라인의 컬럼별로 가져오는 코드
                    print(it)
                    print(",")
                }
                println("-----")
            }
        }
    }