[컴] vuejs 에서 dropdown menu

확장 / 추가 메뉴 버튼 / 다양한 메뉴

vuejs 에서 dropdown menu

  • 동작 : button 을 누르면, dropdown menu 가 보이고, button 을 누르면 사라진다. 또는 dropdown 외의 곳을 click 해도 메뉴가 사라진다.
참고로 아래 v-click-outside 를 사용하는 경우 버튼 이외의 click 이 발생하면 항상 동작하게 된다. 이 부분에 대한 처리를 위해서, listener 를 remove 를 따로 해줘야 할 수도 있다.
 
<template>
<div class="ddmenuWarpper" v-click-outside="onClickOutside">
  <button class="ddmenuBtn" @click="onClickButton">
    show submenu
  </button>
  <div class="dropdownMenu">
    <div class="bubbleArrow"></div>
    <div>sub menu 1</div>
    <div>sub menu 2</div>
  </div>
</div>
</template>

<script>
import Vue from "vue";

// 'v-click-outside' directive 생성, 
Vue.directive("click-outside", {
  bind(el, binding, vnode) {
    el.clickOutsideEvent = (event) => {
      if (!(el === event.target || el.contains(event.target))) {
        vnode.context[binding.expression](event); // onClickOutside
      }
    };
    document.body.addEventListener("click", el.clickOutsideEvent);
  },
  unbind(el) {
    document.body.removeEventListener("click", el.clickOutsideEvent);
  },
});

const _ = {
  name: 'ButtonWithDropdown',
  props: {},
  data() {
    return {
      isOpen: false,
      isDarkMode: false,
    }
  },
  methods: {
    onClickOutside(evt) {
      this.isOpen = false
    },
    onClickButton(evt) {
      this.isOpen = !this.isOpen
      evt.stopPropagation()
    },
  },
  watch: {},
}

export default _
</script>

<style>
.ddmenuWarpper {
    position: relative;
    width: 44px;
    height: 27px;
    border-radius: 8px;
    background: white;
    border: 1px solid #eee;

}
.ddmenuWarpper .ddmenuBtn {
    border: none;
    font-size: inherit;
    background: none;
    outline: none;
    border-radius: 4px;
    position: absolute;
    top: 0;
    left: 0;
    display: flex;
    align-items: center;
    padding: 0;
    margin: 0;
    line-height: 1;
    width: 100%;
    height: 100%;
    z-index: 2;
    cursor: pointer;
}
.ddmenuWarpper .dropdownMenu {
    position: absolute;
    top: 150%;
    min-width: 100px;
    min-height: 10px;
    border-radius: 8px;
    border: 1px solid #eee;
    background: white;
    padding: 10px 30px;
    z-index: 99;
    animation: aniMenu 0.3s ease forwards;
}
.ddmenuWarpper .dropdownMenu .bubbleArrow:before {
    content: "";
    width: 0px;
    height: 0px;
    position: absolute;
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
    border-top: 10px solid transparent;
    border-bottom: 10px solid #eee;
    right: 80%;
    top: -20px;
}

.ddmenuWarpper .dropdownMenu .bubbleArrow:after {
    content: "";
    width: 0px;
    height: 0px;
    position: absolute;
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
    border-top: 10px solid transparent;
    border-bottom: 10px solid #fff;
    right: 80%;
    top: -19px;
}
@keyframes aniMenu {
    from {
      transform: translate3d(0, 30px, 0);
    }
    to {
      transform: translate3d(0, 20px, 0);
    }
}
</style>

Reference

  1. How to Detect Clicks Outside an Element with Vue.js? - The Web Dev

[컴][db] MySQL, MariaDB 에서 pagination 을 위해 total count 를 얻을때

마리아 db , mysql database pagination 속도 향상 / MySQL, MariaDB 에서 pagination 을 위해 total count 를 얻을때

MySQL, MariaDB 에서 pagination 을 효과적으로 하는 법

Note

The SQL_CALC_FOUND_ROWS query modifier and accompanying FOUND_ROWS() function are deprecated as of MySQL 8.0.17; expect them to be removed in a future version of MySQL. As a replacement, considering executing > your query with LIMIT, and then a second query with COUNT(*) and without LIMIT to determine whether there are additional rows. For example, instead of these queries:

SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name WHERE id > 100 LIMIT 10;
SELECT FOUND_ROWS();

Use these queries instead:

SELECT * FROM tbl_name WHERE id > 100 LIMIT 10;
SELECT COUNT(*) FROM tbl_name WHERE id > 100;

COUNT(*) is subject to certain optimizations. SQL_CALC_FOUND_ROWS causes some optimizations to be disabled.

