使用 Prometheus-Operator 監控 Calico

原文鏈接:https://fuckcloudnative.io/posts/monitoring-calico-with-prometheus-operator/

Calico 中最核心的組件就是 Felix,它負責設置路由表和 ACL 規則等,以便為該主機上的 endpoints 資源正常運行提供所需的網絡連接。同時它還負責提供有關網絡健康狀況的數據(例如,報告配置其主機時發生的錯誤和問題),這些數據會被寫入 etcd,以使其對網絡中的其他組件和操作人員可見。

由此可見,對於我們的監控來說,監控 Calico 的核心便是監控 FelixFelix 就相當於 Calico 的大腦。本文將學習如何使用 Prometheus-Operator 來監控 Calico。

本文不會涉及到 CalicoPrometheus-Operator 的部署細節,如果不知道如何部署,請查閱官方文檔和相關博客。

1. 配置 Calico 以啟用指標

默認情況下 Felix 的指標是被禁用的,必須通過命令行管理工具 calicoctl 手動更改 Felix 配置才能開啟,需要提前配置好命令行管理工具。

本文使用的 Calico 版本是 v3.15.0,其他版本類似。先下載管理工具:

$ wget https://github.com/projectcalico/calicoctl/releases/download/v3.15.0/calicoctl -O /usr/local/bin/calicoctl
$ chmod +x /usr/local/bin/calicoctl

接下來需要設置 calicoctl 配置文件(默認是 /etc/calico/calicoctl.cfg)。如果你的 Calico 後端存儲使用的是 Kubernetes API,那麼配置文件內容如下:

apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
  datastoreType: "kubernetes"
  kubeconfig: "/root/.kube/config"

如果 Calico 後端存儲使用的是 etcd,那麼配置文件內容如下:

apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
  datastoreType: "etcdv3"
  etcdEndpoints: https://192.168.57.51:2379,https://192.168.57.52:2379,https://192.168.57.53:2379
  etcdKeyFile: /opt/kubernetes/ssl/server-key.pem
  etcdCertFile: /opt/kubernetes/ssl/server.pem
  etcdCACertFile: /opt/kubernetes/ssl/ca.pem

你需要將其中的證書路徑換成你的 etcd 證書路徑。

配置好了 calicoctl 之後就可以查看或修改 Calico 的配置了,先來看一下默認的 Felix 配置:

$ calicoctl get felixConfiguration default -o yaml

apiVersion: projectcalico.org/v3
kind: FelixConfiguration
metadata:
  creationTimestamp: "2020-06-25T14:37:28Z"
  name: default
  resourceVersion: "269031"
  uid: 52146c95-ff97-40a9-9ba7-7c3b4dd3ba57
spec:
  bpfLogLevel: ""
  ipipEnabled: true
  logSeverityScreen: Info
  reportingInterval: 0s

可以看到默認的配置中沒有啟用指標,需要手動修改配置,命令如下:

$ calicoctl patch felixConfiguration default  --patch '{"spec":{"prometheusMetricsEnabled": true}}'

Felix 暴露指標的端口是 9091,可通過檢查監聽端口來驗證是否開啟指標:

$ ss -tulnp|grep 9091
tcp    LISTEN     0      4096   [::]:9091               [::]:*                   users:(("calico-node",pid=13761,fd=9))

$ curl -s http://localhost:9091/metrics
# HELP felix_active_local_endpoints Number of active endpoints on this host.
# TYPE felix_active_local_endpoints gauge
felix_active_local_endpoints 1
# HELP felix_active_local_policies Number of active policies on this host.
# TYPE felix_active_local_policies gauge
felix_active_local_policies 0
# HELP felix_active_local_selectors Number of active selectors on this host.
# TYPE felix_active_local_selectors gauge
felix_active_local_selectors 0
...

2. Prometheus 採集 Felix 指標

啟用了 Felix 的指標后,就可以通過 Prometheus-Operator 來採集指標數據了。Prometheus-Operator 在部署時會創建 PrometheusPodMonitorServiceMonitorAlertManagerPrometheusRule 這 5 個 CRD 資源對象,然後會一直監控並維持這 5 個資源對象的狀態。其中 Prometheus 這個資源對象就是對 Prometheus Server 的抽象。而 PodMonitorServiceMonitor 就是 exporter 的各種抽象,是用來提供專門提供指標數據接口的工具,Prometheus 就是通過 PodMonitorServiceMonitor 提供的指標數據接口去 pull 數據的。

ServiceMonitor 要求被監控的服務必須有對應的 Service,而 PodMonitor 則不需要,本文選擇使用 PodMonitor 來採集 Felix 的指標。

PodMonitor 雖然不需要應用創建相應的 Service,但必須在 Pod 中指定指標的端口和名稱,因此需要先修改 DaemonSet calico-node 的配置,指定端口和名稱。先用以下命令打開 DaemonSet calico-node 的配置:

$ kubectl -n kube-system edit ds calico-node

然後在線修改,在 spec.template.sepc.containers 中加入以下內容:

        ports:
        - containerPort: 9091
          name: http-metrics
          protocol: TCP

創建 Pod 對應的 PodMonitor

# prometheus-podMonitorCalico.yaml
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  labels:
    k8s-app: calico-node
  name: felix
  namespace: monitoring
spec:
  podMetricsEndpoints:
  - interval: 15s
    path: /metrics
    port: http-metrics
  namespaceSelector:
    matchNames:
    - kube-system
  selector:
    matchLabels:
      k8s-app: calico-node
$ kubectl apply -f prometheus-podMonitorCalico.yaml

有幾個參數需要注意:

  • PodMonitor 的 name 最終會反應到 Prometheus 的配置中,作為 job_name

  • podMetricsEndpoints.port 需要和被監控的 Pod 中的 ports.name 相同,此處為 http-metrics

  • namespaceSelector.matchNames 需要和被監控的 Pod 所在的 namespace 相同,此處為 kube-system

  • selector.matchLabels 的標籤必須和被監控的 Pod 中能唯一標明身份的標籤對應。

最終 Prometheus-Operator 會根據 PodMonitor 來修改 Prometheus 的配置文件,以實現對相關的 Pod 進行監控。可以打開 Prometheus 的 UI 查看監控目標:

注意 Labels 中有 pod="calico-node-xxx",表明監控的是 Pod。

3. 可視化監控指標

採集完指標之後,就可以通過 Grafana 的儀錶盤來展示監控指標了。Prometheus-Operator 中部署的 Grafana 無法實時修改儀錶盤的配置(必須提前將儀錶盤的 json 文件掛載到 Grafana Pod 中),而且也不是最新版(7.0 以上版本),所以我選擇刪除 Prometheus-Operator 自帶的 Grafana,自行部署 helm 倉庫中的 Grafana。先進入 kube-prometheus 項目的 manifests 目錄,然後將 Grafana 相關的部署清單都移到同一個目錄下,再刪除 Grafana:

$ cd kube-prometheus/manifests
$ mkdir grafana
$ mv grafana-* grafana/
$ kubectl delete -f grafana/

然後通過 helm 部署最新的 Grafana:

$ helm install grafana stable/grafana -n monitoring

訪問 Grafana 的密碼保存在 Secret 中,可以通過以下命令查看:

$ kubectl -n monitoring get secret grafana -o yaml

apiVersion: v1
data:
  admin-password: MnpoV3VaMGd1b3R3TDY5d3JwOXlIak4yZ3B2cTU1RFNKcVY0RWZsUw==
  admin-user: YWRtaW4=
  ldap-toml: ""
kind: Secret
metadata:
...

對密碼進行解密:

$ echo -n "MnpoV3VaMGd1b3R3TDY5d3JwOXlIak4yZ3B2cTU1RFNKcVY0RWZsUw=="|base64 -d

解密出來的信息就是訪問密碼。用戶名是 admin。通過用戶名和密碼登錄 Grafana 的 UI:

添加 Prometheus-Operator 的數據源:

Calico 官方沒有單獨 dashboard json,而是將其放到了 ConfigMap 中,我們需要從中提取需要的 json,提取出 felix-dashboard.json 的內容,然後將其中的 datasource 值替換為 prometheus。你可以用 sed 替換,也可以用編輯器,大多數編輯器都有全局替換的功能。如果你實在不知道如何提取,可以使用我提取好的 json:

修改完了之後,將 json 內容導入到 Grafana:

最後得到的 Felix 儀錶盤如下圖所示:

如果你對我截圖中 Grafana 的主題配色很感興趣,可以參考這篇文章:Grafana 自定義主題。

Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12離線安裝包發布地址http://store.lameleg.com ,歡迎體驗。 使用了最新的sealos v3.3.6版本。 作了主機名解析配置優化,lvscare 掛載/lib/module解決開機啟動ipvs加載問題, 修復lvscare社區netlink與3.10內核不兼容問題,sealos生成百年證書等特性。更多特性 https://github.com/fanux/sealos 。歡迎掃描下方的二維碼加入釘釘群 ,釘釘群已經集成sealos的機器人實時可以看到sealos的動態。

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

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

