宇宙第一IDE是誰?

更多精彩文章,盡在碼農翻身

微服務把我坑了

如何降低程序員的工資?

程序員,你得選准跑路的時間!

兩年,我學會了所有的編程語言!

一直CRUD,一直996,我煩透了,我要轉型

字節碼萬歲!

上帝託夢給我說:一切皆文件

Javascript: 一個屌絲的逆襲

Node.js :我只需要一個店小二

我是一個線程

TCP/IP之大明郵差

一個故事講完Https

CPU 阿甘

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

C#9.0 終於來了,您還學的動嗎? 帶上VS一起解讀吧!(應該是全網第一篇)

一:背景

1. 講故事

好消息,.NET 5.0 終於在2020年6月10日發布了第五個預覽版,眼尖的同學一定看到了在這個版本中終於支持了 C# 9.0,此處有掌聲,太好了!!!

.Net5官方鏈接

可以看到目前的C#9還是預覽版,實現了一部分新語法供開發者提前嘗鮮,從github的roslyn倉庫上可以看到目前準備實現 17個新特性,現階段已經實現了8個,其中的 In Progress 表示正在開發中。

新特性預覽

2. 安裝必備

  • 下載最新的net5 sdk吧: dotnet-sdk-5.0.100-preview.5.20279.10-win-x64.exe

  • 下載最新的 visual studio 2019 preview 2

找好你自己的vs版本類型哦。。。

二:新特性研究

1. Target-typed new

這個取名一定要留給學易經的大師傅,沒見過世面的我不敢造次,取得不佳影響時運,所謂 運去金成鐵, 時來鐵似金 ,不過大概意思就是說直接new你定義的局部變量的類型,用issues中總結的話就是:


Summary: Allow Point p = new (x, y);
Shipped in preview in 16.7p1.

接下來就是全部代碼,看看使用前使用后 的具體差別。


    class Program
    {
        static void Main(string[] args)
        {
            //老語法
            var person = new Person("mary", "123456");

            //新語法
            Person person2 = new("mary", "123456");

            Console.WriteLine($"person={person}person2={person2}");
        }
    }

    public class Person
    {
        private string username;
        private string password;

        public Person(string username, string password)
        {
            this.username = username;
            this.password = password;
        }

        public override string ToString()
        {
            return $"username={username},password={password} \n";
        }
    }

然後用ilspy去看看下面的il代碼,是不是省略了Person,讓自己心裏踏實一點。

總的來說這語法還行吧,能起到延長鍵盤使用壽命的功效。

2. Lambda discard parameters

從字面上看大概就是說可以在lambda上使用取消參數,聽起來怪怪的,那本意是什麼呢?有時候lambda上的匿名方法簽名的參數是不需要的,但在以前必須實打實的定義,這樣就會污染方法體,也就是可以在body中被訪問,如下圖:

但有時候因為客觀原因必須使用Func<int,int,int>這樣的委託,而且還不想讓方法簽名的參數污染方法體,我猜測在函數式編程中有這樣的場景吧,可能有點類似MVC中的EmptyResult效果。

好了,我想你大概知道啥意思了,接下來實操一把。。。


    Func<int, int, int> func = (_, _) =>
    {
        return 0;
    };

    var result = func(10, 20);

從圖中可以看到,我在方法體中是找不到所謂的 _ 變量的,這就神奇了,怎麼做到的呢? 帶着這個好奇心看看它的IL代碼是個什麼樣子。