위의 글에서는 pagination 의 속도를 높이는 몇가지 방법을 소개한다. 몇가지를 정리하면,

  • id 를 같이 보내서, offset 보다 id 로 검색할 대상을 줄이는 방법
  • 주변의 page 여러개를 같이 가져온다. 그렇게 미리미리 page 를 가져온다.

Reference

  1. mysql - Which is fastest? SELECT SQL_CALC_FOUND_ROWS FROM table, or SELECT COUNT(*) - Stack Overflow

[컴] Diagrams, python code 로 diagram 그리는 툴

 

다이어그램 / visio / 비지오 / 그림 그리기 / draw

Diagrams, python code 로 diagram 그리는 툴

아래 예제를 보고 몇번 그려보면 쉽게 할 수 있다. 개인적으로 편리하게 그릴 수 있는 툴이라 생각한다. 문제는 복잡한 diagram 이 되면, 보기가 쉽게 node를 배치하는 것이 어렵다.

from diagrams import Cluster, Diagram, Edge
from diagrams.custom import Custom
from diagrams.onprem.compute import Server

from diagrams.onprem.database import MariaDB

from diagrams.onprem.inmemory import Redis
from diagrams.onprem.aggregator import Fluentd
from diagrams.onprem.monitoring import Grafana, Prometheus
from diagrams.onprem.network import Nginx
from diagrams.onprem.queue import Kafka
from diagrams.aws.compute import EC2Instance 
from diagrams.aws.database import RDS
from diagrams.generic.os import Android
from urllib.request import urlretrieve


'''

myserver1 --+
            |
            V
myserver2 --> db --> telegraf --> kafka --+--> kafka_consumer --> RDS --> myserver3
                                        |
                                        +--> myserver4 --> db
 
'''

# download the icon image file
telegrafIconUrl = "https://pbs.twimg.com/media/EpU6-f6XcAApdHh?format=png&name=small"
telegrafIcon = "telegraf_small.png"
urlretrieve(telegrafIconUrl, telegrafIcon)  # download and save it as 'telegraf_small.png'

springIconUrl = "https://pbs.twimg.com/profile_images/1235868806079057921/fTL08u_H_400x400.png"
springIcon = "spring.png"
urlretrieve(springIconUrl, springIcon)

with Diagram("My Web Service", show=False):
    app = Android("app")
    wasmyserver2 = Custom("myserver2", springIcon)
    wasmyserver1 = Custom("myserver1", springIcon)
    
    with Cluster("DB Cluster"):
        dbCluster = [
            MariaDB("node1:db1-db2"),
            MariaDB("node2:db1-db2"),
            MariaDB("node3:db1-db2")]

    telegraf = Custom("telegraf", telegrafIcon)
    kafka = Kafka("kafka")

    wasmyserver2 >> Edge(label="") >> dbCluster
    app >> wasmyserver1 >> Edge(label="") >> dbCluster
    dbCluster[0] >> telegraf >> kafka \
        >> Custom("kafka_consumer", springIcon) \
        >> RDS("RDS") \
        >> Custom("myserver3", springIcon)

    # for edge attributes
    # ref: https://graphviz.org/docs/edges/
    myserver4 = Custom("myserver4", springIcon)
    # kafka >> myserver4 >> Edge(xlabel="to db2", color="red", fontcolor="red") >> dbCluster
    kafka >> myserver4
    dbCluster << Edge(label="to db2", color="#30638e", fontcolor="#30638e") << myserver4 

See Also

  1. 쿠…sal: [컴] code 로 cloud architecture 그리기
  2. 쿠…sal: [컴][유틸] Mermaid - markdown 형식으로 diagram 을 그릴 수 있다.5

Reference

  1. Diagrams · Diagram as Code

[컴] kafka listner 가 network 외부에 존재하는 경우, kafka 의 설정

카프카 설정 / 리스너 / listener config / configuration / 리스너 설정

kafka listner 가 network 외부에 존재하는 경우, kafka 의 설정

kafka client 의 시작시 동작

kafka client 는 kafka 에 대한 설정값을 가지고 있다. 그래서 어느 host/port 에 request 를 할 지 알고 있다.

kafka client 는 시작할 때, 어떤 broker 가 그 partition 의 leader 인지를 알려달라는 metadata 를 요청한다. 이것에 대한 대답은 아무 broker 에서 가능하다.

return되는 metadata 는 그 partition 의 Leader broker 의 위치를 알려준다. 그러면 client 는 broker 에 연결해서 data 를 read/write 하기위해 그 endpoint 들을 이용하게 된다.

  • listeners는 kafka 가 어디에 bind 할 것인지를 알려주는 설정값이라 보면 되고,
  • advertised.listeners 는 외부 kafka client 가 어떻게 broker 에 연결될 수 있는지를 알려주는 값이라고 보면 된다.
  • inter.broker.listener.name 은 kafka broker들이 broker들끼리 통신할 때 어떤 broker 를 사용할지를 정해주는 값이다.