Shader專題:卡通着色(一)控制顏色的藝術

什麼是 Shader?

關於什麼是 Shader ,各種百科各種教程都有說過,但是今天我們就從一個另一個角度去試着理解什麼是 Shader?

我們先看下 Shade 的英文意思,如下:
v.給…遮擋(光線);把…塗暗

其中 把…塗暗 更貼近我們想要的意思。
所以:Shader 這個單詞從字面上理解,就是把什麼東西塗暗。

再強調一次:Shader 從單詞字面上理解,就是把什麼東西塗暗。
再強調一次:把什麼東西塗暗的就是 Shader,就是着色器。

Shader 把什麼塗暗了?

當然是遊戲世界的各個物體,總所周知:有光明就有黑暗,有光照物體就有明暗對比,同時也會有陰影,而 Shader 之所以叫 Shader 是因為起初的時候,Shader 就是用來給物體增加明暗對比的,有了明暗對比,物體在遊戲世界中就會更加立體,從而畫面會更加真實。

所以 Shader 的作用就是給物體添加明暗對比。

Shader 為什麼叫 Shader

當然以上純屬個人推測。現在 Shader 不止可以給物體添加明暗對比,而且還可以做很多濾鏡效果,也可以做很多性能優化(比如減少包大小、減少圖片內存等)的事情。

也許,一開始給 Shader 起名叫 Shader 的時候,Shader 功能非常有限,僅僅只是給物體添加明暗對比(也就是光照計算),後來由於硬件和軟件的發展, 很多離線渲染(電影 CG)的算法都逐步應用在實時渲染(主要是 遊戲 和3D 仿真等),Shader 能做的事情就越來越多,發展到今天,Shader 主要的功能並不只有光照計算。這樣導致,在概念理解上給很多初學者增加了很多阻礙。

教練有一次聽過一位搞圖形學的朋友說:“我們搞實時渲染的都是那些搞視頻(離線渲染)玩剩的”。

Shader 是着色器

什麼是 Shader,中文叫做着色器,也就是給物體上色的意思,也就是說寫 Shader 就是給物體上色的藝術。而這個上色不只是簡單的色彩填充,而是涵蓋了非常多的技巧(幾何計算、顏色計算、貼圖等)

所以中文的着色器,是一個非常精準的翻譯。

群內的笑笑說了一個比較不錯的說法:Shader 主要是光線數據作用在不同數據的物體上產生不同效果。

Shader 學習的順序

不管是 Shader 還是其它某個科目,都有一些最常用、最簡單的知識點。

而這些知識點很容易學以致用,也就是說,這種知識點,我們學習完了就能馬上落地。

所以,教練要做的就是,把 Shader 中的知識點按照是否常用和是否簡單這兩個維度進行排列篩選,然後把它們一個個整理成案例,這樣童鞋們的學習體驗就會大幅上升。

主題式研究第三個階段

  • 第一個階段:確定主題(關鍵字)
  • 第二個階段:搜索資料、搜索信息(搜集情報)
  • 第三個階段:構建知識體系(畫腦圖、寫大綱)

到此,Shader 這個主題,我們目前已經到了第三個階段,也就是構建知識體系的階段。

當然,這一整篇,都再講,我們要怎麼怎麼做,接下來幹嗎,並沒有學習 Shader 的任何一個知識點。

那麼今天就學習一點 Shader 知識意思一下。

顏色的控制

現有一張貼圖,如下:

用來控制顏色的 shader 代碼如下:

float4 frag (v2f i) : SV_Target
{
    // 圖片上每個像素的顏色值
    float4 color = tex2D(_MainTex, i.uv);
                
    // 返回顏色,表示將改像素的顏色值輸出到屏幕上
    return color;
}

我們只看方法中的代碼,先不要在意一些細節。

雖然,我們沒有 Shader 的語法學習經驗,但是憑我們的 C# 經驗,可以將上述代碼推測個大概來。

首先 float4 是一個類型,可以存儲 4 個 float 數值。而顏色一般都是由 r(red 紅色)、g(green,綠色)、b(blue,藍色)、a(alpha,透明度) 四個值控制。所以 float4 可以存儲一個顏色。

現在,我們把圖片中每個像素顏色重的紅色值設置為 0,圖片結果則如下所示:

代碼如下所示:

float4 frag (v2f i) : SV_Target
{
    // 圖片上每個像素的顏色值
    float4 color = tex2D(_MainTex, i.uv);
                
    color.r = 0;

    // 返回顏色,表示將改像素的顏色值輸出到屏幕上
    return color;
}

我們看到,圖片變成了藍綠色。

小結

Shader 是一門控制顏色的藝術,Shader 的核心也是如此。
在此篇,我們學習了 Shader 的兩個重要知識點:

  1. float4 結構體
  2. 顏色的 rgb 控制

這兩個知識點非常簡單,也非常基礎,但是是非常常用的兩個知識點。

這片文章的內容就這些。

知識地圖

相關下載:

轉載請註明地址:liangxiegame.com

更多內容
QFramework 地址:https://github.com/liangxiegame/QFramework
QQ 交流群:623597263
涼鞋的主頁:https://liangxiegame.com/zhuanlan
關注公眾號:liangxiegame 獲取第一時間更新通知及更多的免費內容。

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

【其他文章推薦】

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

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

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

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

東京奧運聖火傳遞福島起點 被查出輻射量異常

摘錄自2019年12月4日自由時報報導

日本東京奧運聖火明年3月底從福島縣的足球國練中心「J-VILLAGE」出發,但日本環境省今(4日)透露,「J-VILLAGE」相鄰的停車場有部分區域空間輻射量較高,當局已要求東京電力公司再次去污。

J-VILLAGE位於福島縣濱通南部,2011年福島核災發生後,由於此處距離福島核一廠僅有20公里,被政府借用為核災事故處理的對應據點,該中心今年4月下旬才全面恢復營運,因具有災區重建的重大象徵意義,所以被選為聖火傳遞的起點。

根據《共同社》報導,環保團體綠色和平組織10月對J-VILLAGE周圍展開調查,發現異常的輻射量,隨後將結果送交環境省。

環境省表示,空間輻射量較高的是與J-VILLAGE相鄰的楢葉町營停車場部分區域,已要求東電對該地區未經鋪設的地面再次去污。東電3日去除了周圍約0.03立方米的土和草,調查放射性物質的種類等。

根據東電的調查,在去污地區1公尺高的位置測得每小時1.79微西弗的輻射量,超過日本政府訂定的0.23微西弗的去污標準。地表輻射量為70.2微西弗。

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

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

澳洲野火持續燃燒 摧毀約四成台灣面積

整理:劉妙慈(環境資訊中心實習編輯)

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

【其他文章推薦】

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

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

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

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

奧迪2018年量產首款純電動SUV汽車

奧迪準備2018年在布魯塞爾量產首款純電動SUV汽車。布魯塞爾的奧迪工廠會同時製造汽車和電池,它還要向大眾其它汽車提供電池。

在2015年舉行的法蘭克福汽車展上,奧迪展示了e-tron概念車,它預示著奧迪即將推出量產版本的SUV,汽車取名為“Q6 e-tron”。

Q6 e-tron配有3個電動機,一個位於前軸,兩個放在後面。大型電池組安裝在前後軸之間,位於乘客座位的下方,這樣可以降低重心,提供更好的平衡性。

Q6 e-tron安裝的電池來自韓國LG化學和三星SDI,充電一次可以行駛約500千米。資料是以歐洲測試週期作為標準的,如果用美國環境保護署(EPA)的標準測試里程會短一些。因此,Q6 e-tron充電一次的行駛距離估計為390千米,這個資料更為合理一些。

目前布魯塞爾的奧迪工廠主要負責生產A1,奧迪會將A1生產線轉移到西班牙工廠,讓布魯塞爾負責生產Q6 e-tron。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

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

Nissan、BMW聯手 在美安裝更多電動車充電樁

Nissan與BMW宣布,為共同強化各自旗下的電動車產品Nissan LEAF與BMW i3的客戶服務網,將合作在全美19州、共120處安裝雙頭快速充電樁。此舉未來可望刺激美國市場的電動車銷售量,並幫助電動車車主享有更便捷、廣泛的服務。

Nissan LEAF是目前全球總銷量最好的電動車款之一,充電樁設備分布在社區、企業公司以及Nissan的經銷門市。與BMW的合作,將可加速提升充電樁設備的數量,強化用戶使用經驗同時開拓市場。

