Kerberos์™€ Ranger ์‚ฌ์šฉ

๋‹ค์Œ ์˜ˆ์‹œ์—์„œ๋Š” Ranger ๋ฐ Solr ๊ตฌ์„ฑ์š”์†Œ๊ฐ€ ์žˆ๋Š” Kerberos ์‚ฌ์šฉ ์„ค์ • Dataproc ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๋งŒ๋“ค๊ณ  ์‚ฌ์šฉํ•˜์—ฌ Hadoop, YARN, HIVE ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž์˜ ์•ก์„ธ์Šค๋ฅผ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ :

  • Ranger ์›น UI๋Š” ๊ตฌ์„ฑ์š”์†Œ ๊ฒŒ์ดํŠธ์›จ์ด๋ฅผ ํ†ตํ•ด ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Kerberos์™€ Ranger ํด๋Ÿฌ์Šคํ„ฐ์—์„œ Dataproc์€ Kerberos ์‚ฌ์šฉ์ž์˜ ์˜์—ญ๊ณผ ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ Kerberos ์‚ฌ์šฉ์ž๋ฅผ ์‹œ์Šคํ…œ ์‚ฌ์šฉ์ž์— ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Kerberos ์ฃผ ๊ตฌ์„ฑ์› user1/cluster-m@MY.REALM์€ ์‹œ์Šคํ…œ user1์— ๋งคํ•‘๋˜๊ณ  Ranger ์ •์ฑ…์€ user1์— ๋Œ€ํ•œ ๊ถŒํ•œ์„ ํ—ˆ์šฉํ•˜๊ฑฐ๋‚˜ ๊ฑฐ๋ถ€ํ•˜๋„๋ก ์ •์˜๋ฉ๋‹ˆ๋‹ค.

  1. Ranger ๊ด€๋ฆฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  2. Kerberos ๋ฃจํŠธ ์ฃผ ๊ตฌ์„ฑ์› ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  3. ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

    1. ๋‹ค์Œ gcloud ๋ช…๋ น์–ด๋Š” ๋กœ์ปฌ ํ„ฐ๋ฏธ๋„ ์ฐฝ์ด๋‚˜ ํ”„๋กœ์ ํŠธ์˜ Cloud Shell์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
      gcloud dataproc clusters create cluster-name \
          --region=region \
          --optional-components=SOLR,RANGER \
          --enable-component-gateway \
          --properties="dataproc:ranger.kms.key.uri=projects/project-id/locations/global/keyRings/keyring/cryptoKeys/key,dataproc:ranger.admin.password.uri=gs://bucket/admin-password.encrypted" \
          --kerberos-root-principal-password-uri=gs://bucket/kerberos-root-principal-password.encrypted \
          --kerberos-kms-key=projects/project-id/locations/global/keyRings/keyring/cryptoKeys/key
      
  4. ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ์‹คํ–‰๋œ ํ›„ Google Cloud ์ฝ˜์†”์—์„œ Dataproc ํด๋Ÿฌ์Šคํ„ฐ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•œ ๋‹ค์Œ ํด๋Ÿฌ์Šคํ„ฐ ์ด๋ฆ„์„ ์„ ํƒํ•˜์—ฌ ํด๋Ÿฌ์Šคํ„ฐ ์„ธ๋ถ€์ •๋ณด ํŽ˜์ด์ง€๋ฅผ ์—ฝ๋‹ˆ๋‹ค. ์›น ์ธํ„ฐํŽ˜์ด์Šค ํƒญ์„ ํด๋ฆญํ•˜์—ฌ ํด๋Ÿฌ์Šคํ„ฐ์— ์„ค์น˜๋œ ๊ธฐ๋ณธ ๋ฐ ์„ ํƒ์  ๊ตฌ์„ฑ์š”์†Œ์˜ ์›น ์ธํ„ฐํŽ˜์ด์Šค์— ๊ตฌ์„ฑ์š”์†Œ ๊ฒŒ์ดํŠธ์›จ์ด ๋งํฌ ๋ชฉ๋ก์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. Ranger ๋งํฌ๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

  5. '๊ด€๋ฆฌ' ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ Ranger ๊ด€๋ฆฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์—ฌ Ranger์— ๋กœ๊ทธ์ธํ•ฉ๋‹ˆ๋‹ค.

  6. Ranger ๊ด€๋ฆฌ UI๊ฐ€ ๋กœ์ปฌ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์—ด๋ฆฝ๋‹ˆ๋‹ค.

YARN ์•ก์„ธ์Šค ์ •์ฑ…