.method private hidebysig static 
	void Main (
		string[] args
	) cil managed 
{
	// Method begins at RVA 0x2048
	// Code size 45 (0x2d)
	.maxstack 3
	.entrypoint
	.locals init (
		[0] class [System.Runtime]System.Func`3<int32, int32, int32> func,
		[1] int32 result
	)

	IL_0000: nop
	IL_0001: ldsfld class [System.Runtime]System.Func`3<int32, int32, int32> ConsoleApp1.Program/'<>c'::'<>9__0_0'
	IL_0006: dup
	IL_0007: brtrue.s IL_0020

	IL_0009: pop
	IL_000a: ldsfld class ConsoleApp1.Program/'<>c' ConsoleApp1.Program/'<>c'::'<>9'
	IL_000f: ldftn instance int32 ConsoleApp1.Program/'<>c'::'<Main>b__0_0'(int32, int32)
	IL_0015: newobj instance void class [System.Runtime]System.Func`3<int32, int32, int32>::.ctor(object, native int)
	IL_001a: dup
	IL_001b: stsfld class [System.Runtime]System.Func`3<int32, int32, int32> ConsoleApp1.Program/'<>c'::'<>9__0_0'

	IL_0020: stloc.0
	IL_0021: ldloc.0
	IL_0022: ldc.i4.s 10
	IL_0024: ldc.i4.s 20
	IL_0026: callvirt instance !2 class [System.Runtime]System.Func`3<int32, int32, int32>::Invoke(!0, !1)
	IL_002b: stloc.1
	IL_002c: ret
} // end of method Program::Main

從上面的IL代碼來看 匿名方法 變成了<>c類的<Main>b__0_0方法,完整簽名: ConsoleApp1.Program/'<>c'::'<Main>b__0_0'(int32, int32),然後再找一下 <Main>b__0_0 方法的定義。


.class nested private auto ansi sealed serializable beforefieldinit '<>c'
	extends [System.Runtime]System.Object
	.method assembly hidebysig 
		instance int32 '<Main>b__0_0' (
			int32 _,
			int32 _
		) cil managed 
	{
		// Method begins at RVA 0x2100
		// Code size 7 (0x7)
		.maxstack 1
		.locals init (
			[0] int32
		)

		IL_0000: nop
		IL_0001: ldc.i4.0
		IL_0002: stloc.0
		IL_0003: br.s IL_0005

		IL_0005: ldloc.0
		IL_0006: ret
	} // end of method '<>c'::'<Main>b__0_0'

這說明什麼呢? 說明兩個參數是真實存在的,但編譯器搗了鬼,做了語法上的限制,不讓你訪問所謂的 _

等等。。。有一個問題,IL中的方法簽名怎麼是這樣的: <Main>b__0_0 (int32 _,int32 _) , 大家應該知道方法簽名中不可以出現重複的參數名,比如下面這樣定義肯定是報錯的。

這說明什麼? 說明這個語法糖不僅需要編譯器支持,更需要底層的JIT支持,那怎麼證明呢?我們用windbg去底層挖一挖。。。為了方便調試,修改如下:


        static void Main(string[] args)
        {
            Func<int, int, int> func = (_, _) =>
            {
                Console.WriteLine("進入方法體了!!!");
                Console.ReadLine();
                return 0;
            };

            var result = func(10, 20);
        }

0:000> !clrstack -p
OS Thread Id: 0x52e8 (0)
0000007035F7E5C0 00007ffaff362655 ConsoleApp1.Program+c.b__0_0(Int32, Int32) [C:\5\ConsoleApp1\ConsoleApp1\Program.cs @ 13]
    PARAMETERS:
        this (0x0000007035F7E600) = 0x000001968000cb48
        _ (0x0000007035F7E608) = 0x000000000000000a
        _ (0x0000007035F7E610) = 0x0000000000000014

從圖中可以看到,雖然都是 _ ,但在線程棧上是完完全全的兩個棧地址。 0x0000007035F7E6080x0000007035F7E610

三:總結

總的來說,C#是越來越向函數式編程靠攏,越來越像Scala,就像Jquery的口號一樣: Write less,do more。

好了,先就說這兩個吧,大家先安裝好工具,明天繼續解剖~~~

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

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

20萬就能買到全新寶馬轎車?!因為它真的來了

新車基於UKL前驅平台打造,1系三廂將會是前驅車型,新車的動力系統或為1。5T 136馬力+6速自動變速箱,2。0T 192馬力/231馬力+8擋手自一體變速箱,其中官方聲稱1。5T車型的百公里油耗最低可以達到5。5L。新車將會有無鑰匙啟動、抬頭显示、倒車影像、全景天窗、LED大燈、pM2。

寶馬1系三廂自從誕生的那一刻就備受關注,吸睛無數,小編也和大家一樣,時刻關注着寶馬1系三廂的所有信息。畢竟,哪個男人心裏沒有這一個藍天白雲夢,開寶馬也是很多人的心愿。

但是寶馬作為豪華品牌,價格不是每個消費者都能承受的起的。寶馬進口1系的價格不是很貴,但是國人就是對兩廂車有一定的排斥心理,比較鍾愛三廂車,所以即使進口1系兩廂的價格足夠便宜,但是買單的人照樣不多。

當然,寶馬3系是三廂車,但是3系的價格在30萬左右,還是有點小貴。所以在20萬級別這個領域,出現了一個市場空缺。如果能有一台20萬的三廂寶馬,這應該是極好的選擇。

看看奧迪A3就知道了,作為豪華品牌的A3將價格做到了20萬元左右,在這個沒有直接競爭對手的領域,A3的銷量好的一塌糊塗,A3在11月份交出了9883輛的銷量,將近萬輛的銷量足以看出來這個細分市場有很大的潛力。

所以寶馬義不容辭的推出了國產版的1系三廂。

寶馬1系三廂版基於Compact Sedan概念車打造出來的,新車的設計借鑒了概念車的設計元素,同時也具有着寶馬家族化的設計風格,前大燈的造型與3系比較相似,側麵線條比較平直,從外觀看像是縮小的3系,看起來短小精悍,富有運動感。

內飾看起來還是那麼熟悉的感覺,畢竟也是採用了寶馬家族化的設計特徵,中控台造型很有層次感,並配備了8.8英寸液晶屏,同時還有大面積的鍍鉻裝飾,可以增強內飾的精緻感。

新車基於UKL前驅平台打造,1系三廂將會是前驅車型,新車的動力系統或為1.5T 136馬力+6速自動變速箱,2.0T 192馬力/231馬力+8擋手自一體變速箱,其中官方聲稱1.5T車型的百公里油耗最低可以達到5.5L。

新車將會有無鑰匙啟動、抬頭显示、倒車影像、全景天窗、LED大燈、pM2.5濾清器等,這些都是國人比較看重的配置。新車的預售價為20.5萬起,這就意味着也許不到20萬的價格就可以買到帥氣的三廂寶馬,估計很多消費者都會心動吧!如果實際售價能比預售價還低一點的話,那麼A3就會瞬間感到壓力了。

競爭對手

奧迪A3

指導價:18.49-28.10萬

A3在國內的成就有目共睹,但是它真正的競爭對手預計會在2月份正式上市銷售,憑藉著“藍天白雲”在國內的號召力,A3將會面臨很大壓力,那麼它能否守住自己的陣地,就讓我們拭目以待吧!本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

【C#】AutoMapper 使用手冊

目錄

  • 1 入門例子
  • 2 註冊
    • 2.1 Profile
  • 3 配置
    • 3.1 命名約定
    • 3.2 配置可見性
    • 3.3 全局屬性/字段過濾
    • 3.4 識別前綴和後綴
    • 3.5 替換字符
  • 4 調用構造函數
  • 5 數組和列表映射
    • 5.1 處理空集合
    • 5.2 集合中的多態
  • 6 方法到屬性映射
  • 7 自定義映射
  • 8 扁平化映射
    • 8.1 IncludeMembers
  • 9 嵌套映射

本文基於 AutoMapper 9.0.0

AutoMapper 是一個對象-對象映射器,可以將一個對象映射到另一個對象。

官網地址:http://automapper.org/

官方文檔:https://docs.automapper.org/en/latest/

1 入門例子

public class Foo
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class FooDto
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public void Map()
{
    var config = new MapperConfiguration(cfg => cfg.CreateMap<Foo, FooDto>());

    var mapper = config.CreateMapper();

    Foo foo = new Foo { ID = 1, Name = "Tom" };

    FooDto dto = mapper.Map<FooDto>(foo);
}

2 註冊

在使用 Map 方法之前,首先要告訴 AutoMapper 什麼類可以映射到什麼類。

var config = new MapperConfiguration(cfg => cfg.CreateMap<Foo, FooDto>());

每個 AppDomain 只能進行一次配置。這意味着放置配置代碼的最佳位置是在應用程序啟動中,例如 ASP.NET 應用程序的 Global.asax 文件。

從 9.0 開始 Mapper.Initialize 方法就不可用了。

2.1 Profile

Profile 是組織映射的另一種方式。新建一個類,繼承 Profile,並在構造函數中配置映射。

public class EmployeeProfile : Profile
{
    public EmployeeProfile()
    {
        CreateMap<Employee, EmployeeDto>();
    }
}

var config = new MapperConfiguration(cfg =>
{
    cfg.AddProfile<EmployeeProfile>();
});

Profile 內部的配置僅適用於 Profile 內部的映射。應用於根配置的配置適用於所有創建的映射。

AutoMapper 也可以在指定的程序集中掃描從 Profile 繼承的類,並將其添加到配置中。

var config = new MapperConfiguration(cfg =>
{
    // 掃描當前程序集
    cfg.AddMaps(System.AppDomain.CurrentDomain.GetAssemblies());
    
    // 也可以傳程序集名稱(dll 名稱)
    cfg.AddMaps("LibCoreTest");
});

3 配置

3.1 命名約定

默認情況下,AutoMapper 基於相同的字段名映射,並且是 不區分大小寫 的。

但有時,我們需要處理一些特殊的情況。

  • SourceMemberNamingConvention 表示源類型命名規則
  • DestinationMemberNamingConvention 表示目標類型命名規則

LowerUnderscoreNamingConventionPascalCaseNamingConvention 是 AutoMapper 提供的兩個命名規則。前者命名是小寫並包含下劃線,後者就是帕斯卡命名規則(每個單詞的首字母大寫)。

我的理解,如果源類型和目標類型分別採用了 蛇形命名法駝峰命名法,那麼就需要指定命名規則,使其能正確映射。

public class Foo
{
    public int Id { get; set; }

    public string MyName { get; set; }
}

public class FooDto
{
    public int ID { get; set; }

    public string My_Name { get; set; }
}

public void Map()
{
    var config = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<Foo, FooDto>();

        cfg.SourceMemberNamingConvention = new PascalCaseNamingConvention();
        cfg.DestinationMemberNamingConvention = new LowerUnderscoreNamingConvention();
    });

    var mapper = config.CreateMapper();

    Foo foo = new Foo { Id = 2, MyName = "Tom" };

    FooDto dto = mapper.Map<FooDto>(foo);
}

3.2 配置可見性

默認情況下,AutoMapper 僅映射 public 成員,但其實它是可以映射到 private 屬性的。

var config = new MapperConfiguration(cfg =>
{
    cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.SetMethod.IsPrivate;
    cfg.CreateMap<Source, Destination>();
});

需要注意的是,這裏屬性必須添加 private set,省略 set 是不行的。

3.3 全局屬性/字段過濾

默認情況下,AutoMapper 嘗試映射每個公共屬性/字段。以下配置將忽略字段映射。

var config = new MapperConfiguration(cfg =>
{
	cfg.ShouldMapField = fi => false;
});

3.4 識別前綴和後綴

var config = new MapperConfiguration(cfg =>
{
    cfg.RecognizePrefixes("My");
    cfg.RecognizePostfixes("My");
}

3.5 替換字符

var config = new MapperConfiguration(cfg =>
{
    cfg.ReplaceMemberName("Ä", "A");
});

這功能我們基本上用不上。

4 調用構造函數

有些類,屬性的 set 方法是私有的。

public class Commodity
{
    public string Name { get; set; }

    public int Price { get; set; }
}

public class CommodityDto
{
    public string Name { get; }

    public int Price { get; }

    public CommodityDto(string name, int price)
    {
        Name = name;
        Price = price * 2;
    }
}

AutoMapper 會自動找到相應的構造函數調用。如果在構造函數中對參數做一些改變的話,其改變會反應在映射結果中。如上例,映射后 Price 會乘 2。

禁用構造函數映射:

var config = new MapperConfiguration(cfg => cfg.DisableConstructorMapping());

禁用構造函數映射的話,目標類要有一個無參構造函數。

5 數組和列表映射

數組和列表的映射比較簡單,僅需配置元素類型,定義簡單類型如下:

public class Source
{
    public int Value { get; set; }
}

public class Destination
{
    public int Value { get; set; }
}

映射:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Source, Destination>();
});
IMapper mapper = config.CreateMapper();

var sources = new[]
{
    new Source { Value = 5 },
    new Source { Value = 6 },
    new Source { Value = 7 }
};

IEnumerable<Destination> ienumerableDest = mapper.Map<Source[], IEnumerable<Destination>>(sources);
ICollection<Destination> icollectionDest = mapper.Map<Source[], ICollection<Destination>>(sources);
IList<Destination> ilistDest = mapper.Map<Source[], IList<Destination>>(sources);
List<Destination> listDest = mapper.Map<Source[], List<Destination>>(sources);
Destination[] arrayDest = mapper.Map<Source[], Destination[]>(sources);

具體來說,支持的源集合類型包括:

  • IEnumerable
  • IEnumerable
  • ICollection
  • ICollection
  • IList
  • IList
  • List
  • Arrays

映射到現有集合時,將首先清除目標集合。如果這不是你想要的,請查看AutoMapper.Collection。

5.1 處理空集合

映射集合屬性時,如果源值為 null,則 AutoMapper 會將目標字段映射為空集合,而不是 null。這與 Entity Framework 和 Framework Design Guidelines 的行為一致,認為 C# 引用,數組,List,Collection,Dictionary 和 IEnumerables 永遠不應該為 null

5.2 集合中的多態

這個官方的文檔不是很好理解。我重新舉個例子。實體類如下:

public class Employee
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class Employee2 : Employee
{
    public string DeptName { get; set; }
}

public class EmployeeDto
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class EmployeeDto2 : EmployeeDto
{
    public string DeptName { get; set; }
}

數組映射代碼如下:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Employee, EmployeeDto>().Include<Employee2, EmployeeDto2>();
    cfg.CreateMap<Employee2, EmployeeDto2>();
});
IMapper mapper = config.CreateMapper();

var employees = new[]
{
    new Employee { ID = 1, Name = "Tom" },
    new Employee2 { ID = 2, Name = "Jerry", DeptName = "R & D" }
};

var dto = mapper.Map<Employee[], EmployeeDto[]>(employees);

可以看到,映射后,dto 中兩個元素的類型,一個是 EmployeeDto,一個是 EmployeeDto2,即實現了父類映射到父類,子類映射到子類。

如果去掉 Include 方法,則映射后 dto 中兩個元素的類型均為 EmployeeDto

6 方法到屬性映射

AutoMapper 不僅能實現屬性到屬性映射,還可以實現方法到屬性的映射,並且不需要任何配置,方法名可以和屬性名一致,也可以帶有 Get 前綴。

例如下例的 Employee.GetFullName() 方法,可以映射到 EmployeeDto.FullName 屬性。

public class Employee
{
    public int ID { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string GetFullName()
    {
        return $"{FirstName} {LastName}";
    }
}

public class EmployeeDto
{
    public int ID { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string FullName { get; set; }
}

7 自定義映射

當源類型與目標類型名稱不一致時,或者需要對源數據做一些轉換時,可以用自定義映射。

public class Employee
{
    public int ID { get; set; }

    public string Name { get; set; }

    public DateTime JoinTime { get; set; }
}

public class EmployeeDto
{
    public int EmployeeID { get; set; }

    public string EmployeeName { get; set; }

    public int JoinYear { get; set; }
}

如上例,IDEmployeeID 屬性名不同,JoinTimeJoinYear 不僅屬性名不同,屬性類型也不同。

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Employee, EmployeeDto>()
        .ForMember("EmployeeID", opt => opt.MapFrom(src => src.ID))
        .ForMember(dest => dest.EmployeeName, opt => opt.MapFrom(src => src.Name))
        .ForMember(dest => dest.JoinYear, opt => opt.MapFrom(src => src.JoinTime.Year));
});

8 扁平化映射

對象-對象映射的常見用法之一是將複雜的對象模型並將其展平為更簡單的模型。

public class Employee
{
    public int ID { get; set; }

    public string Name { get; set; }

    public Department Department { get; set; }
}

public class Department
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class EmployeeDto
{
    public int ID { get; set; }

    public string Name { get; set; }

    public int DepartmentID { get; set; }

    public string DepartmentName { get; set; }
}

如果目標類型上的屬性,與源類型的屬性、方法都對應不上,則 AutoMapper 會將目標成員名按駝峰法拆解成單個單詞,再進行匹配。例如上例中,EmployeeDto.DepartmentID 就對應到了 Employee.Department.ID

8.1 IncludeMembers

如果屬性命名不符合上述的規則,而是像下面這樣:

public class Employee
{
    public int ID { get; set; }

    public string Name { get; set; }

    public Department Department { get; set; }
}

public class Department
{
    public int DepartmentID { get; set; }

    public string DepartmentName { get; set; }
}

public class EmployeeDto
{
    public int ID { get; set; }

    public string Name { get; set; }

    public int DepartmentID { get; set; }

    public string DepartmentName { get; set; }
}

Department 類中的屬性名,直接跟 EmployeeDto 類中的屬性名一致,則可以使用 IncludeMembers 方法指定。

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Employee, EmployeeDto>().IncludeMembers(e => e.Department);
    cfg.CreateMap<Department, EmployeeDto>();
});

9 嵌套映射

有時,我們可能不需要展平。看如下例子:

public class Employee
{
    public int ID { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    public Department Department { get; set; }
}

public class Department
{
    public int ID { get; set; }

    public string Name { get; set; }

    public string Heads { get; set; }
}

public class EmployeeDto
{
    public int ID { get; set; }

    public string Name { get; set; }

    public DepartmentDto Department { get; set; }
}

public class DepartmentDto
{
    public int ID { get; set; }

    public string Name { get; set; }
}

我們要將 Employee 映射到 EmployeeDto,並且將 Department 映射到 DepartmentDto

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Employee, EmployeeDto>();
    cfg.CreateMap<Department, DepartmentDto>();
});

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

南非克魯格公園防疫封鎖 動物佔領度假屋

摘錄自2020年8月31日中央社報導

南非為防止武漢肺炎(COVID-19)擴大進行各階段封鎖,知名的克魯格國家公園住宿小屋因長時間無人入住,部分屋舍遭動物佔領與破壞,園方已展開維修,準備重新逐步開放。

武漢肺炎爆發後,南非自3月26日進入最嚴格的第5級全國封鎖,幾個月來因疫情變化逐漸開放,8月18日起改善第2級,國家公園開放旅遊觀光。

新聞網站「時報即時消息」(TimesLIVE)今(31日)引述南非國家公園管理處執行長姆克特尼(Fundisile Mketeni)表示,克魯格國家公園(Kruger National Park)準備重新開放面臨許多挑戰,特別是清潔與維修工作。疫情封鎖期間,部分住宿小屋被靈長類動物、松鼠與蝙蝠佔領和破壞。

姆克特尼指出,已迅速維修,預計9月份會有旅遊高峰。

國際新聞
南非
防疫
國家公園

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

南加州也傳野火 竟是寶寶性別揭曉派對煙火惹禍

摘錄自2020年9月7日中央社報導

美國加州消防當局今(7日)表示,南加州昨(6日)上午爆發一場野火延燒至今,已摧毀2800公頃土地,迫使許多居民逃離家園,起火原因竟是一場寶寶性別揭曉派對施放的煙火炮。

法新社報導,這場火災發生在聖伯納地諾(San Bernardino)東邊的艾多雷多(El Dorado)。加州森林防火廳(California Department of Forestry and Fire Protection)表示,已出動500多名消防員和4架直升機在現場滅火。有數個社區的居民被要求撤離。

污染治理
國際新聞
美國
野火

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

這三款國產家轎都帶全景攝像頭,最低只要6萬多

在市區遊走並不費力,雙離合變速箱在低速行車時會有拖拽感,偶爾也會卡在2擋不願升擋。內飾設計上,以酒紅色和黑色搭配,看上去較為時尚。中控的按鈕雖然多,但是都有中文標示,上手難度不大。6。99萬就有全景攝像頭,這在同級中也是絕無僅有。

當你開着車去到一些只有狹窄停車位的地方時,即便有倒車雷達也要挪得小心翼翼,生怕兩側或者車頭會發生一些刮蹭。不過,如果你的車有全景攝像頭的話,在這種情況下就可以從容淡定不少了。而有些車的全景攝像頭,甚至可以在低速前進時開啟,這無疑更好地解決了城村匯車時的煩惱。

雖說國產車的配置相當豐富,但是在13萬內能有全景攝像頭的汽車依舊是鳳毛麟角。下面編者我就給大家推薦三款帶全景攝像頭的國產車。

東風裕隆-納5

指導價:8.58-11.98萬

帶全景攝像頭的車型:11.58萬的自動智尊型和11.98萬的自動旗艦型

編者點評:納5的全景影像雖然精度不高且有一定程度的變形,但是已經能清楚看到周圍的情況,新手倒車也不再有難度。除了全景攝像頭以外,以上所說的那兩個車型還配備了前後駐車雷達,簡直是武裝到了牙齒。遇到一些較窄的拐角位,也不用像一般司機那樣拚命把頭往前探來看位置。

納5隻有一款1.8T發動機可選,與之匹配的是5擋手動和6擋手自一體變速箱,最大輸出180馬力和256牛米,整個動力相當充足。內飾設計以黑色為主,兼具運動感與高級感,烤黑鋼琴漆的面板,不失優雅。

比亞迪-速銳

指導價:6.99-9.59萬

帶全景攝像頭的車型:6.99萬的手動精英型、8.59萬的手動旗艦型和9.59萬的自動旗艦型

編者點評:速銳也只有一款1.5L發動機可選,與之匹配的是5擋手動和6擋雙離合變速箱,最大輸出109馬力和145牛米。在市區遊走並不費力,雙離合變速箱在低速行車時會有拖拽感,偶爾也會卡在2擋不願升擋。

內飾設計上,以酒紅色和黑色搭配,看上去較為時尚。中控的按鈕雖然多,但是都有中文標示,上手難度不大。6.99萬就有全景攝像頭,這在同級中也是絕無僅有。除了全景攝像頭,前後駐車雷達同樣沒有缺席,配置相當豐富。

東風乘用車-東風風神L60

指導價:8.97-12.97萬

帶全景攝像頭的車型:12.97萬的自動新睿型

編者點評:從显示的效果來說,確實是這三台車中最好的,四個角度的銜接自然。除了全景攝像以外,頂配車型還有無鑰匙進入與啟動這個亮點配置。整個內飾讓人覺得很有小清新的感覺,各處做工亦頗為精良,中央显示屏四周的烤黑鋼琴漆點綴得恰到好處。

動力總成上,L60提供1.6L與1.8L發動機,與前者匹配的是5擋手動變速箱,而後者則多了一副6擋手自一體變速箱。1.6L發動機最大輸出117馬力和150牛米,而1.8L發動機最大輸出139馬力和172牛米。總的來說,1.6L發動機動力偏弱,1.8L會顯得更為游刃有餘。

編者總結

隨着時代的發展,車越來越多,越做越大。有些狹窄路段,老司機應付起來都要小心翼翼,就更不用說新手了,所以帶有全景攝像頭的這三款車可以說是新手的福音。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

Nginx 的變量究竟是怎麼一回事?

之前說了很多關於 Nginx 模塊的內容,還有一部分非常重要的內容,那就是 Nginx 的變量。變量在 Nginx 中可以說無處不在,認識了解這些變量的作用和原理同樣是必要的,下面幾乎囊括了關於 Nginx 的所有變量,單獨看起來可能比較枯燥,放心,後面依然有實戰內容。

Nginx 變量的運行原理

圍繞 Nginx 中的變量模塊可以分為兩類,一類是提供變量的模塊,另外一類是使用變量的模塊。

  • 提供變量的模塊
    • 在 Preconfiguration 源代碼中定義變量名以及可以解析出變量的方法
  • 使用變量的模塊
    • 解析 nginx.conf 時定義變量的使用方式

也就是在 Nginx 啟動時,已經定義了變量,而只有當真正處理請求的時候,才會根據 nginx.conf 解析出來的變量使用方式調用 Preconfiguration 中定義的方法來實際獲取值。

這也是變量的兩個特性:

  • 惰性求值:只有使用的時候才會去調方法解析
  • 變量值可以時刻變化,其值為使用的那一時刻的值。例如發送響應包體字節數,實際在發送的過程中是一直在變化的。

除了 Nginx 的模塊之外,Nginx 框架也包含許多的變量,這些變量不需要通過編譯模塊來引入,而且,Nginx 框架所提供的變量往往反映了處理請求的細節,因此,了解 Nginx 框架所提供的變量是十分有必要的。

HTTP 請求相關的變量

先來看一下關於 HTTP 請求的相關變量。

  • arg_參數名:URL 中某個具體參數的值

  • query_string:與 args 變量完全相同

  • args:全部 URL 參數

  • is_args:如果請求 URL 中有參數則返回 ?,否則返回空

  • content_length:HTTP 請求中標識包體長度的 Content-Length 頭部的值。如果請求中沒有攜帶這個參數,那麼就取不到對應的值。

  • content_type:標識請求包體類型的 Content-Type 頭部的值。同樣需要用戶請求中攜帶對應的參數。

  • uri:請求的 URI(不同於 URL,不包括 ? 后的參數)

  • document_uri:與 uri 完全相同。由於歷史原因而存在的。

  • request_uri:請求的 URL(包括 URI 以及完整的參數)

  • scheme:協議名,例如 HTTP 或者 HTTPS

  • request_method:請求方法,例如 GET 或者 POST

  • request_length:所有請求內容的大小,包括請求行、頭部、包體等

  • remote_user:由 HTTP Basic Authentication 協議傳入的用戶名

  • request_body_file:很多時候會將用戶請求的包體存放到文件中,這個變量就是臨時存放請求包體的文件

    • 如果包體非常小則不會存文件
    • client_body_in_file_only 指令強制所有包體存入文件,且可決定是否刪除
  • request_body:請求中的包體,這個變量當且僅當使用反向代理,且設定用內存暫存包體時才有效

  • request:原始的 URL 請求,含有方法與協議版本,例如 GET /?a=1&b=22 HTTP/1.1

  • host

    • 先從請求行中獲取
    • 如果含有 Host 頭部,則用其值替換掉請求行中的主機名
    • 如果前兩者都取不到,則使用匹配上的 server_name
  • http_頭部名字:返回一個具體請求頭部的值

    特殊變量,這些變量會做一些處理。

    • http_host
    • http_user_agent
    • http_referer
    • http_via
    • http_x_forwarded_for
    • http_cookie

    通用變量,除了以上的變量,都可以取到對應的值。

TCP 連接相關的變量

下面是關於 TCP 連接的變量。

  • binary_remote_addr:客戶端地址的整形格式,對於 IPv4 是 4 字節,對於 IPv6 是 16 字節,所以在 limit_req 和 limit_conn 中通常可以用作 key (詳見:Nginx 處理 HTTP 請求的 11 個階段 中的 preaccess 階段)
  • connection:遞增的連接序號
  • connection_requests:當前連接上執行過的請求數,對 keepalive 連接有意義
  • remote_addr:客戶端地址
  • remote_port:客戶端端口
  • proxy_protocol_addr:若使用了 proxy_protocol 協議,則返回協議中的地址,否則返回空
  • proxy_protocol_port:若使用了 proxy_protocol 協議則返回協議中的端口,否則返回空
  • server_addr:服務端地址
  • server_port:服務器端端口
  • TCP_INFO:TCP 內核層參數,包括 $tcpinfo_rtt, ​$tcpinfo_rttvar,​$tcpinfo_snd_cwnd, $tcpinfo_rcv_space
  • server_protocol:服務器端協議,例如 HTTP/1.1

Nginx 處理請求過程中產生的變量

Nginx 處理 HTTP 請求的過程中也會產生很多變量。

  • request_time:請求處理到現在的耗時,單位為秒,精確到毫秒
  • server_name:匹配上請求的 server_name 值
  • https:如果開啟了 TLS/SSL 則返回 on,否則返回空
  • request_completion:若請求處理完則返回 OK,否則返回空
  • request_id:以 16 進制輸出的請求表示 id,該 id 共含有 16 個字節,是隨機生成的
  • request_filename:待訪問文件的完整路徑
  • document_root:由 URI 和 root、alias 規則生成的文件夾路徑
  • realpath_root:將 document_root 中的軟鏈接等換成真實路徑
  • limit_rate:返回客戶端響應時的速度上限,單位為每秒字節數。可以通過 set 指令修改對請求產生的效果

發送 HTTP 響應時相關的變量

  • body_bytes_sent:響應中 body 包體的長度

  • bytes_sent:全部 http 響應的長度

  • status:http 響應中的返回碼

  • sent_trailer_名字:把響應結尾內容里的值返回

  • sent_http_頭部名字:響應中某個具體頭部的值

    特殊處理,下面這些變量需要經過特殊處理:

    • sent_http_content_type
    • sent_http_content_length
    • sent_http_location
    • sent_http_last_modified
    • sent_http_connection
    • sent_http_keep_alive
    • sent_http_transfer_encoding
    • sent_http_cache_control
    • sent_http_link

    通用:除了上面這些頭部,其他的頭部都是通用型的,也就是可以直接拿來用。

Nginx 系統變量

  • time_local:以本地時間標準輸出的當前時間,例如 14/Nov/2018:15:55:37 +0800
  • time_iso8601:使用 ISO8601 標準輸出的當前時間,例如 2018-11-14T15:55:37+08:00
  • nginx_version:Nginx 版本號
  • pid:所屬 worker 進程的進程 id
  • pipe:使用了管道則返回 p,否則返回 .
  • hostname:所在服務器的主機名,與 hostname 命令輸出一致
  • msec:1970 年 1 月 1 日到現在的時間,單位為秒,小數點后精確到毫秒

實戰

配置文件:

log_format  vartest  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status bytes_sent=$bytes_sent body_bytes_sent=$body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$sent_http_abc"';

server {
	server_name var.ziyang.com localhost;
	#error_log logs/myerror.log debug;
	access_log logs/vartest.log vartest;
	listen 9090;
	
	location / {
		set $limit_rate 10k;
        # return 200; tcpinfo: $tcpinfo_rtt,$tcpinfo_rttvar, $tcpinfo_snd_cwnd, $tcpinfo_rcv_space 
		return 200 '
arg_a: $arg_a,arg_b: $arg_b,args: $args
connection: $connection,connection_requests: $connection_requests
cookie_a: $cookie_a
uri: $uri,document_uri: $document_uri, request_uri: $request_uri
request: $request
request_id: $request_id
server: $server_addr,$server_name,$server_port,$server_protocol
            
host: $host,server_name: $server_name,http_host: $http_host
limit_rate: $limit_rate
hostname: $hostname
content_length: $content_length
status: $status
body_bytes_sent: $body_bytes_sent,bytes_sent: $bytes_sent
time: $request_time,$msec,$time_iso8601,$time_local
';
	}	
}

從上面這個配置文件中,我們可以看出來,返回的響應裡面包含了一系列的變量,實際驗證一下:

  test_nginx curl -H 'Content-Length: 0' -H 'Cookie: a=c1' 'localhost:9090?a=1&b=22'

arg_a: 1,arg_b: 22,args: a=1&b=22
connection: 2,connection_requests: 1
cookie_a: c1
uri: /,document_uri: /, request_uri: /?a=1&b=22
request: GET /?a=1&b=22 HTTP/1.1
request_id: 5d40b1ff29d2b87d5db5c4f95ebf5e4d
server: 127.0.0.1,var.ziyang.com,9090,HTTP/1.1
host: localhost,server_name: var.ziyang.com,http_host: localhost:9090
limit_rate: 10240
hostname: yuanzizhen.local
content_length: 0
status: 200
body_bytes_sent: 0,bytes_sent: 0
time: 0.000,1590842354.866,2020-05-30T20:39:14+08:00,30/May/2020:20:39:14 +0800

大家可以對比一下響應和配置文件中的值是不是一一對應的,更加深刻的理解一下變量的含義。

好了,這一節咱們學習了。關於 Nginx 的變量就講完了,下一節講一下實際應用變量的兩個模塊,大家會有更深刻的理解。

本文首發於我的個人博客:iziyang.github.io,所有配置文件我已經放在了 Nginx 配置文件,大家可以自取。

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

一文入門Kafka,必知必會的概念通通搞定

Kakfa在大數據消息引擎領域,絕對是沒有爭議的國民老公。

這是kafka系列的第一篇文章。預計共出20篇系列文章,全部原創,從0到1,跟你一起死磕kafka。

本文盤點了 Kafka 的各種術語並且進行解讀,術語可能比較枯燥,但真的是精髓中的精髓!

了解Kafka之前我們必須先掌握它的相關概念和術語,這對於後面深入學習 Kafka 各種功能將大有裨益。所以,枯燥你也得給我看完!

大概是有這麼些東西要掌握,不多不多,預計20分鐘可以吃透:

主題層

主題層有三個兒子,分別叫做:Topic、Partition、Replica。既然我說是三個兒子,那你懂了,是不可分割的整體。

Topic(主題)

Kafka 是分佈式的消息引擎系統,它的主要功能是提供一套完備的消息(Message)發布與訂閱解決方案。

在 Kafka 中,發布訂閱的對象是主題(Topic),你可以為每個業務、每個應用甚至是每類數據都創建專屬的主題。

一個Topic是對一組消息的歸納。也可以理解成傳統數據庫里的表,或者文件系統里的一個目錄。

Partition(分區)

一個Topic通常都是由多個partition組成的,創建topic時候可以指定partition數量。

分區優勢

為什麼需要將Topic分區呢?如果你了解其他分佈式系統,你可能聽說過分片、分區域等說法,比如 MongoDB 和 Elasticsearch 中的 Sharding、HBase 中的 Region,其實它們都是相同的原理。

試想,如果一個Topic積累了太多的數據以至於單台 Broker 機器都無法容納了,此時應該怎麼辦呢?

一個很自然的想法就是,能否把數據分割成多份保存在不同的機器上?這不就是分區的作用嗎?其實就是解決伸縮性的問題,每個partition都可以放在獨立的服務器上。

當然優勢不僅於此,也可以提高吞吐量。kafka只允許單個partition的數據被一個consumer線程消費。因此,在consumer端,consumer并行度完全依賴於被消費的分區數量。綜上所述,通常情況下,在一個Kafka集群中,partition的數量越多,意味着可以到達的吞吐量越大。

partition結構

每個partition對應於一個文件夾,該文件夾下存儲該partition的數據和索引文件。

如圖所示,可以看到兩個文件夾,都對應着一個叫做asd的topic,在該台服務器上有兩個分區,0和2,那麼1呢?在其他服務器上啦!畢竟是分佈式分佈的!

我們進去asd-0目錄中看看是什麼?有後綴為.index和.log的文件,他們就是該partition的數據和索引文件:

現在先不管它們是何方神聖,因為我會在【分區機制原理】這篇文章中詳細描述。

partition順序性

現在,我需要你睜大眼睛看看關於分區非常重要的一點:

【每個partition內部保證消息的順序。但是分區之間是不保證順序的】

這一點很重要,例如kafka中的消息是某個業務庫的數據,mysql binlog是有先後順序的,10:01分我沒有付款,所以pay_date為null,而10:02分我付款了,pay_date被更新了。

但到了kafka那,由於是分佈式的,多分區的,可就不一定能保證順序了,也許10:02分那條先來,這樣可就會引發嚴重生產問題了。因此,一般我們需要按表+主鍵來分區。保證同一主鍵的數據發送到同一個分區中。

如果你想要 kafka 中的所有數據都按照時間的先後順序進行存儲,那麼可以設置分區數為 1。

Replica (副本)

每個partition可以配置若干個副本。Kafka 定義了兩類副本:領導者副本(Leader Replica)和追隨者副本(Follower Replica)。只能有 1 個領導者副本和 N-1 個追隨者副本。

為啥要用副本?也很好理解,反問下自己為什麼重要的文件需要備份多份呢?備份機制(Replication)是實現高可用的一個手段。

需要注意的是:僅Leader Replica對外提供服務,與客戶端程序進行交互,生產者總是向領導者副本寫消息,而消費者總是從領導者副本讀消息。而Follower Replica不能與外界進行交互,它只做一件事:向領導者副本發送請求,請求領導者把最新生產的消息發給它,保持與領導者的同步。

如果對於剛剛所說的主題、分區、副本還有疑惑,那麼結合下面這張圖再思考一下,我相信你就可以玩轉它了:

下圖所示,TopicA,具有三個partition,每個partion都有1 個leader副本和 1 個follower者副本。為了保證高可用性,一台機器宕機不會有影響,因此leader副本和follower副本必然分佈在不同的機器上。

消息層

Kafka的官方定義是message system,由此我們可以知道Kafka 中最基本的數據單元無疑是消息message,它可理解成數據庫里的一條行或者一條記錄。消息是由字符數組組成。關於消息你必須知道這幾件事:

消息key

發送消息的時候指定 key,這個 key 也是個字符數組。key 用來確定消息寫入分區時,進入哪一個分區。你可以用有明確業務含義的字段作為key,比如用戶號,這樣就可以保證同一個用戶號進入同一個分區。

批量寫入

為了提高效率, Kafka 以批量batch的方式寫入。

一個 batch 就是一組消息的集合, 這一組的數據都會進入同一個 topic 和 partition(這個是根據 producer 的配置來定的) 。

每一個消息都進行一次網絡傳輸會很消耗性能,因此把消息收集到一起再同時處理就高效的多。

當然,這樣會引入更高的延遲以及吞吐量:batch 越大,同一時間處理的消息就越多。batch 通常都會進行壓縮,這樣在傳輸以及存儲的時候效率都更高一些。

位移
生產者向分區寫入消息,每條消息在分區中的位置信息由一個叫位移(Offset)的數據來表徵。分區位移總是從 0 開始,假設一個生產者向一個空分區寫入了 10 條消息,那麼這 10 條消息的位移依次是 0、1、2、…、9。

服務端

Kafka 的服務器端由被稱為 Broker 的服務進程構成,即一個 Kafka 集群由多個 Broker 組成,Kafka支持水平擴展,broker數量越多,集群吞吐量越高。在集群中每個broker都有一個唯一brokerid,不得重複。Broker 負責接收和處理客戶端發送過來的請求,以及對消息進行持久化。

一般會將不同的 Broker 分散運行在不同的機器上,這樣如果集群中某一台機器宕機,kafka可以自動選舉出其他機器上的 Broker 繼續對外提供服務。這其實就是 Kafka 提供高可用的手段之一。

controller

Kafka集群中會有一個或者多個broker,其中有且僅有一個broker會被選舉為控制器(Kafka Controller),它負責管理整個集群中所有分區和副本的狀態。

當某個分區的leader副本出現故障時,由控制器負責為該分區選舉新的leader副本。當檢測到某個分區的ISR集合發生變化時,由控制器負責通知所有broker更新其元數據信息。當為某個topic增加分區數量時,同樣還是由控制器負責分區的重新分配。

這幾句話可能會讓你覺得困惑不要方 只是突出下控制器的職能很多,而這些功能的具體細節會在後面的文章中做具體的介紹。

Kafka中的控制器選舉的工作依賴於Zookeeper,成功競選為控制器的broker會在Zookeeper中創建/controller這個臨時(EPHEMERAL)節點,此臨時節點的內容參考如下:

其中version在目前版本中固定為1,brokerid表示稱為控制器的broker的id編號,timestamp表示競選稱為控制器時的時間戳。

兩種客戶端

Kafka有兩種客戶端。生產者和消費者。我們把生產者和消費者統稱為客戶端(Clients)。

向主題Topic發布消息Message的客戶端應用程序稱為生產者(Producer),生產者程序通常持續不斷地向一個或多個主題發送消息。

而訂閱這些主題消息的客戶端應用程序就被稱為消費者(Consumer)。和生產者類似,消費者也能夠同時訂閱多個主題的消息。

Producer

Producer 用來創建Message。在發布訂閱系統中,他們也被叫做 Publisher 發布者或 writer 寫作者。

通常情況下,會發布到特定的Topic,並負責決定發布到哪個分區(通常簡單的由負載均衡機制隨機選擇,或者通過key,或者通過特定的分區函數選擇分區。)
Producer分為Sync Producer 和 Aync Producer。

Sync Producer同步的生產者,即一定要某條消息成功才會發送下一條。所以它是低吞吐率、一般不會出現數據丟失。

Aync Producer異步的生產者,有個隊列的概念,是直接發送到隊列裏面,批量發送。高吞吐率、可能有數據丟失的。

Consumer 和 Consumer Group

消費者

Consumer 讀取消息。在發布訂閱系統中,也叫做 subscriber 訂閱者或者 reader 閱讀者。消費者訂閱一個或者多個主題,然後按照順序讀取主題中的數據。

消費位移

消費者需要記錄消費進度,即消費到了哪個分區的哪個位置上,這是消費者位移(Consumer Offset)。注意,這和上面所說的消息在分區上的位移完全不是一個概念。上面的“位移”表徵的是分區內的消息位置,它是不變的,即一旦消息被成功寫入到一個分區上,它的位移值就是固定的了。

而消費者位移則不同,它可能是隨時變化的,畢竟它是消費者消費進度的指示器嘛。通過存儲最後消費的 Offset,消費者應用在重啟或者停止之後,還可以繼續從之前的位置讀取。保存的機制可以是 zookeeper,或者 kafka 自己。

消費者組

ConsumerGroup:消費者組,指的是多個消費者實例組成一個組來消費一組主題,分區只能被消費者組中的其中一個消費者去消費,組員之間不能重複消費。

為什麼要引入消費者組呢?主要是為了提升消費者端的吞吐量。多個消費者實例同時消費,加速整個消費端的吞吐量(TPS)。

當然它的作用不僅僅是瓜分訂閱主題的數據,加速消費。它們還能彼此協助。假設組內某個實例掛掉了,Kafka 能夠自動檢測到,然後把這個 Failed 實例之前負責的分區轉移給其他活着的消費者,這個過程稱之為重平衡(Rebalance)。

你務必先把這個詞記住,它是kafka大名鼎鼎的重平衡機制,生產出現的異常問題很多都是由於它導致的。後續我會在【kafka大名鼎鼎又臭名昭著的重平衡】文章中詳細分析。

Zookeeper

zookeeper目前在kafka中扮演着舉重輕重的角色和作用~是kafka不可缺少的一個組件。

目前,Apache Kafka 使用 Apache ZooKeeper 來存儲它的元數據,比如brokers信息、分區的位置和主題的配置等數據就是存儲在 ZooKeeper 集群中。

注意我的用詞,我只說是目前。why?在 2019 年社區提出了一個計劃,以打破這種依賴關係,並將元數據管理引入 Kafka 本身。因為擁有兩個系統會導致大量的重複。

在之前的設計中,我們至少需要運行三個額外的 Java 進程,有時甚至更多。事實上,我們經常看到具有與 Kafka 節點一樣多的 ZooKeeper 節點的 Kafka 集群!此外,ZooKeeper 中的數據還需要緩存在 Kafka 控制器上,這導致了雙重緩存。

更糟糕的是,在外部存儲元數據限制了 Kafka 的可伸縮性。當 Kafka 集群啟動時,或者一個新的控制器被選中時,控制器必須從 ZooKeeper 加載集群的完整狀態。隨着元數據數量的增加,加載過程需要的時間也會增加,這限制了 Kafka 可以存儲的分區數量。

最後,將元數據存儲在外部會增加控制器的內存狀態與外部狀態不同步的可能性。

因此,未來,Kafka 的元數據將存儲在 Kafka 本身中,而不是存儲在 ZooKeeper 之類的外部系統中。可以持續關注kafka社區動態哦!

總結

一個典型的kafka集群包含若干個producer(向主題發布新消息),若干consumer(從主題訂閱新消息,用Consumer Offset表徵消費者消費進度),cousumergroup(多個消費者實例共同組成的一個組,共同消費多個分區),若干broker(服務器端進程)。還有zookeeper。

kafka發布訂閱的對象叫主題,每個Topic下可以有多個Partition,Partition中每條消息的位置信息又叫做消息位移(Offset),Partition有副本機制,使得同一條消息能夠被拷貝到多個地方以提供數據冗餘,副本分為領導者副本和追隨者副本。

可以用下面這張圖來形象表達kafka的組成:

另外,再po一張思維導圖助你回顧本文所述的術語。

重要!!關注【胖滾豬學編程】公眾號發送”kafka”。獲取本文所有架構圖以及Kafka全系列思維導圖!

本文來源於公眾號:【胖滾豬學編程】。一枚集顏值與才華於一身,不算聰明卻足夠努力的女程序媛。用漫畫形式讓編程so easy and interesting!求關注!

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

聯合國生物多樣性報告:10年愛知目標 沒有一項完全達成

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

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案