아마존의 Redshift와 구글의 Bigtable을 고려한 적이 있었는데..


"빅 데이터를 지탱하는 기술"이라는 책에서 잠깐 내용을 소개하자면..




중요한 차이점이 하나 있는데. Redshift는 전용(dedicated)인 반면, Bigtable은 멀티테넌트 기반의 공유(shared) 자원 기반이라는 점이다.


따라서 Redshift는 다른 사용자가 사용할 없어서 성능이 안정적이다. 항상 일정한 성능이 나온다.


반면, BigTable은 데이터를 분산하기 때문에 고속화를 실현한다. 다수의 디스크에 데이터가 분산되는 형태를 갖는다. (muti-tenancy 구조이다.)




https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-clusters.html



https://cloud.google.com/blog/products/gcp/bigquery-under-the-hood


Posted by '김용환'
,


'뱅뱅이론' 


남들이 얘기하길래 찾아본 이론이다.


역시 내 생각과 실제는 다른 것 같다.  



http://www.ddanzi.com/ddanziNews/141355230



http://news.donga.com/3/all/20130730/56737249/1



http://www.fashionchannel.co.kr/main/news.php?table=papernews&query=view&uid=5566

Posted by '김용환'
,


pyenv 정리하다가 실수로 .pyenv를 삭제할 수 있다. 

pip 실행시 아래와 같이 로그가 나오면...


/Users/samuel.kim/.pyenv/shims/pip: line 21: /usr/local/Cellar/pyenv/1.2.7/libexec/pyenv: No such file or directory

/Users/samuel.kim/.pyenv/shims/pip: line 21: /usr/local/Cellar/pyenv/1.2.7/libexec/pyenv: No such file or directory

-bash: /Users/samuel.kim/.spark/venv/bin/python3: No such file or directory

-bash: /Users/samuel.kim/.spark/venv/bin/activate: No such file or directory





 pyenv rehash를 실행하면 pyenv 환경이 제대로 되고 위 에러가 발생하지 않는다.

Posted by '김용환'
,


늘 자주 사용하긴 하지만 


kafka-01.internal.google.com에서 kafka-20.internal.google.com까지의 ip 주소를 얻고 싶다면 



number=0; for i in $(seq 1 20); do if [ $i -le 9 ]; then number=0$i ; else number=$i  ; fi ; ping -c1 -t 1 kafka-$number.internal.google.com  ; done



결과는 나오지만 지저분하게 나오려면 다음처럼 awk를 써서 처음 라인의 호스트와 ip만 나오게 한다.




number=0; for i in $(seq 1 20); do if [ $i -le 9 ]; then number=0$i ; else number=$i  ;fi ; ping -c1 -t 1 kafkatest-$numberr.internal.google.com | awk 'NR==1{print $2$3 ; exit}'  ; done



