2018年7月26日 星期四

實作每秒千萬級別的訊息發送系統

場景

網路協議:       TCP/IP
網路程式介面: socket
CCU:            1000,000
每秒發送訊息次數: 10
總訊息傳送次數:    1000,000*10=10,000,000

瓶頸

linux內核
每秒送出的TCP/IP封包次數上限約 10,000,000/sec


要遍歷全部的連線,一個一個發送訊息,所以需要加鎖。
數量高達1000,000,所以這個過程很久,導致其他操作無法執行。
例如login,logout,都要等全部發送完解鎖後,才能執行。

頻寬
頻寬約需400MB-600MB之間。

解法

針對linux內核發送TCP/IP封包次數上限瓶頸
減少發送次數,一秒內的訊息,全部組合成一個訊息,統一發送。

針對鎖的瓶頸
把1000,000連線,分拆為多個集合,用併發的方式同步處理,
可有效減少上鎖時間。
鎖用讀寫鎖,不用互斥鎖。

針對頻寬瓶頸
訊息壓鎖。
換1GB網卡,加大頻寬。

單機架構



分散架構

2018年7月25日 星期三

MySQL 輸出結果到檔案


範例

select * from table_name
INTO OUTFILE '/directory/output.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'


以上執行select * from table_name 輸出到 '/directory/output.csv',
以逗號為欄位的分隔符號,然後每個欄位資料以雙引號刮起來,
每筆資料結尾以 '\n' 結束。

MySQL FOREIGN KEY

條件

使用innodb

範例

CREATE TABLE product (
prod_id INT NOT NULL,
prod_name CHAR(20),
PRIMARY KEY (prod_id))
ENGINE = INNODB;

CREATE TABLE order (
order_id INT NOT NULL,
prod_id INT,
FOREIGN KEY(prod_id) REFERENCES product(prod_id)
ON DELETE CASCADE
ON UPDATE CASCADE,
PRIMARY KEY (order_id))
ENGINE = INNODB;


設定 foreign key
 order table 的 prod_id 為foreign key

設定參數
ON DELETE CASCADE
ON UPDATE CASCADE

效果
此時如果 delete product table的某筆資料,
也會 delete order 有foreign key參考到的資料。

此時如果update product table的某筆 prod_id,
也會 update order 有foreign key參考到的 prod_id。

此時drop product table 會出錯,因為 order table 參考到它。

Foreign Key 參數說明

[ON DELETE {CASCADE | SET NULL | NO ACTION | RESTRICT}]
[ON UPDATE {CASCADE | SET NULL | NO ACTION | RESTRICT}]

當關聯父資料表的主鍵紀錄行被刪除或修改時,InnoDB 對子資料表中紀錄行的處理方式:

CASCADE - 會將有所關聯的紀錄行也會進行刪除或修改。
SET NULL - 會將有所關聯的紀錄行設定成 NULL。
NO ACTION - 有存在的關聯紀錄行時,會禁止父資料表的刪除或修改動作。
RESTRICT - 與 NO ACTION 相同。

Foreign Key效用

  1. 利用 db schema 防止程式錯誤及阻擋不合法寫入。
  2. 加速 join 效率。


2018年7月10日 星期二

Golang Primary Data Type


18種基本type
8種複合type

go lang 只有傳值,沒有傳參考
slice,map,pointer,channel都是參考類型,底層都有一個對應的資料結構
當傳slice,map,pointer當參數,修改其內容,也會改到底層對應資料

map
value,ok:=map["key"]
value=value
if無此key-value pair,value ==map element type的零值
if ok==true   表示有此key-value pair
if ok==false  表示無此key-value pair


Data type零值
int=0
bool = false
string= ""
複合類型 =nil
map,slice=nil
function =nil

closure 閉包
保留某個變數,以後可以使用。
不需要每次都建立該變數。
http://openhome.cc/Gossip/JavaScript/Closure.html

方法
是某個附屬於自定義類型的函式
或是附屬於自定義類型對應的指標類型的函式


Interface
只要一個類型實現了該interface的所以方法,那就是實現了該 interface

網路 Layers

OSI 網路七層 TCP/IP網路四層

OSI(Open System Interconnection) 網路七層                TCP/IP四層


應用層Application Layer   應用層Application Layer
表現層Presentation Layer
會談層Session Layer

傳送層Transport Layer       傳送層Transport Layer

網路層Network Layer          網路層Internet Layer
資料鏈結層Data Link Layer  鏈結層Link Layer
實體層

各層協定

應用層Application Layer

應用程式之間實際溝通的協定,大部分傳輸層建立在TCP之上
HTTP/WebSocket/FTP/SMTP/POP3/SSH/NFS/DNS/DHCP/IMAP
telnet/

傳送層Transport Layer

實際資料傳輸的協定
TCP(Transmission Control Protocol)
HTTP/FTP/SMTP/SSH/telnet/WebSocket
TCP會把TCP 會在傳輸層對將上層送來的過大訊息分割成多個分段(TCP segments)

