分類: 3C資訊

  • 新種海蟑螂出現!酷似星際大戰「黑武士」

    新種海蟑螂出現!酷似星際大戰「黑武士」

    摘錄自2020年7月18日自由時報報導

    新加坡與印尼研究團隊將2018年發現一種外貌如星際大戰「黑武士」的14足生物,認證為新品種海蟑螂。綜合媒體報導,新加坡國立大學教授黃䙫麟(Peter K. L. Ng)從2018年與印尼科學院合作,共同探勘印尼西爪哇外海63個地點後,發現12個未登錄在科學文獻的新物種。

    本(7)月8日,黃䙫麟與印尼團隊的論文登上生物學期刊《ZooKeys》,將發現的一種甲殼類生物命為「Bathynomus raksasa」,是「大王巨足蟲屬」(Bathynomus)的一種,其長相雖貌似陸地的蟑螂或鼠婦(woodlice of land),實際上與螃蟹、蝦子等海生動物關係更近。

    一般等足動物長約33公分,但由於天敵稀少、深海環境寒冷,「Bathynomus raksasa」的身體能夠長到50公分左右,為目前科學界已知第二長的等足動物,僅次於「大王巨足蟲」(Bathynomus giganteus)。



    新加坡與印尼研究團隊近日在學術期刊發表論文,將2018年發現一種外貌如星際大戰「黑武士」的14足生物,認證為新品種海蟑螂。圖片來源:Twitter(galamedianews.com)


    生物多樣性
    國際新聞
    印尼
    新加坡
    新物種

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    ※教你寫出一流的銷售文案?

  • 飛機停飛郵輪不航行 氣象專家憂心:難發現「颱風熱點」

    摘錄自2020年7月18、19日鏡週刊、自由時報報導

    歐洲中程天氣預報中心表示,未來若所有航班都消失,預報準確率將會降低多達15%。為了準確預測天氣變化,氣象中心仰賴各種監測工具蒐集到的資訊來演算和預測,包括飛機、郵輪、衛星、浮標、氣象氣球、地面站和雷達。然而,近來受到疫情影響,從飛機和郵輪獲得的數據銳減,水面上的觀測也受到限制。

    CNN 報導,蘭卡斯特大學生態中心(Lancaster University’s Environment Centre)研究發現,疫情之下各地航班密度降低,使得今年3月到5月的地面天氣預報準確性下降。接下來颱風季即將來臨,蘭卡斯特大學生態中心的研究員陳穎(Dr.Ying Chen)表示,若無法精準掌握氣溫,就無法即時發現颱風熱點。

    陳穎也提到,在疫情之下不同地區所面臨到的天氣預報準確率降幅也大有不同,像是一些難以用既有設施觀測的地區,如格陵蘭和西伯利亞地區等,在航班減少的情況下,將會更加難以準確地進行天氣預測。

    氣候變遷
    國際新聞
    美國
    氣象預測
    天氣監測
    疫情下的食衣住行
    颱風
    氣象

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 比衣服纖維掉更多 研究:輪胎塑膠微粒隨風入海、傳送全球

    環境資訊中心綜合外電;姜唯 編譯;林大利 審校

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 馬來西亞登嘉樓立法緊急保護海龜蛋

    摘錄自2020年7月19日法廣報導

    在馬來西亞,臨海的登嘉樓州(Terengganu)頒布了一項新法律,禁止販賣海龜蛋。當地出名的原因之一,也是因為這裡可以品嘗得到瀕臨滅絕的珍稀動物海龜的蛋。儘管現在可以看到思維開始轉變,但動物保護工作依然複雜。

    就在海龜保護機構九年來致力於搶救小海龜的同時,20公里外的Chukai市場上,海龜蛋被混在水果中,一起銷售。當地一名女商販指出,儘管這一做法沒有得到大家一致認同,但這種生意依然火紅。這名商販表示,海龜蛋的氣味在近距離真的很難聞,但它有益於防範AVC腦血管意外(中風),有人就是因此而購買,價格為2歐元三個。

    登嘉樓州的新法對保護瀕臨滅絕物種是一個進步,但當局尚未公布對違法分子如何量刑。

    生物多樣性
    國際新聞
    馬來西亞
    海龜蛋

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

    網頁設計最專業,超強功能平台可客製化

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 荷研發植物製塑膠瓶 一年內可生物分解

    摘錄自2020年7月21日公視報導

    荷蘭一間生化公司開發出以植物原料製造的塑膠瓶,使用完不僅可以回收,它還能在一年內自行分解。

    荷蘭生化公司技術總監古魯特表示:「而且因為從隔離膜的角度來看,PEF(生質聚酯塑膠)性能確實很好,因為紙瓶的優勢來自於紙質製造,只需要一層薄薄的PEF即可實現阻隔(液體)的性能,能好好將內容物妥善保存一段時間。」

    這種植物塑膠,是由玉米、小麥,和甜菜根作成,可以用來盛裝包括氣泡型的飲料,能大幅減少塑膠污染,跟市場對化石燃料的依賴。經過將瓶子放入淡水、鹽水、泥土跟沉澱物的實驗證明,這種塑膠經過堆肥處理後,一年內就可以完全分解,就算放在戶外,也只要幾年時間就能分解。

    生化公司認為這些瓶子,可以回收再利用,因此爭取到了美國可口可樂公司,和丹麥啤酒製造商「嘉士伯」的支持,持續開發。由於植物塑膠的製作成本,生化公司了解一開始無法在價格上占有市場優勢,因此預計先每年生產5000公噸,預計將在2023年前,會與飲料公司合作,讓產品上架。

    污染治理
    國際新聞
    荷蘭
    可生物分解
    廢棄物

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 研究:提高空調能源效率、改用氣候友善製冷劑 將可省下數千億噸碳排

    環境資訊中心綜合外電;姜唯 編譯;林大利 審校

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※超省錢租車方案

    ※別再煩惱如何寫文案,掌握八大原則!

    ※回頭車貨運收費標準

    ※教你寫出一流的銷售文案?

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

  • 在k8s上部署日誌系統elfk

    在k8s上部署日誌系統elfk

    日誌系統elfk

    前言

    經過上周的技術預研,在本周一通過開會研究,根據公司的現有業務流量和技術棧,決定選擇的日誌系統方案為:elasticsearch(es)+logstash(lo)+filebeat(fi)+kibana(ki)組合。es選擇使用aliyun提供的es,lo&fi選擇自己部署,ki是阿里雲送的。因為申請ecs需要一定的時間,暫時選擇部署在測試&生產環境(吐槽一下,我司測試和生產公用一套k8s並且託管與aliyun……)。用時一天(前期有部署的差不多過)完成在kubernetes上部署完成elfk(先部署起來再說,優化什麼的後期根據需要再搞)。

    組件簡介

    es 是一個實時的、分佈式的可擴展的搜索引擎,允許進行全文、結構化搜索,它通常用於索引和搜索大量日誌數據,也可用於搜索許多不同類型的文。

    lo 主要的有點就是它的靈活性,主要因為它有很多插件,詳細的文檔以及直白的配置格式讓它可以在多種場景下應用。我們基本上可以在網上找到很多資源,幾乎可以處理任何問題。

    作為 Beats 家族的一員,fi 是一個輕量級的日誌傳輸工具,它的存在正彌補了 lo 的缺點fi作為一個輕量級的日誌傳輸工具可以將日誌推送到中心lo。

    ki是一個分析和可視化平台,它可以瀏覽、可視化存儲在es集群上排名靠前的日誌數據,並構建儀錶盤。ki結合es操作簡單集成了絕大多數es的API,是專業的日誌展示應用。

    數據採集流程圖

    日誌流向:logs_data—> fi —> lo —> es—> ki。

    logs_data通過fi收集日誌,輸出到lo,通過lo做一些過濾和修改之後傳送到es數據庫,ki讀取es數據庫做分析。

    部署

    根據我司的實際集群狀況,此文檔部署將完全還原日誌系統的部署情況。

    在本地MAC安裝kubectl連接aliyun託管k8s

    在客戶端(隨便本地一台虛機上)安裝和託管的k8s一樣版本的kubectl

    curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.14.8/bin/linux/amd64/kubectl   
    chmod +x ./kubectl 
    mv ./kubectl /usr/local/bin/kubectl  
    將阿里雲託管的k8s的kubeconfig 複製到$HOME/.kube/config 目錄下,注意用戶權限的問題
    
    部署ELFK

    申請一個名稱空間(一般一個項目一個名稱空間)。

    # cat kube-logging.yaml 
    apiVersion: v1
    kind: Namespace
    metadata:
      name: loging
    

    部署es。網上找個差不多的資源清單,根據自己的需求進行適當的修改,運行,出錯就根據日誌進行再修改。

    # cat elasticsearch.yaml 
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: local-class
      namespace: loging
    provisioner: kubernetes.io/no-provisioner
    volumeBindingMode: WaitForFirstConsumer
    # Supported policies: Delete, Retain
    reclaimPolicy: Delete
    ---
    kind: PersistentVolume
    apiVersion: v1
    metadata:
      name: datadir1
      namespace: logging
      labels:
        type: local
    spec:
      storageClassName: local-class
      capacity:
        storage: 5Gi
      accessModes:
        - ReadWriteOnce
      hostPath:
        path: "/data/data1"
    --- 
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: elasticsearch
      namespace: loging
    spec:
      serviceName: elasticsearch
      selector:
        matchLabels:
          app: elasticsearch
      template:
        metadata:
          labels:
            app: elasticsearch
        spec:
          containers:
          - name: elasticsearch
            image: elasticsearch:7.3.1
            resources:
                limits:
                  cpu: 1000m
                requests:
                  cpu: 100m
            ports:
            - containerPort: 9200
              name: rest
              protocol: TCP
            - containerPort: 9300
              name: inter-node
              protocol: TCP
            volumeMounts:
            - name: data
              mountPath: /usr/share/elasticsearch/data
            env:
              - name: "discovery.type"
                value: "single-node"
              - name: cluster.name
                value: k8s-logs
              - name: node.name
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.name
              - name: ES_JAVA_OPTS
                value: "-Xms512m -Xmx512m"
          initContainers:
          - name: fix-permissions
            image: busybox
            command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
            securityContext:
              privileged: true
            volumeMounts:
            - name: data
              mountPath: /usr/share/elasticsearch/data
          - name: increase-vm-max-map
            image: busybox
            command: ["sysctl", "-w", "vm.max_map_count=262144"]
            securityContext:
              privileged: true
          - name: increase-fd-ulimit
            image: busybox
            command: ["sh", "-c", "ulimit -n 65536"]
            securityContext:
              privileged: true
      volumeClaimTemplates:
      - metadata:
          name: data
          labels:
            app: elasticsearch
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: "local-class"
          resources:
            requests:
              storage: 5Gi
    ---
    kind: Service
    apiVersion: v1
    metadata:
      name: elasticsearch
      namespace: loging
      labels:
        app: elasticsearch
    spec:
      selector:
        app: elasticsearch
      clusterIP: None
      ports:
        - port: 9200
          name: rest
        - port: 9300
          name: inter-node
    

    部署ki。因為根據數據採集流程圖,ki是和es結合的,配置相對簡單。

    # cat kibana.yaml 
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: kibana
      namespace: loging
      labels:
        k8s-app: kibana
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: kibana
      template:
        metadata:
          labels:
            k8s-app: kibana
        spec:
          containers:
          - name: kibana
            image: kibana:7.3.1
            resources:
              limits:
                cpu: 1
                memory: 500Mi
              requests:
                cpu: 0.5
                memory: 200Mi
            env:
              - name: ELASTICSEARCH_HOSTS
    #注意value是es的services,因為es是有狀態,用的無頭服務,所以連接的就不僅僅是pod的名字了
                value: http://elasticsearch:9200   
            ports:
            - containerPort: 5601
              name: ui
              protocol: TCP
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: kibana
      namespace: loging
    spec:
      ports:
      - port: 5601
        protocol: TCP
        targetPort: ui
      selector:
        k8s-app: kibana
    

    配置ingress-controller。因為我司用的是阿里雲託管的k8s自帶的nginx-ingress,並且配置了強制轉換https。所以kibana-ingress也要配成https。

    # openssl genrsa -out tls.key 2048
    # openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=kibana.test.realibox.com
    # kubectl create secret tls kibana-ingress-secret --cert=tls.crt --key=tls.key
    

    kibana-ingress配置如下。提供兩種,一種是https,一種是http。

    https:
    # cat kibana-ingress.yaml 
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: kibana
      namespace: loging
    spec:
      tls:
      - hosts:
        - kibana.test.realibox.com
        secretName: kibana-ingress-secret
      rules:
      - host: kibana.test.realibox.com
        http:
          paths:
          - path: /
            backend:
              serviceName: kibana
              servicePort: 5601
    
    http:
    # cat kibana-ingress.yaml 
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: kibana
      namespace: loging
    spec:
      rules:
      - host: kibana.test.realibox.com
        http:
          paths:
          - path: /
            backend:
              serviceName: kibana
              servicePort: 5601
    

    部署lo。因為lo的作用是對fi收集到的日誌進行過濾,需要根據不同的日誌做不同的處理,所以可能要經常性的進行改動,要進行解耦。所以選擇以configmap的形式進行掛載。

    # cat logstash.yaml
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: logstash
      namespace: loging
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: logstash
      template:
        metadata:
          labels:
            app: logstash
        spec:
          containers:
          - name: logstash
            image: elastic/logstash:7.3.1
            volumeMounts:
            - name: config
              mountPath: /opt/logstash/config/containers.conf
              subPath: containers.conf
            command:
            - "/bin/sh"
            - "-c"
            - "/opt/logstash/bin/logstash -f /opt/logstash/config/containers.conf"
          volumes:
          - name: config
            configMap:
              name: logstash-k8s-config
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: logstash
      name: logstash
      namespace: loging
    spec:
      ports:
        - port: 8080       
          targetPort: 8080
      selector:
        app: logstash
      type: ClusterIP
    
    # cat logstash-config.yaml 
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: logstash
      name: logstash
      namespace: loging
    spec:
      ports:
        - port: 8080       
          targetPort: 8080
      selector:
        app: logstash
      type: ClusterIP
    ---
    
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: logstash-k8s-config
      namespace: loging
    data:
      containers.conf: |
        input {
          beats {
            port => 8080  #filebeat連接端口
          }
        }
        output {
          elasticsearch {
            hosts => ["elasticsearch:9200"]  #es的service
            index => "logstash-%{+YYYY.MM.dd}"
          }
        }
    注意:修改configmap 相當於修改鏡像。必須重新apply 應用資源清單才能生效。根據數據採集流程圖,lo的數據由fi流入,流向es。
    

    部署fi。fi的主要作用是進行日誌的採集,然後將數據交給lo。

    # cat filebeat.yaml 
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: filebeat-config
      namespace: loging
      labels:
        app: filebeat
    data:
      filebeat.yml: |-
        filebeat.config:
          inputs:
            # Mounted `filebeat-inputs` configmap:
            path: ${path.config}/inputs.d/*.yml
            # Reload inputs configs as they change:
            reload.enabled: false
          modules:
            path: ${path.config}/modules.d/*.yml
            # Reload module configs as they change:
            reload.enabled: false
        # To enable hints based autodiscover, remove `filebeat.config.inputs` configuration and uncomment this:
        #filebeat.autodiscover:
        #  providers:
        #    - type: kubernetes
        #      hints.enabled: true
        output.logstash:
          hosts: ['${LOGSTASH_HOST:logstash}:${LOGSTASH_PORT:8080}']   #流向lo
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: filebeat-inputs
      namespace: loging
      labels:
        app: filebeat
    data:
      kubernetes.yml: |-
        - type: docker
          containers.ids:
          - "*"
          processors:
            - add_kubernetes_metadata:
                in_cluster: true
    ---
    apiVersion: extensions/v1beta1
    kind: DaemonSet
    metadata:
      name: filebeat
      namespace: loging
      labels:
        app: filebeat
    spec:
      selector:
        matchLabels:
          app: filebeat
      template:
        metadata:
          labels:
            app: filebeat
        spec:
          serviceAccountName: filebeat
          terminationGracePeriodSeconds: 30
          containers:
          - name: filebeat
            image: elastic/filebeat:7.3.1
            args: [
              "-c", "/etc/filebeat.yml",
              "-e",
            ]
            env:   #注入變量
            - name: LOGSTASH_HOST
              value: logstash
            - name: LOGSTASH_PORT
              value: "8080"
            securityContext:
              runAsUser: 0
              # If using Red Hat OpenShift uncomment this:
              #privileged: true
            resources:
              limits:
                memory: 200Mi
              requests:
                cpu: 100m
                memory: 100Mi
            volumeMounts:
            - name: config
              mountPath: /etc/filebeat.yml
              readOnly: true
              subPath: filebeat.yml
            - name: inputs
              mountPath: /usr/share/filebeat/inputs.d
              readOnly: true
            - name: data
              mountPath: /usr/share/filebeat/data
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
              readOnly: true
          volumes:
          - name: config
            configMap:
              defaultMode: 0600
              name: filebeat-config
          - name: varlibdockercontainers
            hostPath:
              path: /var/lib/docker/containers
          - name: inputs
            configMap:
              defaultMode: 0600
              name: filebeat-inputs
          # data folder stores a registry of read status for all files, so we don't send everything again on a Filebeat pod restart
          - name: data
            hostPath:
              path: /var/lib/filebeat-data
              type: DirectoryOrCreate
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRoleBinding
    metadata:
      name: filebeat
    subjects:
    - kind: ServiceAccount
      name: filebeat
      namespace: loging
    roleRef:
      kind: ClusterRole
      name: filebeat
      apiGroup: rbac.authorization.k8s.io
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRole
    metadata:
      name: filebeat
      labels:
        app: filebeat
    rules:
    - apiGroups: [""] # "" indicates the core API group
      resources:
      - namespaces
      - pods
      verbs:
      - get
      - watch
      - list
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: filebeat
      namespace: loging
      labels:
        app: filebeat
    ---
    

    至此完成在k8s上部署es+lo+fi+ki ,進行簡單驗證。

    驗證

    查看svc、pod、ingress信息

    # kubectl get svc,pods,ingress -n loging
    NAME                    TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)             AGE
    service/elasticsearch   ClusterIP   None              <none>        9200/TCP,9300/TCP   151m
    service/kibana          ClusterIP   xxx.168.239.2xx   <none>        5601/TCP            20h
    service/logstash        ClusterIP   xxx.168.38.1xx   <none>        8080/TCP            122m
    
    NAME                            READY   STATUS    RESTARTS   AGE
    pod/elasticsearch-0             1/1     Running   0          151m
    pod/filebeat-24zl7              1/1     Running   0          118m
    pod/filebeat-4w7b6              1/1     Running   0          118m
    pod/filebeat-m5kv4              1/1     Running   0          118m
    pod/filebeat-t6x4t              1/1     Running   0          118m
    pod/kibana-689f4bd647-7jrqd     1/1     Running   0          20h
    pod/logstash-76bc9b5f95-qtngp   1/1     Running   0          122m
    
    NAME                        HOSTS                       ADDRESS        PORTS     AGE
    ingress.extensions/kibana   kibana.test.realibox.com   xxx.xx.xx.xxx   80, 443   19h
    
    web配置

    配置索引

    發現

    至此算是簡單完成。後續需要不斷優化,不過那是後事了。

    問題總結

    這應該算是第一次親自在測試&生產環境部署應用了,而且是自己很不熟悉的日子系統,遇到了很多問題,需要總結。

    1. 如何調研一項技術棧;
    2. 如何選定方案;
    3. 因為網上幾乎沒有找到類似的方案(也不曉得別的公司是怎麼搞的,反正網上找不到有效的可能借鑒的)。需要自己根據不同的文檔總結嘗試;
    4. 一個組件的標籤盡可能一致;
    5. 如何查看公司是否做了端口限制和https強制轉換;
    6. 遇到IT的事一定要看日誌,這點很重要,日誌可以解決絕大多數問題;
    7. 一個人再怎麼整也會忽略一些點,自己先嘗試然後請教朋友,共同進步。
    8. 項目先上線再說別的,目前是這樣,一件事又百分之20的把握就可以去做了。百分之80再去做就沒啥意思了。
    9. 自學重點學的是理論,公司才能學到操作。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※台北網頁設計公司全省服務真心推薦

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※推薦評價好的iphone維修中心

  • MySql輕鬆入門系列——第二站 使用visual studio 對mysql進行源碼級調試

    MySql輕鬆入門系列——第二站 使用visual studio 對mysql進行源碼級調試

    一:背景

    1. 講故事

    上一篇說了mysql的架構圖,很多同學反饋說不過癮,畢竟還是聽我講故事,那這篇就來說一說怎麼利用visual studio 對 mysql進行源碼級調試,畢竟源碼面前,不談隱私,聖人面前,皆為螻蟻。

    二:工具合集

    mysql是C++寫的,要想在windows上編譯,還需要下載幾個必備小工具。

    • mysql-5.7.12.zip
    • cmake-3.17.3-win64-x64.msi
    • boost_1_59_0.tar.gz
    • bison-2.4.1-setup.exe
    • windows 10 x64

    這裏簡單說一下:可以用 cmake 將源碼生成 *.sln 可打開的解決方案,比如可以通過它最終生成 MySQL.sln。boost 是C++中非常強大的基礎庫,bison 一個流行的語法分析器程序,用於給mysql提供語法分析,最後就是下載正確的mysql版本5.7.12。

    三. 詳細安裝

    我會寫的比較細,畢竟我也花了一下午時間,寒酸(┬_┬)

    1. cmake-3.17.3-win64-x64.msi 和 bison-2.4.1-setup.exe

    cmake 和 bison 安裝起來比較方便,一鍵安裝就可以了,不過這裡有一個大坑注意了,在安裝Bison的時候,千萬不要使用默認路徑,因為默認路徑有空格,會導致你後面vs編譯的時候卡住,又不显示什麼原因,可氣!!! 所以我換成自定義的: C:\2\GnuWin32。

    最後確保 cmake 和 bison 的bin文件都在 環境變量中即可。

    2. mysql-5.7.12.zip

    這裏我用 C:\2作為根文件夾,所有的小工具都在這裏,如圖:

    接下來將 mysql-5.7.12.zip 解壓一下,然後進入解壓后的文件夾,新建一個boost文件夾,將boost_1_59_0.tar.gz放入其中,然後再新建一個 brelease 文件夾可用於存放最終生成的MySql.sln。。

    3. cmake編譯

    都準備好了之後,可以開始cmake編譯了。

    
    PS C:\2\mysql-5.7.12\brelease> cmake ..  -DDOWNLOAD_BOOST=1 -DWITH_BOOST="C:\2\mysql-5.7.12\boost\boost_1_59_0.tar.gz"
    -- Building for: Visual Studio 16 2019
    CMake Deprecation Warning at CMakeLists.txt:26 (CMAKE_POLICY):
      The OLD behavior for policy CMP0018 will be removed from a future version
      of CMake.
    -- Cannot find wix 3, installer project will not be generated
    -- COMPILE_DEFINITIONS: _WIN32_WINNT=0x0601;WIN32_LEAN_AND_MEAN;NOGDI;NOMINMAX;HAVE_CONFIG_H
    -- CMAKE_C_FLAGS: /DWIN32 /D_WINDOWS /W3 /MP /wd4800 /wd4805 /wd4996
    -- CMAKE_CXX_FLAGS: /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MP /wd4800 /wd4805 /wd4996 /we4099
    -- CMAKE_C_FLAGS_DEBUG: /MTd /Z7 /Ob1 /Od /RTC1 /EHsc -DENABLED_DEBUG_SYNC -DSAFE_MUTEX
    -- CMAKE_CXX_FLAGS_DEBUG: /MTd /Z7 /Ob1 /Od /RTC1 /EHsc -DENABLED_DEBUG_SYNC -DSAFE_MUTEX
    -- CMAKE_C_FLAGS_RELWITHDEBINFO: /MT /Z7 /O2 /Ob1 /DNDEBUG /EHsc -DDBUG_OFF
    -- CMAKE_CXX_FLAGS_RELWITHDEBINFO: /MT /Z7 /O2 /Ob1 /DNDEBUG /EHsc -DDBUG_OFF
    -- Configuring done
    -- Generating done
    -- Build files have been written to: C:/2/mysql-5.7.12/brelease
    
    

    當看到最後一句 Build files have been written to: C:/2/mysql-5.7.12/brelease,恭喜你,MySQL.sln生成好了。

    4. 打開 MySQL.sln 編譯項目

    我的電腦安裝的是visual studio 2019,接下來打開MySql.Sln整體編譯,需要等個十幾分鐘,看到下面的輸出就算安裝成功。

    三: 啟動mysql並調試insert

    1. mysql的初始化

    這裏要做兩件事情,第一件事是將mysql的調試模式打開,第二件事就是附加 --initialize 啟動參數。

    <1> mysql 調試模式打開

    修改C:\2\mysql-5.7.12\sql\mysqld.cc中的 test_lc_time_sz方法中的 DBUG_ASSERT(0); 改成 DBUG_ASSERT(1); 如下圖:

    <2> vs的command增加啟動參數

    上一篇大家都知道了,mysqld項目是mysql的啟動項目,main函數也在其中,在F5調試之前增加初始化參數 --console --initialize,如下圖:

    2. 繼續入坑出坑

    啟動之後,有103個報錯,氣人呀。。。看錯誤信息應該是編碼問題,如下圖:

    修改起來也很簡單,將 C:\2\mysql-5.7.12\sqlsql_locale.cc 用 [utf-8 + BOM] 格式保存一下,然後對mysqld項目Rebuild再Ctrl+F5直接運行,終於謝天謝地,從輸出可以看到,搞定啦。。。太不容易啦。

    從上圖中可以看到,默認密碼是:zJDE>IC5o+ya,先記錄下這個密碼,然後再把CommandLine Arguments 中的–initialize去掉再重啟Console。

    可以看到,3306端口已開啟,然後用剛才的 zJDE>IC5o+ya 連接即可,這裏我使用navicat。

    連接上去後會提示修改默認密碼,設置我就設置為:123456 ,嘿嘿,一切搞定~~~

    3. 繼續追蹤 write_row

    上一篇我們追蹤到了 write_row 就斷掉了,我當時說它是一個虛方法,由底層具體的存儲引擎去調用,代碼如下:

    
    int handler::ha_write_row(uchar *buf)
    {
        MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,{ error= write_row(buf); })
    }
    
    //這是一個虛方法
    virtual int write_row(uchar *buf __attribute__((unused)))
    {
        return HA_ERR_WRONG_COMMAND;
    }
    
    

    到底這話虛不虛,這次我親自調試一下給大家看看,證據先行哈。。。為了方便,我生成一條創表sql。

    
    drop database if exists `datamip`;
    create database `datamip`;
    drop table if exists `datamip`.`customer`;
    create table `datamip`.`customer` (
     `customerID` int NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
     `customerName` varchar(50) COMMENT '用戶姓名',
     `email` varchar(50) COMMENT '郵箱地址',
     `desc` varchar(50) COMMENT '描述',
     primary key (`customerID`)
    ) ENGINE=InnoDB charset=utf8 collate=utf8_bin;
    
    

    接下來,大家看仔細了,在源碼 int handler::ha_write_row(uchar *buf) 方法處下一個斷點,然後F5調試應用程序。

    接下來可以執行insert操作,這地方會命中斷點的。

    
    insert into  `datamip`.`customer`(customerName,email,`desc`) values('mary','123456789@qq.com','vip');
    
    

    可以看到,斷點命中了,然後進行單步調試,最終你會看到代碼會進入到 C:\2\mysql-5.7.12\storage\innobase\handler\ha_innodb.cc中的 int ha_innobase::write_row 方法,如下圖:

    然後找幾個局部變量和調用堆棧看看。。。

    四: 總結

    這就是我花了一下午的時間總結出的進坑出坑指南,希望能幫助大家節省時間,還是那句話,源碼面前,不談隱私,若還能進行調試,那一切皆為螻蟻!

    如您有更多問題與我互動,掃描下方進來吧~

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    台北網頁設計公司這麼多該如何選擇?

    ※智慧手機時代的來臨,RWD網頁設計為架站首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※回頭車貨運收費標準

  • 簡單5步,輕鬆debug K8S服務!

    簡單5步,輕鬆debug K8S服務!

    作者:
    Ram Rai,性能、可擴展性以及軟件架構的愛好者

    原文鏈接:
    https://medium.com/better-programming/debug-your-kubernetes-service-in-5-easy-steps-1457974f024c

    在Kubernetes中,服務是一個核心概念。在本文中,將介紹如何調試K8S服務,這些服務是由多個Pod組成的工作負載的抽象接口(主機+端口)。

    在我們深入探索debug方法之前,我們先簡單回顧一下網絡,這是Kubernetes服務的基礎。

    • 在一個pod中的容器共享相同的網絡空間和IP。

    • 所有的pod都能通過IP彼此通信。

    • 每個節點都能看到所有的Pod,反之亦然。

    • Pod可以看到所有的服務。

    那麼,在實踐中這些意味着什麼呢?

    在圖中:

    • 位於Pod1中的容器B可以直接作為localhost尋址容器A

    • 容器B可以通過其IP直接尋址Pod2(kubectl get pod -o wide)。我們知道當pod2出現故障時着不是一個可靠的通信渠道,並且一個新的pod可以出現在其位置中。但是我們無法追逐不斷變化的目標。

    • 接下來,容器B可以通過Service x訪問pod 2和pod 3,後者將它們的IP與負載均衡捆綁在一起;因此,在K8S上支持基於微服務的應用程序起着至關重要的作用

    儘管對Kubernetes的內部網絡結構的檢查不在本文的討論範圍內,但我稍後會發布一些參考資料以供大家進一步研究。

    對於當下,我還是鼓勵你花費一點時間在實踐中經歷和理解Kubernetes中的網絡。例如,你可以啟動一個Kubernetes測試pod並且嘗試從該pod中訪問其他pod、節點和服務。此處显示的命令將在Pod內彈出一個Linux shell。

    kubectl run -it networktest --image=alpine bin/ash --restart=Never --rm
    

    現在你在Kubernetes網絡空間內並且你可以隨意使用wegtpingnslookup之類的命令進行實驗。例如,測試你的Kubernetes集群中先前列出的網絡要求,nslookup <servicename>, ping <PodIP>

    現在讓我們回到我們的話題,troubleshooting Kubernetes服務,這實際上是一種網絡結構。

    Step1:檢查服務是否存在

    kubectl get svc
    

    如果服務不存在,應該是服務創建出現了故障,因此要去檢查你的服務定義。

    Step2:測試你的服務

    請記住,一個內部的Kubernetes ClusterIP服務是無法在集群外部訪問的。因此,有兩種方法可以對其進行測試。方法一,你可以啟動一個測試Pod,通過SSH進入該pod,然後嘗試像這樣訪問你的服務:

    kubectl run -it testpod --image=alpine bin/ash --restart=Never --rm
    

    在本文中我們啟動一個alpine Docker鏡像作為pod來從其內部測試服務:

    #works for http services
    wget <servicename>:<httpport>
    
    #Confirm there is a DNS entry for the service!
    nslookup <servicename>
    

    或者,你可以轉發到本地計算機並在本地進行測試。

    kubectl port-forward <service_name> 8000:8080
    

    現在,你可以通過localhost:8000訪問服務。

    Step3:檢查服務是否target相關Pod

    Kubernetes服務會根據標籤selector將入站流量路由到其中一個pod,流量通過其IP路由到目標Pod。所以,請檢查服務是否綁定到那些pod。

    kubectl describe service <service-name> | grep Endpoints
    

    執行上述命令之後,你應該看到與列出的工作負載相關的所有Pod的IP。如果沒有看到,請執行Step4。

    Step4:檢查Pod標籤

    確保在Kubernetes服務中的selector與pod的標籤相匹配。

    kubectl get pods --show-labels
    kubectl describe svc <service_name>
    

    從下面的截圖的中可以看到,pod的標籤在右邊。四個pod被標記為app=tinywebsitetier=frontend,這些標籤與下面“described”的服務selector相匹配。

    在這四個匹配的Pod中,只有三個正在運行,其IP在突出显示的行中被列為服務的端點(endpoint)。你還可以在IP列中看到相同的IP。

    Step5:確認服務端口與pod相匹配

    最後,確保在你的pod中的代碼能夠監聽到你為服務指定的targetPort(例如,你在上方截圖中看到的port8001)!

    這十分簡單,為了讓你更進一步深入了解和研究Kubernetes的網絡世界,歡迎你閱讀以下文章。

    • 在Kubernetes中部署一個應用程序

    • Debug服務

    • Kubernetes網絡

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • RocketMQ系列(四)順序消費

    RocketMQ系列(四)順序消費

    折騰了好長時間才寫這篇文章,順序消費,看上去挺好理解的,就是消費的時候按照隊列中的順序一個一個消費;而併發消費,則是消費者同時從隊列中取消息,同時消費,沒有先後順序。RocketMQ也有這兩種方式的實現,但是在實踐的過程中,就是不能順序消費,好不容易能夠實現順序消費了,發現採用併發消費的方式,消費的結果也是順序的,頓時就蒙圈了,到底怎麼回事?哪裡出了問題?百思不得其解。

    經過多次調試,查看資料,debug跟蹤程序,最後終於搞清楚了,但是又不知道怎麼去寫這篇文章,是按部就班的講原理,講如何配置到最後實現,還是按照我的調試過程去寫呢?我覺得還是按照我的調試過程去寫這篇文章吧,因為我的調成過程應該和大多數人的理解思路是一致的,大家也更容易重視。

    環境回顧

    我們先來回顧一下前面搭建的RocketMQ的環境,這對於我們理解RocketMQ的順序消費是至關重要的。我們的RocketMQ環境是一個兩主兩從的異步集群,其中有兩個broker,broker-a和broker-b,另外,我們創建了兩個Topic,“cluster-topic”,這個Topic我們在創建的時候指定的是集群,也就是說我們發送消息的時候,如果Topic指定為“cluster-topic”,那麼這個消息應該在broker-a和broker-b之間負載;另外創建的一個Topic是“broker-a-topic”,這個Topic我們在創建的時候指定的是broker-a,當我們發送這個Topic的消息時,這個消息只會在broker-a當中,不會出現在broker-b中。

    和大家羅嗦了這麼多,大家只要記住,我們的環境中有兩個broker,“broker-a”和“broker-b”,有兩個Topic,“cluster-topic”和“broker-a-topic”就可以了。

    cluster-topic可以順序消費嗎

    我們發送的消息,如果指定Topic為“cluster-topic”,那麼這種消息將在broker-a和broker-b直接負載,這種情況能夠做到順序消費嗎?我們試驗一下,

    消費端的代碼如下:

    @Bean(name = "pushConsumerOrderly", initMethod = "start",destroyMethod = "shutdown")
    public DefaultMQPushConsumer pushConsumerOrderly() throws MQClientException {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("pushConsumerOrderly");
        consumer.setNamesrvAddr("192.168.73.130:9876;192.168.73.131:9876;192.168.73.132:9876;");
        consumer.subscribe("cluster-topic","*");
        consumer.registerMessageListener((MessageListenerOrderly) (msgs, context) -> {
            Random random = new Random();
            try {
                Thread.sleep(random.nextInt(5) * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (MessageExt msg : msgs) {
                System.out.println(new String(msg.getBody()));
            }
            return ConsumeOrderlyStatus.SUCCESS;
        });
        return consumer;
    }
    
    • 消費者組的名稱,連接的NameServer,訂閱的Topic,這裏就不多說了;
    • 再來看一下註冊的消息監聽器,它是MessageListenerOrderly,順序消費,具體實現里我們打印出了消息體的內容,最後返回消費成功ConsumeOrderlyStatus.SUCCESS。
    • 重點看一下打印語句之前的隨機休眠,這是非常重要的一步,它可以驗證消息是否是順序消費的,如果消費者是消費完一個消息以後,再去取下一個消息,那麼順序是沒有問題,但是如果消費者是併發地取消息,但是每個消費者的休眠時間又不一樣,那麼打印出來的就是亂序

    生產端我們採用同步發送的方式,代碼如下:

    @Test
    public void producerTest() throws Exception {
    
        for (int i = 0;i<5;i++) {
            Message message = new Message();
            message.setTopic("cluster-topic");
            message.setKeys("key-"+i);
            message.setBody(("this is simpleMQ,my NO is "+i+"---"+new Date()).getBytes());
    
            SendResult sendResult = defaultMQProducer.send(message);
            System.out.println("i=" + i);
            System.out.println("BrokerName:" + sendResult.getMessageQueue().getBrokerName());
        }
    }
    

    和前面一樣,我們發送5個消息,並且打印出i的值和broker的名稱,發送消息的順序是0,1,2,3,4,發送完成后,我們觀察一下消費端的日誌,如果順序也是0,1,2,3,4,那麼就是順序消費。我們運行一下,看看結果吧。

    生產者的發送日誌如下:

    i=0
    BrokerName:broker-a
    i=1
    BrokerName:broker-a
    i=2
    BrokerName:broker-a
    i=3
    BrokerName:broker-a
    i=4
    BrokerName:broker-b
    

    發送5個消息,其中4個在broker-a,1個在broker-b。再來看看消費端的日誌:

    this is simpleMQ,my NO is 3---Wed Jun 10 13:48:57 CST 2020
    this is simpleMQ,my NO is 2---Wed Jun 10 13:48:57 CST 2020
    this is simpleMQ,my NO is 4---Wed Jun 10 13:48:57 CST 2020
    this is simpleMQ,my NO is 1---Wed Jun 10 13:48:57 CST 2020
    this is simpleMQ,my NO is 0---Wed Jun 10 13:48:56 CST 2020
    

    順序是亂的?怎麼回事?說明消費者在並不是一個消費完再去消費另一個,而是拉取了一個消息以後,並沒有消費完就去拉取下一個消息了,那這不是併發消費嗎?可是我們程序中設置的是順序消費啊。這裏我們就開始懷疑是broker的問題,難道是因為兩個broker引起的?順序消費只能在一個broker里才能實現嗎?那我們使用broker-a-topic這個試一下吧。

    broker-a-topic可以順序消費嗎?

    我們把上面的程序稍作修改,只把訂閱的Topic和發送消息時消息的Topic改為broker-a-topic即可。代碼在這裏就不給大家重複寫了,重啟一下程序,發送消息看看日誌吧。

    生產者端的日誌如下:

    i=0
    BrokerName:broker-a
    i=1
    BrokerName:broker-a
    i=2
    BrokerName:broker-a
    i=3
    BrokerName:broker-a
    i=4
    BrokerName:broker-a
    

    我們看到5個消息都發送到了broker-a中,再來看看消費端的日誌,

    this is simpleMQ,my NO is 0---Wed Jun 10 14:00:28 CST 2020
    this is simpleMQ,my NO is 2---Wed Jun 10 14:00:29 CST 2020
    this is simpleMQ,my NO is 3---Wed Jun 10 14:00:29 CST 2020
    this is simpleMQ,my NO is 4---Wed Jun 10 14:00:29 CST 2020
    this is simpleMQ,my NO is 1---Wed Jun 10 14:00:29 CST 2020
    

    消費的順序還是亂的,這是怎麼回事?消息都在broker-a中了,為什麼消費時順序還是亂的?程序有問題嗎?review了好幾遍沒有發現問題。

    問題排查

    問題卡在這個地方,卡了好長時間,最後在官網的示例中發現,它在發送消息時,使用了一個MessageQueueSelector,我們也實現一下試試吧,改造一下發送端的程序,如下:

    SendResult sendResult = defaultMQProducer.send(message, new MessageQueueSelector() {
        @Override
        public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
            return mqs.get(0);
        }
    },i);
    

    在發送的方法中,我們實現了MessageQueueSelector接口中的select方法,這個方法有3個參數,mq的集合,發送的消息msg,和我們傳入的參數,這個參數就是最後的那個變量i,大家不要漏了。這個select方法需要返回的是MessageQueue,也就是mqs變量中的一個,那麼mqs中有多少個MessageQueue呢?我們猜測是2個,因為我們只有broker-a和broker-b,到底是不是呢?我們打斷點看一下,

    MessageQueue有8個,並且brokerName都是broker-a,原來Broker和MessageQueue不是相同的概念,之前我們都理解錯了。我們可以用下面的方式理解,

    集群 ——–》 Broker ————》 MessageQueue

    一個RocketMQ集群里可以有多個Broker,一個Broker里可以有多個MessageQueue,默認是8個。

    那現在對於順序消費,就有了正確的理解了,順序消費是只在一個MessageQueue內,順序消費,我們驗證一下吧,先看看發送端的日誌,

    i=0
    BrokerName:broker-a
    i=1
    BrokerName:broker-a
    i=2
    BrokerName:broker-a
    i=3
    BrokerName:broker-a
    i=4
    BrokerName:broker-a
    

    5個消息都發送到了broker-a中,通過前面的改造程序,這5個消息應該都是在MessageQueue-0當中,再來看看消費端的日誌,

    this is simpleMQ,my NO is 0---Wed Jun 10 14:21:40 CST 2020
    this is simpleMQ,my NO is 1---Wed Jun 10 14:21:41 CST 2020
    this is simpleMQ,my NO is 2---Wed Jun 10 14:21:41 CST 2020
    this is simpleMQ,my NO is 3---Wed Jun 10 14:21:41 CST 2020
    this is simpleMQ,my NO is 4---Wed Jun 10 14:21:41 CST 2020
    

    這回是順序消費了,每一個消費者都是等前面的消息消費完以後,才去消費下一個消息,這就完全解釋的通了,我們再把消費端改成併發消費看看,如下:

    @Bean(name = "pushConsumerOrderly", initMethod = "start",destroyMethod = "shutdown")
    public DefaultMQPushConsumer pushConsumerOrderly() throws MQClientException {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("pushConsumerOrderly");
        consumer.setNamesrvAddr("192.168.73.130:9876;192.168.73.131:9876;192.168.73.132:9876;");
        consumer.subscribe("broker-a-topic","*");
        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
            Random random = new Random();
            try {
                Thread.sleep(random.nextInt(5) * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (MessageExt msg : msgs) {
                System.out.println(new String(msg.getBody()));
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });
        return consumer;
    }
    

    這回使用的是併發消費,我們再看看結果,

    i=0
    BrokerName:broker-a
    i=1
    BrokerName:broker-a
    i=2
    BrokerName:broker-a
    i=3
    BrokerName:broker-a
    i=4
    BrokerName:broker-a
    

    5個消息都在broker-a中,並且知道它們都在同一個MessageQueue中,再看看消費端,

    this is simpleMQ,my NO is 1---Wed Jun 10 14:28:00 CST 2020
    this is simpleMQ,my NO is 0---Wed Jun 10 14:28:00 CST 2020
    this is simpleMQ,my NO is 3---Wed Jun 10 14:28:00 CST 2020
    this is simpleMQ,my NO is 2---Wed Jun 10 14:28:00 CST 2020
    this is simpleMQ,my NO is 4---Wed Jun 10 14:28:00 CST 2020
    

    是亂序的,說明消費者是併發的消費這些消息的,即使它們在同一個MessageQueue中。

    總結

    好了,到這裏終於把順序消費搞明白了,其中的關鍵就是Broker中還有多個MessageQueue,同一個MessageQueue中的消息才能順序消費。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化