BMW的北美電子移動經理Cliff Fietzek強調,與Nissan的合作還包含遠程行車的服務。一但電動車能提供更遠程的行駛距離,使用者就更能體驗電子移動科技的便利之處。

這項合作將以Nissan的充電樁技術與BMW的DC快充技術為基礎,每座快充充電樁都有CHAdeMO與SAE Combo雙街頭,輸出功率50kW,可適用於Nissan LEAF與BMW i3兩種車款以及其他擁有快充埠的電動車。50kW的快充設備可在20-30分鐘之內將Nissan LEAF或BMW i3的電池充到80%左右,比目前最常見的Level 2 240V 充電服務的效率更好。

Nissan與BMW的電動車充電樁服務範圍包括:加州、康乃迪克州、佛羅里達、喬治亞州、伊利諾州、印第安納州、馬里蘭州、明尼蘇達州、密蘇里州、新墨西哥州、內華達州、紐約、南北卡羅萊納州、俄亥俄州、賓州、田納西州、維吉尼亞州以及威斯康辛州。只要透過BWM i3的ConnectedDrive軟體,或者Nissan EZ-Charge智慧型手機app,就能快速找到充電站位置,電費可用Nissan EZ-Charge卡片結帳。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

FastDFS圖片服務器單機安裝步驟(修訂版)

前面已經講 ,通過此文章可以了解FastDFS組件中單機安裝流程。

單機版架構圖

以下為單機FastDFS安裝步驟

一、環境準備

CentOS 7.X

使用的版本: libfastcommon-1.0.41.tar.gz

使用的版本: fastdfs-6.01.tar.gz

使用的版本:fastdfs-nginx-module-1.21.tar.gz

使用的版本: nginx-1.16.1.tar.gz

二、安裝過程

1、安裝 libfastcommon-1.0.41.tar.gz

tar -zxvf libfastcommon-1.0.41.tar.gz
cd libfastcommon-1.0.41/
./make.sh
./make.sh install

2、安裝 FastDFS

tar -zxvf  fastdfs-6.01.tar.gz
cd fastdfs-6.01/
./make.sh
./make.sh install

準備配置文件

cp /etc/fdfs/tracker.conf.sample /etc/fdfs/tracker.conf
cp /etc/fdfs/storage.conf.sample /etc/fdfs/storage.conf
cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf
cd /opt/apps/fastdfs-6.01/conf
cp http.conf mime.types /etc/fdfs/

Tracker Server 配置

vim /etc/fdfs/tracker.conf
修改配置如下:
#tracker server端口號
port=22122
#存儲日誌和數據的根目錄
base_path=/opt/fastdfs/tracker
#HTTP服務端口
http.server_port=80
開放防火牆端口

1、打開跟蹤端口

vim /etc/sysconfig/iptables

2、添加以下端口行:

-A INPUT -m state --state NEW -m tcp -p tcp --dport 22122 -j ACCEPT

3、重啟防火牆

service iptables restart
啟動Tracker
/etc/init.d/fdfs_trackerd start

Storage Server 配置

vim /etc/fdfs/storage.conf
修改配置如下:
#storage server端口號
port=23000
#數據和日誌文件存儲根目錄
base_path=/opt/fastdfs/storage
#第一個存儲目錄
store_path0=/opt/fastdfs/storepath0
#tracker服務器IP和端口
tracker_server=192.168.0.1:22122
#http訪問文件的端口(默認8888,看情況修改,和nginx中保持一致)
http.server_port=8888
開放防火牆端口

1、打開跟蹤端口

vim /etc/sysconfig/iptables

2、添加以下端口行:

-A INPUT -m state --state NEW -m tcp -p tcp --dport 23000 -j ACCEPT

3、重啟防火牆

service iptables restart
啟動Storage
/etc/init.d/fdfs_storaged start
查看集群狀態
 fdfs_monitor /etc/fdfs/storage.conf list

查看狀態是否正常

Storage 1:
id = 6.0.36.243
ip_addr = 6.0.36.243 (anantes-651-1-49-net.w2-0.abo.wanadoo.fr) ACTIVE

Client配置

vim /etc/fdfs/client.conf
修改配置如下:
#
base_path=/opt/apps/fastdfs/client
#tracker服務器IP和端口
tracker_server=192.168.0.1:22122 
上傳一個圖片測試是否能上傳成功
 fdfs_upload_file /etc/fdfs/client.conf test.jpg

test.jpg 是測試本地上傳的圖片,路徑請填寫正確

3、安裝Nginx和 fastdfs-nginx-module

#解壓fastdfs-nginx-module
tar -zxvf fastdfs-nginx-module-1.21.tar.gz
cd fastdfs-nginx-module-1.21/
cp ./src/mod_fastdfs.conf /etc/fdfs
#解壓nginx
tar -zxvf nginx-1.16.1.tar.gz
cd nginx-1.16.1/
#安裝nginx_http_image_filter_module
yum -y install gd-devel
yum -y install zlib zlib-devel openssl openssl--devel pcre pcre-devel
#添加模塊
./configure --add-module=../fastdfs-nginx-module-1.21/src --prefix=/usr/local/nginx --with-http_image_filter_module 
#編譯nginx
make
#安裝nginx
make install

查看是否安裝成功

/usr/local/nginx/sbin/nginx -V

查看插件是否安裝成功

[root@FastDFS nginx-1.16.1]# /usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.16.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) 
configure arguments: --add-module=../fastdfs-nginx-module-1.21/src --prefix=/usr/local/nginx --with-http_image_filter_module
[root@FastDFS nginx-1.16.1]# 

修改Nginx訪問

vim /etc/fdfs/mod_fastdfs.conf

修改配置如下:

#
connect_timeout=10
#tracker服務器IP和端口
tracker_server=192.168.0.1:22122
#是否啟用group組名
url_have_group_name=true
#
store_path0=/opt/fastdfs/storepath0

修改Nginx配置:

vim /usr/local/nginx/conf/nginx.conf

修改配置如下:

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    location / {
        root   html;
        index  index.html index.htm;
    }
    #圖片帶壓縮訪問
    location ~ /group1/M00/(.*)\.(jpg|gif|png)!format=([0-9]+)_([0-9]+) {
        alias  /home/fastdfs/storage/data/;
        ngx_fastdfs_module;
        set $w $3;
        set $h $4;

        rewrite group1/M00(.+)\.(jpg|gif|png)!format=([0-9]+)_([0-9]+)$ group1/M00$1.$2 break;

        image_filter resize $w $h;
        image_filter_buffer 5M;
    }
    #主圖訪問
    location ~ /group([0-9])/M00/(.+)\.?(.+) {
        alias /home/fastdfs/storage/data/;
        ngx_fastdfs_module;
    }
...
}

啟動Nginx

#啟動
/usr/local/nginx/sbin/nginx
#停止
/usr/local/nginx/sbin/nginx -s stop
#重啟
/usr/local/nginx/sbin/nginx -s reload

通過以上配置完成FastDFS的搭建。

測試圖片訪問

圖片訪問示例:

主圖訪問

http://218.2.204.124:30308/group1/M00/00/03/BgAk813IvTCAIxxxAAD44NFKFPc908.png

壓縮圖片 (主圖后加 !format=寬度_高度)訪問

http://218.2.204.124:30308/group1/M00/00/03/BgAk813IvTCAIxxxAAD44NFKFPc908.png!format=400_10

未解決的問題

壓縮圖片使用主圖后?format=寬度_高度

本文由博客一文多發平台 發布!

再次感謝!!! 您已看完全文,歡迎關注微信公眾號猿碼 ,你的支持是我持續更新文章的動力!

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

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

C表達式中的彙編指令

C 表達式中的彙編指令

asm 為 gcc 中的關鍵字,asm 表達式為在 C代碼中嵌套彙編指令,該表達式只是單純的替換出彙編代碼,並不對彙編代碼的含義進行解析。

asm 表達式有兩種形式,第二種 asm-qualifiers 包含了 goto 語句。
第一種形式為常見的用法,AssemblerTemplate 和 OutputOperands 必須存在, 其中 Clobbers 存在需要 InputOperands 也出現。

asm asm-qualifiers ( AssemblerTemplate 
                 : OutputOperands 
                 [ : InputOperands
                 [ : Clobbers ] ])

asm asm-qualifiers ( AssemblerTemplate 
                      : 
                      : InputOperands
                      : Clobbers
                      : GotoLabels)

Qualifiers 的類型

  • volatile, 避免編譯器的優化
  • inline, 內斂限定符,最小的體積
  • goto, 包含跳轉指令

