串燒 JavaCAS相關知識

JMM與問題引入

為啥先說JMM,因為CAS的實現類中維護的變量都被volatile修飾, 這個volatile 是遵循JMM規範(不是百分百遵循,下文會說)實現的保證多線程併發訪問某個變量實現線程安全的手段

一連串的知識點慢慢縷

首先說什麼是JMM, JMM就是大家所說的java的內存模型, 它是人們在邏輯上做出的劃分, 或者可以將JMM當成是一種規範, 有哪些規範呢? 如下

  1. 可見性: 某一個線程對內存中的變量做出改動后,要求其他的線程在第一事件內馬上馬得到通知,在CAS的實現中, 可見性其實是通過不斷的while循環讀取而得到的通知, 而不是被動的得到通知
  2. 原子性: 線程在執行某個操作的時,要麼一起成功,要麼就一起失敗
  3. 有序性: 為了提高性能, 編譯器處理器會進行指令的重排序, 源碼-> 編譯器優化重排 -> 處理器優化重排 -> 內存系統重排 -> 最終執行的命令

JVM運行的實體是線程, 每一個線程在創建之後JVM都會為其創建一個工作空間, 這個工作空間是每一個線程之間的私有空間, 並且任何兩條線程之間的都不能直接訪問到對方的工作空間, 線程之間的通信,必須通過共享空間來中轉完成

JMM規定所有的變量全部存在主內存中,主內存是一塊共享空間,那麼如果某個線程相對主內存中共享變量做出修改怎麼辦呢? 像下面這樣:

  1. 將共享變量的副本拷貝到工作空間中
  2. 對變量進行賦值修改
  3. 將工作空間中的變量寫回到內存中

JMM還規定如下:

  • 任何線程在解鎖前必須將工作空間的共享變量立即刷新進內存中
  • 線程在加鎖前必須讀取主內存中的值更新到自己的工作空間中
  • 加鎖和解鎖是同一把鎖

問題引入

這時候如果多個線程併發按照上面的三步走去訪問主內存中的共享變量的話就會出現線程安全性的問題, 比如說 現在主內存中的共享變量是c=1, 有AB兩個線程去併發訪問這個c變量, 都想進行c++, 現在A將c拷貝到自己的工作空間進行c++, 於是c=2 , 於此同時線程B也進行c++, c在B的工作空間中=2, AB線程將結果寫回工作空間最終的結果就是2, 而不是我們預期的3

相信怎麼解決大家都知道, 就是使用JUC,中的原子類就能規避這個問題

而原子類的底層實現使用的就是CAS技術

什麼是CAS

CAS(compare and swap) 顧名思義: 比較和交換,在JUC中原子類的底層使用的都是CAS無鎖實現線程安全,是一門很炫的技術

如下面兩行代碼, 先比較再交換, 即: 如果從主內存中讀取到的值為4就將它更新為2019

        AtomicInteger atomicInteger = new AtomicInteger(4);
        atomicInteger.compareAndSet(4,2019);