내부, 외부에서 같은 이름으로 접근할 수 있다면

만약 내부에서도, 외부에서도 같은 host 로 접근이 가능한 상태라면, 아래처럼 설정을 할 수 있다. 아래를 보면 대충 알 수 있겠지만, PLAINTEXT는 protocol 이 아니라 listener name 이다.

이 글을 보면, PLAINTEXT 는 secure protocol 중에 그냥 아무런 encrypt 도 안하고 보내는 protocol 을 이야기 한다고 한다.

  • https://github.com/apache/kafka/blob/trunk/config/kraft/broker.properties#L32
  • listeners = listener_name://host_name:port
listeners=PLAINTEXT://0.0.0.0:9092
advertised.listeners=PLAINTEXT://mylocalexternal.mine.com:9092
inter.broker.listener.name=PLAINTEXT

만약 외부, 내부에서 접근할 수 있는 host 가 다르다면

만약 외부에서 접근할 수 있는 host(또는 ip address) 가 내부에서 접근할 수 있는 host/ip 와 다르다면, 당연한 이야기겠지만, 양쪽을 다 적어줘야 한다. 그래서 다음처럼 내부(internal), 외부(external) 에 대한 설정을 해줘야 한다.

listeners=INTERNAL://0.0.0.0:19092,EXTERNAL://0.0.0.0:9092
listener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
advertised.listeners=INTERNAL://mylocal.com:19092,EXTERNAL://myexternal.mine.com:9092
inter.broker.listener.name=INTERNAL
  • advertised.listeners : kafka client 가 내부(INTERNAL) 에서는 mylocal.com:19092 에 접속하고, 외부(EXTERNAL) 에서는 myexternal.mine.com:9092 에 접속을 시도하게 된다.
  • listeners : kafka 는 다음 2개의 listener 를 만든다.
    • 내부: INTERNAL://0.0.0.0:19092
    • 외부: EXTERNAL://0.0.0.0:9092

참고: Kafka Listeners :: Kafka Tutorial : 링크의 그림참고

docker compose.yml

# compose.yml
version: '3'

# https://hub.docker.com/r/bitnami/kafka 
# --> Apache Kafka development setup example

networks:
  app-tier:
    driver: bridge

services:
  zookeeper:
    image: 'bitnami/zookeeper:latest'
    ports:
      - '2181:2181'
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
    networks:
      - app-tier
  kafka:
    # https://hub.docker.com/r/bitnami/kafka
    image: 'bitnami/kafka:latest'
    # hostname: kafkah0
    container_name: kafka0
    ports:
      - '9092:9092'
    environment:
      - KAFKA_BROKER_ID=1
      - KAFKA_CFG_LISTENERS=INTERNAL://:9094,OUTSIDE://:9092
      - KAFKA_CFG_ADVERTISED_LISTENERS=INTERNAL://kafka0:9094,OUTSIDE://127.0.0.1:9092
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=INTERNAL:PLAINTEXT,OUTSIDE:PLAINTEXT
      - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=INTERNAL
      - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
    depends_on:
      - zookeeper
    networks:
      - app-tier
  kafka-ui:
    image: provectuslabs/kafka-ui
    container_name: kafka-ui-0
    ports:
      - "8980:8080"
    # restart: always
    environment:
      - KAFKA_CLUSTERS_0_NAME=local
      # connect using INTERNAL
      - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka0:9094
      - KAFKA_CLUSTERS_0_READONLY=true
    depends_on:
      - kafka
    networks:
      - app-tier

See Also

  1. 쿠…sal: [컴] kafka 특징
  2. 쿠…sal: [컴] kafka 설치하기
  3. 쿠...sal: [컴] kafka 개발용, docker

Reference

  1. Kafka Listeners - Explained

[컴] docker compose 에서 이미 존재하는 docker network 에 접근하려 할 때

 

도커 / 네트워크 / 접근 /

docker compose 에서 이미 존재하는 docker network 에 접근하려 할 때

services:
  # ...
networks:
  default:
    name: my-pre-existing-network
    external: true

Reference

  1. Networking in Compose | Docker Documentation

[컴] kafka-ui, kafka topic 보는 client

 

kafka client / gui / 보는 법 / 메시지 확인 방법 / 어떻게 확인 / 내용

kafka-ui, kafka topic 보는 client

compose.yml :

아래는 만약 이미 docker 로 kafka 를 실행하고 있는 경우, 그 network 에 붙어서 ui 를 사용하려 할 때 사용할 수 있다.