參數

  • AssemblerTemplate
    – 彙編指令模板是包含彙編器指令的文字字符串,編輯器替換引用輸入,編譯器不會解析該指令的含義。
  • OutputOperands
    – 由 AssemblerTemplate 中的指令修改的C變量的逗號分隔列表,允許使用空列表。
  • InputOperands
    – 由 AssemblerTemplate 中的指令讀取的C變量的逗號分隔列表,允許使用空列表。
  • Clobbers
    – 用逗號分隔的寄存器列表或由 AssemblerTemplate 修改的值,不能出現在 OutputOperands 和 InputOperands 中被提及,允許使用空列表。
  • GotoLabels
    – 當使用asm的goto形式時,此部分包含 AssemblerTemplate 中的代碼可能跳轉到的所有C標籤的列表。

AssemblerTemplate

彙編指令由一個字符串給出,多條彙編指令結合在一起使用的時候,中間以 \r\t 隔開,如

asm("inc %0\n\tinc %0" : "=r"(res) : "0"(res));

/APP
# 11 "asm.c" 1
        inc %rax
        inc %rax
# 0 "" 2
/NO_APPs

需要轉義的字符:%, =, {, }, |

故在ATT彙編中,對寄存器進行操作的需要雙 %%, 如 inc %%rax.

OutputOperands

操作數之間用逗號分隔。 每個操作數具有以下格式:

[ [asmSymbolicName] ] constraint (cvariablename)
  • asmSymbolicName
    – 為操作數指定名稱,格式為 %[name]
    c // res = num asm("movq %[num], %[res]" : [res] "=r"(res) : [num] "m"(num));
    – 如果未指定名稱使用数字, 從 output 域開始,第一個參數為 %0, 一次類推, 這裏的 res 為 %0, num 為 %1
    c // res = num asm("movq %1, %0" : "=r"(res) : "m"(num));
  • constraint
    – 一個字符串常量,用於指定對操作數的存儲的 , 需要以 “=” 或 “+” 開頭
  • cvariablename
    – 指定一個C左值表達式來保存輸出,通常是一個變量名。 括號是語法的必需部分

第一個參數為增加可讀性使用的,現在我們有代碼如下

int64_t res;
int64_t num = 1;

asm("movq %[num], %[res]" : [res] "=r"(res) : [num] "m"(num));
asm("movq %1, %0" : "=r"(res) : "m"(num));
asm("movq %1, %0" : "=m"(res) : "m"(num));
asm("movq %1, %0" : "=r"(res) : "r"(num));

// 對應的彙編代碼, 只保留asm表達式中的代碼
# 13 "asm.c" 1
        movq -16(%rbp), %rax  // asm-1
 # 0 "" 2
/NO_APP

/APP
 # 15 "asm.c" 1
        movq -16(%rbp), %rax  // asm-2
 # 0 "" 2
/NO_APP

/APP
 # 17 "asm.c" 1
        movq -16(%rbp), -8(%rbp)  // asm-3
 # 0 "" 2
/NO_APP

/APP
 # 19 "asm.c" 1
        movq %rax, %rax  // asm-4
 # 0 "" 2
/NO_APP
  1. 使用名稱替換和数字替換效果一樣,見 asm-1 和 asm-2
  2. 約束的用法,這裏使用比較簡單通用的的兩種情況,r 為通過寄存器尋址操作,m 通過內存尋址操作,所以看到當約束了 r 就對應寄存器的操作。
  3. 結果保存在 res 也就是 cvariablename 中

InputOperands

輸入操作數使C變量和表達式中的值可用於彙編代碼。

[ [asmSymbolicName] ] constraint (cexpression)
  • asmSymbolicName 和輸出列表的用法完全一致
  • constraint 約束不能使用 =+. 可以使用 “0”, 這表明在輸出約束列表中(從零開始)的條目,指定的輸入必須與輸出約束位於同一位置。
int64_t res = 3;
int64_t num = 1;
asm("addq %1, %0" : "=g"(res) : "0"(num));

// 輸入輸出位置相同
        movq    $3, -8(%rbp)
        movq    $1, -16(%rbp)
        movq    -16(%rbp), %rax
/APP
# 32 "asm.c" 1
        addq %rax, %rax
# 0 "" 2
/NO_APP
  • cexpression 可以不為左值,作為彙編表達式的輸入值即可

Clobbers

破壞列表,主要用於指示編譯器生成的彙編指令。

從asm表達式中看到輸出操作數中列出條目的更改編譯器是可以確定的,但內聯彙編代碼可能不僅對輸出進行了修改。 例如,計算可能需要其他寄存器,或者處理器可能會由於特定彙編程序指令而破壞寄存器的值。 為了將這些更改通知編譯器,在Clobber列表中列出這些會產生副作用的條目。 破壞列表條目可以是寄存器名稱,也可以是特殊的破壞列表項(在下面列出)。 每個內容列表條目都是一個字符串常量,用雙引號引起來並用逗號分隔。

  • 寄存器

      ```c
      asm volatile("movc3 %0, %1, %2"
              : /* No outputs. */
              : "r"(from), "r"(to), "g"(count)
              : "%rbx", "%rcx", "%rdx", "memory");
    
      /APP
      # 25 "asm.c" 1
              movc3 %rax, %r8, -72(%rbp)
      # 0 "" 2
      /NO_APP
      ```
    
      可以看到使用到了 rax 寄存器,然後修改程序在 Clobbers 增加 %rax, 結果如下
    
      ```c
      asm volatile("movc3 %0, %1, %2"
              : /* No outputs. */
              : "r"(from), "r"(to), "g"(count)
              : "%rax", "%rbx", "%rcx", "%rdx", "memory");
    
      /APP
      # 25 "asm.c" 1
              movc3 %r8, %r9, -72(%rbp)
      # 0 "" 2
      /NO_APP
      ```
      編譯器在產生的彙編代碼中就未使用 %rax 寄存器了。
  • 特殊破壞列表項
    – “cc”, 表示彙編代碼修改了標誌寄存器
    – “memory”, 為了確保內存中包含正確的值,編譯器可能需要在執行asm之前將特定的寄存器值刷新到內存中

編譯器為了破壞列表項的值受到破壞,當這些條目是寄存器時,不對其進行使用;為特殊參數時,重新刷新得到最新的值。

約束

  • 一些基礎的約束
約束名 說明
whitespace 空白字符被忽略
m 允許使用內存操作數,以及機器通常支持的任何類型的地址
o 允許使用內存操作數,但前提是地址是可偏移的
V 允許使用內存操作數,不可偏移的內存地址,與 “o’互斥
r 允許在通用寄存器中使用的寄存器操作數,其中可以指定寄存器,如 a(%rax), b(%rbx)
i 允許使用立即整數操作數
n 允許使用具有已知數值的立即整數操作數, ‘I’, ‘J’, ‘K’, … ‘P’ 更應該使用 n
F 允許使用浮點立即數
g 允許使用任何寄存器,內存或立即數整數操作數,但非通用寄存器除外
X 允許任何操作數, ‘0’, ‘1’, ‘2’, … ‘9’
p 允許使用有效內存地址的操作數
  • 標識符約束
標識符 說明
= 表示此操作數是由該指令寫入的:先前的值將被丟棄並由新數據替換
+ 表示該操作數由指令讀取和寫入
& 表示(在特定替代方法中)此操作數是早期指令操作數,它是在使用輸入操作數完成指令之前寫入的,故輸入操作數部分不能分配與輸出操作數相同的寄存器
% 表示該操作數與後續操作數的可交換指令

內核示例

  1. x86 的內存屏障指令。
// 避免編譯器的優化,聲明此處內存可能發生破壞
#define barrier() asm volatile("" ::: "memory")
// 在32位的CPU下,lock 指令為鎖總線,加上一條內存操作指令就達到了內存屏障的作用,64位的cpu已經有新增的 *fence 指令可以使用
// mb() 執行一個內存屏障作用的指令,為指定CPU操作;破壞列表聲明 cc memory 指示避免編譯器進行優化
#ifdef CONFIG_X86_32
#define mb() asm volatile(ALTERNATIVE("lock; addl $0,-4(%%esp)", "mfence", \
                                X86_FEATURE_XMM2) ::: "memory", "cc")
#define rmb() asm volatile(ALTERNATIVE("lock; addl $0,-4(%%esp)", "lfence", \
                                X86_FEATURE_XMM2) ::: "memory", "cc")
#define wmb() asm volatile(ALTERNATIVE("lock; addl $0,-4(%%esp)", "sfence", \
                                X86_FEATURE_XMM2) ::: "memory", "cc")
#else
#define mb()    asm volatile("mfence":::"memory")
#define rmb()   asm volatile("lfence":::"memory")
#define wmb()   asm volatile("sfence" ::: "memory")
#endif
  1. x86 下獲取 current 的值
DECLARE_PER_CPU(struct task_struct *, current_task);

#define this_cpu_read_stable(var)   percpu_stable_op("mov", var)

static __always_inline struct task_struct *get_current(void)
{
        return this_cpu_read_stable(current_task);
}