์ด ์˜ˆ์‹œ์—์„œ๋Š” YARN ๋ฃจํŠธ.๊ธฐ๋ณธ ํ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์•ก์„ธ์Šค๋ฅผ ํ—ˆ์šฉํ•˜๊ณ  ๊ฑฐ๋ถ€ํ•˜๋Š” Ranger ์ •์ฑ…์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

  1. Ranger ๊ด€๋ฆฌ UI์—์„œ yarn-dataproc๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

  2. yarn-dataproc ์ •์ฑ… ํŽ˜์ด์ง€์—์„œ ์ƒˆ ์ •์ฑ… ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค. ์ •์ฑ… ๋งŒ๋“ค๊ธฐ ํŽ˜์ด์ง€์—์„œ ๋‹ค์Œ ํ•„๋“œ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

    • Policy Name: 'yarn-policy-1'
    • Queue: "root.default"
    • Audit Logging: '์˜ˆ'
    • Allow Conditions:
      • Select User: '์‚ฌ์šฉ์ž1'
      • Permissions : ๋ชจ๋“  ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋ ค๋ฉด '๋ชจ๋‘ ์„ ํƒ'
    • Deny Conditions:

      • Select User: '์‚ฌ์šฉ์ž2'
      • Permissions : ๋ชจ๋“  ๊ถŒํ•œ์„ ๊ฑฐ๋ถ€ํ•˜๋ ค๋ฉด '๋ชจ๋‘ ์„ ํƒ'

      ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ •์ฑ…์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด ์ •์ฑ…์€ yarn-dataproc ์ •์ฑ… ํŽ˜์ด์ง€์— ๋‚˜์—ด๋ฉ๋‹ˆ๋‹ค.

  3. ๋งˆ์Šคํ„ฐ SSH ์„ธ์…˜ ์ฐฝ์—์„œ Hadoop ๋งต๋ฆฌ๋“€์Šค ์ž‘์—…์„ ์‚ฌ์šฉ์ž1๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    userone@example-cluster-m:~$ hadoop jar /usr/lib/hadoop-mapreduce/hadoop-mapreduced-examples.
    jar pi 5 10
    

    1. Ranger UI๋Š” userone๊ฐ€ ์ž‘์—…์„ ์ œ์ถœํ•˜๋„๋ก ํ—ˆ์šฉ๋˜์—ˆ์Œ์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
  4. VM ๋งˆ์Šคํ„ฐ SSH ์„ธ์…˜ ์ฐฝ์—์„œ Hadoop ๋งต๋ฆฌ๋“€์Šค ์ž‘์—…์„ usertwo๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    usertwo@example-cluster-m:~$ hadoop jar /usr/lib/hadoop-mapreduce/hadoop-mapreduced-examples.
    jar pi 5 10

    1. Ranger UI๋Š” usertwo๊ฐ€ ์ž‘์—…์„ ์ œ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ์•ก์„ธ์Šค๊ฐ€ ๊ฑฐ๋ถ€๋˜์—ˆ์Œ์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

HDFS ์•ก์„ธ์Šค ์ •์ฑ…

์ด ์˜ˆ์‹œ์—์„œ๋Š” HDFS /tmp ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์•ก์„ธ์Šค๋ฅผ ํ—ˆ์šฉ ๋ฐ ๊ฑฐ๋ถ€ํ•˜๋Š” Ranger ์ •์ฑ…์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

  1. Ranger ๊ด€๋ฆฌ UI์—์„œ hadoop-dataproc๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

  2. hadoop-dataproc ์ •์ฑ… ํŽ˜์ด์ง€์—์„œ ์ƒˆ ์ •์ฑ… ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค. ์ •์ฑ… ๋งŒ๋“ค๊ธฐ ํŽ˜์ด์ง€์—์„œ ๋‹ค์Œ ํ•„๋“œ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

    • Policy Name: 'hadoop-policy-1'
    • Resource Path: '/tmp'
    • Audit Logging: '์˜ˆ'
    • Allow Conditions:
      • Select User: '์‚ฌ์šฉ์ž1'
      • Permissions : ๋ชจ๋“  ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋ ค๋ฉด '๋ชจ๋‘ ์„ ํƒ'
    • Deny Conditions:

      • Select User: '์‚ฌ์šฉ์ž2'
      • Permissions : ๋ชจ๋“  ๊ถŒํ•œ์„ ๊ฑฐ๋ถ€ํ•˜๋ ค๋ฉด '๋ชจ๋‘ ์„ ํƒ'

      ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ •์ฑ…์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ •์ฑ…์€ hadoop-dataproc ์ •์ฑ… ํŽ˜์ด์ง€์— ๋‚˜์™€ ์žˆ์Šต๋‹ˆ๋‹ค.

  3. HDFS /tmp ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์‚ฌ์šฉ์ž1๋กœ ์•ก์„ธ์Šคํ•ฉ๋‹ˆ๋‹ค.

    userone@example-cluster-m:~$ hadoop fs -ls /tmp
    

    1. Ranger UI๋Š” userone๊ฐ€ HDFS /tmp ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์•ก์„ธ์Šคํ•˜๋„๋ก ํ—ˆ์šฉ๋˜์—ˆ์Œ์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
  4. HDFS /tmp ๋””๋ ‰ํ„ฐ๋ฆฌ์— usertwo๋กœ ์•ก์„ธ์Šค:

    usertwo@example-cluster-m:~$ hadoop fs -ls /tmp
    

    1. Ranger UI๋Š” usertwo๊ฐ€ HDFS /tmp ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๊ฐ€ ๊ฑฐ๋ถ€๋˜์—ˆ์Œ์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

