標籤: 網頁設計公司

  • 無人駕駛電動車?傳蘋果正在研發車類產品

    無人駕駛電動車?傳蘋果正在研發車類產品

      據知情人士透露,蘋果公司早在一年前就成立了汽車研發團隊,目前該團隊共有 100 多名員工,正在研發一款代號為 Titan 的電動車,同時蘋果公司與汽車產業中無人駕駛方面的資深人士互動頻繁,研發方向很有可能是一款無人駕駛的電動車。   蘋果公司對於汽車類產品和服務的研發計劃不僅僅局限在軟體系統,而是以打造整車為目標。在研發方面蘋果並沒有與傳統汽車廠商建立太多聯繫,據知情人士透露蘋果正在與汽車零組件廠商諮詢,主要是電力和車聯網方面的公司,這些諮詢並沒有涉及合作的部分。   蘋果公司已經招募了不少汽車產業的資深人士,包括前 Benz 北美研發中心的總裁 Johann Jungwirth,他在 2014 年 9 月加入蘋果四,此前曾負責 Benz 的自動駕駛、用戶界面設計、產品風格設計等工作。     本文全文授權轉載自《科技新報》─〈〉

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

    【其他文章推薦】

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

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

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

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

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

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

  • Tesla 力拚中國市場,買車送充電樁

    Tesla 力拚中國市場,買車送充電樁

    2014 年 Tesla 公司虧損額擴大了三倍,押寶中國市場收穫了名氣卻輸了銷量,主要問題是中國市場的充電站嚴重缺乏,Tesla 為解決這一難題宣布將免費為中國車主安裝家用充電樁,這是 Tesla 首次在整車銷售中提供這一服務。  
        據 Tesla 財報顯示,2014 年公司營收為 31.93 億美元,淨虧損達 2.94 億美元,Tesla 設定 2014 年中國市場電動車銷售目標為 1 萬輛,實際銷量只有 2,000 多輛。充電站缺乏是導致 Tesla 電動車在中國市場慘敗的重要原因。   Tesla 拿出的第一個對策是為車主免費安裝家用充電器樁,此前客戶在購車後需要支付安裝費,這是 Tesla 面向全球客戶統一的做法。安裝一個充電樁大約是 8,000 多元人民幣,不但給客戶省錢了,也省了很多事。   以 Tesla Model S 在中國高達 80 萬人民幣的售價而言,僅佔 1% 的充電樁費用免去能夠吸引客戶嗎?Tesla 憑藉一己之力很難在中國市場完成充電站的布局,目前 Tesla 在中國市場的超級充電站僅有 60  多個,充電樁大約 1,000 個,很難滿足消費者的需求。     本文全文授權轉載自《科技新報》─〈〉

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

    【其他文章推薦】

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

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

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

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

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

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

  • 三星收購電池部門 傳將研發電動車

    蘋果(Apple)研發電動車的傳聞滿天飛,三星(Samsung)不甘示弱跟進,打算在電動車界跟蘋果再次一決雌雄?   韓聯社和 Tomˋs Hardware 報導,南韓電池製造龍頭 Samsung SDI 23 日宣布收購汽車零件商 Magna Steyr 的電池部門,購併金額未對外透露。   Tomˋs Hardware 網站認為,Samsung SDI 是 BMW i3 電動車的電池供應商,購併固然可能只是要強化電池部門實力,但也有可能代表三星打算跨足電動車。三星集團旗下業務橫跨電機、化學、造船、工具機等,如果真的要生產電動車,三星握有的技術資源更勝蘋果。

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

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

  • 蟬聯兩年!Tesla Models S 再登美國年度最佳汽車

    美國消費者報告(Consumer Reports)的調查顯示,電動車製造商 Tesla 的 Model S 已連續 2 年榮登年度最佳汽車。   消費者報告是根據道路表現、可靠度和防撞測試結果來評比車輛,除了選出整體表現最佳的汽車外,也會按照車種來評比。Model S 今年之所以蟬聯年度最佳汽車,原因除了充滿電後能跑 426 公里外,能夠透過網路升級軟體、及 Tesla 已克服初期面臨的技術問題,也是這輛車獲得青睞的原因。   在消費者報告劃分的十大分類中,只有 6 類是由日本車贏得最佳汽車頭銜,為消費者報告 19 年前開始評比以來最少,贏得最佳汽車頭銜的美國汽車品牌則有 3 個。除了 Tesla,另外 2 個品牌是 Buick 及雪佛蘭(Chevrolet)。

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

    【其他文章推薦】

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

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

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

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

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

  • 日本充電樁達4萬個 超傳統加油站

    日產汽車(Nissan)日前宣佈,目前日本全國有4萬個充電設施,其中包括家用充電站,而加油站只有3.4萬個,充電樁數量已超過傳統加油站。   去年5月,豐田、日產、本田、三菱這四大日本汽車製造商與日本政策投資銀行共同成立了“日本充電服務”公司,承擔起在商業設施等地設置充電樁的成本及8年內充電樁的維護費用。   日本便利店巨頭也表示將加快完善電動車充電設施,期待以此增加客流量。全家便利店在今年3月底之前將可為電動車及插電式混合動力車快速充電的店鋪增加至650家,期待達到同行業數量之最,並成為首個能源補給設施遍佈日本全境的便利店企業。羅森便利店也計畫在今年5月前將電動車充電樁由目前的12個增至200個左右。

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

    【其他文章推薦】

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

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

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

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

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

  • 比亞迪電動巴士入日本市場 遭日本人吐槽「跑跑就散架」

    比亞迪電動巴士入日本市場 遭日本人吐槽「跑跑就散架」

    近日,比亞迪電動巴士K9亮相日本京都地區,成為首個進入日本市場的中國汽車品牌。據日本當地媒體報導,本次引入京都的比亞迪電動巴士共計5輛,每輛車核定乘員人數69人,將由京都急行巴士株式會社運營。   環球網掌握的公開資料顯示,該款單層電動巴士完成單次充電後,可行駛約250公里。比亞迪在美國亦有生產電動巴士K9,售價約80萬美元。而從 2011年3月比亞迪與丹麥最大的公交公司Movia達成純電動公交合作開始,K9已經駛入了全球五大洲的多個城市,從德國的法蘭克福、到美國的華盛頓、再到英國的倫敦,多個新能源公交領域的訂單花落比亞迪。   而對於比亞迪電動巴士的亮相,日本各界表現出了截然相反的態度。一方面,日本國土交通省對於中國自主品牌積極「點贊」。在京都國立博物館內舉行的K9運營啟動儀式上,日本國土交通省官員阪部光雄表示:「非常高興能在京都迎來比亞迪的純電動巴士,這是京都公交系統首次採用零排放的純電動巴士,運營純電動巴士對於地區的環境治理意義非常深遠。」

    但也有一些日本線民並不是表現那麼「淡定」,他們反應強烈。有網友在網上留言表示,「還不知道一年後是啥樣兒••••估計跑著跑著就散架了,這都能想像到!反正我堅決不坐。」有的網友則質疑純電動公車的續航里程,「到底一次能跑幾個小時啊?不說滿電能跑幾天,也不說充滿電能運行多久••••總感覺這車的事故處理費用和乘客賠償費用會跟高啊!」

    有的甚至表示,「買這廉價玩意兒,還不如讓有軌電車重新上路呢!」還有人則對日本媒體對此事的報導不滿,「看到這條新聞,總感覺很不爽,報導最後竟然還來了一句「今後訪問京都的中國遊客多數人都會看到BYD在日本街頭的雄姿」。」

    不少人則開始擔憂中國產品大量湧入日本,其驚呼,「(中國製造開始不斷湧入日本市場了!)從電視到電腦,再到智慧手機,現在居然輪到汽車了啊!」

    也有一些上了年紀的日本網友感歎中國製造的迅速崛起,「日本的車企也在做HV巴士,但純電動巴士好像還沒有在做呢。估計(比亞迪K9)比較便宜吧,但還是希望安全第一。1985年的時候,日本贈送給了北京兩輛公車,30年後,中國巴士開始進入日本了!好神奇!不過首先讓我們來一起見證這輛車的性能吧!」   文章來源:環球網

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

    【其他文章推薦】

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

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

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

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

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

  • 使用 nuget server 的 API 來實現搜索安裝 nuget 包

    使用 nuget server 的 API 來實現搜索安裝 nuget 包

    使用 nuget server 的 API 來實現搜索安裝 nuget 包

    Intro

    nuget 現在幾乎是 dotnet 開發不可缺少的一部分了,還沒有用過 nuget 的就有點落後時代了,還不快用起來

    nuget 是 dotnet 里的包管理機制,類似於前端的 npm ,php 的 composer,java 里的 maven …

    nuget 定義了一套關於 nuget server 的規範,使得用戶可以自己實現一個 nuget server

    也正是這些規範,使得我們可以根據這些規範來實現 nuget server 的包管理的功能,今天主要介紹一下,根據 nuget server 的 api 規範使用原始的 HTTP 請求來實現 nuget 包的搜索和使用 nuget 提供的客戶端 SDK 來實現 nuget 包的搜索和下載

    Nuget Server Api

    Nuget 協議介紹

    nuget 的協議有好幾個版本,目前主要用的是 v3,開源的 nuget server Baget 也實現了基於 nuget protocal v3 的規範

    我們添加 nuget 源的時候會指定一個 source url,類似 https://api.nuget.org/v3/index.json 這樣的,着通常被稱為 Service Index,是一個 nuget 源的入口,有點類似於 Identity Server 里的發現文檔,通過這個地址可以獲取到一系列的資源的地址

    有一些資源是協議規範里定義的必須要實現的,有一些是可選的,具體參考官方文檔,以後隨着版本變化,可能會有差異,目前 nuget.org 提供的資源如下:

    Nuget.org 提供了兩種搜索的方式,

    一個是 SearchQuery,會根據包名稱、 tag、description 等信息去匹配關鍵詞,

    一個是 SearchAutocomplete 根據包名稱的前綴去匹配包的名稱

    獲取某個 nuget 包的版本信息,可以使用 PackageBaseAddress 來獲取

    ServiceIndex 返回的信息示例如下:

    返回的信息會有一個 resources 的數組,會包含各種不同類型的資源,對應的 @id 就是調用這種類型的API要用到的地址,下面來看一個搜索的示例

    在每個 API 的文檔頁面可以看到會使用的 @type,調用這個 API 的時候應該使用這些 @type 對應的資源

    這裏的 @id 就是上面的 resource 對應的 @id

    參數說明:

    q 搜索時所用的關鍵詞,

    skip/take 用來分頁显示查詢結果,

    prelease 用來指定是否限制預覽版的 package,true 包含預覽版的 nuget 包,false 只包含已經正式發布的 nuget 包

    semVerLevel 是用來指定包的語義版本

    The semVerLevel query parameter is used to opt-in to SemVer 2.0.0 packages. If this query parameter is excluded, only packages with SemVer 1.0.0 compatible versions will be returned (with the standard NuGet versioning caveats, such as version strings with 4 integer pieces). If semVerLevel=2.0.0 is provided, both SemVer 1.0.0 and SemVer 2.0.0 compatible packages will be returned. See the SemVer 2.0.0 support for nuget.org for more information

    packageType 用來指定 nuget 包的類型,目前支持的類型包括 Dependency(默認)項目依賴項,DotnetTool(dotnetcore 2.1 引入的 dotnet cli tool),Template (dotnet new 用) 自定義的項目模板

    其他的 API 可以自行參考官方文檔:https://docs.microsoft.com/en-us/nuget/api/service-index

    Packages

    SearchQuery 返回的信息比較多而且可能並不準確,適用於不清楚包的名稱的時候使用,如果知道 nuget 包的名稱(PackageId) ,可以使用 SearchAutocomplete 來搜索,這樣更精準,返回的信息也更簡單,只有匹配的 package 名稱

    通過原始 api 調用的方式實現 nuget 包的搜索

    using var httpClient = new HttpClient(new NoProxyHttpClientHandler());
    // loadServiceIndex
    var serviceIndexResponse = await httpClient.GetStringAsync(NugetServiceIndex);
    var serviceIndexObject = JObject.Parse(serviceIndexResponse);
    
    var keyword = "weihanli";
    
    //https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource
    var queryEndpoint = serviceIndexObject["resources"]
        .First(x => x["@type"].Value<string>() == "SearchQueryService")["@id"]
        .Value<string>();
    var queryUrl = $"{queryEndpoint}?q={keyword}&skip=0&take=5&prerelease=false&semVerLevel=2.0.0";
    var queryResponse = await httpClient.GetStringAsync(queryUrl);
    Console.WriteLine($"formatted queryResponse:");
    Console.WriteLine($"{JObject.Parse(queryResponse).ToString(Formatting.Indented)}");
    
    // https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource
    var autoCompleteQueryEndpoint = serviceIndexObject["resources"]
        .First(x => x["@type"].Value<string>() == "SearchAutocompleteService")["@id"]
        .Value<string>();
    var autoCompleteQueryUrl = $"{autoCompleteQueryEndpoint}?q={keyword}&skip=0&take=5&prerelease=false&semVerLevel=2.0.0";
    var autoCompleteQueryResponse = await httpClient.GetStringAsync(autoCompleteQueryUrl);
    Console.WriteLine($"formatted autoCompleteQueryResponse:");
    Console.WriteLine($"{JObject.Parse(autoCompleteQueryResponse).ToString(Formatting.Indented)}");
    
    

    output 示例:

    Query 返回示例

    Autocomplete 返回結果

    從上面我們可以看到 Query 接口返回了很多的信息,Autocomplete 接口只返回了 package 的名稱,返回的信息更為簡潔,所以如果可以使用 Autocomplete 的方式就盡可能使用 Autocomplete 的方式

    Package Versions

    前面我們提到了可以使用 PackageBaseAddress 來查詢某個 nuget 包的版本信息,文檔地址:https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource,來看一下示例:

    using (var httpClient = new HttpClient(new NoProxyHttpClientHandler()))
    {
        // loadServiceIndex
        var serviceIndexResponse = await httpClient.GetStringAsync(NugetServiceIndex);
        var serviceIndexObject = JObject.Parse(serviceIndexResponse);
    
        // https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource
        var packageVersionsEndpoint = serviceIndexObject["resources"]
            .First(x => x["@type"].Value<string>() == "PackageBaseAddress/3.0.0")["@id"]
            .Value<string>();
    
        var packageVersionsQueryUrl = $"{packageVersionsEndpoint}/dbtool.core/index.json";
        var packageVersionsQueryResponse = await httpClient.GetStringAsync(packageVersionsQueryUrl);
        Console.WriteLine("DbTool.Core versions:");
        Console.WriteLine(JObject.Parse(packageVersionsQueryResponse)
                          .ToString(Formatting.Indented));
    }
    

    output 示例:

    注:api 地址中的 packageId 要轉小寫

    Nuget Client SDK

    除了上面的根據 api 自己調用,我們還可以使用 nuget 提供的客戶端 sdk 實現上述功能,這裏就不詳細介紹了,有需要可能查閱官方文檔:https://docs.microsoft.com/en-us/nuget/reference/nuget-client-sdk

    下面給出一個使用示例:

    var packageId = "WeihanLi.Common";
    var packageVersion = new NuGetVersion("1.0.38");
    
    var logger = NullLogger.Instance;
    var cache = new SourceCacheContext();
    // 在 SDK 的概念里,每一個 nuget 源是一個 repository
    var repository = Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json");
    
    // SearchQuery
    {
        var resource = await repository.GetResourceAsync<PackageSearchResource>();
        var searchFilter = new SearchFilter(includePrerelease: false);
    
        var results = await resource.SearchAsync(
            "weihanli",
            searchFilter,
            skip: 0,
            take: 20,
            logger,
            CancellationToken.None);
        foreach (var result in results)
        {
            Console.WriteLine($"Found package {result.Identity.Id} {result.Identity.Version}");
        }
    }
    // SearchAutoComplete
    {
        var autoCompleteResource = await repository.GetResourceAsync<AutoCompleteResource>();
        var packages =
            await autoCompleteResource.IdStartsWith("WeihanLi", false, logger, CancellationToken.None);
        foreach (var package in packages)
        {
            Console.WriteLine($"Found Package {package}");
        }
    }
    //
    {
        // get package versions
        var findPackageByIdResource = await repository.GetResourceAsync<FindPackageByIdResource>();
        var versions = await findPackageByIdResource.GetAllVersionsAsync(
            packageId,
            cache,
            logger,
            CancellationToken.None);
    
        foreach (var version in versions)
        {
            Console.WriteLine($"Found version {version}");
        }
    }
    

    More

    你可以使用 nuget sdk 方便的實現 nuget 包的下載安裝,內部實現了簽名校驗等,這樣就可以把本地不存在的 nuget 包下載到本地了,

    實現示例:

    {
        var pkgDownloadContext = new PackageDownloadContext(cache);
        var downloadRes = await repository.GetResourceAsync<DownloadResource>();
    
        var downloadResult = await RetryHelper.TryInvokeAsync(async () =>
            await downloadRes.GetDownloadResourceResultAsync(
                new PackageIdentity(packageId, packageVersion),
                pkgDownloadContext,
                @"C:\Users\liweihan\.nuget\packages", // nuget globalPackagesFolder
                logger,
                CancellationToken.None), r => true);
        Console.WriteLine(downloadResult.Status.ToString());
    }
    

    最後提供一個解析 nuget globalPackagesFolder 的兩種思路:

    一個是前面有篇文章介紹的,有個默認的配置文件,然後就是默認的配置,寫了一個解析的方法示例,支持 Windows/Linux/Mac:

    {
        var packagesFolder = Environment.GetEnvironmentVariable("NUGET_PACKAGES");
    
        if (string.IsNullOrEmpty(packagesFolder))
        {
            // Nuget globalPackagesFolder resolve
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                var defaultConfigFilePath =
                    $@"{Environment.GetEnvironmentVariable("APPDATA")}\NuGet\NuGet.Config";
                if (File.Exists(defaultConfigFilePath))
                {
                    var doc = new XmlDocument();
                    doc.Load(defaultConfigFilePath);
                    var node = doc.SelectSingleNode("/configuration/config/add[@key='globalPackagesFolder']");
                    if (node != null)
                    {
                        packagesFolder = node.Attributes["value"]?.Value;
                    }
                }
    
                if (string.IsNullOrEmpty(packagesFolder))
                {
                    packagesFolder = $@"{Environment.GetEnvironmentVariable("USERPROFILE")}\.nuget\packages";
                }
            }
            else
            {
                var defaultConfigFilePath =
                    $@"{Environment.GetEnvironmentVariable("HOME")}/.config/NuGet/NuGet.Config";
                if (File.Exists(defaultConfigFilePath))
                {
                    var doc = new XmlDocument();
                    doc.Load(defaultConfigFilePath);
                    var node = doc.SelectSingleNode("/configuration/config/add[@key='globalPackagesFolder']");
                    if (node != null)
                    {
                        packagesFolder = node.Attributes["value"]?.Value;
                    }
                }
    
                if (string.IsNullOrEmpty(packagesFolder))
                {
                    defaultConfigFilePath = $@"{Environment.GetEnvironmentVariable("HOME")}/.nuget/NuGet/NuGet.Config";
                    if (File.Exists(defaultConfigFilePath))
                    {
                        var doc = new XmlDocument();
                        doc.Load(defaultConfigFilePath);
                        var node = doc.SelectSingleNode("/configuration/config/add[@key='globalPackagesFolder']");
                        if (node != null)
                        {
                            packagesFolder = node.Value;
                        }
                    }
                }
    
                if (string.IsNullOrEmpty(packagesFolder))
                {
                    packagesFolder = $@"{Environment.GetEnvironmentVariable("HOME")}/.nuget/packages";
                }
            }
        }
    
        Console.WriteLine($"globalPackagesFolder: {packagesFolder}");
    }
    

    另一個是可以根據 nuget 提供的一個命令查詢 nuget locals global-packages -l,通過命令輸出獲取

    Reference

    • https://github.com/WeihanLi/SamplesInPractice/blob/master/NugetSample/RawApiSample.cs
    • https://github.com/WeihanLi/SamplesInPractice/blob/master/NugetSample/NugetClientSdkSample.cs
    • https://docs.microsoft.com/en-us/nuget/reference/nuget-client-sdk
    • https://docs.microsoft.com/en-us/nuget/create-packages/set-package-type
    • https://docs.microsoft.com/en-us/nuget/api/overview
    • https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource

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

    【【其他文章推薦】

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

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

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

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

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

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

  • Zookeeper分佈式過程協同技術 – 群首選舉

    Zookeeper分佈式過程協同技術 – 群首選舉

    Zookeeper分佈式過程協同技術 – 群首選舉

    群首概念

    群首為集群中服務器選擇出來的一個服務器,並被集群認可。設置群首目的在與對客戶端所發起的狀態變更請求進行排序,包括:create、setData、delete操作。群首將每一個請求轉換為一個事務並將事務發送給追隨者,確保集群按照群首確定的順序接受並處理這些事務。

    Zookeeper事務

    Zookeeper服務器會在本地處理只讀請求(例如:exists、getData、getChildren)。如果一台服務器接收到客戶端的getData請求,服務器讀取該狀態信息,並將這些信息返回客戶端。由於服務器在本地處理讀請求,所以在處理以只讀請求為主要負載時,性能會比較高。

    那些會改變狀態的客戶端請求(create、delete、setData)將會被轉發給群首,由群首執行相應的請求,完成狀態的更新,這就是Zookeeper的事務。

    選舉過程

    每個服務器啟動後進入LOOKING狀態,服務器之間進行通信來選舉一個群首,通過信息交換對群首選舉達成共識。在本次選舉中勝出的服務器將進入LEADING狀態,而集群中其他服務器將進入FOLLOWING狀態。

    群首選舉消息(leader election notifications)或簡單的稱為通知。當一個服務器進入LOOKING狀態就會向集群中的每一個服務器發送一個通知消息。消息中包含該服務器的投票信息。

    投票信息包含服務器標識符(sid)和最近執行的事務的zxid信息,例如投票信息(1,5)代表機器ID為1,最近執行的事務zxid為5。

    zxid為一個long型(64位)整數,分為2部分:時間戳部分和計數器部分,每個部分為32位。

     當一個服務器收到一個投票信息,該服務器將會根據以下規則修改自己的投票信息:

    1. 將接受的voteId和voteZxid作為一個標識符,並獲取接收方當前的投票中的zxid,用myZxid和mySid表示接收方服務器自己的值。
    2. 如果(voteZxid > myZxid)或者(voteZxid = myZxid 且 voteId > mySid),保留當前的投票信息。
    3. 否則,修改自己的投票信息,將voteZxid賦值給myZxid,將voteId賦值給mySid。

    當一個服務器收到的仲裁數量的服務器發來的投票信息都一樣時,就表示群首選舉成功,如果被選舉的群首為某個服務器自己,該服務器將會開始行使群首角色,否則就會成為一個追隨者並嘗試連接被選舉的群首服務器。一旦連接成功,追隨者和群首之間將會進行狀態同步,在同步完成后,追隨者才可以處理新的請求。 

     

     

    通過例子來演示選舉過程,三台服務器在分別發送出不同的選舉投票信息,其投票值包含服務器的標識符和最新的zxid。每個服務器都會收到另外兩個服務器發送的投票信息,在第一輪之後,服務器S2和S3將會改變其投票信息為(1,6),之後服務器S2和S3在改變投票信息之後會發送新的通知消息,S1服務器在接收到仲裁數量的通知消息擁有一樣的投票信息,最後S1被選舉出為集群的群首。

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

    【其他文章推薦】

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

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

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

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

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

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

  • Python 簡明教程 — 20,Python 類中的屬性與方法

    Python 簡明教程 — 20,Python 類中的屬性與方法

    微信公眾號:碼農充電站pro
    個人主頁:https://codeshellme.github.io

    與客戶保持良好的關係可以使生產率加倍。
    —— Larry Bernstain

    目錄

    類中的變量稱為屬性,類中的函數稱為方法

    類中的屬性分為:

    • 實例屬性:對象所有,互不干擾
    • 類屬性:類所有,所有對象共享

    類中的方法分為:

    • 實例方法:定義中有self 參數
    • 類方法:定義中有cls 參數,使用@classmethod 裝飾器
    • 靜態方法:定義中即沒有self 參數,也沒有cls 參數,使用@staticmethod 裝飾器

    1,實例屬性與類屬性

    類的對象,就是類的一個實例。類的實例屬性被對象所有,包含在每個對象之中,不同的對象之間,互不干擾。類的類屬性被類所有,被包含在類中,是所有的類對象共享。

    一般情況下,實例屬性會在__init__ 方法中聲明並初始化,並且使用self 來綁定。而類屬性是在類作用域中被聲明,並且不使用self 來綁定。

    例如下面代碼中,country 為類屬性,__name 為實例屬性:

    #! /usr/bin/env python3
    
    class People:
    
        country = 'china'
    
        def __init__(self, name):
            self.__name = name
    

    訪問實例屬性時使用對象.屬性名的格式,實例屬性屬於對象各自的,互不影響:

    >>> p1 = People('小明')
    >>> p2 = People('小美')
    >>> 
    >>> p1.get_name()
    '小明'
    >>> p2.get_name()
    '小美'
    

    類屬性被所有對象共有,一旦被改變,所有對象獲取到的值都會被改變。訪問類屬性時使用類名.屬性名的格式,也可以使用對象.屬性名的格式來訪問:

    >>> People.country              # 用`類名.屬性名`的格式訪問
    'CHINA'
    >>> p1.country                  # 用`對象.屬性名`的格式訪問
    'china'
    >>> p2.country
    'china'
    >>> 
    >>> People.country = 'CHINA'    # 類屬性的值被改變
    >>> p1.country                  # 每個對象獲取到的值也會被改變
    'CHINA'
    >>> p2.country
    'CHINA'
    

    注意,在使用對象.屬性名的格式訪問對象時,不要以這種格式對類屬性進行賦值,否則結果可能不會像你想象的一樣:

    >>> p1 = People('小明')
    >>> p2 = People('小美')
    >>> People.country
    'china'
    >>> p1.country
    'china'
    >>> p2.country
    'china'
    >>> p1.country = '中國'   # 使用`對象.屬性名`的格式對類對象進行賦值
    >>> p1.country           # 只有 p1.country 被改變
    '中國'
    >>> p2.country           # p2.country 沒有被改變
    'china'
    >>> People.country       # People.country 也沒有被改變
    'china'
    

    從上面代碼中可以看到,在Python 中以對象.屬性名格式對類屬性進行賦值時,只有p1.country 的值被改變了,p2.countryPeople.country 的值都沒有被改變。

    實際上,這種情況下,類屬性的值並沒有被改變,而是對象p1 中多了一個country 實例屬性,此後,p1.country 訪問的是p1 的實例屬性,p1.country對屬性country的訪問屏蔽了類中的country屬性,而p2.countryPeople.country 訪問的依然是原來的類屬性

    所以,類名.屬性名對象.屬性名的格式都可以訪問類屬性的值,但盡量避免使用對象.屬性名的格式對類屬性的值進行賦值,否則可能會發生混亂。

    建議:

    不管是訪問還是改變類屬性的值,都只用類名.屬性名的格式

    2,實例方法,類方法,靜態方法

    Python 類中有三種方法:

    • 實例方法
    • 類方法
    • 靜態方法

    實例方法屬於對象,方法中都有一個self 參數(代表對象本身)。實例方法只能由對象調用,不能通過類名訪問。實例方法中可以訪問實例屬性和類屬性。

    類方法屬於類,方法中都有一個cls 參數(代表類本身)。類方法即可以通過類名訪問,也可以通過對象訪問,類方法中只能訪問類屬性,不能訪問實例屬性。

    注意:

    Python 解釋器在構造類與對象時,是先於對象產生的。

    因此,類屬性與類方法是先於實例屬性與實例方法 產生的。

    所以當類方法產生時,還沒有實例屬性,因此,類方法中不能訪問實例屬性。

    靜態方法中,沒有self 參數,也沒有cls 參數。因此,在靜態方法中,即不能訪問類屬性,也不能訪問實例屬性。靜態方法可以使用類名訪問,也可以使用對象訪問。

    在Python 中,定義類方法需要用到裝飾器@classmethod,定義靜態方法需要用到裝飾器@staticmethod

    實例方法演示

    #! /usr/bin/env python3
    
    class People:
    
        country = 'china'
    
        def __init__(self, name):
            self.__name = name
    
        # 實例方法中有self 參數
        def instance_method_test(self):
            # 在實例方法中訪問了實例屬性和類屬性
            print('name:%s country:%s' % (self.__name, People.country))
    

    使用:

    >>> p = People('小明')
    >>> p.instance_method_test()
    name:小明 country:china
    

    在實例方法中訪問了實例屬性__name和類屬性country,均可以被訪問。

    類方法演示

    #! /usr/bin/env python3
    
    class People:
    
        country = 'china'
    
        def __init__(self, name):
            self.__name = name
    
        # 類方法中都有cls 參數
        @classmethod
        def class_method_test1(cls):
            print('在類方法中訪問類屬性country:%s' % cls.country)
    
        @classmethod
        def class_method_test2(cls):
            print('在類方法中訪問實例屬性__name:%s' % self.__name)
    

    使用:

    >>> p = People('小明')
    >>> p.class_method_test1()         # 在類方法中訪問類屬性,可以
    在類方法中訪問類屬性country:china
    >>>
    >>> p.class_method_test2()         # 在類方法中訪問實例屬性,出現異常
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/home/wp/to_beijing/People.py", line 18, in class_method_test2
        print('在類方法中訪問實例屬性__name:%s' % self.__name)
    NameError: name 'self' is not defined
    

    從上面代碼中可以看到,在類方法中可以訪問類屬性,但在類方法中訪問實例屬性,會出現異常。

    靜態方法演示

    #! /usr/bin/env python3
    
    class People:
    
        country = 'china'
    
        def __init__(self, name):
            self.__name = name
    
        # 靜態方法中即沒有self 參數也不沒有cls 參數
        @staticmethod
        def static_method_test1():
            print('在靜態方法中訪問類屬性country:%s' % cls.country)
    
        @staticmethod
        def static_method_test2():
            print('在靜態方法中訪問實例屬性__name:%s' % self.__name)
    

    使用:

    >>> p = People('小明')
    >>> p.static_method_test1()      # 在靜態方法中訪問類屬性,出現異常
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/home/wp/to_beijing/People.py", line 14, in static_method_test1
        print('在靜態方法中訪問類屬性country:%s' % cls.country)
    NameError: name 'cls' is not defined
    >>>
    >>> p.static_method_test2()     # 在靜態方法中訪問實例屬性,出現異常
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/home/wp/to_beijing/People.py", line 18, in static_method_test2
        print('在靜態方法中訪問實例屬性__name:%s' % self.__name)
    NameError: name 'self' is not defined
    

    從上面代碼中可以看到,在靜態方法中無論訪問實例方法還是類方法,都會出現異常。

    3,專有方法

    我們之前講到過的魔法方法,即以雙下劃線__開頭且結尾的方法__xxx__,就是專有方法。這些方法都被Python 賦予了特殊的含義,用戶可以根據需要,來實現這些方法。

    下面我們介紹一些 Python 中常見的專有方法。

    __len__ 方法

    實現該方法的類的對象,可以用len() 函數計算其長度。

    __str__ 方法

    實現該方法的類的對象,可以轉化為字符串。

    __call__ 方法

    實現該方法的類的對象,可以像函數一樣調用。

    __iter__ 方法

    實現該方法的類的對象,是可迭代的。

    __setitem__ 方法

    實現該方法的類的對象,可以用索引的方式進行賦值。

    __getitem__ 方法

    實現該方法的類的對象,可以用索引的方式進行訪問。

    __contains__ 方法

    實現該方法的類的對象,可以進行in 運算。

    __add__ 方法

    實現該方法的類的對象,可以進行加+運算。

    __sub__ 方法

    實現該方法的類的對象,可以進行減-運算。

    __mul__ 方法

    實現該方法的類的對象,可以進行乘*運算。

    __div__ 方法

    實現該方法的類的對象,可以進行除/運算。

    __pow__ 方法

    實現該方法的類的對象,可以進行乘方運算。

    __mod__ 方法

    實現該方法的類的對象,可以進行取模運算。

    __eq__ 方法

    實現該方法的類的對象,可以進行相等==比較。

    __ne__ 方法

    實現該方法的類的對象,可以進行不等於!=比較。

    __gt__ 方法

    實現該方法的類的對象,可以進行大於>比較。

    __ge__ 方法

    實現該方法的類的對象,可以進行大於等於>=比較。

    __lt__ 方法

    實現該方法的類的對象,可以進行小於<比較。

    __le__ 方法

    實現該方法的類的對象,可以進行小於等於<=比較。

    (完。)

    推薦閱讀:

    Python 簡明教程 — 15,Python 函數

    Python 簡明教程 — 16,Python 高階函數

    Python 簡明教程 — 17,Python 模塊與包

    Python 簡明教程 — 18,Python 面向對象

    Python 簡明教程 — 19,Python 類與對象

    歡迎關注作者公眾號,獲取更多技術乾貨。

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

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

  • 基於flink和drools的實時日誌處理

    基於flink和drools的實時日誌處理

    1、背景

    日誌系統接入的日誌種類多、格式複雜多樣,主流的有以下幾種日誌:

    • filebeat採集到的文本日誌,格式多樣
    • winbeat採集到的操作系統日誌
    • 設備上報到logstash的syslog日誌
    • 接入到kafka的業務日誌

    以上通過各種渠道接入的日誌,存在2個主要的問題:

    • 格式不統一、不規範、標準化不夠
    • 如何從各類日誌中提取出用戶關心的指標,挖掘更多的業務價值

    為了解決上面2個問題,我們基於flink和drools規則引擎做了實時的日誌處理服務。

    2、系統架構

    架構比較簡單,架構圖如下:

     

    各類日誌都是通過kafka匯總,做日誌中轉。

    flink消費kafka的數據,同時通過API調用拉取drools規則引擎,對日誌做解析處理后,將解析后的數據存儲到Elasticsearch中,用於日誌的搜索和分析等業務。

    為了監控日誌解析的實時狀態,flink會將日誌處理的統計數據,如每分鐘處理的日誌量,每種日誌從各個機器IP來的日誌量寫到Redis中,用於監控統計。

    3、模塊介紹

    系統項目命名為eagle。

    eagle-api:基於springboot,作為drools規則引擎的寫入和讀取API服務。

    eagle-common:通用類模塊。

    eagle-log:基於flink的日誌處理服務。

    重點講一下eagle-log:

    對接kafka、ES和Redis

    對接kafka和ES都比較簡單,用的官方的connector(flink-connector-kafka-0.10和flink-connector-elasticsearch6),詳見代碼。

    對接Redis,最開始用的是org.apache.bahir提供的redis connector,後來發現靈活度不夠,就使用了Jedis。

    在將統計數據寫入redis的時候,最開始用的keyby分組后緩存了分組數據,在sink中做統計處理后寫入,參考代碼如下:

            String name = "redis-agg-log";
            DataStream<Tuple2<String, List<LogEntry>>> keyedStream = dataSource.keyBy((KeySelector<LogEntry, String>) log -> log.getIndex())
                    .timeWindow(Time.seconds(windowTime)).trigger(new CountTriggerWithTimeout<>(windowCount, TimeCharacteristic.ProcessingTime))
                    .process(new ProcessWindowFunction<LogEntry, Tuple2<String, List<LogEntry>>, String, TimeWindow>() {
                        @Override
                        public void process(String s, Context context, Iterable<LogEntry> iterable, Collector<Tuple2<String, List<LogEntry>>> collector) {
                            ArrayList<LogEntry> logs = Lists.newArrayList(iterable);
                            if (logs.size() > 0) {
                                collector.collect(new Tuple2(s, logs));
                            }
                        }
                    }).setParallelism(redisSinkParallelism).name(name).uid(name);

    後來發現這樣做對內存消耗比較大,其實不需要緩存整個分組的原始數據,只需要一個統計數據就OK了,優化后:

            String name = "redis-agg-log";
            DataStream<LogStatWindowResult> keyedStream = dataSource.keyBy((KeySelector<LogEntry, String>) log -> log.getIndex())
                    .timeWindow(Time.seconds(windowTime))
                    .trigger(new CountTriggerWithTimeout<>(windowCount, TimeCharacteristic.ProcessingTime))
                    .aggregate(new LogStatAggregateFunction(), new LogStatWindowFunction())
                    .setParallelism(redisSinkParallelism).name(name).uid(name);

    這裏使用了flink的聚合函數和Accumulator,通過flink的agg操作做統計,減輕了內存消耗的壓力。

    使用broadcast廣播drools規則引擎

    1、drools規則流通過broadcast map state廣播出去。

    2、kafka的數據流connect規則流處理日誌。

    //廣播規則流
    env.addSource(new RuleSourceFunction(ruleUrl)).name(ruleName).uid(ruleName).setParallelism(1)
                    .broadcast(ruleStateDescriptor);
    
    //kafka數據流
    FlinkKafkaConsumer010<LogEntry> source = new FlinkKafkaConsumer010<>(kafkaTopic, new LogSchema(), properties);
    env.addSource(source).name(kafkaTopic).uid(kafkaTopic).setParallelism(kafkaParallelism);
    //數據流connect規則流處理日誌 BroadcastConnectedStream<LogEntry, RuleBase> connectedStreams = dataSource.connect(ruleSource); connectedStreams.process(new LogProcessFunction(ruleStateDescriptor, ruleBase)).setParallelism(processParallelism).name(name).uid(name);

    具體細節參考開源代碼。

    4、小結

    本系統提供了一個基於flink的實時數據處理參考,對接了kafka、redis和elasticsearch,通過可配置的drools規則引擎,將數據處理邏輯配置化和動態化。

    對於處理后的數據,也可以對接到其他sink,為其他各類業務平台提供數據的解析、清洗和標準化服務。

     

    項目地址:

    https://github.com/luxiaoxun/eagle

     

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

    【其他文章推薦】

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

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

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

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

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