#define percpu_stable_op(op, var)           \
({                          \
        typeof(var) pfo_ret__;              \
        switch (sizeof(var)) {              \
        case 8:                     \
                asm(op "q "__percpu_arg(P1)",%0"    \
                : "=r" (pfo_ret__)          \
                : "p" (&(var)));            \
                break;                  \
        }                       \
        pfo_ret__;                  \
})

current_task 為一個 struct task_struct 類型的指針,追蹤宏調用,在x86-64 下命中了 case 8: 的彙編代碼, 展開的代碼為

asm("mov" "q ""%%""gs" ":" "%" "P1"",%0" : "=r" (pfo_ret__) : "p" (&(current_task)));
// 變換一下為
asm("movq %%gs:%P1, %0" : "=r"(pfo_ret__) : "p"(&(current_task)));

這行代碼的含義為將 約束輸入部分必須為有效的地址(p約束), 將CPU id(通過段寄存器gs和偏移通過GDT得到,這裏後文分析了)通過寄存器(r約束)賦值給 pfo_ret__.

參考

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

【其他文章推薦】

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

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

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

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

Spring Boot 2.X(十六):應用監控之 Spring Boot Actuator 使用及配置

Actuator 簡介

Actuator 是 Spring Boot 提供的對應用系統的自省和監控功能。通過 Actuator,可以使用數據化的指標去度量應用的運行情況,比如查看服務器的磁盤、內存、CPU等信息,系統的線程、gc、運行狀態等等。

Actuator 通常通過使用 HTTP 和 JMX 來管理和監控應用,大多數情況使用 HTTP 的方式。

Actuator 端點說明

端點 描述
auditevents 獲取當前應用暴露的審計事件信息
beans 獲取應用中所有的 Spring Beans 的完整關係列表
caches 獲取公開可以用的緩存
conditions 獲取自動配置條件信息,記錄哪些自動配置條件通過和沒通過的原因
configprops 獲取所有配置屬性,包括默認配置,显示一個所有 @ConfigurationProperties 的整理列版本
env 獲取所有環境變量
flyway 獲取已應用的所有Flyway數據庫遷移信息,需要一個或多個 Flyway Bean
liquibase 獲取已應用的所有Liquibase數據庫遷移。需要一個或多個 Liquibase Bean
health 獲取應用程序健康指標(運行狀況信息)
httptrace 獲取HTTP跟蹤信息(默認情況下,最近100個HTTP請求-響應交換)。需要 HttpTraceRepository Bean
info 獲取應用程序信息
integrationgraph 显示 Spring Integration 圖。需要依賴 spring-integration-core
loggers 显示和修改應用程序中日誌的配置
logfile 返回日誌文件的內容(如果已設置logging.file.name或logging.file.path屬性)
metrics 獲取系統度量指標信息
mappings 显示所有@RequestMapping路徑的整理列表
scheduledtasks 显示應用程序中的計劃任務
sessions 允許從Spring Session支持的會話存儲中檢索和刪除用戶會話。需要使用Spring Session的基於Servlet的Web應用程序
shutdown 關閉應用,要求endpoints.shutdown.enabled設置為true,默認為 false
threaddump 獲取系統線程轉儲信息
heapdump 返回hprof堆轉儲文件
jolokia 通過HTTP公開JMX bean(當Jolokia在類路徑上時,不適用於WebFlux)。需要依賴 jolokia-core
prometheus 以Prometheus服務器可以抓取的格式公開指標。需要依賴 micrometer-registry-prometheus

Actuator 使用及配置

快速使用

項目依賴

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
</dependencies>

配置文件

management.endpoints.enabled-by-default=true
#啟動所有端點
management.endpoints.web.exposure.include=*
#自定義管理端點路徑
#management.endpoints.web.base-path=/manage

Spring Boot 2.X 中,Actuator 默認只開放 health 和 info 兩個端點。

添加management.endpoints.web.exposure.include=*配置后啟動應用,訪問 http://127.0.0.1:8080/actuator 我們可以看到所有的 Actuator 端點列表。

如果將management.endpoints.enabled-by-default設置為false,則禁用所有端點,如需啟用則如下:

management.endpoints.enabled-by-default=false
management.endpoint.info.enabled=true

禁用的端點將從應用程序上下文中完全刪除。如果只想更改公開端點,使用include和exclude屬性。使用如下:

management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env,beans

management.endpoints.web.base-path=/manage 配置表示將 /actuator 路徑重定義為 /manage。

常用端點詳解

health

主要用來檢測應用的運行狀況,是使用最多的一個監控點。監控軟件通常使用該接口實時監測應用運行狀況,在系統出現故障時把報警信息推送給相關人員,如磁盤空間使用情況、數據庫和緩存等的一些健康指標。
默認情況下 health 端點是開放的,訪問 http://127.0.0.1:8080/actuator/health 即可看到應用運行狀態。

{"status":"UP"}

如果需要看到詳細信息,則需要做添加配置:

management.endpoint.health.show-details=always

訪問返回信息如下:

{"status":"UP","details":{"diskSpace":{"status":"UP","details":{"total":180002725888,"free":8687988736,"threshold":10485760}}}}

info

查看應用信息是否在 application.properties 中配置。如我們在項目中配置是:

info.app.name=Spring Boot Actuator Demo
info.app.version=v1.0.0
info.app.description=Spring Boot Actuator Demo

啟動項目,訪問 http://127.0.0.1:8080/actuator/info 返回信息如下:

{"app":{"name":"Spring Boot Actuator Demo","version":"v1.0.0","description":"Spring Boot Actuator Demo"}}

env

通過 env 可以獲取到所有關於當前 Spring Boot 應用程序的運行環境信息,如:操作系統信息(systemProperties)、環境變量信息、JDK 版本及 ClassPath 信息、當前啟用的配置文件(activeProfiles)、propertySources、應用程序配置信息(applicationConfig)等。

可以通過 http://127.0.0.1:8080/actuator/env/{name} ,name表示想要查看的信息,可以獨立显示。

beans

訪問 http://127.0.0.1:8080/actuator/beans 返回部分信息如下:

{
    "contexts": {
        "Spring Boot Actuator Demo": {
            "beans": {
                "endpointCachingOperationInvokerAdvisor": {
                    "aliases": [
                    ],
                    "scope": "singleton",
                    "type": "org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor",
                    "resource": "class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.class]",
                    "dependencies": [
                        "environment"
                    ]
                },
                "defaultServletHandlerMapping": {
                    "aliases": [
                    ],
                    "scope": "singleton",
                    "type": "org.springframework.web.servlet.HandlerMapping",
                    "resource": "class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]",
                    "dependencies": [
                    ]
                },
                ...
            }
        }
    }
}

從返回的信息中我們可以看出主要展示了 bean 的別名、類型、是否單例、類的地址、依賴等信息。

conditions

通過 conditions 可以在應用運行時查看代碼了某個配置在什麼條件下生效,或者某個自動配置為什麼沒有生效。

訪問 http://127.0.0.1:8080/actuator/conditions 返回部分信息如下:

{
    "contexts": {
        "Spring Boot Actuator Demo": {
            "positiveMatches": {
                "SpringBootAdminClientAutoConfiguration": [
                    {
                        "condition": "OnWebApplicationCondition",
                        "message": "@ConditionalOnWebApplication (required) found 'session' scope"
                    },
                    {
                        "condition": "SpringBootAdminClientEnabledCondition",
                        "message": "matched"
                    }
                ],
                "SpringBootAdminClientAutoConfiguration#metadataContributor": [
                    {
                        "condition": "OnBeanCondition",
                        "message": "@ConditionalOnMissingBean (types: de.codecentric.boot.admin.client.registration.metadata.CompositeMetadataContributor; SearchStrategy: all) did not find any beans"
                    }
                ],
                ...
            }
        }
    }
}

loggers

獲取系統的日誌信息。

訪問 http://127.0.0.1:8080/actuator/loggers 返回部分信息如下:

{
    "levels": [
        "OFF",
        "ERROR",
        "WARN",
        "INFO",
        "DEBUG",
        "TRACE"
    ],
    "loggers": {
        "ROOT": {
            "configuredLevel": "INFO",
            "effectiveLevel": "INFO"
        },
        "cn": {
            "configuredLevel": null,
            "effectiveLevel": "INFO"
        },
        "cn.zwqh": {
            "configuredLevel": null,
            "effectiveLevel": "INFO"
        },
        "cn.zwqh.springboot": {
            "configuredLevel": null,
            "effectiveLevel": "INFO"
        },
        ...
    }
}

mappings

查看所有 URL 映射,即所有 @RequestMapping 路徑的整理列表。

訪問 http://127.0.0.1:8080/actuator/mappings 返回部分信息如下:

{
    "contexts": {
        "Spring Boot Actuator Demo": {
            "mappings": {
                "dispatcherServlets": {
                    "dispatcherServlet": [
                        {
                            "handler": "ResourceHttpRequestHandler [class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/], class path resource []]",
                            "predicate": "/**/favicon.ico",
                            "details": null
                        },
                        ...
                    ]
                }
            }
        }
    }
}

heapdump

訪問:http://127.0.0.1:8080/actuator/heapdump會自動生成一個 GZip 壓縮的 Jvm 的堆文件 heapdump,我們可以使用 JDK 自帶的 Jvm 監控工具 VisualVM 打開此文件查看。如圖:

VisualVM下載:https://visualvm.github.io/download.html

threaddump

獲取系統線程的轉儲信息,主要展示了線程名、線程ID、線程的狀態、是否等待鎖資源等信息。在工作中,我們可以通過查看線程的情況來排查相關問題。

訪問 http://127.0.0.1:8080/actuator/threaddump 返回部分信息如下:

{
    "threads": [
        {
            "threadName": "DestroyJavaVM",
            "threadId": 40,
            "blockedTime": -1,
            "blockedCount": 0,
            "waitedTime": -1,
            "waitedCount": 0,
            "lockName": null,
            "lockOwnerId": -1,
            "lockOwnerName": null,
            "inNative": false,
            "suspended": false,
            "threadState": "RUNNABLE",
            "stackTrace": [
            ],
            "lockedMonitors": [
            ],
            "lockedSynchronizers": [
            ],
            "lockInfo": null
        },
        ...
    ]
}

shutdown

開啟可以接口關閉 Spring Boot 應用,要使用這個功能需要做如下配置:

management.endpoint.shutdown.enabled=true

可以通過 post(僅支持 post) 請求訪問 http://127.0.0.1:8080/actuator/shutdown 關閉應用。

metrics

訪問 http://127.0.0.1:8080/actuator/metrics 可以獲取系統度量指標信息項如下:

{
    "names": [
        "jvm.memory.max",
        "jvm.threads.states",
        "jvm.gc.pause",
        "http.server.requests",
        "process.files.max",
        "jvm.gc.memory.promoted",
        "system.load.average.1m",
        "jvm.memory.used",
        "jvm.gc.max.data.size",
        "jvm.memory.committed",
        "system.cpu.count",
        "logback.events",
        "tomcat.global.sent",
        "jvm.buffer.memory.used",
        "tomcat.sessions.created",
        "jvm.threads.daemon",
        "system.cpu.usage",
        "jvm.gc.memory.allocated",
        "tomcat.global.request.max",
        "tomcat.global.request",
        "tomcat.sessions.expired",
        "jvm.threads.live",
        "jvm.threads.peak",
        "tomcat.global.received",
        "process.uptime",
        "tomcat.sessions.rejected",
        "process.cpu.usage",
        "tomcat.threads.config.max",
        "jvm.classes.loaded",
        "jvm.classes.unloaded",
        "tomcat.global.error",
        "tomcat.sessions.active.current",
        "tomcat.sessions.alive.max",
        "jvm.gc.live.data.size",
        "tomcat.threads.current",
        "process.files.open",
        "jvm.buffer.count",
        "jvm.buffer.total.capacity",
        "tomcat.sessions.active.max",
        "tomcat.threads.busy",
        "process.start.time"
    ]
}

對應訪問 names 中的指標,可以查看具體的指標信息。如訪問 http://127.0.0.1:8080/actuator/metrics/jvm.memory.used 返回信息如下:

{
    "name": "jvm.memory.used",
    "description": "The amount of used memory",
    "baseUnit": "bytes",
    "measurements": [
        {
            "statistic": "VALUE",
            "value": 1.16828136E8
        }
    ],
    "availableTags": [
        {
            "tag": "area",
            "values": [
                "heap",
                "nonheap"
            ]
        },
        {
            "tag": "id",
            "values": [
                "Compressed Class Space",
                "PS Survivor Space",
                "PS Old Gen",
                "Metaspace",
                "PS Eden Space",
                "Code Cache"
            ]
        }
    ]
}

示例代碼

參考文檔

https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/html/production-ready-features.html

非特殊說明,本文版權歸 所有,轉載請註明出處.

原文標題:Spring Boot 2.X(十六):應用監控之 Spring Boot Actuator 使用及配置

原文地址:

如果文章對您有幫助,請掃碼關注下我的公眾號,文章持續更新中…

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

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

深入理解計算機系統 — 信息的表示和處理

1. 信息的存儲

    大多數計算機使用 8 位的塊,或者字節,作為最小的尋址內存單位,而非訪問內存中單獨的位,機器級程序將內存視為一個非常大的字節數組,稱為 虛擬內存 ,內存的每個字節都用一個唯一的数字標識,稱為它的 地址 。以 C 語言的指針為例,指針使用時指向某一個存儲塊的首字節的 虛擬地址 ,C 編譯器將指針和其類型信息結合起來,這樣即可以根據指針的類型,生成不同的機器級代碼來訪問存儲在指針所指向位置處的值。每個程序對象可以簡單視為一個字節塊,而程序本身就是一個字節序列。

1.1 十六進製表示法

    一個字節由 8 位組成。用二進製表示即 00000000 ~ 11111111 。十進製表示為 0 ~ 255 。由於兩者表示要麼過於冗餘,要麼轉換不遍,因此通常使用十六進制來表示一個字節。這幾種進制的轉換在此就不多說了。

1.2 字數據大小

    每台計算機都會有一個字長(此處字長非字節長度),指明 指針數據的標稱大小(nominal size),因為虛擬地址是以這樣的一個字來進行編碼的,所以字長決定的最重要的一個系統參數即是虛擬地址空間的最大大小。 對於一個字長為 w 位的機器而言,虛擬地址的範圍為 0 ~ (2 ^w )- 1 ,程序最多訪問 2 ^ w 個字節。以 32 位機器為例,32位字長限制虛擬地址空間為 (2 ^32) -1 ,程序最多訪問 2 ^ 32 個字節,大約為 4 x 10^9 字節,即4 GB ( 根據 2 ^ 10 (1024) 約等於 10 ^ 3 (1000) ,可以得到 2 ^ 32 =  4 * 2^30 = 4 * 10 ^ 9 ) 。64位機器的限制虛擬地址空間為 16 EB。大約為 1.84 x 10 ^9 。

1.3 尋址和字節順序

    對於跨越多個字節的對象,我們必須建立兩個規則:這個對象的地址是什麼以及在內存中如何排列這些字節。在幾乎所有的機器上,多字節對象都被存儲為連續的字節序列,對象的地址為這個字節序列中最小的字節地址。以 int 類型為例,假定int 大小為32 位,有變量 int x = 0x01234567 。若 x 的地址為 0x100 ,則 x 的 4 個字節將被存儲在 0x100 , 0x101 , 0x102, 0x103 的位置,此時 4個字節的值分別為 0x01, 0x23, 0x45, 0x67,那麼在內存中的排列順序有如下兩種情況,

  • 大端法:最高有效字節放在最前面的方式稱為大端法,即將一個数字的最高位字節放在最小的字節地址。
  • 小端法:最低有效字節放在最前面的方式稱為小端法,即將一個数字的最低位字節放在最小的字節地址。

  以上面的 x 為例,x 的最高位字節是 0x01 ,將其放在最小的字節地址即 0x100。x 的最低位字節為 0x67 ,將其放在最小的字節地址 0x100 。即大小端對應高低位字節。對於我們來說,機器的字節順序是完全不可見的,我們大部分情況下也無需關心其字節順序,但是在不同類型的機器之間通過網絡傳遞二進制數據的時候,如小端法機器傳送數據給大端法機器時,接受方接收到的字節序會變成反序,為了避免這種問題的產生,發送方和接收方都需要遵循一個網絡規則,發送方將二進制數據轉換成網絡標準,接收方再將這個網絡標準的字節序轉換成自己的字節序。此外,我們在閱讀機器級代碼的時候,可能會出現如下的情況:

  暫時忽略這條指令的意義,可以看到左邊6個字節分別為 01 05 43 0b 20 00 ,而右邊的指令中的地址為 0x200b43,可以看到從左邊的第三個字節開始,43 0b 20 是右邊指令地址的倒序,因此在閱讀這種機器級代碼的時候,也需要注意字節序的問題。此外還存在一種情況。如下圖所示。

    我們可以看到, show_bytes 這個函數可以打印出 start 指針指向的地址開始的 len 個字節內容,且不受字節序的影響,那麼它是如何做到的呢?在 show_int 函數中,可以看到它將 參數 x 的地址強制類型轉換為了 byte_pointer , 即 unsigned char * 。通過強制類型轉換的 start 指針指向的仍是 x 的最低字節地址,但是其類型改變了,通過其類型編譯器會認為該指針指向的對象大小為 1 個字節,此時將該指針進行 ++ 操作可以得到順延下一個字節的內容,從而得到對應的整個對象的字節序列中每個字節的內容而不受字節序影響。