Hive ์•ก์„ธ์Šค ์ •์ฑ…

์ด ์˜ˆ์‹œ์—์„œ๋Š” Hive ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์•ก์„ธ์Šค๋ฅผ ํ—ˆ์šฉ ๋ฐ ๊ฑฐ๋ถ€ํ•˜๋Š” Ranger ์ •์ฑ…์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

  1. ๋งˆ์Šคํ„ฐ ์ธ์Šคํ„ด์Šค์—์„œ hive CLI๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์€ employee ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

    hive> CREATE TABLE IF NOT EXISTS employee (eid int, name String); INSERT INTO employee VALUES (1 , 'bob') , (2 , 'alice'), (3 , 'john');
    

  2. Ranger ๊ด€๋ฆฌ UI์—์„œ hive-dataproc๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

  3. hive-dataproc ์ •์ฑ… ํŽ˜์ด์ง€์—์„œ ์ƒˆ ์ •์ฑ… ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค. ์ •์ฑ… ๋งŒ๋“ค๊ธฐ ํŽ˜์ด์ง€์—์„œ ๋‹ค์Œ ํ•„๋“œ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

    • Policy Name: 'hive-policy-1'
    • database: '๊ธฐ๋ณธ๊ฐ’'
    • table: '์ง์›'
    • Hive Column: '*'
    • Audit Logging: '์˜ˆ'
    • Allow Conditions:
      • Select User: '์‚ฌ์šฉ์ž1'
      • Permissions : ๋ชจ๋“  ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋ ค๋ฉด '๋ชจ๋‘ ์„ ํƒ'
    • Deny Conditions:

      • Select User: '์‚ฌ์šฉ์ž2'
      • Permissions : ๋ชจ๋“  ๊ถŒํ•œ์„ ๊ฑฐ๋ถ€ํ•˜๋ ค๋ฉด '๋ชจ๋‘ ์„ ํƒ'

      ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ •์ฑ…์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด ์ •์ฑ…์€ hive-dataproc ์ •์ฑ… ํŽ˜์ด์ง€์— ๋‚˜์—ด๋ฉ๋‹ˆ๋‹ค.

  4. Hive ์ง์› ํ…Œ์ด๋ธ”๊ณผ ๋น„๊ตํ•˜์—ฌ VM ๋งˆ์Šคํ„ฐ SSH ์„ธ์…˜์—์„œ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉ์ž1๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    userone@example-cluster-m:~$ beeline -u "jdbc:hive2://$(hostname -f):10000/default;principal=hive/$(hostname -f)@REALM" -e "select * from employee;"
    

    1. ์‚ฌ์šฉ์ž1 ์ฟผ๋ฆฌ๊ฐ€ ์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค.
      Connected to: Apache Hive (version 2.3.6)
      Driver: Hive JDBC (version 2.3.6)
      Transaction isolation: TRANSACTION_REPEATABLE_READ
      +---------------+----------------+
      | employee.eid  | employee.name  |
      +---------------+----------------+
      | 1             | bob            |
      | 2             | alice          |
      | 3             | john           |
      +---------------+----------------+
      3 rows selected (2.033 seconds)
      
  5. Hive ์ง์› ํ…Œ์ด๋ธ”๊ณผ ๋น„๊ตํ•˜์—ฌ VM ๋งˆ์Šคํ„ฐ SSH ์„ธ์…˜์—์„œ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉ์ž2๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    usertwo@example-cluster-m:~$ beeline -u "jdbc:hive2://$(hostname -f):10000/default;principal=hive/$(hostname -f)@REALM" -e "select * from employee;"
    

    1. ์‚ฌ์šฉ์ž2๋Š” ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๊ฐ€ ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค.
      Error: Could not open client transport with JDBC Uri:
      ...
      Permission denied: user=usertwo, access=EXECUTE, inode="/tmp/hive"
      

