分類: 3C資訊

  • 對象創建與堆

    對象創建與堆

    這一節主要介紹對象創建時,在堆中的一些過程。

    回憶下,我們之前說的,什麼時候會發生垃圾回收?

    除了在一些安全點處也許會發生垃圾回收(只是也許),如果在所需內存不足的情況下,一定會發生垃圾回收。

    分配堆空間

    首先通過設置參數,把堆空間設置為 20M,其中 新生代 10M,老年代 10M。

    參數設置:

    -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails

    結果為:

    Heap
     PSYoungGen      total 9216K, used 1685K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
      eden space 8192K, 20% used [0x00000007bf600000,0x00000007bf7a5580,0x00000007bfe00000)
      from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
      to   space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
     ParOldGen       total 10240K, used 0K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
      object space 10240K, 0% used [0x00000007bec00000,0x00000007bec00000,0x00000007bf600000)
    

    創建一個新對象

    我們首先創建一個對象,這個對象佔用 2M 的空間。

    package heap;
    
    public class CreateObject {
        public static void main(String[] args) {
            byte[] obj1 = new byte[1024 * 1024 * 2];
        }
    }
    

    最後的輸出:

    Heap
     PSYoungGen      total 9216K, used 3733K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
      eden space 8192K, 45% used [0x00000007bf600000,0x00000007bf9a5590,0x00000007bfe00000)
      from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
      to   space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
     ParOldGen       total 10240K, used 0K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
      object space 10240K, 0% used [0x00000007bec00000,0x00000007bec00000,0x00000007bf600000)
    

    可以看到,新生代 被佔用了,老年代佔用為 0K,沒有被使用。

    所以,new 的對象先放在 eden 區。

    填滿 eden 區

    在填滿 eden 區后,會發生什麼呢?因為 survivor 區實在太小了,很難看到。所以,這裏可以藉助 Visual VM,來觀察,更加直觀。

    程序如下:

    package heap;
    
    public class CreateObject {
        public static void main(String[] args) {
            while(true){
                byte[] bytes = new byte[1024 * 512];
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
    

    重點是看右邊的記錄圖。注意,這裏我們將每次創建對象的大小設置為了 0.5M。

    當 Eden 滿的時候,會調用垃圾回收器,調用垃圾回收器后,Eden 出現了低谷,Survivor 出現了一個增長。老年區也出現了一個增長。

    當 Eden 滿的時候,如果 Survivor 區有足夠的空間容納存活對象,那麼可以把存活對象放入 Survivor,多的對象放入老年區。

    現在,我們把對象的大小調大。設置為 2M,這樣 Survivor 就無法存放下。

    可以看到,在經過一次垃圾回收的時候(可以看到GC Time 上有波峰,說明執行了一次垃圾回收),但我們注意到,Survivor 區中並沒有被佔用。說明垃圾回收過程中,直接將存活對象放到了老年代中。

    再來聊聊 survivor 區

    對象通常在 Eden 區里誕生,如果經過第一次 MInor GC 后仍然存活,並且能夠被 Survivor 容納的話,該對象會被移動到 Survivor 區,並且將其年齡設置為 1 歲。對象在 Survivor 區每熬過一次 Minor GC,年齡就增加 1 歲,當它年齡增大到一定程度(默認是 15 歲),就會被晉陞到老年代。

    特殊情況

    有些時候,如果用戶創建了大對象,如很長的字符串或者元素很多的數組的時候。這種大對象都佔用大量的內存,像這種大對象,有很大概率是長時間使用的,不然為什麼要創建大對象。

    如果大對象朝生夕滅,我們知道在 Java 8 中,新生代默認採用的 標記-複製 算法,那麼對於大對象而言,是非常耗時的。

    所以,如果 JVM 設置了一個閾值,那麼當分配的對象大於這個閾值的時候,會直接被分配到老年代。

    總結

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

    【其他文章推薦】

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

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

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

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

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

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

  • python動態柱狀圖圖表可視化:歷年軟科中國大學排行

    python動態柱狀圖圖表可視化:歷年軟科中國大學排行

    本來想參照:https://mp.weixin.qq.com/s/e7Wd7aEatcLFGgJUDkg-EQ搞一個往年編程語言動態圖的,奈何找不到數據,有數據來源的歡迎在評論區留言。

    這裏找到了一個,是2020年6月的編程語言排行,供大家看一下:https://www.tiobe.com/tiobe-index/

     

    我們要實現的效果是:

    大學排名來源:http://www.zuihaodaxue.com/ARWU2003.html

    部分截圖:

    在http://www.zuihaodaxue.com/ARWU2003.html中的年份可以選擇,我們解析的頁面就有了:

    "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)

    初步獲取頁面的html信息的代碼:

    def get_one_page(year):
        try:
            headers = {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
                }
            url = "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)
            response=requests.get(url,headers=headers)
            if response.status_code == 200:
                return response.content
        except RequestException:
            print('爬取失敗')

    我們在頁面上進行檢查:

    數據是存儲在表格中的,這樣我們就可以利用pandas獲取html中的數據,基本語法:

    tb = pd.read_html(url)[num]

    其中的num是標識網頁中的第幾個表格,這裏只有一個表格,所以標識為0。初步的解析代碼就有了:

    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        return tb

    我們還要將爬取下來的數據存儲到csv文件中,基本代碼如下:

    def save_csv(tb):
        start_time=time.time()
        tb.to_csv(r'university.csv', mode='a', encoding='utf_8_sig', header=True, index=0)
        endtime = time.time()-start_time
        print('程序運行了%.2f秒' %endtime)

    最後是一個主函數,別忘了還有需要導入的包:

    import requests
    from requests.exceptions import RequestException
    import pandas as pd
    import time
    def main(year):
        for i in range(2003,year):
            html=get_one_page(i)
            tb=parse_on_page(html,i)
            #print(tb)
            save_csv(tb)
    if __name__ == "__main__":
        main(2004)

    運行之後,我們在同級目錄下就可以看到university.csv,部分內容如下:

    存在幾個問題:

    (1)缺少年份

    (2)最後一列沒有用

    (3)國家由於是圖片表示,沒有爬取下來

    (4)排名100以後的是一個區間

    我們接下來一一解決:

    (1)刪掉沒用的列

    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2, 'score',4]
        tb.drop([2,4],axis=1,inplace=True)
        return tb

    新的結果:

    (2) 對100以後的進行唯一化,增加一列index作為排名標識

    tb['index_rank'] = tb.index
    tb['index_rank'] = tb['index_rank'].astype(int) + 1

    (3)新增加年份

    tb['year'] = i

    (4)新增加國家

    首先我們進行檢查:

    發現國家在td->a>img下的圖像路徑中有名字:UnitedStates。 我們可以取出src屬性,並用正則匹配名字即可。

    def get_country(html):
        soup = BeautifulSoup(html,'lxml')
        countries = soup.select('td > a > img')
        lst = []
        for i in countries:
            src = i['src']
            pattern = re.compile('flag.*\/(.*?).png')
            country = re.findall(pattern,src)[0]
            lst.append(country)
        return lst

    然後這麼使用:

    # read_html沒有爬取country,需定義函數單獨爬取
    tb['country'] = get_country(html)

    最終解析的整體函數如下:

    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2, 'score',4]
        tb.drop([2,4],axis=1,inplace=True)
        tb['index_rank'] = tb.index
        tb['index_rank'] = tb['index_rank'].astype(int) + 1
        tb['year'] = i
        # read_html沒有爬取country,需定義函數單獨爬取
        tb['country'] = get_country(html)
        return tb

    運行之後:

    最後我們要提取屬於中國部分的相關信息:

    首先將年份改一下,獲取到2019年為止的信息:

    if __name__ == "__main__":
        main(2019)

    然後我們提取到中國高校的信息,直接看代碼理解:

    def analysis():
        df = pd.read_csv('university.csv')
        # 包含港澳台
        # df = df.query("(country == 'China')|(country == 'China-hk')|(country == 'China-tw')|(country == 'China-HongKong')|(country == 'China-Taiwan')|(country == 'Taiwan,China')|(country == 'HongKong,China')")[['university','year','index_rank']]
    
        # 只包括內地
        df = df.query("(country == 'China')")
        df['index_rank_score'] = df['index_rank']
        # 將index_rank列轉為整形
        df['index_rank'] = df['index_rank'].astype(int)
    
        # 美國
        # df = df.query("(country == 'UnitedStates')|(country == 'USA')")
    
        #求topn名
        def topn(df):
            top = df.sort_values(['year','index_rank'],ascending = True)
            return top[:20].reset_index()
        df = df.groupby(by =['year']).apply(topn)
    
        # 更改列順序
        df = df[['university','index_rank_score','index_rank','year']]
        # 重命名列
        df.rename (columns = {'university':'name','index_rank_score':'type','index_rank':'value','year':'date'},inplace = True)
    
        # 輸出結果
        df.to_csv('university_ranking.csv',mode ='w',encoding='utf_8_sig', header=True, index=False)
        # index可以設置

    本來是想爬取從2003年到2019年的,運行時發現從2005年開始,頁面不一樣了,多了一列:

    方便起見,我們就只從2005年開始了,還需要修改一下代碼:

        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2,3, 'score',5]
        tb.drop([2,3,5],axis=1,inplace=True)

    最後是整體代碼:

    import requests
    from requests.exceptions import RequestException
    import pandas as pd
    import time
    from bs4 import BeautifulSoup
    import re
    def get_one_page(year):
        try:
            headers = {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
                }
            url = "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)
            response=requests.get(url,headers=headers)
            if response.status_code == 200:
                return response.content
        except RequestException:
            print('爬取失敗')
    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2,3, 'score',5]
        tb.drop([2,3,5],axis=1,inplace=True)
        tb['index_rank'] = tb.index
        tb['index_rank'] = tb['index_rank'].astype(int) + 1
        tb['year'] = i
        # read_html沒有爬取country,需定義函數單獨爬取
        tb['country'] = get_country(html)
        return tb
    def save_csv(tb):
        start_time=time.time()
        tb.to_csv(r'university.csv', mode='a', encoding='utf_8_sig', header=True, index=0)
        endtime = time.time()-start_time
        print('程序運行了%.2f秒' %endtime)
    # 提取國家名稱
    def get_country(html):
        soup = BeautifulSoup(html,'lxml')
        countries = soup.select('td > a > img')
        lst = []
        for i in countries:
            src = i['src']
            pattern = re.compile('flag.*\/(.*?).png')
            country = re.findall(pattern,src)[0]
            lst.append(country)
        return lst
    def analysis():
        df = pd.read_csv('university.csv')
        # 包含港澳台
        # df = df.query("(country == 'China')|(country == 'China-hk')|(country == 'China-tw')|(country == 'China-HongKong')|(country == 'China-Taiwan')|(country == 'Taiwan,China')|(country == 'HongKong,China')")[['university','year','index_rank']]
    
        # 只包括內地
        df = df.query("(country == 'China')")
        df['index_rank_score'] = df['index_rank']
        # 將index_rank列轉為整形
        df['index_rank'] = df['index_rank'].astype(int)
    
        # 美國
        # df = df.query("(country == 'UnitedStates')|(country == 'USA')")
    
        #求topn名
        def topn(df):
            top = df.sort_values(['year','index_rank'],ascending = True)
            return top[:20].reset_index()
        df = df.groupby(by =['year']).apply(topn)
    
        # 更改列順序
        df = df[['university','index_rank_score','index_rank','year']]
        # 重命名列
        df.rename (columns = {'university':'name','index_rank_score':'type','index_rank':'value','year':'date'},inplace = True)
    
        # 輸出結果
        df.to_csv('university_ranking.csv',mode ='w',encoding='utf_8_sig', header=True, index=False)
        # index可以設置
    def main(year):
        for i in range(2005,year):
            html=get_one_page(i)
            tb=parse_on_page(html,i)
            save_csv(tb)
            print(i,'年排名提取完成完成')
            analysis()
    if __name__ == "__main__":
        main(2019)

    運行之後會有一個university_ranking.csv,部分內容如下:

    接下來就是可視化過程了。

    1、 首先,到作者的github主頁:  
    https://github.com/Jannchie/Historical-ranking-data-visualization-based-on-d3.js

    2、克隆倉庫文件,使用git

    # 克隆項目倉庫
    git clone https://github.com/Jannchie/Historical-ranking-data-visualization-based-on-d3.js
    # 切換到項目根目錄
    cd Historical-ranking-data-visualization-based-on-d3.js
    # 安裝依賴
    npm install

    這裏如果git clone超時可參考:

    https://www.cnblogs.com/xiximayou/p/12305209.html

    需要注意的是,這裏的npm是我之前裝node.js裝了的,沒有的自己需要裝一下。

    在執行npm install時會報錯:

    先執行:

    npm init

    之後一直回車即可:

    再執行npm install

    任意瀏覽器打開bargraph.html網頁,點擊選擇文件,然後選擇前面輸出的university_ranking.csv文件,看下效果:

    只能製作動圖上傳了。

    可以看到,有了大致的可視化效果,但還存在很多瑕疵,比如:表順序顛倒了、字體不合適、配色太花哨等。可不可以修改呢?

    當然是可以的,只需要分別修改文件夾中這幾個文件的參數就可以了:

    • config.js 全局設置各項功能的開關,比如配色、字體、文字名稱、反轉圖表等等功能;

    • color.css 修改柱形圖的配色;

    • stylesheet.css 具體修改配色、字體、文字名稱等的css樣式;

    • visual.js 更進一步的修改,比如圖表的透明度等。

    知道在哪裡修改了以後,那麼,如何修改呢?很簡單,只需要簡單的幾步就可以實現:

    • 打開網頁,右鍵-檢查,箭頭指向想要修改的元素,然後在右側的css樣式表裡,雙擊各項參數修改參數,修改完元素就會發生變化,可以不斷微調,直至滿意為止。

        

    • 把參數複製到四個文件中對應的文件里並保存。

    • Git Bash運行npm run build,之後刷新網頁就可以看到優化后的效果。(我發現這一步其實不需要,而且會報錯,我直接修改config.js之後運行也成功了)

    這裏我主要修改的是config.js的以下項:

      // 倒序,使得最短的條位於最上方 
      reverse: true,
      // 附加信息內容。
      // left label
      itemLabel: "本年度第一大學",
      // right label
      typeLabel: "世界排名",
      //為了避免名稱重疊
      item_x: 500,
      // 時間標籤坐標。建議x:1000 y:-50開始嘗試,默認位置為x:null,y:null
      dateLabel_x: 1000,
      dateLabel_y: -50,

    最終效果:

    至此,就全部完成了。

    看起來簡單,還是得要自己動手才行。

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

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

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

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

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

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※回頭車貨運收費標準

  • angular 接入 IdentityServer4

    angular 接入 IdentityServer4

    angular 接入 IdentityServer4

    Intro

    最近把活動室預約的項目做了一個升級,預約活動室需要登錄才能預約,並用 IdentityServer4 做了一個統一的登錄註冊中心,這樣以後就可以把其他的需要用戶操作的應用統一到 IdentityServer 這裏,這樣就不需要在每個應用里都做一套用戶的機制,接入 IdentityServer 就可以了。

    目前活動室預約的服務器端和基於 angular 的客戶端已經完成了 IdentityServer 的接入,並增加了用戶的相關的一些功能,比如用戶可以查看自己的預約記錄並且可以取消自己未開始的預約,

    還有一個小程序版的客戶端暫時還未完成接入,所以小程序版目前暫時是不能夠預約的

    為什麼要寫這篇文章

    目前在網上看到很多都是基於 implicit 模式接入 IdentityServer,這樣實現起來很簡單,但是現在 OAuth 已經不推薦這樣做了,OAuth 推薦使用 code 模式來代替 implicit

    implicit 模式會有一些安全風險,implicit 模式會將 accessToken 直接返回到客戶端,而 code 模式只是會返回一個 code,accessToken 和 code 的分離的兩步,implicit 模式很有可能會將 token 泄露出去

    詳細可以參考 StackOverflow 上的這個問答

    https://stackoverflow.com/questions/13387698/why-is-there-an-authorization-code-flow-in-oauth2-when-implicit-flow-works

    除此之外,還有一個小原因,大多是直接基於 oidc-client 的 一個 npm 包來實現的,我是用了一個針對 angular 封裝的一個庫 angular-oauth2-oidc,如果你在用 angular ,建議你可以嘗試一下,針對 angular 做了一些封裝和優化,對 angular 更友好一些

    準備接入吧

    API 配置

    預約系統的 API 和網站管理系統是在一起的,針對需要登錄才能訪問的 API 單獨設置了的 policy 訪問

    services.AddAuthentication()
        .AddIdentityServerAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme, options =>
        {
            options.Authority = Configuration["Authorization:Authority"];
            options.RequireHttpsMetadata = false;
    
            options.NameClaimType = "name";
            options.RoleClaimType = "role";
        })
        ;
    
    services.AddAuthorization(options =>
    {
        options.AddPolicy("ReservationApi", builder => builder
            .AddAuthenticationSchemes(IdentityServerAuthenticationDefaults.AuthenticationScheme)
            .RequireAuthenticatedUser()
            .RequireScope("ReservationApi")
        );
    });
    

    需要授權才能訪問的接口設置 Authorize 並指定 Policy 為 ReservationApi

    [Authorize(Policy = "ReservationApi")]
    [HttpPost]
    public async Task<IActionResult> MakeReservation([FromBody] ReservationViewModel model)
    

    IdentityServer Client 配置

    首先我們需要在 IdentityServer 這邊添加一個客戶端,因為我們要使用 code 模式,所以授權類型需要配置 authorization-code 模式,不使用 implicit 模式

    允許的作用域(scope) 是客戶端允許訪問的 api 資源和用戶的信息資源,openid 必選,profile 是默認的用戶基本信息的集合,根據自己客戶端的需要進行配置,ReservationApi 是訪問 API 需要的 scope,其他的 scope 根據客戶端需要進行配置

    angular 客戶端配置

    安裝 angular-oauth2-oidc npm 包,我現在使用的是 9.2.0 版本

    添加 oidc 配置:

    export const authCodeFlowConfig: AuthConfig = {
      issuer: 'https://id.weihanli.xyz',
    
      // URL of the SPA to redirect the user to after login
      redirectUri: window.location.origin + '/account/callback',
    
      clientId: 'reservation-angular-client',
    
      dummyClientSecret: 'f6f1f917-0899-ef36-63c8-84728f411e7c',
    
      responseType: 'code',
    
      scope: 'openid profile ReservationApi offline_access',
    
      useSilentRefresh: false,
    
      showDebugInformation: true,
    
      sessionChecksEnabled: true,
    
      timeoutFactor: 0.01,
    
      // disablePKCI: true,
    
      clearHashAfterLogin: false
    };
    

    在 app.module 引入 oauth 配置

      imports: [
        BrowserModule,
        AppRoutingModule,
        AppMaterialModule,
        HttpClientModule,
        FormsModule,
        ReactiveFormsModule,
        BrowserAnimationsModule,
        OAuthModule.forRoot({
          resourceServer: {
            allowedUrls: ['https://reservation.weihanli.xyz/api'],
            sendAccessToken: true
          }
        })
      ]
    

    OAuthModule 里 resourceServer 中的 allowedUrls 是配置的資源的地址,訪問的資源符合這個地址時就會自動發送 accessToken,這樣就不需要自己實現一個 interceptor 來實現自動在請求頭中設置 accessToken 了

    在 AppComponment 的構造器中初始化 oauth 配置,並加載 ids 的發現文檔

    export class AppComponent {
      constructor(
            private oauth: OAuthService
        ) {
        this.oauth.configure(authConfig.authCodeFlowConfig);
        this.oauth.loadDiscoveryDocument();
        }
        // ...
    }
    

    添加一個 AuthGuard,路由守衛,需要登錄才能訪問的頁面自動跳轉到 /account/login 自動登錄

    AuthGuard:

    import { Injectable } from '@angular/core';
    import { CanActivate, Router } from '@angular/router';
    import { OAuthService } from 'angular-oauth2-oidc';
    
    @Injectable({
      providedIn: 'root'
    })
    export class AuthGuard implements CanActivate {
      constructor(private router: Router, private oauthService: OAuthService) {}
    
      canActivate() {
        if (this.oauthService.hasValidAccessToken()) {
          return true;
        } else {
          this.router.navigate(['/account/login']);
          return false;
        }
      }
    }
    
    

    路由配置:

    import { NgModule } from '@angular/core';
    import { Routes, RouterModule } from '@angular/router';
    import { ReservationListComponent } from './reservation/reservation-list/reservation-list.component';
    import { NoticeListComponent } from './notice/notice-list/notice-list.component';
    import { NoticeDetailComponent } from './notice/notice-detail/notice-detail.component';
    import { AboutComponent } from './about/about.component';
    import { NewReservationComponent } from './reservation/new-reservation/new-reservation.component';
    import { LoginComponent } from './account/login/login.component';
    import { AuthGuard } from './shared/auth.guard';
    import { AuthCallbackComponent } from './account/auth-callback/auth-callback.component';
    import { MyReservationComponent } from './account/my-reservation/my-reservation.component';
    
    const routes: Routes = [
      { path: '', component: ReservationListComponent },
      { path: 'reservations/new', component:NewReservationComponent, canActivate: [AuthGuard] },
      { path: 'reservations', component: ReservationListComponent },
      { path: 'notice', component: NoticeListComponent },
      { path: 'notice/:noticePath', component: NoticeDetailComponent },
      { path: 'about', component: AboutComponent },
      { path: 'account/login', component: LoginComponent },
      { path: 'account/callback', component: AuthCallbackComponent },
      { path: 'account/reservations', component: MyReservationComponent, canActivate: [AuthGuard] },
      { path: '**', redirectTo: '/'}
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule]
    })
    export class AppRoutingModule { }
    

    AccountLogin 會將用戶引導到 ids 進行登錄,登錄之後會跳轉到配置的重定向 url,我配置的是 account/callback

    import { Component, OnInit } from '@angular/core';
    import { OAuthService } from 'angular-oauth2-oidc';
    
    @Component({
      selector: 'app-login',
      templateUrl: './login.component.html',
      styleUrls: ['./login.component.less']
    })
    export class LoginComponent implements OnInit {
    
      constructor(private oauthService: OAuthService) {
      }
    
      ngOnInit(): void {
        // 登錄
        this.oauthService.initLoginFlow();
      }
    
    }
    

    Auth-Callback

    import { Component, OnInit } from '@angular/core';
    import { OAuthService } from 'angular-oauth2-oidc';
    import { Router } from '@angular/router';
    
    @Component({
      selector: 'app-auth-callback',
      templateUrl: './auth-callback.component.html',
      styleUrls: ['./auth-callback.component.less']
    })
    export class AuthCallbackComponent implements OnInit {
    
      constructor(private oauthService: OAuthService, private router:Router) {
      }
    
      ngOnInit(): void {
        this.oauthService.loadDiscoveryDocumentAndTryLogin()
        .then(_=> {
          this.oauthService.loadUserProfile().then(x=>{
            this.router.navigate(['/reservations/new']);
          });
        });
      }
    
    }
    

    More

    當前實現還不太完善,重定向現在始終是跳轉到的新預約的頁面,應當在跳轉登錄之前記錄一下當前的地址保存在 storage 中,在 auth-callback 里登錄成功之後跳轉到 storage 中之前的地址

    Reference

    • https://sunnycoding.cn/2020/03/14/angular-spa-auth-with-ocelot-and-ids4-part3/#i-2
    • https://github.com/OpenReservation/angular-client
    • https://github.com/manfredsteyer/angular-oauth2-oidc/
    • https://github.com/OpenReservation/ReservationServer

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

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

  • 思考:如何保證服務穩定性?

    最近一直在忙618大促的全鏈路壓測&穩定性保障相關工作,結果618還未開始,生產環境就出了幾次生產故障,且大多都是和系統穩定性、性能相關的bad case。

    生產全鏈路壓測終於告一段落,抽出時間將個人收集的穩定性相關資料整理review了一遍,順帶從不同的維度,談談穩定性相關的“務虛”認知和思考。。。

     

    一、SLA!

    在開始談穩定性保障之前,我們先來聊聊業內經常提及的一個Topic:SLA!

    業內喜歡用SLA (服務等級協議,全稱:service level agreement)來衡量系統的穩定性,對互聯網公司來說就是網站服務可用性的一個保證。

    9越多代表全年服務可用時間越長服務越可靠,停機時間越短。就以一個標準99.99%為例,停機時間52.6分鐘,平均到每周也就是只能有差不多1分鐘的停機時間,

    也就是說網絡抖動這個時間可能就沒了。保證一個系統四個9或者更高的五個9,需要一套全體共識嚴格標準的規章制度,沒有規矩不成方圓。創建的規範有如下幾種:

    1、研發規範、自身穩定;

    2、事務中不能包含遠程調用;

    3、超時時間和重試次數要合理;

    4、表數據操作必須double check,合理利用索引,避免出現慢查詢、分庫分表不走分表鍵;

    5、沒有有效的資源隔離, 避免不同業務共用一個線程池或連接池;

    6、合理的系統拓撲,禁止不合理的服務依賴,能去依賴就去依賴,否則同步依賴盡量改成異步弱依賴;

    7、精簡的代碼邏輯;

    8、核心路徑流程必須進行資源隔離,確保任何突發情況主流程不能受影響。

     

    二、單服務穩定性

    關鍵字:開關可控、單一職責、服務隔離、異常兜底、監控發現!

    對於穩定性來說,拋開整體系統架構設計,單就每個業務域服務的穩定性也是非常的重要。

    只有每個業務環節都穩如泰山,才可以保障整個穩定性。單服務的穩定可以從以下幾個方面來進行:

    1、禁用設計:應該提供控制具體功能是否開啟可用的配置,在相應的功能服務出現故障時,快速下線局部功能,以保證整體服務的可用性;

    2、必要的緩存:緩存是解決併發的利器,可以有效的提高系統的吞吐量。按照業務以及技術的緯度必要時可以增加多級緩存來保證其命中率;

    3、接口無狀態性:服務接口應該是無狀態的,當前接口訪問不應該依賴上層接口的狀態邏輯;

    4、接口單一職責性:對於核心功能的接口,不應該過多的耦合不屬於它的功能。如果一個接口做的事情太多應做拆分,保證單接口的穩定性和快速響應;

    5、第三方服務隔離性:任何依賴於第三方的服務(不論接口還是中間件等),都應該做到熔斷和降級,不能有強耦合的依賴;

    6、業務場景兜底方案:核心業務場景需要做到完整的兜底方法,從前端到後端都應該有兜底措施;

    7、服務監控與及時響應:每個服務應該做好對應的監控工作,如有異常應及時響應,不應累積。

     

    三、集群穩定性

    關鍵字:系統架構、部署發布、限流熔斷、監控體系、壓測機制!

    對於集群維度的穩定性來說,穩定性保障會更加複雜。單服務是局部,集群是全局。一個見微知著,一個高瞻遠矚。

    1、合理的系統架構:合理的系統架構是穩定的基石;

    2、小心的代碼邏輯:代碼時刻都要小心,多擔心一點這裡會不會有性能問題,那裡會不會出現併發,代碼就不會有多少問題;

    3、優秀的集群部署:一台機器永遠會有性能瓶頸,優秀的集群部署,可以將一台機器的穩定放大無限倍,是高併發與大流量的保障;

    4、科學的限流熔斷:高併發來臨時,科學的限流和熔斷是系統穩定的必要條件;

    5、精細的監控體系:沒有監控體系,你永遠不會知道你的系統到底有多少隱藏的問題和坑,也很難知道瓶頸在哪裡;

    6、強悍的壓測機制:壓測是高併發穩定性的試金石,能提前預知高併發來臨時,系統應該出現的模樣;

    7、膽小的開發人員:永遠需要一群膽小的程序員,他們討厭bug,害怕error,不放過每一個波動,不信任所有的依賴。

     

    四、穩定性專項

    專項指的是針對某些特定場景下的特定問題而梳理出對應的方案。下面是針對一些常見的穩定性專項的概述:

    1、預案:分為定時預案和緊急預案,定時預案是大促常規操作對於一系列開關的編排,緊急預案是應對突發情況的特殊處理,都依賴於事前梳理;

    2、預熱:分為JIT代碼預熱和數據預熱,阿里內部有專門的一個產品負責這塊,通過存儲線上的常態化流量或者熱點流量進行回放來提前預熱,

      起源於某年雙十一零點的毛刺問題,原因是訪問了數據庫的冷數據rt增高導致的一系列上層限流,現在預熱已經成了大促之前的一個必要流程。

    3、強弱依賴:梳理強弱依賴是一個偏人肉的過程,但是非常重要,這是一個系統自查識別潛在風險點併為後續整理開關限流預案和根因分析的一個重要參考,

      阿里內部有一個強弱依賴檢測的平台,通過對測試用例注入RPC調用的延遲或異常來觀察鏈路的依賴變化,自動梳理出強弱依賴關係。

    4、限流降級熔斷:應對突發流量防止請求超出自身處理能力系統被擊垮的必要手段;

    5、監控告警&鏈路追蹤:監控分為業務監控、系統監控和中間件監控和基礎監控,作為線上問題發現和排查工具,重要性不言而喻。

     

    五、穩定性建設

    穩定性建設,就和基礎技術建設一樣,是一個長期迭代和不斷調整的過程,業內常見的穩定性建設類型,主要有如下幾種:

    1、容量規劃:個人感覺容量規劃在大廠里也並沒有做的很好,更多依賴的是業務方自己拍腦袋,然後全鏈路壓測期間驗證,不夠就再加機器。

    2、混沌工程:混沌工程是近幾年比較火的名詞,通過不斷給系統找麻煩來驗證並完善系統能力,阿里在這塊花了很大的精力建設紅藍軍對抗攻防,進行定期和不定期的演練,

      最後以打分的形式來給各個部門系統做排名,除了系統層面的故障演練外還有資金演練,篡改線上sql語句製造資損來測試業務監控糾錯的能力,通過製造小錯來避免大錯。

      跳轉門:混沌工程-初識

    3、流量調度:通過metric秒級監控和聚類算法實時找出異常單機來降低RPC流量權重,提升集群整體吞吐能力減少異常請求。

    4、容災&異地多活:起源於15年某施工隊將光纖挖斷帶來的支付寶故障,由此出來的三地五中心和單元化架構,異地多活本身的成本比較高,

      然後又存在數據同步的延時問題和切流帶來的臟數據問題,對於業務和技術都有比較高的要求。常見的容災有如下幾種:

      1)緩存掛掉,集群重啟緩存預熱如何處理?本地緩存,多級緩存是否可以替代?

      2)分佈式鎖,是否有開關一鍵切換?比如:ZK/ETCD編寫的分佈式鎖;

      3)大促峰值流量,如何防止外部ddos攻擊?如何識別流量類型?

      4)資源隔離:資源隔離,服務分組,流量隔離;

      5)高可用思想:避免單點設計!

      6)容錯:容錯上游,防禦下游。容錯主要需要注意如下幾點:

         6-1:外部依賴的地方都要做熔斷,避免雪崩;

         6-2:對於依賴我們的上游要限流,防止上游突發流量超過自己系統能夠扛住的最大QPS;

         6-3:對於下游既要評估好接口超時時間,防止下游接口超時異常導致自己系統被拖累;

         6-4:下游的接口要考慮各種異常情況,需要考慮中間狀態,通過引入柔性事務,確保數據最終一致。

    5、異地多活

    異地多活的本質,是數據中心架構的演進

    1)演進:單機房——雙機房——異地災備——異地多活;

    2)定義:分多個地域、多個數據中心運行線上的業務,並且每個IDC均提供在線服務;

    3)優點:彈性擴展能力、流量就近接入、靈活調度、提升可用性與用戶體驗、容災;

    4)步驟

      4-1:基礎設施:機房之間專線互聯,保證網絡質量穩定;

      4-2:持久存儲:一主三從,主IDC同步複製,異地IDC異步複製;

      4-3:中間件:DB、MQ、分佈式存儲;

      4-4:應用部署:根據應用域劃分,不同應用部署在不同地域,保持親緣性;

      4-5:流量接入與調度:網絡協議兼容,DNS,動態調度用戶就近訪問;

      4-6:監控與運維保障:專線實時監控,確保發生故障時可以觸發Failover(失效備援)和流量調度。

     

    六、穩定性思考

    關鍵字:階段工作、角色轉變!

    穩定性建設是一個演進的階段性過程,主要分為三個階段:

    1、發現問題解決問題:當問題較多時候就很被動,很多時候我們通過不斷完善監控來確保我們來快速定位問題,但仍處於被動的一方;

    2、主動尋找問題:混沌工程、破壞性測試、極限壓測、紅藍對抗等手段,一方作為創造問題方不斷挑戰系統極限,另一方見招拆招快速修復。

    3、角色轉變:這個過程中會積累很多處理問題的經驗,不斷完善系統健壯性,爭取在用戶發現問題前消滅於萌芽中。角色轉變,變被動為主動。

     

    七、推薦閱讀

    聊聊服務災備

    大促穩定性建設

    運維監控體系建設

    這樣的高可用,我不要

    高併發限流,到底限的什麼鬼

    新浪微博平台穩定性體系介紹

    StabilityGuide—穩定大於一切

    沒有預熱,不叫高併發,叫併發高

    信號量限流,高併發限流不得不說的秘密

     

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

    【其他文章推薦】

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

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

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

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

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

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

  • 中國四部委再次要求 破除新能源車地方保護

    中國財政部等四部委近日聯合公布了第二批新能源汽車推廣應用城市名單,公告再次明確提出了破除新能源汽車地方保護的要求。業內人士表示,京滬兩大新能源汽車推廣主力城市需要拿出姿態,以警示後續的地方保護行為。

    去(2013)年9月17日,財政部曾在公布的新一輪新能源汽車補貼政策中明確指出,示范城市或區域推廣應用的車輛中外地品牌數量不得低於30%,且不得設置或變相設置障礙限制採購外地品牌車輛。

    隨著國家扶持新能源汽車相關政策不斷出台,北京、上海、天津等地紛紛打造當地新能源汽車產業,考慮到利於當地企業的發展,在引入外非本地企業的新能源汽車品牌時,會制定一些差異化條款,比如優先購買本地新能源汽車等。

    因此在國家推薦的節能與新能源汽車產品目錄之下,地方政府還設定了一個地方性的產品目錄。其中,北京與上海市場針對外地新能源汽車品牌皆有相應的條件要求。

    重慶、呼和浩特等地也紛紛提出,採購和補貼的對象是符合當地政府認定的新能源汽車。天津、河南等地在節能與新能源汽車採購對象上也明確規定,在技術、服務等指標滿足採購需要的前提下,優先採購納入政府採購范圍的電動汽車。

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

    【其他文章推薦】

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

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

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

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

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

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

  • 中國電動車購買補助高於預期 特斯拉股價攀新高

    據新浪財經消息,受中國財政部宣布的電動汽車補貼縮減幅度低於市場預期,可望為特斯拉下月起在中國銷售Model S創造良好環境的影響,特斯拉汽車(TSLA)昨(10)日股價漲5.38%至196.56美元的新高。特斯拉方面表示,雖然Model S不在直接補貼範圍內,但希望中國也能考慮給予直接補貼待遇。

    據《新華社》報導,中國去(2013)年向電動車消費者每台車補貼約 3.5 至 6 萬元人民幣,而今年與明 (2015) 年補貼金額將分別減少至 5% 與 10%,僅為原先公布補貼縮減幅度的一半。

    特斯拉上月宣布的報告指出,去年第 4 季一共售出 6900 輛 Model S 車款,銷售輛季增 25%,也比先前預期高出 20%,也帶動公司股價穩定回升。

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

    【其他文章推薦】

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

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

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

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

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

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

  • 搶先日產 比亞迪全電動計程車隊進入倫敦

    中國汽車廠商比亞迪(BYD)今(11)日宣布,首支英國倫敦史上全電動計程車隊正式上路,在2018年前批量供應零排放出租車的競爭中,搶在了日產(Nissan)等國際競爭對手之前。不到2個月前,比亞迪還交付了倫敦史上首批全電動公共汽車。

    據《金融時報》報導,倫敦市長鮑里斯約翰遜(Boris Johnson)設定了全市計程車必須在2018年前實現零排放的目標,引發汽車廠商爭相開發新車。

    比亞迪趕在該期限之前率先打入了倫敦交通市場。比亞迪將推出20輛電動汽車組成的車隊,由出租車公司Thriev營運。

    另一方面,日本電動車廠商日產(Nissan)與英國經典黑出租車製造商倫敦出租車公司(London Taxi Company) ,也準備趕在2018年期限之前開發出全電動車型。

    著名的股神華倫•巴菲特(Warren Buffett)持有比亞迪9.9%股份。

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

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

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

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

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

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※回頭車貨運收費標準

  • 萬向李澤楷競買菲斯科 今日將出結果

    據《華爾街日報》報導,美國電動汽車品牌菲斯科(Fisker)最終將於美國當地時間2月12日在紐約進行拍賣,美國法院表示會在一個工作日後宣判結果,李澤楷控股的混合動力技術控股有限公司與萬向集團仍是最有可能的競買成功者。

    據路透社的消息,混合動力為加強此次競買工作以及公司的管理,特別聘請了曾主要負責福特歐洲業務的前高管Martin Leach。Leach表示,混合動力目前最大的困境是,萬向集團在一年前收購了A123系統公司,而A123是Fisker的主要電池供應商,不過混合動力可以得到另一家電池公司波士頓動力的支持。

    美國汽車經銷協會首席經濟學家史蒂文表示,競買的最終贏家將獲得的不僅是Fisker的汽車產品或設計,還包括其知識產權,其中涉及的36項專利(大約一半為待定),包括電氣傳動系統、太陽能等專利技術。

    據悉,萬向錢潮作為萬向集團控股的汽車零部件製造和銷售公司,其股價近日來也因受各種消息刺激連續上漲。

    萬向錢潮並於昨(12)日發佈公告表示,從2000年開展電動汽車研發以來,控股股東萬向集團一直致力於發展清潔能源產業,但與國際先進技術相比尚有一定差距。為此,萬向集團希望通過併購聯合方式提升技術能力等。此前,萬向集團掌門人魯冠球曾表示,對同特斯拉電動車結盟合作抱開放態度。

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

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

  • 特斯拉Model S在港正式銷售 入門級57.9萬港幣

    昨(13)日有消息稱,特斯拉Model S車型已正式在香港銷售,其中入門級配置僅售57.9萬港幣。此外有報導稱,比亞迪將與ABB集團及德國戴姆勒共建全球最大電動汽車快速充電網,ABB將在未來6年內為兩家公司提供直流快速充電樁。

    上述消息為A股正紅火的新能源汽車相關概念再添一把柴。截至昨天收盤,充電樁概念逆市上漲0.67%,漲幅居前,奧特迅領漲,漲幅為7.60%。特斯拉概念表現較為抗跌僅下挫0.51%,金瑞科技漲停,比亞迪也大漲8.26%。鋰電池概念跌0.93%,其中南洋科技漲9.48%。

    證券方面人士認為,在政府大力建設新型城鎮化、發展城市公共交通的背景下,對新能源汽車的政策扶持將會給電池業、電池電機上游的鋰和稀土資源行業、充電站行業、乘用車企業帶來機遇。

    但需要注意的是,未來的上漲空間將取決於政策的落實情況和上市公司的基本面,並且投資者不可對其期望過高,尤其是目前市場處於震盪的情形下,一旦后續資金追高乏力,相關個股很難擺脫大勢的影響。

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

    【其他文章推薦】

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

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

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

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

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

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

  • 萬向集團出價1.49億美元 最終競得菲斯科

    萬向集團出價1.49億美元 最終競得菲斯科

    據外電報道,中國汽車零件製造商萬向集團擊敗李澤楷旗下的Hybrid Tech,在美國豪華混合動力汽車製造商Fisker的破產資產拍賣中勝出。萬向出價1.492億美元,大約是Fisker最初尋求的收購價的6倍。

    這次拍賣持續了三天,經歷了19輪投標。美國破產法官Kevin Gross按計劃將於2月18日批准此次出售。

    菲斯科在2009年獲得了美國能源部的5.29億美元綠色貸款。但能源部在2011年中期凍結支付,稱菲斯科在開發新車型上狀況頻出,一再拖延。

    2013年11月,菲斯科申請破產,並要求破產法官準許Hybrid Tech以2500萬美元的低價,向美國能源部購入Fisker原本總值1.6億多美元的貸款。Hybrid Tech從而成為Fisker的高級擔保貸款人,更表明有意進一步收購Fisker。

    但無擔保債權人反對這一報價,從而幫助中國最大的汽車零部件供應商於12月進入到交易環節中。

    在此筆交易達成后,萬向集團將努力重振菲斯科在中國汽車市場的發展,該集團也獲得了一個打進美國市場的入口點。據資料顯示,萬向為中國投資美國製造業、新能源和房地產的先行者,在過去20年,萬向於美國的投資遍布美國14個州,涉及汽車零件製造、不動產、新能源和私募基金等。

    2012年底時,萬向曾以近2.6億美元擊敗江森自控,成功拍得美國破產電池生產商A123鋰電池公司資產,這家公司正是Fisker的電池供應商。經營汽車零部件業務的萬向集團一直期望進軍整車制造領域。

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

    【其他文章推薦】

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

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

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

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

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

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