1.4 字符串

    在C語言中,字符串被編碼為一個以 null (其值為0 )字符結尾的字符數組。每個字符都有某個標準編碼來表示,最常見的則是 ASCII 字符碼。假如我們調用 show_bytes(“12345”, 6),那麼會輸出 31 32 33 34 35 00 。可以看到最後打印出了一個終止符,所以通常 C 字符串的長度為實際字符串長度 + 1。 在C 標準庫中的 strlen 函數可以傳入一個字符串得出其長度,這裏的長度即是實際長度,不包含終止符。

2. 整數表示

    在本章節中,介紹了編碼整數的兩種不同的方式,一種只能表示非負數,另一種則能夠表示負數,正數和零。接下來逐一進行介紹。

2.1 整型數據類型

    C語言中,整數有多種數據類型,如下圖所示,此外可以通過加上 unsigned 符號來限定該數據類型為非負數。這些數據類型有的是根據機器的字長(32位和64位)決定其實際最大值和最小值的範圍。我們可以看到,圖中最小值和最大值的取值範圍是不對稱的,負數的取值範圍比正數大一,當我們考慮如何表現負數時,會看到為什麼會這樣。

    關於無符號整數的編碼,其實與普通的十進制正數轉換成二進制沒有什麼區別,假設字長 w = 32 位,轉換后大於 32 位的数字將被捨去。這裏主要介紹一下關於有符號数字的編碼,通常計算機使用的編碼錶示方式為 補碼 ,在這個表示方式中,將字的最高有效位(即符號位)表示為負權,權重為 – 2^(w-1) ,當 w 位的值為 1 時表示為負數,反之為正數。以 -1 為例,-1 的補碼為1111 1111  …. …. 1111 ,即 -2^31 + 2^30 + … + 2^0 = -1 ,通常我們看到一個負數想要直接將其使用補碼錶示還是有些不方便的,因此我們可以先使用原碼錶示,所謂原碼和普通的十進制數轉二進制數沒有區別,只不過最高位用來表示符號位,然後再求其反碼,即符號位不變,其餘位取反加 1,就可以得到這個負數的補碼了,還是以 -1 舉例, -1 的原碼為 1000 0000 …. 0001 ,其反碼的值為 1111 1111 …. 1111 ,與 -1 的補碼值是相同的。而正數的補碼為其本身,不需要做這種轉換。

    那麼為什麼要使用補碼這種表示方式呢,首先,二進制補碼可以使正負數相加時仍然採用正常加法的邏輯,不需要做特殊的處理,此外,如果不採用補碼錶示,採用原碼的表示方法,那麼會出現幾個問題,正負零的存在,以及提高了減法的計算複雜度,而補碼可以十分簡單的計算正負數相加,只需求出兩者的補碼對其進行加法,更多關於補碼的解釋可以參考  。

PS: 為什麼正負數補碼相加會得到正確的結果,這裏個人的見解是:由於補碼最高位為負權,而正數與負數補碼相加相當於正數去抵消這個負權。比如 -16 的補碼為 1111 …. 1111 0000,加上正數 1,由於正數的補碼為本身,所以等價於 -16 + 1  == (-2^31 + 2^30 + … + 2^4 ) +  2^ 0 ,相當於多了一個 2^0 的正權去抵消其最高位的負權。

2.2 有符號數和無符號數之間的轉換

    C語言允許各種不同的数字類型之間進行強制類型轉換, 如 int x= -1 ; unsigned y = (unsigned) x ; 此時會將 x 的值強制類型轉換成 unsigned 類型然後賦值給 y ,那麼此時 y 的值是多少呢?可以通過打印兩者的十六進制值來看有什麼區別。下面為 test.c 的代碼:

int main()

{

int x = -1;

unsigned y = (unsigned) x;

printf(“%x \n”, x);

printf(“%x \n”, x);

return 0;

}

此處為編譯后可執行文件的輸出結果:

ffffffff
ffffffff

可以看到, x 和 y 的十六進制值是相同的,這也說明了,強制類型轉換並不會改變數據底層的位表示,只是改變了解釋位模式的方式。我們可以利用 printf 的指示符進一步驗證這個結果,使用 %d (有符號十進制), %u (無符號十進制), 來打印 x 和 y 的值。以下是代碼:

int main()

{

int x = 1;

unsigned y = (unsigned) x;

printf(“x format d = %d , format u = %u \n”, x, x);

printf(“y format d = %d , format u = %u \n”, y, y);

return 0;

}

這是編譯后可執行文件的對應輸出:

x format d = -1 , format u = 4294967295
y format d = -1 , format u = 4294967295

 我們可以看到,我們使用指示符控制了解釋這些位的方式,得到的結果是一致的。

2.3 整數運算

 關於整數的運算,主要就是加減乘除四種運算,補碼的加減乘除都比較簡單明了,這裏主要說一下除法的舍入問題,首先,我們先確認下 C 語言中的舍入方式,在 C 語言中,浮點數被賦值給整數時,小數位總是被捨去,如

float f = 1.5;

int x = f ;

printf(“%d \n “, x);

輸出的結果為:

1

當 f 為負數時結果又是如何呢 ?

float f = -1.5 ;

int x = f;

printf(“%d \n”, x);

輸出的結果為:

-1

因此我們可以認為,C語言的舍入方式為向零舍入。接下來看一下除法的舍入問題。此處先以除以 2 的冪的無符號除法為例,

上圖表示 12340 / 2^k 的時候二進制與對應的十進制的表示,此時的舍入是完全沒有問題的。接下來看下除以 2 的冪的有符號除法。

    當k = 4 的時候,-12340 / 2^ 4 == -771.25,此時的正確舍入值應該為 -771,但是其卻舍入成了 -772。這是因為,如果我們單純使用右移來進行除法的時候,其舍入方式為向下舍入,即總是往更小值的方向舍入,在沒有小數位的情況下是正確的,但是如果有小數位的時候,如 -771.25 舍入為 -772, 771.25 舍入為 771。而C語言的舍入方式為向零舍入,即總是往靠近零的值舍入,如 771.25 舍入為 771, -771.25 舍入為 -771。那麼如何實現這種舍入方式呢。當被除數為負數時,我們可以通過加上一個偏置值來糾正這種不正確的舍入方式。

    我們可以觀察一下上圖的有符號除法例子,可以發現,當右移的 k 位單獨拿出來,不為 0 的時候,會導致舍入結果不正確,這是因為,k 位的值不為 0 的時候,表示該結果有小數,所以可以通過 (x + (1 << k) – 1) >> k 得到正確的結果, (1 << k) – 1 可以獲得 k 個 1,x 加上 k 個 1 可以使捨去的 k 位不為 0 時產生進位,x >> k 的結果加一,從而使舍入正確。

關於整數的表示和運算,個人覺得有幾個需要關注的點,一是溢出問題,由於使用有限的位來表示整數,所以當数字過大的時候可能會產生溢出,溢出的位會被捨去,但是有符號數的溢出可能會使符號位被置反,如 0111 1111 …. 1111 + 1 = 1000 0000 …. 0000,0111 1111 …. 1111 為 INT_MAX , INT_MAX + 1 會得到 INT_MIN。此外,無符號數與有符號數進行比較的時候,會使有符號數強制轉換為無符號數,如果有以下循環代碼:

for(size_t i = 10; i >= 0 ; i–);

由於 i 為無符號數,當 i == 0 的時候,判斷還會繼續循環下去, 0 – 1  = -1 , -1 的補碼錶示為 1111 1111 …. 1111 , 剛好是無符號數的最大值,會導致死循環。因此也需要注意一切與無符號類型數據的運算,以及強制類型轉換可能出現的問題。

3. 浮點數

    終於來到了這一章的重點內容之一(其實感覺這本書哪裡都挺重要的),這裏主要介紹浮點數是如何表示的,並且介紹浮點數舍入的問題(和上面講到的舍入不大一樣),浮點數的表示及其運算標準稱為 IEEE754 標準,初看可能會讓你覺得有些晦澀難懂,但是理解之後會覺得設計的十分巧妙。

3.1 定點表示法

    首先讓我們先看下十進制的浮點數是如何表示的,浮點數的定義與小數點息息相關,定義在小數點左邊的数字的權是 10 的正冪,右邊的数字為 10 的負冪,如 12.34 表示 1 * 10^ 1 + 2 * 10^0 + 3 * 10 ^-1 + 4 * 10 ^ -2 = 12又34/100,同理可以得到二進制的浮點數表示,即定義在小數點左邊的数字的權是 2 的正冪,右邊的数字為 2 的負冪,如 101.11 = 1 * 2^2 + 0 * 2^1 + 1 * 2^0 + 1 * 2^-1 + 1 * 2^-2 。這種浮點數的表示方法是有缺陷的,無法精準的表示特定的数字,以 1/5 為例,可以用 十進制数字 0.2 表示,但是我們無法用二進制數字錶示它,只能近似的表示它,通過增加二進製表示的長度可以提升表示的精度。如下圖所示。