version: '3'

networks:
  # kafka 가 돌고 있는 network 를 찾아서 적으면 된다. docker network ls 를 이용하자.
  myexnetwork_app-tier:
    external: true

# https://github.com/provectus/kafka-ui/blob/master/docker-compose.md
# env variables: https://github.com/provectus/kafka-ui#env_variables
services:
  kafka-ui:
    image: provectuslabs/kafka-ui
    container_name: kafka-ui
    ports:
      - "8980:8080"
    # restart: always
    environment:
      - KAFKA_CLUSTERS_0_NAME=local
      - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka0:9092
      - KAFKA_CLUSTERS_0_READONLY=true
    networks:
      - myexnetwork_app-tier

docker network ls :

d:\a\prog\docker\kafka-ui>docker network ls
NETWORK ID     NAME                  DRIVER    SCOPE
8b79b620bc24   myexnetwork_app-tier  bridge    local
a48e9fa36a77   myexnetwork_default   bridge    local
9fa07d5fc255   blastradius_default   bridge    local
2c6e85339fa8   bridge                bridge    local
05cc789c7158   host                  host      local
202083e7995d   kafka-ui_app-tier     bridge    local
9c0654dab8ef   kafka-ui_default      bridge    local
a2d8a8f8fe89   none                  null      local
2ea1d4968012   testnet_mybridge      bridge    local

kafka docker compose

다음과 같은 compose.yml 을 실행하는 경우, 위의 kafka ui 를 사용하려 한다면, KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS 를 지정해 줘야 한다. 위의 kafka-ui의 compose.yml 이 그것을 위한 것이다. networks.<name>.external = true 가 핵심이라고 할 수 있겠다.

version: '3'

# https://hub.docker.com/r/bitnami/kafka 
# --> Apache Kafka development setup example

networks:
  app-tier:
    driver: bridge

services:
  zookeeper:
    image: 'bitnami/zookeeper:latest'
    ports:
      - '2181:2181'
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
    networks:
      - app-tier
  kafka:
    # https://hub.docker.com/r/bitnami/kafka
    image: 'bitnami/kafka:latest'
    hostname: kafkah0
    container_name: kafka0
    ports:
      - '9092:9092'
    environment:
      - KAFKA_BROKER_ID=1
      - KAFKA_CFG_LISTENERS=PLAINTEXT://kafkah0:9092
      - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafkah0:9092
      - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
    depends_on:
      - zookeeper
    networks:
      - app-tier
  # kafka-ui:
  #   image: provectuslabs/kafka-ui
  #   container_name: kafka-ui-0
  #   ports:
  #     - "8980:8080"
  #   # restart: always
  #   environment:
  #     - KAFKA_CLUSTERS_0_NAME=local
  #     - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafkah0:9092
  #     - KAFKA_CLUSTERS_0_READONLY=true
  #   depends_on:
  #     - kafka
  #   networks:
  #     - app-tier

See Also

  1. 쿠…sal: [컴] docker compose 에서 container_name 과 hostname 의 차이

Reference

  1. GitHub - lensesio/kafka-topics-ui: Web Tool for Kafka Topics |

[컴] kafka 개발용, docker

디버깅 / debug / dev / 개발 할 때 손쉽게 카프카 사용

kafka 개발용, docker

간단하게 docker compose up 으로 kafka 를 실행해서, 개발시 사용할 수 있다. kafka-ui 는 browser 에서 'http://localhost:8980' 로 접근하면 사용할 수 있다.

# compose.yml
version: '3'

# https://hub.docker.com/r/bitnami/kafka 
# --> Apache Kafka development setup example

networks:
  app-tier:
    driver: bridge

services:
  zookeeper:
    image: 'bitnami/zookeeper:latest'
    ports:
      - '2181:2181'
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
    networks:
      - app-tier
  kafka:
    # https://hub.docker.com/r/bitnami/kafka
    image: 'bitnami/kafka:latest'
    hostname: kafkah0
    container_name: kafka0
    ports:
      - '9092:9092'
    environment:
      - KAFKA_BROKER_ID=1
      - KAFKA_CFG_LISTENERS=PLAINTEXT://kafkah0:9092
      - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafkah0:9092
      - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
    depends_on:
      - zookeeper
    networks:
      - app-tier
  kafka-ui:
    image: provectuslabs/kafka-ui
    container_name: kafka-ui-0
    ports:
      - "8980:8080"
    # restart: always
    environment:
      - KAFKA_CLUSTERS_0_NAME=local
      - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafkah0:9092
      - KAFKA_CLUSTERS_0_READONLY=true
    depends_on:
      - kafka
    networks:
      - app-tier