UDP(User Datagram Protocol)
DNS/DHCP/某些影音串流
UDP 訊息過大時(整體封包長度超過 MTU),
會由 host 或 router 在 IP 層對封包進行分割,
將一個 IP packet 分割成多個 IP fragments,
接收端的系統需要做 IP 封包的重組,將多個 fragments 重組合併為原本的 IP 封包,
同時也會增加封包遺失的機率。
只要其中一個 IP fragment 遺失了,
接收端就會無法順利重組 IP 封包,因而造成封包的遺失。
安全做法是封包大小不能超過MTU。

PPTP(翻牆)

網路層Internet Layer

定義實體介面卡的邏輯位置(IP),及定義資料封包如何繞送的規則。
IP
ICMP:基於IP之上
常用工具ping:向目標主機傳出一個ICMP echo@要求封包,並等待接收echo回應封包。
常用工具trace:

鏈結層Link Layer

網路實際硬體、各種線材、機器
LAN/WAN/ARP/RJ-45乙太網路線/光纖/VDSL

各層資料

應用層Application Layer

傳送層Transport Layer

資料進入傳送層,會包上傳送層表頭,此時稱為segment(資料段)

網路層Internet Layer

資料段進入網路層,包入表頭後稱為packet(封包)

鏈結層Link Layer

packet進入鏈結層處理之後,會將封包前後分別加入表頭以及表尾,整個稱之為訊框(frame)
鏈結層也是唯一的一層,同時在資料的前後加入資訊。

net package of Golang

net package是幫network I/O 提供一個可攜性的介面

包括 TCP/IP, UDP, domain name solution, Unix domain socket.

net package 支援的網路類型 network

基本四類 ip, tcp, udp, unix ,請見文件Dial 一節

"tcp",
"tcp4" (IPv4-only),
"tcp6" (IPv6-only)
"udp",
"udp4" (IPv4-only),
"udp6" (IPv6-only),
"ip", "ip4" (IPv4-only)
"ip6" (IPv6-only)
"unix"
"unixgram"
"unixpacket".

network又可分為兩類
無連接 ip, udp, unix(DGRAM),
建立連接 tcp, unix(STREAM),需要監聽,有listener。

無連接基礎interface是Conn
有連接基礎interface是PacketConn

network interface 三個主要組成

1. sever 負責listen,取得conn
2. client 負責連上server (dial),建立conn
3. conn  stream導向的連線(Conn is a generic stream-oriented network connection.)

整個核心就是對conn的操作

基本模型
1. listen(server side)取得listener, accept之後取得conn
2. dial(client side)取得conn
3. conn的操作

Dial / Listen func
func Dial(network, address string) (Conn, error)
func Listen(net, laddr string) (Listener, error)


Example:
Dial("tcp", "golang.org:http")
Dial("tcp", "192.0.2.1:http")
Dial("tcp", "198.51.100.1:80")
Dial("udp", "[2001:db8::1]:domain")
Dial("udp", "[fe80::1%lo0]:53")
Dial("tcp", ":80")


//client
conn, err := net.Dial("tcp", "golang.org:80")

if err != nil {
 // handle error
}
fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
status, err := bufio.NewReader(conn).ReadString('\n')


//server
ln, err := net.Listen("tcp", ":8080")
if err != nil {
 // handle error
}
for {
 conn, err := ln.Accept()
 if err != nil {
  // handle error
 }
 go handleConnection(conn)
}

Conn是各種conn的基礎interface,
Dial()會判斷網路類型,回傳對應的conn。
例如是TCP網路,回傳TCPConn。

可以用dial()取得conn或是用各自的dial取得各自的conn。

取得Conn
func Dial(network, address string)(Conn,error)
func DialTimeout(network, address string, timeout time.Duration)(Conn,error)
func FileConn(f *os.File)(c Conn, err error)
func Pipe()(Conn,Conn)

取得Listener
func FileListener(f *os.File)(ln Listener, err error)
func Listen(network, address string)(Listener, error)


type Conn interface {
  
     Read(b []byte) (n int, err error)

     Write(b []byte) (n int, err error)
  
     Close() error
  
     LocalAddr() Addr
 
     RemoteAddr() Addr
 
     SetDeadline(t time.Time) error
 
     SetReadDeadline(t time.Time) error
 
     SetWriteDeadline(t time.Time) error
 }

type PacketConn interface {
  
     ReadFrom(b []byte) (n int, addr Addr, err error)

     Close() error

     LocalAddr() Addr

     SetDeadline(t time.Time) error

     SetReadDeadline(t time.Time) error

     SetWriteDeadline(t time.Time) error
}

各種CONN


Conn
  a interface, generic stream-oriented network connection.
  Read()
  Write()
PacketConn
  a interface, generic packet-oriented network connection.
網路層的conn
  ReadFrom()
  WriteTo()

Conn跟PacketConn是兩種基礎interface,實際應用的四種Conn分別實作他們。

IPConn
  實作Conn及PacketConn的IP network connections.
  func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error)
  func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error)

TCPConn
  實作Conn的TCP network connections.
  func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error)
  func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error)

UDPConn
  實作Conn及PacketConn的UDP network connections.
  func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error)
  func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error)