3.2 IEEE754標準

    在前面談到的定點表示法不能有效的表示一個比較大的数字,例如 5 x 2^100 是用 101 後面跟隨 100 個零的位模式,我們希望能夠通過給定 x 和 y 的值來表示如 x * 2 ^y 的数字。IEEE754 標準使用 V = ( – 1)^S * M * 2^E 的形式來表示一個數。

  • 符號(Sign): S 決定這個數是負數(S = 1 )還是正數 (S = 0), 對於數值為 0 的符號位做特殊解釋。
  • 尾數(Significand): M 是一個二進制小數,範圍為 1 ~ 2 – e , 或者是 0 ~ 1 – e 。
  • 階碼(Exponent): E 的作用是對浮點數進行加權,這個權重是 2 的 E 次冪(E 可能為負數)。

通過將浮點數的位劃分為三個字段,分別對這些值進行編碼:

  • 一個單獨的符號位 S 。
  • k 位的階碼字段 ,exp = e(0) e(1) e(2) … e(k-1) ,exp 用來編碼階碼 E。
  • n 位的小数字段 ,   frac = f(n-1) … f(1) f(0) ,frac 用來編碼尾數 M。

下圖是該標準下封裝到字中的兩種最常見的格式。

此外,根據階碼值(exp),被編碼的值可以分為下圖幾種情況(階碼值全為 0 ,階碼值全為 1 , 階碼值不全為 0 也不全為 1):

接下來對這幾種格式進行一一介紹~:

  • 規格化浮點數 : 這是最普遍的情況,當 exp 的值不全為 0 也不全為 1 時,就屬於這種情況,這種情況下,階碼值 E = e – bias ,其中 e 為無符號數,即 exp 的值,而 bias 是一個 2^(k-1) – 1 的偏置值(單精度為 127,雙精度為 1023),而小数字段 frac 被解釋為描述小數值 f ,其中 0 <= f < 1,其二進製表示為 0.f(n-1)…f(1)f(0) 的数字,也就是二進制小數點在最高有效位的左邊的形式。尾數定義為 M = 1 + f 。 有時候這種方式也叫做 隱含 1 開頭的表示(implied leading  1),因為這種定義我們可以把 M 看成一個二進製表示為 1.f(n-1) … f(1)f(0) 的数字。既然我們總是能調整階碼 E ,使得尾數 M 在範圍 1 <= M < 2 之中(假設沒有溢出),那麼這樣可以節約一個位,因為第一位總是為 1 。
  • 非規格化浮點數 : 當 exp 的值全為 0 的時候,所表示的浮點數為非規格化類型,E = 1 – bias ,而尾數的值為 M = f 。不含開頭的 1 。非規格化有兩種用途,首先它提供了表示  0 的方法,因為規格化數使得 M >=  1,所以不能表示 0 ,另外非規格化數另一個功能則是表示那些非常接近於 0.0 的數,他們提供了一種屬性,稱為逐漸溢出,其中,可能的數值均勻分佈接近於 0.0 。
  • 特殊值 : 最後一類數值是指當階碼全為 1 的時候出現的。當小數域全為 0 時,表示為無窮大/小,當我們將兩個非常大的數相乘時,或者除以零時,無窮能夠表示溢出的結果。當小數域為非 0 時,結果為 NaN(Not a Number),一些運算的結果不能為實數或者無窮時,會返回 NaN,比如 根號 -1 ,或者 無窮減無窮。此外,在某些應用中也可以用來表示未初始化的數值。

    首先,通過一個字長為 8 位的例子,來看一下IEEE754標準實際上使用時是如何表示的 :

    上圖為展示了假定 w = 8 的字長,k = 4 的階碼位以及 n = 3 的小數位。偏移量為 2 ^ ( k -1 ) -1 = (2 ^ 3) – 1 = 7。圖中分別展示了非規格化數,規格化數以及特殊值是如何編碼的,以及如何結合在一起表示 V = (2^E) * M。我們可以看到,從最大非規格化數到最小規格化數,其值的轉變十分平滑,從 7/512 到 8/512 。這得益於非規格化數的 E 定義為 1 – bias ,最大的非規格化數的階碼值 E 與最小的規格化數的階碼值 E 是相等的,兩者唯一的區別在於 M 值,規格化數尾數 M = 1 + f ,而非規格化的尾數 M = f ,因為非規格化值是用於表示 [0, 1] 區間的小數的,當 f 達到最大值時, f 接近於 1 ,此時最大的非規格化數再進一位,小數 M 只能表示為 1 ,因為此時限制於 f 的位數,沒有比 f 大又比 1 小的小數值 ,進位後轉換成了規格化數,此時 f = 0 , 在階碼值 E 相等的情況下,讓規格化的 M = 1 + f 恰好可以使兩者進行平滑的轉換。

    假如我們使非規格化數的 E = 0 – bias = -7 ,那麼會導致最大非規格化數和最小規格化數的粒度過大,兩者的值分別為 7/1024 和 8/512 。這種定義可以彌補非規格化數的尾數沒有隱含的 1 。通過上述的例子,我們可以發現 ,假如我們把上述的例子按無符號整數表示的話,會發現它的值是有序上升的,這不是偶然的,IEEE 格式如此設計就是為了浮點數能夠使用整數排序函數進行排序。

    通過練習將整數值轉換為浮點數值形式對理解浮點數很有用,以 12345(十進制) 為例,其二進製表示為 1100 0000 1110 01 . 0  ,通過將小數點左移 13 位得到 1.1000000111001 * 2^13 ,我們丟棄開頭的 1 (這裏的 1 就是規格化數隱含的 1),構造小数字段,當 f 不足 23 位的時候,往後填充 0 ,即 M = 1 + f = 1 + 1000 0001 1100 1000 0000 000 ,當 f 大於 23 位的時候,f 多出的位會被捨棄(這裏可以看出浮點數的兩個性質,以 int 類型和 float 類型舉例,當 int 值 大於 2^24 的時候,int 轉換成 float 兩者很有可能值會不相等,因為多出的部分被捨棄了,二是 float 可以表示的數值遠遠大於 int 類型,V =  (-1 ^ S)  * M * 2^E  ,E 最高可以等於 127 ,float 的最大值為 (2^127) * (1 + f),而 int 最大值為 (2^31) -1。

3.3 舍入

    浮點數的舍入方式有四種,分別是向上舍入,向下舍入,向零舍入,向偶數舍入。下圖是幾種舍入方式的例子 :

偶數舍入是浮點數默認的舍入方式,可以看到,向偶數舍入時,當小數值為中間值時,會使最低有效数字總為偶數,如 2.5 和 1.5 都舍入為 2 。為什麼使用向偶數舍入呢,假設我們採用向上舍入,用這種方法舍入一組數值,會在計算這些值的平均值中引入統計偏差。我們採用這種方式舍入得到的平均值總是比這些數本身的平均值要略高一些,反之向下舍入亦然,向偶數舍入則可以使在 50% 的時間內向上舍入,50% 的時間內向下舍入。

4. 小結

    • 計算機將信息編碼為位(bit),通常組織成字節序列,有不同的編碼方式來表示整數,實數和字符串。不同的計算機模型在編碼数字和多字節數據中的字節順序時使用不同的約定。
    • 絕大部分機器使用補碼來編碼整數。對於浮點數使用 IEEE754 標準來編碼。
    • 在進行對無符號和有符號整數進行強制類型轉換時,底層的位模式是不變的。(浮點數與整數轉換則會進行 改變,如 float f = 1.25; int x = f; 此時打印兩者的十六進制值,可以分別輸出為 f = 92463258 ,x = 1 )
    • 由於編碼的長度有限,當超出表示範圍時,有限長度會引起數值溢出,如 x * x 可能會得到負數。當浮點數非常接近於 0.0 時,轉換成 0 時也會產生下溢。
    • 使用補碼運算 ~x + 1 = -x (不適用於 INT_MIN) 。可以通過 (2^k) – 1 生成一個 k 位的掩碼。
    • 浮點數不具備結合率,因為可能發生溢出或者舍入,從而失去精度。如(le20 * le20) * le-20 = 正無窮,而 le20 * (le20 * le-20) = le20 。此外也不具備分配性,如 le20 * (le20 – le20) = 0.0 ,而 le20 * le20 – le20 * le20 = NaN。

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

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