์„ธ๋ถ„ํ™”๋œ Hive ์•ก์„ธ์Šค

Ranger๋Š” Hive์—์„œ ๋งˆ์Šคํ‚น ๋ฐ ํ–‰ ์ˆ˜์ค€ ํ•„ํ„ฐ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ์‹œ์—์„œ๋Š” ๋งˆ์Šคํ‚น ๋ฐ ํ•„ํ„ฐ ์ •์ฑ…์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด์ „ hive-policy-1๋ฅผ ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค.

  1. Ranger ๊ด€๋ฆฌ UI์—์„œ hive-dataproc๋ฅผ ์„ ํƒํ•œ ๋‹ค์Œ ๋งˆ์Šคํ‚น ํƒญ๊ณผ ์ƒˆ ์ •์ฑ… ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

    1. ์ •์ฑ… ๋งŒ๋“ค๊ธฐ ํŽ˜์ด์ง€์—์„œ ์ง์› ์ด๋ฆ„ ์—ด์„ ๊ฐ€๋ฆฌ๋Š”(๋ฌดํšจํ™”ํ•˜๋Š”) ์ •์ฑ…์„ ๋งŒ๋“ค๋ ค๋ฉด ๋‹ค์Œ ํ•„๋“œ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

      • Policy Name: 'hive ๋งˆ์Šคํ‚น ์ •์ฑ…'
      • database: '๊ธฐ๋ณธ๊ฐ’'
      • table: '์ง์›'
      • Hive Column: '์ด๋ฆ„'
      • Audit Logging: '์˜ˆ'
      • Mask Conditions:
        • Select User: '์‚ฌ์šฉ์ž1'
        • Access Types: ์ถ”๊ฐ€/์ˆ˜์ • ๊ถŒํ•œ '์„ ํƒ'
        • Select Masking Option: '๋ฌดํšจํ™”'

          ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ •์ฑ…์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

  2. Ranger ๊ด€๋ฆฌ UI์—์„œ hive-dataproc๋ฅผ ์„ ํƒํ•œ ๋‹ค์Œ ํ–‰ ์ˆ˜์ค€ ํ•„ํ„ฐ ํƒญ์„ ์„ ํƒํ•˜๊ณ  ์ƒˆ ์ •์ฑ… ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

    1. ์ •์ฑ… ๋งŒ๋“ค๊ธฐ ํŽ˜์ด์ง€์—์„œ ๋‹ค์Œ ํ•„๋“œ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ์„ ํƒํ•˜์—ฌ eid์ด 1์™€ ๊ฐ™์ง€ ์•Š์€ ํ–‰์„ ํ•„ํ„ฐ๋ง(๋ฐ˜ํ™˜)ํ•ฉ๋‹ˆ๋‹ค.

      • Policy Name: 'Hive-filter ์ •์ฑ…'
      • Hive Database: '๊ธฐ๋ณธ๊ฐ’'
      • Hive Table: '์ง์›'
      • Audit Logging: '์˜ˆ'
      • Mask Conditions:
        • Select User: '์‚ฌ์šฉ์ž1'
        • Access Types: ์ถ”๊ฐ€/์ˆ˜์ • ๊ถŒํ•œ '์„ ํƒ'
        • Row Level Filter: 'eid != 1' ํ•„ํ„ฐ ํ‘œํ˜„์‹

          ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ •์ฑ…์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

    2. Hive ์ง์› ํ…Œ์ด๋ธ”๊ณผ ๋น„๊ตํ•˜์—ฌ VM ๋งˆ์Šคํ„ฐ SSH ์„ธ์…˜์˜ ์ด์ „ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉ์ž1๋กœ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

      userone@example-cluster-m:~$ beeline -u "jdbc:hive2://$(hostname -f):10000/default;principal=hive/$(hostname -f)@REALM" -e "select * from employee;"
      

      1. ์ด ์ฟผ๋ฆฌ๋Š” ์ด๋ฆ„ ์—ด์ด ๋งˆ์Šคํ‚น๋˜๊ณ  ๊ฒฐ๊ณผ์—์„œ Bob(eid=1)๋กœ ํ•„ํ„ฐ๋ง๋˜์–ด ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.
        Transaction isolation: TRANSACTION_REPEATABLE_READ
        +---------------+----------------+
        | employee.eid  | employee.name  |
        +---------------+----------------+
        | 2             | NULL           |
        | 3             | NULL           |
        +---------------+----------------+
        2 rows selected (0.47 seconds)