UnixConn
  實作Conn及PacketConn的Unix socket connections.
  SOCK_DGRAM
  func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error)
  func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error)

  SOCK_STREAM
  func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error)
  func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error)

通用func


func ListenPacket(net, laddr string) (PacketConn, error)
監聽ip, udp, unix(DGRAM)等協議,返回packetConn。
packetConn可能是IPConn, UDPConn, UnixConn。

func Listen(net, laddr string) (Listener, error)
監聽tcp, unix(stream)等協議。返回Listener。
Listener有可能是TCPListener, UnixListener。

func Dial(network, address string) (Conn, error)
返回Conn。
依據network有可能是IPConn, UDPConn, TCPConn, UnixConn。

各network(IP/TCP/UDP/Unix)相關的物件


Conn
Addr
Listener

Example:
  IPConn
  IPAddr
  TCPAddr
  TCPConn
  TCPListener
  UDPAddr
  UDPConn
  UnixAddr
  UnixConn
  UnixListener

其他相關物件


Addr
Buffers
IP
IPNet
IPMask
MX
NS
Resolver  支援功能

支援功能


func LookupAddr(addr string) (names []string, err error)
func LookupCNAME(host string) (cname string, err error)
func LookupHost(host string) (addrs []string, err error)
func LookupIP(host string) ([]IP, error)
func LookupMX(name string) ([]*MX, error)
func LookupNS(name string) ([]*NS, error)
func LookupPort(network, service string) (port int, err error)
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error)
func LookupTXT(name string) ([]string, error)

2018年7月9日 星期一

OOP in Golang

method繼承


在struct 中引入其他struct type,
就可以繼承他的method。


2018年7月7日 星期六

Golang Features


Collection

array

長度固定,元素相同。
實際上可以用interface當類型,所以可放不同類型元素。
array進行slice操作後,產生的是slice,非array。

declare array:

var grid [5][5]int
var buffer [20]byte
create array:

[3]string
[3]string{"a","b","c"}
[...]string{"a","b","c"}

grid[1][0],grid[1][1],grid[1][2]=8,6,3
grid2:=[3][3]int{{1,2,3},{1,2,3}}
cities:=[...]string{"a","b","c"}

slice

長度可變,元素相同。
slice底層是建立array,並引用它。 實際上可以用interface當類型,所以可放不同類型元素。
官方function都是使用slice。
同一個slice出來的slice,因為是引用相同array,
所以其中一個改變,會影響所有對該array的引用。


declare slice:

var grid [][]int

create slice:
不聲明數量,就是slice;聲明數量就是array。

[3]string
make([]Type,length,capacity)
make([]Type,length)
[]int{}
[]string{"a","b","c"}
s:=new([7]string)[:]   //new array然後slice全部,所以s是slice

s:=[]string{"a","b","c","d","e"}
t:=s[:5]
u:=s[3:len(s)-1]
u[1]="x"          //改變原本的array引用,所以影響所有slice


slice操作:

//尾部都不包括
s[n]    //slice n
s[n:m]  //slice n to m-1
s[n:]   //slice n to last
s[:m]   //slice 0 to m-1
s[:]    //slice all

內建函數

make

used to create slice,map,channel

len

append

cap

new

new struce,new array
new得到的是pointer

程式執行時的記憶體模型

程式運行時,作業系統會配置一塊記憶體給他使用。
這塊記憶體存放程式執行時的變數及各項資料。
這塊記憶的配置,是由程式所控制的。
記憶體的配置模型可分為三種,global、stack、heap。
程式執行時的記憶體需求,依據不同類型,配置在不同記憶體中。

其中heap是從該記憶體的最高位址開始配置。
stack是從最低位址開始配置。


global

程式中的全域變數或是static變數,配置在這個區域。
程式運行中,這些變數永遠存在,也就是記憶體都在使用,不會回收。

stack 堆疊/棧

生命週期可被預期的變數或是函數資料,配置在這個區域。
因為可以預期,所以這些記憶體可被系統自動管理,
不再使用時,系統自動回收。

常見的資料有:
區域變數
函數的參數
函數的返回地址

後進先出原則

等整個function執行結束,
整個stack都釋放了。

配置方式

stack使用是分次分配的,
每分配一個稱為一個frame。
從底位址往高位址一個一個分配,
後分配的(push )進去的會先釋放。
也就是後進先出。
取出稱為pop。
也因為後進先出、一層一層疊加的特性,
所以記憶體是從低位址開始使用,較為合理。

heap 堆

程式執行時才動態產生,
無法預期何時產生、數量多少、何時回收,
這些資料則配置在heap區域。
或是使用者要求,例如使用malloc函數。
這時記憶體就要由使用者自行回收,
或是由語言的Garbage Collection機制回收。

若回收不完全,就會產生out of memory的錯誤,
導致系統記憶體越用越少。

配置方式

每次配置一塊記憶體,每塊記憶體之間各自獨立。
從低位址往高位址配置
href="http://http://www.ruanyifeng.com/blog/2018/01/assembly-language-primer.html">參考