kafkatest-17.internal.google.com(1.1.1.1

...

Posted by '김용환'
,

mysql에서 여러 개의 master의 데이터를 하나의 slave에 저장할 때 multi-source replication 기법을 사용할 수 있다.

mysql replication과 channel 개념 배우는 자료이다.

Open source India - MySQL Labs: Multi-Source Replication from Shivji kumar Jha


https://dev.mysql.com/doc/refman/5.7/en/replication-multi-source-tutorials.html


Posted by '김용환'
,




google guice는 dependency inject 경량 프레임워크이다.


이를 scala(spark)에서 사용하려면 여러 방법이 있겠지만 내가 아는 방법은 2가지이다.



1. scala-guice를 사용한다.


https://github.com/codingwell/scala-guice


실제로 scala-guice를 사용해 구현해보니 경량스럽게 개발이 가능하다.



google guice와 scala-guice 개념을 이해하는데 도움되는 글


https://www.tutorialspoint.com/guice/guice_provides_annotation.htm


https://www.journaldev.com/2403/google-guice-dependency-injection-example-tutorial


https://medium.freecodecamp.org/a-hands-on-session-with-google-guice-5f25ce588774


AbstractModule을 상속하지 않아도 쉽게 구현 가능하다.

그리고 복잡한 형태의 Module을 사용할 수 있다.






2. finatra의 TwitterModule를 사용한다.


TwitterModule은 scala-guice/google-guice 기반이고 finatra 관련 프로젝트라서 엄청난 dependency를 갖고 있다. 


https://twitter.github.io/finatra/user-guide/getting-started/modules.html#module-configuration-in-servers



TwitterModule은 google-guice의 AbstraceModule을 구현한 것으로 무겁지만(너무 많은 dependency) 쉬운 개발이 가능하고 훨씬 기능이 많다.







Posted by '김용환'
,



UserWarning: The psycopg2 wheel package will be renamed from release 2.8 에러가 나면



psycopg2-binary를 설치하면 에러가 사라진다.



pip install psycopg2-binary





Posted by '김용환'
,




vagrant의  multi-VM environment 설정 예시이다.




# -*- mode: ruby -*-

# vi: set ft=ruby :


# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!

VAGRANTFILE_API_VERSION = "2"


Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|


  config.ssh.insert_key = false


  config.vm.define 'db' do |db|


    db.vm.box = "ubuntu/bionic64"

    db.vm.network "private_network", ip: "192.168.33.11"

    db.ssh.forward_agent = true


    db.vm.provider "virtualbox" do |vb|

      vb.customize ["modifyvm", :id, "--memory", "1024"]

    end

  end


  config.vm.define 'web' do |web|


    web.vm.box = "ubuntu/bionic64"

    web.vm.network "private_network", ip: "192.168.33.10"

    web.ssh.forward_agent = true


    web.vm.provider "virtualbox" do |vb|

      vb.customize ["modifyvm", :id, "--memory", "1024"]

    end


    web.vm.provision "ansible" do |ansible|

      ansible.limit = 'all'

      ansible.playbook = "mezzanine-across-hosts.yml"

    end


  end


end





vagrant ssh db 또는 vagrant ssh web 이렇게 접근할 수 있다. 

Posted by '김용환'
,







profile_tasks 플러그인을 사용하면


각 태스크의 실행 시간과 플레이북의 전체 실행 시간에 대한 요약을 생성한다.



- 태스크가 시작된 날짜와 시간


- 이전 태스크의 실행 시간(괄호 안에 표시)


- 플레이의 누적 실행 시간



Saturday 22 April 2019  20:05:51 -0700 (0:00:01.465)       0:01:02.732 ********

===============================================================================

install nginx ---------------------------------------------------------- 57.82s

Gathering Facts --------------------------------------------------------- 1.90s

restart nginx ----------------------------------------------------------- 1.47s

copy nginx config file -------------------------------------------------- 0.69s

copy index.html --------------------------------------------------------- 0.44s

enable configuration ---------------------------------------------------- 0.35s



Posted by '김용환'
,

ujson (scala) 사용 예시

scala 2019. 1. 25. 15:46


scala에서 json 파싱할 때, 사용할 수 있는 간결한 라이브러리로 ujson이 있다. upickle이 있긴 하지만 아직은 불편하다.


http://www.lihaoyi.com/post/uJsonfastflexibleandintuitiveJSONforScala.html



사용 예시이다.



import ujson.Value


object UjsonSampleMain {

  def main(args: Array[String]): Unit = {

    val input =

      "{\n  \"id\": \"c730433b-082c-4984-9d66-855c243266f0\",\n  \"price\": 10,\n \"emptyValue\": \"\",\n \"name\": \"Foo\",\n " +

        " \"counts\": [1, 2, 3],\n  \"values\": {\n    \"bar\": true,\n    \"baz\": 100.001,\n    \"qux\": [\"a\", \"b\"]\n  }\n}"


    // json을 읽는다

    val data: Value.Value = ujson.read(input)


    // 'id' 값을 읽는다

    println(data("id").isNull)

    println(data("id"))

    println


    // type

    println(data("id"))          // Value.Value

    println(data("id").render()) // String


    // 'counts' 값을 읽는다

    println(data("counts"))

    println


    // 'name' 값을 읽은 후 reverse한 값을 기존 json에 저장한다

    data("name") = data("name").str.reverse

    println(data.render())

    println


    // json의 Map 데이터는 obj에서 관리된다

    println(data.obj)

    println


    // json 문자열을 Map으로 확인한다.

    data.obj.foreach(tuple => println(tuple._1 + ":" + tuple._2))

    println


    // json의 values 문자열을 Map으로 확인한다.

    data.obj("values").obj.foreach { case (k, v) => println(k + ":" + v) }

    println


    // json의 values.bar의 값을 boolean으로 읽는다.

    println(data.obj("values").obj("bar").bool)

    println


    // 숫자 값

    println(data("price").num.intValue())


    try {

      // 잘못된 json

      val wrong = "}" + input + "{"

      ujson.read(wrong)

    } catch {

      case _: Throwable => println("wrong json")

    }

  }

  

  

결과



false

"c730433b-082c-4984-9d66-855c243266f0"


"c730433b-082c-4984-9d66-855c243266f0"

"c730433b-082c-4984-9d66-855c243266f0"

[1,2,3]


{"id":"c730433b-082c-4984-9d66-855c243266f0","price":10,"emptyValue":"","name":"ooF","counts":[1,2,3],"values":{"bar":true,"baz":100.001,"qux":["a","b"]}}


Map(id -> "c730433b-082c-4984-9d66-855c243266f0", price -> 10, emptyValue -> "", name -> "ooF", counts -> [1,2,3], values -> {"bar":true,"baz":100.001,"qux":["a","b"]})


id:"c730433b-082c-4984-9d66-855c243266f0"

price:10

emptyValue:""

name:"ooF"

counts:[1,2,3]

values:{"bar":true,"baz":100.001,"qux":["a","b"]}


bar:true

baz:100.001

qux:["a","b"]


true


10

wrong json




Posted by '김용환'
,