跟進AtomicInteger的源碼如下, 底層維護着一個int 類型的 變量, (當然是因為我選擇的原來類是AtomicInteger類型), 並且這個int類型的值被 volatile 修飾

    private volatile int value;

    /**
     * Creates a new AtomicInteger with the given initial value.
     *
     * @param initialValue the initial value
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

什麼是volatile

volatile是JVM提供的輕量的同步機制, 為什麼是輕量界別呢? , 剛才在上面說了JMM規範中提到了三條特性, 而JVM提供的volatile僅僅滿足上面的規範中的 2/3, 如下:

  1. 保證可見性
  2. 不保證原子性
  3. 禁止指令重排序

單獨的volatile是不能滿足原子性的,即如下代碼在多線程併發訪問的情況下依然會出現線程安全性問題

private volatile int value;
 
public void add(){
  value++;   
}

那麼JUC的原子類是如何實現的 可以滿足原子性呢? 於是就不得不說本片博文的主角, CAS

CAS源碼跟進

我們跟進AtomicInteger中的先遞增再獲取的方法 incrementAndGet()

    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

通過代碼我們看到調用了Unsafe類來實現

什麼是Unsafe類?

進入Unsafe類,可以看到他裏面存在大量的 native方法,這些native方法全部是空方法,

這個unsafe類其實相當於一個後門,他是java去訪問調用系統上 C C++ 函數類庫的方法 如下圖

繼續跟進這個方法incrementAndGet() 於是我們就來到了我們的主角方法, 關於這個方法倒是不難理解,主要是搞清楚方法中的var12345到底代表什麼就行, 如下代碼+註釋

var1: 上一個方法傳遞進來的: this,即當前對象
var2: 上一個方法傳遞進來的valueOffset, 就是內存地址偏移量
      通過這個內存地址偏移量我能精確的找到要操作的變量在內存中的地址
      
var4: 上一個方法傳遞進來的1, 就是每次增長的值
var5: 通過this和內存地址偏移量讀取出來的當前內存中的目標值
public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

注意它用的是while循環, 相對if(flag){} 這種寫法會多一次判斷, 整體的思路就是 在進行修改之前先進行一次比較,如果讀取到的當前值和預期值是相同的,就自增,否則的話就繼續輪詢修改

小總結

通過上面的過程, 其實就能總結出CAS的底層實現原理

  • volatile
  • 自旋鎖
  • unsafe類

補充: CAS通過Native方法的底層實現,本質上是操作系統層面上的CPU的併發原語,JVM會直接實現出彙編層面的指令,依賴於硬件去實現, 此外, 對於CPU的原語來說, 有兩條特性1,必定連續, 2.不被中斷

CAS的優缺點

優點:

它的底層我們看到了通過do-while 實現的自旋鎖來實現, 就省去了在多個線程之間進行切換所帶來的額外的上下文切換的開銷

缺點:

  1. 通過while循環不斷的嘗試獲取, 省去了上下文切換的開銷,但是佔用cpu的資源
  2. CAS只能保證一個共享變量的原子性, 如果存在多個共享變量的話不得不加鎖實現
  3. 存在ABA問題

ABA問題

什麼是ABA問題

我們這樣玩, 還是AB兩個線程, 給AtomicInteger賦初始值0

A線程中的代碼如下:

        Thread.sleep(3000);
        atomicInteger.compareAndSet(0,2019);

B線程中的代碼如下:

        atomicInteger.compareAndSet(0,1);
        atomicInteger.compareAndSet(1,0);

AB線程同時啟動, 雖然最終的結果A線程能成果的將值修改成2019,,但是它不能感知到在他睡眠過程中B線程對數據進行過改變, 換句話說就是A線程被B線程欺騙了

ABA問題的解決— AtomicStampedRefernce.java

帶時間戳的原子引用, 實現的機制就是通過 原子引用+版本號來完成, 每次對指定值的修改相應的版本號會加1, 實例如下

        // 0表示初始化, 1表示初始版本號
        AtomicStampedReference<Integer> reference = new AtomicStampedReference<>(0, 1);
        reference.getStamp(); // 獲取版本號
        reference.attemptStamp(1,2); // 期待是1, 如果是1就更新為2

原子引用

JUC中我們可以找到像AtomicInteger這樣已經定義好了實現類, 但是JUC沒有給我們提供類似這樣 AtomicUser或者 AtomicProduct 這樣自定義類型的原子引用類型啊, 不過java仍然是提供了後門就是 原子引用類型

使用實例:

        User user  = getUserById(1);
        AtomicReference<User> userAtomicReference = new AtomicReference<User>();
        user.setUsername("張三");
        userAtomicReference.compareAndSet(user,user);

歡迎關注我, 會繼續更新筆記

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

3c收購,鏡頭 收購有可能以全新價回收嗎?

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

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

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

賣IPHONE,iPhone回收,舊換新!教你怎麼賣才划算?

[UWP]用Win2D和CompositionAPI實現文字的發光效果,並製作動畫

1. 成果

獻祭了周末的晚上,成功召喚出了上面的番茄鍾。正當我在感慨“不愧是Shadow大人,這難道就是傳說中的五彩斑斕的黑?”

“那才不是什麼陰影效果,那是發光效果。”被路過的老婆吐槽了。

系系系,老婆說的都系對的。我還以為我在做陰影動畫,現在只好改博客標題了?

要實現上面的動畫效果,首先使用CompositionDrawingSurface,在它上面用DrawTextLayout畫出文字,然後用GaussianBlurEffect模仿成陰影,然後用CanvasActiveLayer裁剪文字的輪廓,然後用這個CompositionDrawingSurface創建出CompositionSurfaceBrush,然後創建一個CompositionMaskBrush,將CompositionSurfaceBrush作為它的Mask,然後用CompositionLinearGradientBrush創建出漸變,再用BlendEffect將它變成四向漸變,再用ColorKeyFrameAnimation和ScalarKeyFrameAnimation在它上面做動畫並把它作為CompositionMaskBrush的Source,然後創建SpriteVisual將CompositionMaskBrush應用上去,然後使用兩個PointLight分別從左到右和從右到左照射這個SpriteVisual,再創建一個AmbientLight模仿呼吸燈。

仔細想想……好吧,老婆說得對,我還真的沒有用到任何Shadow的Api,這裏和Shadow大人半毛錢關係都沒有。

這個番茄鍾源碼可以在這裏查看:

也可以安裝我的番茄鍾應用試玩一下,安裝地址:

這篇文章將介紹其中幾個關鍵技術。

2. 使用GaussianBlurEffect模仿陰影

上一篇文章已經介紹過怎麼在CompositionDrawingSurface上寫字,這裏就不再重複。為了可以為文字添加陰影,需要用到CanvasRenderTargetGaussianBlurEffect

CanvasRenderTarget是一個可以用來畫圖的渲染目標。實現文字陰影的步驟如下:將文字畫到CanvasRenderTarget,然後用它作為GaussianBlurEffect.Source產生一張高斯模糊的圖片,這樣看上去就和文字的陰影一樣。然後再在這張模糊的圖片的前面畫上原本的文字。

代碼如下所示:

using (var session = CanvasComposition.CreateDrawingSession(drawingSurface))
{
    session.Clear(Colors.Transparent);
    using (var textLayout = new CanvasTextLayout(session, Text, textFormat, width, height))
    {
        var bitmap = new CanvasRenderTarget(session, width, height);
        using (var bitmapSession = bitmap.CreateDrawingSession())
        {
            bitmapSession.DrawTextLayout(textLayout, 0, 0, FontColor);
        }
        var blur = new GaussianBlurEffect
        {
            BlurAmount = (float)BlurAmount,
            Source = bitmap,
            BorderMode = EffectBorderMode.Hard
        };

        session.DrawImage(blur, 0, 0);
        session.DrawTextLayout(textLayout, 0, 0, FontColor);
    }
}

效果如下(因為我用了白色字體,這時候已經不怎麼像陰影了):

關於CavasRenderTaget,死魚的有詳細介紹。他的這個專欄的文章都很有趣。

3. 使用CanvasActiveLayer裁剪文字

關於裁剪文字,有幾件事需要做。

首先獲取需要裁剪的文字的輪廓,這使用上一篇文章介紹過的CanvasGeometry.CreateText就可以了,這個函數的返回值是一個。然後使用CanvasGeometry.CreateRectangle獲取整個畫布的CanvasGeometry,將他們用相減得出文字以外的部分,具體代碼如下:

var fullSizeGeometry = CanvasGeometry.CreateRectangle(session, 0, 0, width, height);
var textGeometry = CanvasGeometry.CreateText(textLayout);
var finalGeometry = fullSizeGeometry.CombineWith(textGeometry, Matrix3x2.Identity, CanvasGeometryCombine.Exclude);

這裏之所以不直接使用textGeometry,是因為我們並不是真的裁剪出文字的部分,而是像WPF的那樣用透明度控制显示的部分。就是用來實現這個功能。CanvasDrawingSession.CreateLayer函數使用透明度和CanvasGeometry創建一個CanvasActiveLayer,在創建Layer后CanvasDrawingSession的操作都會應用這個透明度,直到Layer關閉。

using (var layer = session.CreateLayer(1, finalGeometry))
{
    //DrawSth
}

最後效果如下:

關於CanvasActiveLayer的更多用法, 可以參考Lindexi的。

4. 製作有複雜顏色的陰影

如上圖所示,UWP中的DropShadow的Color只能有一種顏色,所以DropShadow不能使用複雜的顏色。這時候就要用到,CompositionMaskBrush有兩個主要屬性:Mask和Source。其中Mask是一個CompositionBrush類型的屬性,它指定不透明的蒙板源。簡單來說,CompositionMaskBrush的形狀就是它的Mask的形狀。而Source屬性則是它的顏色,這個屬性可以是 CompositionColorBrush、CompositionLinearGradientBrush、CompositionSurfaceBrush、CompositionEffectBrush 或 CompositionNineGridBrush 類型的任何 CompositionBrush。可以使用前面創建的CompositionDrawingSurface創建出CompositionSurfaceBrush,最後創建一個CompositionMaskBrush,將CompositionSurfaceBrush作為它的Mask。

var maskBrush = Compositor.CreateMaskBrush();
maskBrush.Mask = Compositor.CreateSurfaceBrush(DrawingSurface);
maskBrush.Source = Compositor.CreateLinearGradientBrush();

本來還想做到大紫大紅的,但被吐槽和本來低調內斂的目的不符合,所以復用了以前的配色,CompositionLinearGradientBrush加BlendEffect做成了有些複雜的配色(但實際上太暗了看不出來):

這時候效果如下:

5. 使用PointLight和AmbientLight製作動畫

我在這篇文章里介紹了PointLight的用法及基本動畫,這次豪華些,同時有從左到右的紅光以及從右到左的藍光,這兩個PointLight的動畫效果大致是這樣:

因為PointLight最多只能疊加兩個,所以再使用AmbientLight並對它的Intensity屬性做動畫,這樣動畫就會變得複雜些,最終實現了文章開頭的動畫。

var compositor = Window.Current.Compositor;
var ambientLight = compositor.CreateAmbientLight();
ambientLight.Intensity = 0;
ambientLight.Color = Colors.White;

var intensityAnimation = compositor.CreateScalarKeyFrameAnimation();
intensityAnimation.InsertKeyFrame(0.2f, 0, compositor.CreateLinearEasingFunction());
intensityAnimation.InsertKeyFrame(0.5f, 0.20f, compositor.CreateLinearEasingFunction());
intensityAnimation.InsertKeyFrame(0.8f, 0, compositor.CreateLinearEasingFunction());
intensityAnimation.Duration = TimeSpan.FromSeconds(10);
intensityAnimation.IterationBehavior = AnimationIterationBehavior.Forever;

ambientLight.StartAnimation(nameof(AmbientLight.Intensity), intensityAnimation);

6. 參考

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※公開收購3c價格,不怕被賤賣!

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

※帶您來看台北網站建置台北網頁設計,各種案例分享

帶你漲姿勢的認識一下 Kafka 消費者

之前我們介紹過了 Kafka 整體架構,Kafka 生產者,Kafka 生產的消息最終流向哪裡呢?當然是需要消費了,要不只產生一系列數據沒有任何作用啊,如果把 Kafka 比作餐廳的話,那麼生產者就是廚師的角色,消費者就是客人,只有廚師的話,那麼炒出來的菜沒有人吃也沒有意義,如果只有客人沒有廚師的話,誰會去這個店吃飯呢?!所以如果你看完前面的文章意猶未盡的話,可以繼續讓你爽一爽。如果你沒看過前面的文章,那就從現在開始讓你爽。

Kafka 消費者概念

應用程序使用 KafkaConsumer 從 Kafka 中訂閱主題並接收來自這些主題的消息,然後再把他們保存起來。應用程序首先需要創建一個 KafkaConsumer 對象,訂閱主題並開始接受消息,驗證消息並保存結果。一段時間后,生產者往主題寫入的速度超過了應用程序驗證數據的速度,這時候該如何處理?如果只使用單個消費者的話,應用程序會跟不上消息生成的速度,就像多個生產者像相同的主題寫入消息一樣,這時候就需要多個消費者共同參与消費主題中的消息,對消息進行分流處理。

Kafka 消費者從屬於消費者群組。一個群組中的消費者訂閱的都是相同的主題,每個消費者接收主題一部分分區的消息。下面是一個 Kafka 分區消費示意圖

上圖中的主題 T1 有四個分區,分別是分區0、分區1、分區2、分區3,我們創建一個消費者群組1,消費者群組中只有一個消費者,它訂閱主題T1,接收到 T1 中的全部消息。由於一個消費者處理四個生產者發送到分區的消息,壓力有些大,需要幫手來幫忙分擔任務,於是就演變為下圖

這樣一來,消費者的消費能力就大大提高了,但是在某些環境下比如用戶產生消息特別多的時候,生產者產生的消息仍舊讓消費者吃不消,那就繼續增加消費者。

如上圖所示,每個分區所產生的消息能夠被每個消費者群組中的消費者消費,如果向消費者群組中增加更多的消費者,那麼多餘的消費者將會閑置,如下圖所示

向群組中增加消費者是橫向伸縮消費能力的主要方式。總而言之,我們可以通過增加消費組的消費者來進行水平擴展提升消費能力。這也是為什麼建議創建主題時使用比較多的分區數,這樣可以在消費負載高的情況下增加消費者來提升性能。另外,消費者的數量不應該比分區數多,因為多出來的消費者是空閑的,沒有任何幫助。

Kafka 一個很重要的特性就是,只需寫入一次消息,可以支持任意多的應用讀取這個消息。換句話說,每個應用都可以讀到全量的消息。為了使得每個應用都能讀到全量消息,應用需要有不同的消費組。對於上面的例子,假如我們新增了一個新的消費組 G2,而這個消費組有兩個消費者,那麼就演變為下圖這樣

在這個場景中,消費組 G1 和消費組 G2 都能收到 T1 主題的全量消息,在邏輯意義上來說它們屬於不同的應用。

總結起來就是如果應用需要讀取全量消息,那麼請為該應用設置一個消費組;如果該應用消費能力不足,那麼可以考慮在這個消費組裡增加消費者

消費者組和分區重平衡

消費者組是什麼

消費者組(Consumer Group)是由一個或多個消費者實例(Consumer Instance)組成的群組,具有可擴展性和可容錯性的一種機制。消費者組內的消費者共享一個消費者組ID,這個ID 也叫做 Group ID,組內的消費者共同對一個主題進行訂閱和消費,同一個組中的消費者只能消費一個分區的消息,多餘的消費者會閑置,派不上用場。

我們在上面提到了兩種消費方式

  • 一個消費者群組消費一個主題中的消息,這種消費模式又稱為點對點的消費方式,點對點的消費方式又被稱為消息隊列
  • 一個主題中的消息被多個消費者群組共同消費,這種消費模式又稱為發布-訂閱模式

消費者重平衡

我們從上面的消費者演變圖中可以知道這麼一個過程:最初是一個消費者訂閱一個主題並消費其全部分區的消息,後來有一個消費者加入群組,隨後又有更多的消費者加入群組,而新加入的消費者實例分攤了最初消費者的部分消息,這種把分區的所有權通過一個消費者轉到其他消費者的行為稱為重平衡,英文名也叫做 Rebalance 。如下圖所示

重平衡非常重要,它為消費者群組帶來了高可用性伸縮性,我們可以放心的添加消費者或移除消費者,不過在正常情況下我們並不希望發生這樣的行為。在重平衡期間,消費者無法讀取消息,造成整個消費者組在重平衡的期間都不可用。另外,當分區被重新分配給另一個消費者時,消息當前的讀取狀態會丟失,它有可能還需要去刷新緩存,在它重新恢復狀態之前會拖慢應用程序。

消費者通過向組織協調者(Kafka Broker)發送心跳來維護自己是消費者組的一員並確認其擁有的分區。對於不同不的消費群體來說,其組織協調者可以是不同的。只要消費者定期發送心跳,就會認為消費者是存活的並處理其分區中的消息。當消費者檢索記錄或者提交它所消費的記錄時就會發送心跳。

如果過了一段時間 Kafka 停止發送心跳了,會話(Session)就會過期,組織協調者就會認為這個 Consumer 已經死亡,就會觸發一次重平衡。如果消費者宕機並且停止發送消息,組織協調者會等待幾秒鐘,確認它死亡了才會觸發重平衡。在這段時間里,死亡的消費者將不處理任何消息。在清理消費者時,消費者將通知協調者它要離開群組,組織協調者會觸發一次重平衡,盡量降低處理停頓。

重平衡是一把雙刃劍,它為消費者群組帶來高可用性和伸縮性的同時,還有有一些明顯的缺點(bug),而這些 bug 到現在社區還無法修改。

重平衡的過程對消費者組有極大的影響。因為每次重平衡過程中都會導致萬物靜止,參考 JVM 中的垃圾回收機制,也就是 Stop The World ,STW,(引用自《深入理解 Java 虛擬機》中 p76 關於 Serial 收集器的描述):

更重要的是它在進行垃圾收集時,必須暫停其他所有的工作線程。直到它收集結束。Stop The World 這個名字聽起來很帥,但這項工作實際上是由虛擬機在後台自動發起並完成的,在用戶不可見的情況下把用戶正常工作的線程全部停掉,這對很多應用來說都是難以接受的。

也就是說,在重平衡期間,消費者組中的消費者實例都會停止消費,等待重平衡的完成。而且重平衡這個過程很慢……

創建消費者

上面的理論說的有點多,下面就通過代碼來講解一下消費者是如何消費的

在讀取消息之前,需要先創建一個 KafkaConsumer 對象。創建 KafkaConsumer 對象與創建 KafkaProducer 對象十分相似 — 把需要傳遞給消費者的屬性放在 properties 對象中,後面我們會着重討論 Kafka 的一些配置,這裏我們先簡單的創建一下,使用3個屬性就足矣,分別是 bootstrap.serverkey.deserializervalue.deserializer

這三個屬性我們已經用過很多次了,如果你還不是很清楚的話,可以參考

還有一個屬性是 group.id 這個屬性不是必須的,它指定了 KafkaConsumer 是屬於哪個消費者群組。創建不屬於任何一個群組的消費者也是可以的

Properties properties = new Properties();
        properties.put("bootstrap.server","192.168.1.9:9092");     properties.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer");   properties.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");
KafkaConsumer<String,String> consumer = new KafkaConsumer<>(properties);

主題訂閱

創建好消費者之後,下一步就開始訂閱主題了。subscribe() 方法接受一個主題列表作為參數,使用起來比較簡單

consumer.subscribe(Collections.singletonList("customerTopic"));

為了簡單我們只訂閱了一個主題 customerTopic,參數傳入的是一個正則表達式,正則表達式可以匹配多個主題,如果有人創建了新的主題,並且主題的名字與正則表達式相匹配,那麼會立即觸發一次重平衡,消費者就可以讀取新的主題。

要訂閱所有與 test 相關的主題,可以這樣做

consumer.subscribe("test.*");

輪詢

我們知道,Kafka 是支持訂閱/發布模式的,生產者發送數據給 Kafka Broker,那麼消費者是如何知道生產者發送了數據呢?其實生產者產生的數據消費者是不知道的,KafkaConsumer 採用輪詢的方式定期去 Kafka Broker 中進行數據的檢索,如果有數據就用來消費,如果沒有就再繼續輪詢等待,下面是輪詢等待的具體實現

try {
  while (true) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(100));
    for (ConsumerRecord<String, String> record : records) {
      int updateCount = 1;
      if (map.containsKey(record.value())) {
        updateCount = (int) map.get(record.value() + 1);
      }
      map.put(record.value(), updateCount);
    }
  }
}finally {
  consumer.close();
}
  • 這是一個無限循環。消費者實際上是一個長期運行的應用程序,它通過輪詢的方式向 Kafka 請求數據。
  • 第三行代碼非常重要,Kafka 必須定期循環請求數據,否則就會認為該 Consumer 已經掛了,會觸發重平衡,它的分區會移交給群組中的其它消費者。傳給 poll() 方法的是一個超市時間,用 java.time.Duration 類來表示,如果該參數被設置為 0 ,poll() 方法會立刻返回,否則就會在指定的毫秒數內一直等待 broker 返回數據。
  • poll() 方法會返回一個記錄列表。每條記錄都包含了記錄所屬主題的信息,記錄所在分區的信息、記錄在分區中的偏移量,以及記錄的鍵值對。我們一般會遍歷這個列表,逐條處理每條記錄。
  • 在退出應用程序之前使用 close() 方法關閉消費者。網絡連接和 socket 也會隨之關閉,並立即觸發一次重平衡,而不是等待群組協調器發現它不再發送心跳並認定它已經死亡。

線程安全性

在同一個群組中,我們無法讓一個線程運行多個消費者,也無法讓多個線程安全的共享一個消費者。按照規則,一個消費者使用一個線程,如果一個消費者群組中多個消費者都想要運行的話,那麼必須讓每個消費者在自己的線程中運行,可以使用 Java 中的 ExecutorService 啟動多個消費者進行進行處理。

消費者配置

到目前為止,我們學習了如何使用消費者 API,不過只介紹了幾個最基本的屬性,Kafka 文檔列出了所有與消費者相關的配置說明。大部分參數都有合理的默認值,一般不需要修改它們,下面我們就來介紹一下這些參數。

  • fetch.min.bytes

該屬性指定了消費者從服務器獲取記錄的最小字節數。broker 在收到消費者的數據請求時,如果可用的數據量小於 fetch.min.bytes 指定的大小,那麼它會等到有足夠的可用數據時才把它返回給消費者。這樣可以降低消費者和 broker 的工作負載,因為它們在主題使用頻率不是很高的時候就不用來回處理消息。如果沒有很多可用數據,但消費者的 CPU 使用率很高,那麼就需要把該屬性的值設得比默認值大。如果消費者的數量比較多,把該屬性的值調大可以降低 broker 的工作負載。

  • fetch.max.wait.ms

我們通過上面的 fetch.min.bytes 告訴 Kafka,等到有足夠的數據時才會把它返回給消費者。而 fetch.max.wait.ms 則用於指定 broker 的等待時間,默認是 500 毫秒。如果沒有足夠的數據流入 kafka 的話,消費者獲取的最小數據量要求就得不到滿足,最終導致 500 毫秒的延遲。如果要降低潛在的延遲,就可以把參數值設置的小一些。如果 fetch.max.wait.ms 被設置為 100 毫秒的延遲,而 fetch.min.bytes 的值設置為 1MB,那麼 Kafka 在收到消費者請求后,要麼返回 1MB 的數據,要麼在 100 ms 后返回所有可用的數據。就看哪個條件首先被滿足。

  • max.partition.fetch.bytes

該屬性指定了服務器從每個分區里返回給消費者的最大字節數。它的默認值時 1MB,也就是說,KafkaConsumer.poll() 方法從每個分區里返回的記錄最多不超過 max.partition.fetch.bytes 指定的字節。如果一個主題有20個分區和5個消費者,那麼每個消費者需要至少4 MB的可用內存來接收記錄。在為消費者分配內存時,可以給它們多分配一些,因為如果群組裡有消費者發生崩潰,剩下的消費者需要處理更多的分區。max.partition.fetch.bytes 的值必須比 broker 能夠接收的最大消息的字節數(通過 max.message.size 屬性配置大),否則消費者可能無法讀取這些消息,導致消費者一直掛起重試。 在設置該屬性時,另外一個考量的因素是消費者處理數據的時間。消費者需要頻繁的調用 poll() 方法來避免會話過期和發生分區再平衡,如果單次調用poll() 返回的數據太多,消費者需要更多的時間進行處理,可能無法及時進行下一個輪詢來避免會話過期。如果出現這種情況,可以把 max.partition.fetch.bytes 值改小,或者延長會話過期時間。

  • session.timeout.ms

這個屬性指定了消費者在被認為死亡之前可以與服務器斷開連接的時間,默認是 3s。如果消費者沒有在 session.timeout.ms 指定的時間內發送心跳給群組協調器,就會被認定為死亡,協調器就會觸發重平衡。把它的分區分配給消費者群組中的其它消費者,此屬性與 heartbeat.interval.ms 緊密相關。heartbeat.interval.ms 指定了 poll() 方法向群組協調器發送心跳的頻率,session.timeout.ms 則指定了消費者可以多久不發送心跳。所以,這兩個屬性一般需要同時修改,heartbeat.interval.ms 必須比 session.timeout.ms 小,一般是 session.timeout.ms 的三分之一。如果 session.timeout.ms 是 3s,那麼 heartbeat.interval.ms 應該是 1s。把 session.timeout.ms 值設置的比默認值小,可以更快地檢測和恢復崩憤的節點,不過長時間的輪詢或垃圾收集可能導致非預期的重平衡。把該屬性的值設置得大一些,可以減少意外的重平衡,不過檢測節點崩潰需要更長的時間。

  • auto.offset.reset

該屬性指定了消費者在讀取一個沒有偏移量的分區或者偏移量無效的情況下的該如何處理。它的默認值是 latest,意思指的是,在偏移量無效的情況下,消費者將從最新的記錄開始讀取數據。另一個值是 earliest,意思指的是在偏移量無效的情況下,消費者將從起始位置處開始讀取分區的記錄。

  • enable.auto.commit

我們稍後將介紹幾種不同的提交偏移量的方式。該屬性指定了消費者是否自動提交偏移量,默認值是 true,為了盡量避免出現重複數據和數據丟失,可以把它設置為 false,由自己控制何時提交偏移量。如果把它設置為 true,還可以通過 auto.commit.interval.ms 屬性來控制提交的頻率

  • partition.assignment.strategy

我們知道,分區會分配給群組中的消費者。PartitionAssignor 會根據給定的消費者和主題,決定哪些分區應該被分配給哪個消費者,Kafka 有兩個默認的分配策略RangeRoundRobin

  • client.id

該屬性可以是任意字符串,broker 用他來標識從客戶端發送過來的消息,通常被用在日誌、度量指標和配額中

  • max.poll.records

該屬性用於控制單次調用 call() 方法能夠返回的記錄數量,可以幫你控制在輪詢中需要處理的數據量。

  • receive.buffer.bytes 和 send.buffer.bytes

socket 在讀寫數據時用到的 TCP 緩衝區也可以設置大小。如果它們被設置為 -1,就使用操作系統默認值。如果生產者或消費者與 broker 處於不同的數據中心內,可以適當增大這些值,因為跨數據中心的網絡一般都有比較高的延遲和比較低的帶寬。

提交和偏移量的概念

特殊偏移

我們上面提到,消費者在每次調用poll() 方法進行定時輪詢的時候,會返回由生產者寫入 Kafka 但是還沒有被消費者消費的記錄,因此我們可以追蹤到哪些記錄是被群組裡的哪個消費者讀取的。消費者可以使用 Kafka 來追蹤消息在分區中的位置(偏移量)

消費者會向一個叫做 _consumer_offset 的特殊主題中發送消息,這個主題會保存每次所發送消息中的分區偏移量,這個主題的主要作用就是消費者觸發重平衡後記錄偏移使用的,消費者每次向這個主題發送消息,正常情況下不觸發重平衡,這個主題是不起作用的,當觸發重平衡后,消費者停止工作,每個消費者可能會分到對應的分區,這個主題就是讓消費者能夠繼續處理消息所設置的。

如果提交的偏移量小於客戶端最後一次處理的偏移量,那麼位於兩個偏移量之間的消息就會被重複處理

如果提交的偏移量大於最後一次消費時的偏移量,那麼處於兩個偏移量中間的消息將會丟失

既然_consumer_offset 如此重要,那麼它的提交方式是怎樣的呢?下面我們就來說一下

提交方式

KafkaConsumer API 提供了多種方式來提交偏移量

自動提交

最簡單的方式就是讓消費者自動提交偏移量。如果 enable.auto.commit 被設置為true,那麼每過 5s,消費者會自動把從 poll() 方法輪詢到的最大偏移量提交上去。提交時間間隔由 auto.commit.interval.ms 控制,默認是 5s。與消費者里的其他東西一樣,自動提交也是在輪詢中進行的。消費者在每次輪詢中會檢查是否提交該偏移量了,如果是,那麼就會提交從上一次輪詢中返回的偏移量。

提交當前偏移量

auto.commit.offset 設置為 false,可以讓應用程序決定何時提交偏移量。使用 commitSync() 提交偏移量。這個 API 會提交由 poll() 方法返回的最新偏移量,提交成功后馬上返回,如果提交失敗就拋出異常。

commitSync() 將會提交由 poll() 返回的最新偏移量,如果處理完所有記錄后要確保調用了 commitSync(),否則還是會有丟失消息的風險,如果發生了在均衡,從最近一批消息到發生在均衡之間的所有消息都將被重複處理。

異步提交

異步提交 commitAsync() 與同步提交 commitSync() 最大的區別在於異步提交不會進行重試,同步提交會一致進行重試。

同步和異步組合提交

一般情況下,針對偶爾出現的提交失敗,不進行重試不會有太大的問題,因為如果提交失敗是因為臨時問題導致的,那麼後續的提交總會有成功的。但是如果在關閉消費者或再均衡前的最後一次提交,就要確保提交成功。

因此,在消費者關閉之前一般會組合使用commitAsync和commitSync提交偏移量

提交特定的偏移量

消費者API允許調用 commitSync() 和 commitAsync() 方法時傳入希望提交的 partition 和 offset 的 map,即提交特定的偏移量。

文章參考:

《極客時間-Kafka核心技術與實戰》

《Kafka 權威指南》

關注公眾號獲取更多優質电子書,關注一下你就知道資源是有多好了

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

收購3c,收購IPHONE,收購蘋果電腦-詳細收購流程一覽表

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

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

※公開收購3c價格,不怕被賤賣!

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

SpringSecurity動態加載用戶角色權限實現登錄及鑒權

很多人覺得Spring Security實現登錄驗證很難,我最開始學習的時候也這樣覺得。因為我好久都沒看懂我該怎麼樣將自己寫的用於接收用戶名密碼的Controller與Spring Security結合使用,這是一個先入為主的誤區。後來我搞懂了:根本不用你自己去寫Controller。你只需要告訴Spring Security用戶信息、角色信息、權限信息、登錄頁是什麼?登陸成功頁是什麼?或者其他有關登錄的一切信息。具體的登錄驗證邏輯它來幫你實現。

一、動態數據登錄驗證的基礎知識

在本號之前的文章中,已經介紹了Spring Security的formLogin登錄認證模式,RBAC的權限控制管理模型,並且針對Spring Security的登錄認證邏輯源碼進行了解析等等。我們所有的用戶、角色、權限信息都是在配置文件裏面寫死的,然而在實際的業務系統中,這些信息通常是存放在RBAC權限模型的數據庫表中的。下面我們來回顧一下其中的核心概念:

  • RBAC的權限模型可以從用戶獲取為用戶分配的一個或多個角色,從用戶的角色又可以獲取該角色的多種權限。通過關聯查詢可以獲取某個用戶的角色信息和權限信息。
  • 在源碼解析的文章中,我們知道如果我們不希望用戶、角色、權限信息寫死在配置裏面。我們應該實現UserDetails與UserDetailsService接口,從而從數據庫或者其他的存儲上動態的加載這些信息。

以上是對一些核心的基礎知識的總結,如果您對這些知識還不是很清晰,建議您先往下讀本文。如果看完本文仍然理解困難,建議您翻看本號之前的文章。

二、UserDetails與UserDetailsService接口

  • UserDetailsService接口有一個方法叫做loadUserByUsername,我們實現動態加載用戶、角色、權限信息就是通過實現該方法。函數見名知義:通過用戶名加載用戶。該方法的返回值就是UserDetails。
  • UserDetails就是用戶信息,即:用戶名、密碼、該用戶所具有的權限。

下面我們來看一下UserDetails接口都有哪些方法。

public interface UserDetails extends Serializable {
    //獲取用戶的權限集合
    Collection<? extends GrantedAuthority> getAuthorities();

    //獲取密碼
    String getPassword();

    //獲取用戶名
    String getUsername();

    //賬號是否沒過期
    boolean isAccountNonExpired();

    //賬號是否沒被鎖定
    boolean isAccountNonLocked();

    //密碼是否沒過期
    boolean isCredentialsNonExpired();

    //賬戶是否可用
    boolean isEnabled();
}

現在,我們明白了,只要我們把這些信息提供給Spring Security,Spring Security就知道怎麼做登錄驗證了,根本不需要我們自己寫Controller實現登錄驗證邏輯。

三、實現UserDetails 接口

public class SysUser implements UserDetails{
    
    String password();  //密碼
    String username();  //用戶名
    boolean accountNonExpired;   //是否沒過期
    boolean accountNonLocked;   //是否沒被鎖定
    boolean credentialsNonExpired;  //是否沒過期
    boolean enabled;  //賬號是否可用
    Collection<? extends GrantedAuthority> authorities;  //用戶的權限集合

    //省略構造方法
    //省略set方法
    //省略get方法(即接口UserDetails的方法)
}

我們就是寫了一個適應於UserDetails的java POJO類,所謂的 UserDetails接口實現就是一些get方法。get方法由Spring Security調用,我們通過set方法或構造函數為 Spring Security提供UserDetails數據。

四、實現UserDetailsService接口

@Component
public class MyUserDetailsService implements UserDetailsService{

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            
       //這裏從數據庫sys_user表裡面查詢實體類對象。loadUser方法可使用Mybatis或JDBC或JPA自行實現。
       SysUser sysUser =  loadUser(username);   

        // 判斷用戶是否存在 
       if(user == null)  {  throw  new  UsernameNotFoundException("用戶名不存在");  }

       //從數據庫該用戶所有的角色信息,所有的權限標誌
       //遍歷所有的ROLE角色及所有的Authority權限(菜單、按鈕)。
       //用逗號分隔他們的唯一標誌,具體過程自行實現。
       sysUser.setAuthorities(
               AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_AMIN , system:user:delete"));
        
        //sysUser.setAccountNonLocked(true或false);
        return sysUser;
    }
}
  • 通常數據庫表sys_user字段要和SysUser屬性一一對應,比如username、password、enabled。但是比如accountNonLocked字段用於登錄多次錯誤鎖定,但我們一般不會在表裡存是否鎖定,而是存一個鎖定時間字段。通過鎖定時間是否大於當前時間判斷賬號是否鎖定,所以實現過程中可以靈活做判斷並用好set方法,不必拘泥於一一對應的形式。
  • 角色是一種特殊的權限,在Spring Security我們可以使用hasRole(角色標識)表達式判斷用戶是否具有某個角色,決定他是否可以做某個操作;通過hasAuthority(權限標識)表達式判斷是否具有某個操作權限。

五、最後說明

至此,我們將系統裏面的所有的用戶、角色、權限信息都通過UserDetailsService和UserDetails告知了Spring Security。但是多數朋友可能仍然不知道該怎樣實現登錄的功能,其實剩下的事情很簡單了:

  • 寫一個登錄界面,寫一個登錄表單,表單使用post方法提交到默認的/login路徑
  • 表單的用戶名、密碼字段名稱默認是username、password。
  • 寫一個登錄成功之後的跳轉頁面,比如index.html

然後把這些信息通過配置方式告知Spring Security ,以上的配置信息名稱都可以靈活修改。如果您不知道如何配置請參考本號之前的文章《formLogin登錄認證模式》。

期待您的關注

  • 向您推薦博主的系列文檔:
  • 本文轉載註明出處(必須帶連接,不能只轉文字):。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※高價收購3C產品,價格不怕你比較

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

3c收購,鏡頭 收購有可能以全新價回收嗎?

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

提防披着微商外衣的傳銷套路

  感恩、格局、愛心、大善,這些字眼在他們嘴裏出現的頻率越高,也就讓外界覺得越可笑可嘆。

  近期身邊有好幾位上了年紀的親朋,不約而同地轉發起一些莫名其妙的商城“盛大起航”、“強勢暴擊”的鏈接,雖名字不一,但都是主打所謂未來電商、社交電商概念,點開寥寥可數的頁面,大多都是些可以歸類為“三無”的微商產品,但敢與知名電商比價。要駁斥與打假,還是要先捏着鼻子觀察與了解,耐心聽完了“創始人”的數節課,很遺憾,還不如機場書店循環播放的成功學最初帶來的震撼。

  以自稱外部名頭響的投資已經拿到了B+輪的某商城為例,創始人發布會一張嘴,草台班子江湖賣藝般的雜耍感撲面而來。出身貧寒,高考落榜,一定要在年底開寶馬回村,打臉當初看不起他的鄉鄰;個人奮鬥要往馬雲等知名電商傳奇靠,誰懷疑他就如同當初懷疑馬雲;要在美股或者港股上市(可能都知道A股混上市不易),要燒錢,至年前要燒6.8億,有零有整,煞有介事;高管團隊財富自由,不為掙錢為情懷,要帶“兄弟姐妹”、“家人”們做善事。多加幾個群,會發現這幾點已成創始人發言“標準”流程。

  不過戳穿其牛皮也不難,致命點在於新會員並不能選擇在這些三無商城上直接購物,而是得先從老會員處獲得邀請碼,註冊新會員,才能開始購物。設立邀請碼,很顯然不是為了限制註冊會員的人數,而是為了方便統計上家拉了多少“人頭”。會員的資質審核只有一點:299元、399元不等,購買指定商品。每推廣1名新店主入駐,即可獲得現金獎勵100元,一旦超過20人,黃金晉陞為鉑金后,每推薦一人再翻倍。一層一層下線累積起來超一定規模,鉑金升鑽石,號稱可以參與商城的業績分紅,做永久分紅股東。嫌這些流程慢,也可以直接花數萬元一步到位當鑽石店主。但是,這種交納一定額度的入會費或者購買一定金額的商品后獲得發展下線資格,計酬方式按下線以及下線的下線發展數量進行提成,傳銷、“拉人頭”模式可謂再明顯不過,難道都在裝睡?

  迷惑之處還是在於所謂社交電商的鼓吹,有了社交分享后,除了會員費提成,別人買任何東西另外還可以拿6%左右的傭金,號稱周邊發展20名親朋,每天買生活日用品,就可以小富。這就很fashion?這就與傳銷不一樣了?顯然自欺欺人,正常人哪裡下得了手買價格這麼離譜的三無日用品?到最後收益還是來自於拉人頭開店。因而不少店主表示,從自己加入該商城以來,拼了命折騰,收益也就在幾百元到千元不等,“月入10萬”聽聽而已,也就最上面幾個人喊得起勁。同時,該鏈接上線不到十天,其官方微信公眾平台就因涉嫌違規分銷而被騰訊進行封號處理。聯繫今年3月份,“花生日記”因涉及傳銷違法行為,被廣州市工商行政管理局責令改正,並被處以7456萬元這一目前中國社交電商領域最大的一筆罰款。這幾個同樣鼓吹社交電商,實質上疑似“拉人頭”的傳銷商被處罰也會指日可待。其實,與其信誓旦旦自己不是傳銷,不如直接取消那個299、399到數萬元的入會門檻,有本事直接商城開售有競爭力的產品拿傭金,自然會有人幫你口碑分享。與這一模式相近的“值得買”已經在創業板上市。

  令人不安的是,這些傳銷實質的微商套路,在較低的知識層級與商業素養缺乏的群體,尤其是女性群體中,有熾熱之勢。對於掌握家庭財務大權的部分女性來說,399元不算大錢,萬一呢?而對於一些學歷不高、沉浸於俗事紛擾的小微企業主來說,財經新聞一知半解,日常對外部世界的感知主要通過微信朋友圈,或者快手、抖音短視頻,但階層逆襲一直同樣是心底的呼喊。這一時不我待的逼迫感,催促着這些群體踉踉蹌蹌縱身商海。層層套路下遴選出來的客群,認知水平與消費習慣可想而知。言必稱“家人”,自己人坑自己人卻形成了一個完美的閉環。感恩、格局、愛心、大善,這些字眼在他們嘴裏出現的頻率越高,也就讓外界覺得越可笑可嘆。

(文章來源:證券時報)

(責任編輯:DF380)

【其他文章推薦】

實木地板、海島型地板、耐磨地板怎麼挑? 木地板三倍價差的秘密!!

※新屋購入,尋找台中室內設計師?是否可先免費估價丈量?

※挑好磚一點都不難!馬賽克磚挑選眉角小撇步!

※想知道北部最多平價、庫存出清的家具工廠推薦在哪裡?

※想知道大型演唱會、知名劇場的舞台設計是由哪位設計師一手操刀嗎?

把握投行自身定位 促進經濟新舊動能轉換

  投資銀行是資本市場的重要參與者,在經濟結構調整和轉型過程中,是連接資本和企業的重要橋樑。黨的十九大報告明確指出:“深化金融體制改革,增強金融服務實體經濟能力,提高直接融資比重,促進多層次資本市場健康發展”,點明了金融服務實體經濟的核心定位,也指出了投資銀行作為專業服務機構所應承擔的基本功能和定位。

  當前實體經濟正處在新舊動能轉換的關鍵階段,需要進一步提升直接融資比例,滿足不同類型企業多層次融資需求,從而推動經濟發展由高速增長階段轉向高質量發展階段。新時代背景下投資銀行以其專業性手段,承擔著支持供給側結構性改革、實現實體經濟新舊動能轉換的市場職能。新時代背景下投資銀行需緊密把握自身定位,進一步提升核心業務能力,推動我國經濟向高質量階段發展。

  以服務實體經濟為基本功能

  投資銀行業務起始於有價證券承銷,投資銀行負責將證券以特定價格向投資者出售,機構在證券銷售過程中起到發行人與投資者的中介橋樑作用,幫助市場形成較為公允的風險定價,也進一步促進了資本市場的持續發展。

  投資銀行通過有價證券發行的保薦和承銷職能,幫助企業在首次公開發行、再融資發行以及發行股份購買資產方面獲得資金支持。隨着越來越多的企業及項目獲得資本市場的支持,社會資金逐步向具有發展潛力和優勢的實體企業和行業聚集,為國家經濟的發展提供了重要的資本助力。

  從成熟市場的經驗來看,無論是國家還是金融機構,都高度重視投資銀行的發展,積極運用投行業務服務實體經濟,實現資源優化配置目標。截至2018年底,我國證券公司數量達到131家,總資產為6.26萬億元,凈資產為1.89萬億元。其中,94家機構擁有保薦資格,超過百家的證券公司及投行子公司實現股債承銷收益。全行業2018年實現承銷和保薦業務凈收入達到258億元,財務顧問凈收入32億元。全年完成了IPO發行數量105家,募集資金1378億元。

  過去十年間,我國投資銀行幫助2000多家企業實現IPO融資共計1.8萬億元。通過增發配股、優先股、可轉債和可交換債等方式實現再融資共計8.8萬億元,公司債發行規模達到7.4萬億元。投資銀行通過股債發行的保薦與承銷,有效地幫助了實體經濟擴寬融資渠道、推動企業規模化發展,較好地服務了實體經濟、助力企業成長。

  進一步提升直接融資比重

  有效的金融資本供給能夠為實體經濟發展形成巨大推動力。在早期工業化發展階段,產業供給往往滯後於社會持續增長的需求。實體企業需要獲得資金支持來加速規模擴張,實現規模效益。

  我國金融服務實體經濟長期以間接融資為主要渠道,間接融資在社會融資總量中的佔比約在八成左右。企業主要通過銀行信貸來滿足大部分資金需求。但是隨着企業自身槓桿水平和負債成本達到一定程度,間接融資逐漸難以滿足擴容需求,需要通過直接融資來拓寬企業融資渠道。

  近年來,我國資本市場股權融資規模總體保持增長態勢,從2009年的4500多億元增長至2018年的12000億元。2018年我國社會融資總體規模中,包含債券融資和股票融資在內的直接融資規模達到近3萬億元,但是在社會融資總量中的佔比僅為15%,仍處於較低水平,距離發達國家50%以上的直接融資比重還有較大的差距,一定程度上制約了我國經濟結構調整步伐。

  隨着經濟結構調整步伐加快,科技創新型企業需要拓寬股權融資渠道,控制好自身的資金槓桿和負債規模,因此直接融資逐漸成為不可或缺的融資渠道補充。企業可以通過股權融資或公司債發行獲得直接融資支持。股權融資包括首次公開發行登陸資本市場,之後通過再融資方式擴大融資渠道、匯聚投資者資金,助力經營和發展。

  發揮投資銀行專業服務能力

  我國當前資本市場改革持續深化,已經進入金融供給側結構性改革的重要階段。金融供給側結構性改革旨在解決實體經濟融資過程中的結構性問題,加強金融供給與多元化金融需求、多層次經濟結構之間的匹配性,因而金融供給中的結構性問題將會是改革的重點內容。

  當前經濟結構轉型是以新舊動能轉換為著力點,其中大量中小企業將會成為科技創新的主力。在以間接融資為主的金融供給體系中,銀行風險偏好較低,對於抵押擔保等增信手段要求較高,能夠適應重資產、規模化的工業企業融資需求,但是難以滿足輕資產、重創新、高風險的科技創新型企業的融資需求。因此,亟須調整融資結構,提升直接融資比重,加強金融機構對實體經濟的服務。

  無論是企業初創還是轉型發展,都會存在較大的商業不確定性,傳統的間接融資難以滿足不斷增長的風險投資需求。因此,讓“專業的人”做“專業的事”,發揮投資銀行在保薦承銷、風險定價、財務顧問、金融產品等方面的專業服務能力,能夠有效促進直接融資的形成。

  投資銀行是為企業提供投融資服務的專業化機構,從發達市場經驗來看,其發展歷程經歷了從單一的證券承銷保薦到綜合金融服務商的轉變,以不斷滿足不同市場主體的多元化金融需求。當前我國股票首次公開發行註冊制正逐步推行,投資銀行的專業服務要求也在不斷提高,專業化發展已經成為實現行業差異化、特色化發展格局的重要路徑。

  以投行業務服務為根基

  聚焦股債發行的承銷保薦業務,能夠為投資銀行的長期發展構築良好的基礎。全球知名的金融機構,如摩根大通高盛、UBS、花旗集團等,其長期穩健的發展都離不開傳統的投行業務板塊。金融機構的海外擴張也是首選投行業務作為立足點,以此來打開海外業務市場。這都充分显示出投行業務作為業務核心的重要地位。

  目前,歐美的投資銀行佔據全球投行業務市場的優勢主導地位,擁有較強的全球服務和資產配置能力,服務具有全球影響力的跨國機構及企業客戶。全球大型投資銀行收入排名中,摩根大通美國銀行高盛集團位居領先位置,2018年的營業收入分別達到1042億美元、880億美元和359億美元。全球投資銀行收入規模排名前十位均為歐美投行,在全球資本市場投行業務收入的市場佔有率達到一半。

  未來隨着我國資本市場開放進程加快,國內投行需要加快形成具有差異化、特色化的行業格局。目前我國營業收入排名靠前的投行有中信證券海通證券國泰君安證券,2018年分別實現營業收入372億元、238億元和227億元。全行業營收排名前十位的投行的營收市場佔有率為45%,投行業務收入市場佔有率為46%。實力較強的投資銀行資本實力和團隊實力突出,業務規模長期保持優勢地位。從近十年的行業發展格局來看,如果股債承銷保薦以及財務顧問實力穩定,那麼投資銀行自身往往能夠在激烈的行業競爭中保持穩固地位。

  以風險定價為核心能力

  科創板在發行、上市、交易及退市等基礎制度方面取得了重大的創新和突破,允許未盈利企業首次公開發行和上市交易,採用市場化定價方式,放寬漲跌幅交易限制,要求投資銀行採取“保薦+跟投”模式,制定強制退市規則等。隨着科創板加速落地,再融資規則優化、創業板重組上市放寬、對外開放舉措持續推進,存量改革的步伐也在不斷加快。

  隨着資本市場改革的不斷深化,投資銀行必須加快專業化轉型,適應註冊制環境下投行業務的新要求。由於科創板股票發行與承銷規定採用市場化的新股定價方式,發行人和主承銷商可以通過初步詢價確定發行價格,或者在初步詢價確定發行價格區間后,通過累計投標詢價確定發行價格。市場化的定價方式將突破傳統發行方式的估值限制,同時加大了包銷和跟投對投資銀行帶來的投資風險。這就要求投資銀行須嚴把項目質量關,紮實做好擬上市公司價值研究,為投資者提供較為公允的發行定價區間。

  以合規風控為生命線

  投資銀行的業務基於風險定價開展,有效的內控機制是業務發展的立身之本。從國外投行的發展歷程來看,近百年行業發展的重要階段和事件往往伴隨着市場風險的發生,以及之後不斷完善的金融監管體系演變。以美國為例,從20世紀早期的金融混業經營,到1933年美國《格拉斯-斯蒂格爾法案》(Glass-Steagall Act)出台,確立了分業經營、分業監管體系;1999年《金融服務現代化法案》的出台,標志著混業經營的回歸;而2008年美國次貸危機之後,《多德-弗蘭克法案》加強了對混業經營的大型金融機構監管。

  一個世紀以來美國資本市場運行經驗表明,在市場發展過程中,投資銀行的合規運營和風險管控是保障資本市場穩定的重要基石,也是投資銀行的立身之本。投資銀行業務的重心在於綜合性的機構服務,除了開展股債發行承銷、併購重組財務顧問之外,投資銀行的業務範圍涵蓋了信用業務、做市商業務、衍生品業務、資產證券化業務等。產品和業務的不斷創新為市場帶來活力,加強了投資銀行對機構服務的能力,但也伴隨着相應的風險投資交易風險

  從海外市場發展經驗來看,無論是分業經營還是混業經營,投資銀行都需要不斷加強自身的風險管控,業務開展應當滿足合規要求。當前我國《證券公司合規管理實施指引》的實施對證券公司合規管理和風控提出了更高的要求,證券公司的合規風控在組織架構中的重要性顯著提升。目前,加強投資銀行合規風控已經成為完善組織架構的重要一環,從2017年起國內投行就已經先後開始通過內外招聘的方式擴充內控部門人員規模,以適應監管的要求和公司自身發展的需要。

  當前我國資本市場開放進程不斷加快,A股納入MSCI指數、富時羅素的比重穩步提升,外資機構持股比例限制放開,外資參與市場程度不斷提高。對外開放將加快我國資本市場制度及機制完善,境內投資銀行亟須提升核心競爭實力。

  推動差異化發展形成比較優勢

  隨着科創板及試點註冊制的運行,投資銀行將迎來新的發展階段。未來隨着直接融資比重的穩步提升,資本市場改革深化,投融資環境將獲得持續優化,有利於投資銀行積極發揮資本中介、風險資產定價職能,引導社會資本向科技創新型企業彙集。

  從美國市場的成熟經驗來看,中小規模投行如果能夠形成某項業務特色,在特定產品或服務上具有較強的競爭優勢,也能夠形成較強的競爭實力,其中關鍵在於人力隊伍的建設。在歐美市場,大型投行長期佔據着投行業務收入前十位的位置,但是在細分領域的併購業務收入,精品投行如Lazard、Evercore Partners、Centrerview的業務競爭實力突出,能夠與大型投行直接展開競爭。

  目前,國內證券公司行業差異化、特色化的發展路徑正在顯現:一是綜合類證券公司發揮資源優勢,實現規模化發展;二是專業類證券公司聚焦細分領域的業務突破點,推動特色業務發展,加快形成比較優勢;三是服務創新性證券公司運用技術優勢,推動業務快速發展。長期來看,投資銀行必將進入精細分類階段,需要專註在自身擅長的行業、區域或領域,通過專業化程度來實現差異化發展,聚焦和深耕優勢業務,建立品牌優勢。

  未來我國證券行業市場發展空間廣闊,各地區經濟發展特點不同,中小企業金融服務需求各異,需要各類投資銀行參與細分領域市場,也需要相關行業政策引導和保障,更好地服務實體經濟、盤活市場存量資源,有力支持國家經濟發展戰略目標的實現。

  加強人才儲備增強資本實力

  投資銀行業作為智力密集型的金融服務產業,需要投資銀行中的專業工作人員具備極高的專業性。投資銀行的人才儲備和團隊建設一直是保持競爭力的基本要素。以專業人才和團隊為基礎,投資銀行才能夠逐步形成客戶儲量和業務特色,保證投資銀行的競爭優勢。這既需要我國高等院校持續輸出高質量的金融專業人才,也需要引進國外的專業人士來加強我國投資銀行的人員專業化水平,在合理的薪酬制度設計下有效發揮各類專業人才的積極性,推動我國投資銀行的長遠發展。

  在專業人才隊伍的支持下,投資銀行還需要聚焦投行主業,實現服務實體經濟目標。現代企業的一切投融資活動背後都源自投資銀行的推動和設計,包括企業上市融資、組建股份公司、企業分拆、併購交易、債務重組、投資管理和證券交易等。企業是經濟的命脈,科技創新型的企業成長關係到經濟結構調整,投資銀行應當聚焦服務實體經濟目標,調動投行人力隊伍、發揮專業優勢,與企業共同成長,幫助企業應對行業周期和自身生命周期變化,推動其成長為更具競爭實力的企業。

  長期以來,我國投資銀行一直存在資產體量小、造血能力不足、盈利能力較弱的問題。目前,我國證券公司規模和收入占金融行業比例仍然較低。從上市公司近年來的整體情況來看,我國證券行業上市公司總資產規模僅占所有金融業上市公司總資產的3.4%,凈利潤僅佔6.4%;中國證券公司收入佔比約為5%,而美國投行的收入佔比能夠達到約20%的水平。無論資產規模還是收入規模,我國證券行業佔比明顯較低,與成熟市場的結構還有較大差距。

  綜合類投資銀行保持發展就需要穩步提升資本規模,規模化是提升投資銀行綜合實力的有效路徑。我國投資銀行可以通過引進戰略股東併購重組或再融資、加大資本投入來提升資產規模,同時把握業務的核心競爭力,形成良好的持續經營能力和盈利能力。

  運用金融科技加強內控機制建設

  當前信息技術的發展和應用已經改變了傳統證券業務的成本結構,線上獲客引流的成本要低於實體營業網點的獲客成本,傭金率下降是技術發展和應用的必然結果。這也倒逼投資銀行必須改變“靠天吃飯”的營利和發展模式。投資銀行應當根據自身情況,提高技術和研發投入,根據實體經濟的投融資需求,適度創新產品和服務,提升投行業務的活力。

  投資銀行應逐步提升金融科技的運用,加大信息系統投入,提升公司的運營效率,提升業務專業化水平和服務質量。未來大數據、人工智能及區塊鏈等新技術的應用,必將增強投資銀行在財富管理、投資諮詢、投資交易、產品設計、託管結算以及風險防範等方面的業務能力。金融科技運用將會成為投資銀行提升自身競爭實力的重要因素之一。

  經過了近三年的嚴監管,市場投融資環境得到明顯改善,市場機構的規範性水平顯著提升。“管住人、看住錢、扎牢制度防火牆”,對資本市場和中介機構提出了更高的合規運營要求。因此,合規風控能力是投資銀行核心競爭力的重要體現。投資銀行應不斷加強自身的合規建設,鞏固和夯實發展基礎。

  投資銀行及工作人員應當遵守職業道德和行為準則,防範利益衝突。同時應建立起較為完善的風險防控機制,把關項目質量、研判業務風險。投行機構負責人、高管、下屬單位負責人及其他工作人員,應在經營決策、運營管理和執業行為過程中識別合規風險,主動防範、應對和報告等。強化內控機制是投行服務創新型企業的必要前提,投資銀行應當依法合規運營,嚴把項目質量關,樹立起“生命線”意識,才能夠真正實現競爭力提升的目標。

(文章來源:中國證券報)

(責任編輯:DF380)

【其他文章推薦】

※居家隱形鐵窗安裝施作經驗分享

※純客製手工沙發,古典沙發,專業首選沙發工廠打造屬於您的居家品味!

※解決漏水、壁癌危機,找尋新竹舊屋翻新專業修繕專家

※分享木質地板DIY自行施工教學影片

※想要打造簡約、淡雅兼且收納空間的小資房,台中室內設計推薦哪一家?

投資“開源指南” 讀懂“分紅權”

  投資者投資上市公司,根本上是為了獲取投資回報,實現投資“開源”,而公司分紅是投資收益來源之一。在股市中得到高額收益的長期投資者,往往選擇注重投資者回報、有着對投資者負責任的經營管理團隊的公司,這類型公司往往注重長期分紅

  那麼,分紅權具體是什麼呢?下面這篇“開源指南”,讓我們一起來讀懂股東“分紅權”。

  1、什麼是股東分紅權?

  股東的分紅權,是股東的股利(即股息、紅利)分配請求權,是股東的核心權利。上市公司股東雖然可以在股票市場自由轉讓其股份,從股價波動中賺取差額收益,但股息、紅利也是股東投資獲益的一個重要方式。股利分配是股東投資於公司并行使股東權利的最終目的。

  2、什麼是股利?

  股利是股東依據其所擁有的公司股份從公司分得的利潤。股利分為股息和紅利兩種。

  股息就是股票的利息,是指公司按照一個固定比例向股東支付利息。紅利是一般情況下投資者投資普通股的收益,是公司分派股息后按持股比例向股東分配的剩餘利潤。種類上,主要可分為現金紅利、股票紅利。

  3、現金紅利和股票紅利具體指的是什麼?

  現金紅利,即公司分配時向股東分派現金。這種分紅方式可以使股東獲得直接的現金收益,是最為普遍的一種分紅形式。

  股票紅利,即上市公司以本公司的股票代替現金作為股利向股東分紅的一種方式,又稱為送紅股。所送紅股是由盈餘公積金轉增資本形成的,屬於無償增資發行股票。由於所送股票是按股東所持股份的比例分配的,每位股東在公司擁有的權益比例並不發生變化。同時,這種分紅方式使公司賬戶上的部分留存收益轉化為股本,公司資產及負債並未受到影響。送紅股的好處在於,一方面股東獲得了所派發的股票,日後可以在股票二級市場上出售獲益;另一方面,現金可以保留在公司內部,既增加了公司的資本,又為公司擴大生產經營保存了資金。

  4、股利的分配原則是什麼?

  股利分配,基本上按照資本不變和資本維持原則,避免因無盈餘分配而造成公司資本的實質減少以及損害股東、公司和債權人的利益。公司只有在彌補虧損、提取公積金後有剩餘利潤時,才可向股東分配股利,否則不得分配股利,已經分配的要退還給公司。

  5、公司稅後利潤的分配順序是什麼?

  公司分配當年稅後利潤時,應當提取利潤的10%列入公司法定公積金。公司法定公積金累計額為公司註冊資本的50%以上的,可以不再提取。公司法定公積金不足以彌補以前年度虧損的,在提取法定公積金之前,應當先用當年利潤彌補虧損。公司從稅後利潤中提取法定公積金后,經股東大會決議,可從稅後利潤中提取任意公積金。

  公司彌補虧損和提取公積金后所余稅後利潤,除公司章程另有規定外,按照股東持有的股份比例分配。

  股東大會或者董事會違反前款規定,在公司彌補虧損和提取法定公積金之前向股東分配利潤的,股東必須將違反規定分配的利潤退還公司。

  公司持有的本公司股份不得分配利潤。

  6、股利的分配標準是什麼?

  公司分配股利時,除公司章程另有規定外,應以所持的股份比例為依據,嚴格按照股東平等原則、同股同利原則進行。

  7、現金紅利和股票紅利的分配是否有順序要求?

  上市公司章程中應當明確現金分紅相對於股票股利在利潤分配方式中的優先順序。具備現金分紅條件的,應當採用現金分紅進行利潤分配。

  採用股票股利進行利潤分配的,應當具有公司成長性、每股凈資產的攤薄等真實合理因素。

  8、什麼是差異化的現金分紅政策?

  差異化的現金分紅政策,是指公司應當綜合考慮所處的行業特點、發展階段、自身經營模式、盈利水平以及是否有重大資金支出安排等因素,區分情形,並按照公司章程規定的程序,制定的現金分紅政策。

  根據證監會《上市公司監管指引第3號——上市公司現金分紅》第5條的規定:

  第一,公司發展階段屬成熟期且無重大資金支出安排的,進行利潤分配時,現金分紅在本次利潤分配中所佔比例最低應達到80%;第二,公司發展階段屬成熟期且有重大資金支出安排的,進行利潤分配時,現金分紅在本次利潤分配中所佔比例最低應達到40%;第三,公司發展階段屬成長期且有重大資金支出安排的,進行利潤分配時,現金分紅在本次利潤分配中所佔比例最低應達到20%;第四,公司發展階段不易區分但有重大資金支出安排的,可以按照前項規定處理。

  9、分紅政策可以變更或調整嗎?

  原則上,公司應當嚴格執行公司章程確定的現金分紅政策以及股東大會審議批準的現金分紅方案。

  但若確有必要對公司章程確定的現金分紅政策進行調整或者變更的,應當滿足公司章程規定的條件,經詳細論證后,履行相應的決策程序,並經出席股東大會的股東所持表決權的2/3以上通過。

  10、制定分紅政策時,獨立董事及中小股東可以發揮何種作用?

  上市公司在制定現金分紅具體方案時,董事會應當認真研究和論證公司現金分紅的時機、條件和最低比例、調整條件及其決策程序要求等事宜,獨立董事應當發表明確意見。

  獨立董事可以徵集中小股東意見,提出分紅提案,並直接提交董事會審議。

  股東大會對現金分紅具體方案進行審議前,應當通過多種渠道主動與股東特別是中小股東進行溝通和交流,充分聽取中小股東的意見和訴求,及時答覆中小股東關心的問題。

  11、分紅所得適用什麼稅率?

  2015年頒布的《財政部、國家稅務總局、證監會關於上市公司股息紅利差別化個人所得稅政策有關問題的通知》中對該問題進行了規定:

  紅利所得,目前對於個人從公開發行和轉讓市場取得的上市公司股票,自然人適用20%的稅率計征個人所得稅。

  根據持股期限有所不同:(1)持股期限超過1年的,股息紅利所得暫免徵收個人所得稅;(2)持股期限在一個月以上至1年(含1年)的,其股息紅利所得暫減按50%計入應納稅所得額;(3)持股期限在1個月以內(含1個月)的,其股息紅利所得全額計入應納稅所得額。

(文章來源:上海證券報)

(責任編輯:DF380)

【其他文章推薦】

木地板哪有幾種款式?該如何選購適合的材質呢?

※屬於你的居家品味,家具訂製工廠推薦與心得分享

※想知道舞台設計公司幕後工作人員工作祕辛嗎?

※想知道更多隱形防盜窗Q&A,都在生活知識王!!

※居家裝潢選購心得,沙發訂做推薦,手工沙發推薦CP值破表平價傢俱!

併購重組嚴把質量關

  證監會近日表示,將緊盯發行審核、併購重組等重點領域。截至9月3日,併購重組審核委員會共召開38次會議,審核63單,其中52單過會,過會率為82.5%,較去年同期有所降低。11家被否原因主要集中於標的資產質量、持續盈利能力、關聯交易、財務合規性、信息披露規範性等共性問題。

  總的來看,過會率降低更多在於嚴格把關,以防範後市風險,提升併購重組市場的整體質量。

  從被否原因來看,監管層關注的重點集中於標的資產質量、持續盈利能力、重大關聯交易、信息披露規範性等共性問題。從監管層面來看,過會率有所降低主要在於針對上市材料模糊地帶的監管收緊,辨析評價更加嚴格,避免企業助複雜交易矇混過關達到上市目的。

  通過併購重組實現資產的重新組合,轉移公司所有權或者實際控制權,實現公司資本擴張和業務發展的根本改變,能夠為上市公司提供做優做強的重要資本槓桿和工具。隨着經濟轉型和發展,主動併購成為越來越多上市公司的發展戰略選擇,通過進行產業內橫向縱向以及多元化併購實現價值鏈的延伸,以充分利用外部機會和內部優勢,鞏固市場競爭地位。據悉,為促進併購重組市場的加速運轉,證監會將增加審核的窗口,並對併購重組審核過程實行公開化,同時鼓勵併購基金的發展,充分發揮併購基金、公司債券和權證產品等工具在併購交易中的槓桿作用。

  在經濟轉型升級背景下,資本市場供給側結構性改革也在穩步推進,而併購重組憑藉其靈活性和特殊性或將成為盤活資本市場存量資源的主戰場。通過併購重組實現對產業資源的整合,推動企業去產能、去槓桿,助力產業龍頭骨幹的培育和發展,將有效服務實體經濟高質量發展。

  併購重組委嚴格監管是資本市場嚴把入口的客觀要求,能夠真正從源頭上提高上市公司質量,杜絕講故事企業上市吸金,切實保護投資者利益,提振市場信心。同時,嚴把質量關能夠有效避免劣幣驅逐良幣現象,減少非優質企業通過借殼上市等複雜交易實現上市,從而提高資本市場的資金利用效率,有助於打造一個規範、透明、開放、有活力、有韌性的資本市場。

  隨着市場化改革的推進,併購重組在資本市場中將發揮更為關鍵的存量質量提升作用。在市場需求的推動下政策配套會更加完善。併購重組的特殊性和靈活性將適應多種交易融資需求,為市場提供多元化融資渠道,有效改善存量,提升資源利用效率,相信併購重組市場將在更加規範的道路上推進,為我國資本市場的發展注入持久活力。

(文章來源:證券日報)

(責任編輯:DF380)

【其他文章推薦】

※老舊房屋馬桶不通、水管阻塞,推薦竹北通水管新竹通水管專業師傅,徹底解決多年臭味問題

※門外漢也要知道的超耐磨木地板祕辛?

※中古屋大改造,分享台中室內設計公司隔間重新規劃,擴大實用空間!

※浴室設計小心機,利用馬賽克磁磚,放大你的浴室空間

※打造北歐風,連設計師也極力讚許的古典家具推薦工廠

台電綠島火力發電廠歷時7年整治 終改善地下水污染

摘錄自2019年12月1日聯合新聞網報導

台灣電力公司綠島火力發電廠8年前被檢測出廠址土壤及地下水遭污染,隔年被公告為「須整治污染場址」列管,歷經7年努力改善,台東縣環保局指出,經驗證綠島火力發電廠場址周邊土壤及地下水,已低於土壤及地下水污染管制標準,環保局日前已函報行政院環保署解除「整治污染場址」列管。

台東縣環保局表示,民國100年環保局執行台東縣土壤及地下水污染調查及查證工作計畫時,在綠島火力發電廠檢測出地下水中污染物的柴油總碳氫化合物(TPH-d)濃度高達18900 mg/L,超過地下水污染管制標準的18倍,環保署在101年公告綠島火力發電廠為污染整治場址。

縣環保局表示,在環保局監督及管制下,綠島火力發電廠積極整治,改善土壤及地下水污染問題,經過7年努力,終於解除列管。

【其他文章推薦】

※找工作! 想知道堆高機駕駛日薪是多少嗎? 哪裡有職缺?幫你快速媒合

※隨時健康喝好水,高品質飲水機推薦,優質安全有把關

新北市轉軸代工廠商詢價平台?

防爆隔熱紙規格資訊說明

台南海岸遭侵蝕 復育延續沙洲潟湖有成效

摘錄自2019年11月29日中央通訊社報導

全球氣候暖化,台南海岸遭到侵蝕,沙洲流失,潟湖面積縮小,台南市政府已展開復育工程,8年來有效減緩海岸退縮,也讓沙洲及潟湖得以存續。

台南市政府水利局人員今天(29日)指出,台南縣市合併後,水利局已在沿海的北門區及七股區辦理30件沙洲復育工程,總經費約新台幣2億6000萬元,截至去年,8年來復育沙洲面積約78公頃,長度約16公里,疏濬潟湖土方約93萬立方公尺。

水利局復育沙洲,先從減少外在侵蝕開始,利用竹樁、海事固袋及沙腸袋等近自然工法,消減波浪及暴潮能量,減緩沙洲侵蝕,另再加強沙洲內在的防護強度,以抽砂養灘、編籬定砂及搭配植生復育,以加高培厚沙洲,還能延長潟湖壽命。

以七股區青山港沙洲來說,此地沙洲民國83年至98年期間,每年以平均50公尺的速度退縮,七股潟湖面積也越來越小,但在執行復育工程後,退縮速度大幅減少,從每年平均50公尺減緩至6公尺。

若是比較105年至107年變化,七股區青山港沙洲全線穩定,甚至部分區域有往外海成長的趨勢,顯示沙洲復育已有初步成效。

【其他文章推薦】

※有廠商專門客製化橡膠製品嗎?

噴霧洗滌塔實際應用案例分享

※票選推薦煮婦最愛手壓封口機,省荷包不犧牲品質

※選購空壓機需注意八大事項 !

※DIY自行施工建築隔熱紙,簡易教學大公開 !