go grpc
发布于
go

message.proto

syntax = "proto3";

package pb;

// The greeter service definition.
service Greeter {
// Sends a greeting
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
	string name = 1;
}

// The response message containing the greetings
message HelloReply {
	string message = 1;
}

protoc编译工具

https://github.com/google/protobuf 会跳 https://github.com/protocolbuffers/protobuf

  --cpp_out=OUT_DIR           Generate C++ header and source.
  --csharp_out=OUT_DIR        Generate C# source file.
  --java_out=OUT_DIR          Generate Java source file.
  --javanano_out=OUT_DIR      Generate Java Nano source file.
  --js_out=OUT_DIR            Generate JavaScript source.
  --objc_out=OUT_DIR          Generate Objective C header and source.
  --php_out=OUT_DIR           Generate PHP source file.
  --python_out=OUT_DIR        Generate Python source file.
  --ruby_out=OUT_DIR          Generate Ruby source file.

protoc能生成那么多语言的代码,但居然本身没有产生go的代码,需要调用如protoc-gen-go这样的插件!!!


set GOPROXY=https://goproxy.io
mkdir demo
cd demo
go mod init demo

rem protoc的 --go_out 插件
go get -u github.com/golang/protobuf/protoc-gen-go 
go get -u google.golang.org/grpc

github.com/golang/protobuf/protoc-gen-go 会编译出 protoc-gen-go

要是先 google.golang.org/grpc,在其go mod也会把前者(github.com/golang/protobuf)一并给下载了,protoc-gen-go还是要自行编译下才出来

go mod 也不用 go get google.golang.org/grpc,在go build里也会自行下载

可选

//gogo
go get -u github.com/gogo/protobuf/protoc-gen-gogo
//gofast
go get -u github.com/gogo/protobuf/protoc-gen-gofast

即protoc-gen系列 3 个

  • protoc-gen-go
  • protoc-gen-gogo
  • protoc-gen-gofast

go.mod

module demo

go 1.14

require (
	github.com/golang/protobuf v1.3.5
	google.golang.org/grpc v1.28.1
)

gRPC-go

grpc原是google内部项目,归属golang,放在google.golang.org下,后来对外开放迁移到github

https://github.com/grpc/grpc-go

梳理


protoc --go_out=. message.proto
protoc --go_out=plugins=grpc:. message.proto

第二个产生的则除了第一个的PB序列化和反序列化代码外,还增加服务器和客户端通讯、实现的公共库代码

github.com/gogo/protobuf

  • protoc-gen-gogo
  • protoc-gen-gofast

完全兼容google protobuf,主要extend了一些option

可以修饰field/enum/message/package(即对整个文件都有效)

protoc --gofast_out=plugins=grpc:. message.proto

code

server

package main

import (
	"net"
	"log"
	"google.golang.org/grpc"
	"demo/pb"
	"context"
)

// server is used to implement helloworld.GreeterServer.
type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func main() {
	lis, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	s.Serve(lis)
}

client

package main

import (
	"google.golang.org/grpc"
	"log"
	"demo/pb"
	"context"
)

func main() {
	conn, err := grpc.Dial("localhost:50051",grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)
	r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: "dd"})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.Message)
}

gRPC HTTP协议转换

coreos的博客,转载了grpc官方博客gRPC with REST and Open APIs

etcd3改用grpc后为了兼容原来的api,同时要提供http/json方式的API

为满足这需求,要么开发两套API,要么实现一种转换机制,他们选择了后者

协议转换的网关grpc-gateway,接收客户端请求,然后决定直接转发给grpc服务还是转给http服务,当然,http服务也需要请求grpc服务获取响应,然后转为json响应给客户端

grpc
发布于
go

RPC :数据编码内存对象可传输的字节流 转化),请求映射

数据编码

XML 日薄西山,JSON 风头正盛,Protobuf 方兴未艾

why Protobuf ?谷歌出品,某些场景下效率比 JSON 高

所有的优化都是有代价的。思考选择什么和放弃什么

JSON 缺点 & Protobuf 选择

{ "int":12345, "str": "hello", "bool": true }
{ "int":67890, "str": "hello", "bool": false }
  • 非字符串的编码低效

    int value 12345,内存表示只占两个字节,转成 JSON 却要五个字节。 bool 字段则占了四或五个字节。

  • 信息冗余

    同一个接口同一个对像,只是 int 字段的值不同,每次都还要传输"int"这个字段名

JSON 在可读性和编码效率之间选择了可读性,所以效率方面做了一定的牺牲

Protobuf 一方面用 VarInts 对数字进行编码,解决效率问题;另一方面给每个字段指定一个整数编号,只传字段编号,解决冗余问题

接收方如何知道各个编号对应哪个字段?只能事先约定。Protobuf 用 .proto 文件记录字段和编号的对应关系

message Demo {
  int32 i = 1;
  string s = 2;
  bool b = 3;
}

Protobuf 提供了一系列工具,为 proto 描述的 message 生成各种语言的代码

传输效率上去了,工具链也更加复杂了。gRPC 抓过时一定会怀念 JSON 的

请求映射

.proto 作为 IDL,Protobuf 可做很多 JSON 不方便做的事情。其中最重的就是 RPC 描述!

package demo.hello;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

gRPC 就是用了 Protobuf 的 service 来描述 RPC 接口

proto 文件定义了 Greeter 服务, SayHello 方法,接受 HelloRequest 消息并返回 HelloReply 消息。如何实现这个 Greeter 则是语言无关的,所以叫 IDL

/{包名}.{服务名}/{接口名}

Greeter 服务对应的路径 /demo.hello.Greeter/SayHello

gRPC 协议规定Content-Typeheader 取值 application/grpc,也可application/grpc+proto

想用 JSON 编码,也可application/grpc+json

gRPC 通信(非流式调用,unary)内容

请求内容

POST /demo.hello.Greeter/SayHello HTTP/1.1
Host: grpc.demo.com
Content-Type: application/grpc
Content-Length: 1234

<Length-Prefixed Message>

响应内容

HTTP/1.1 200 OK
Content-Length: 5678
Content-Type: application/grpc

<Length-Prefixed Message>

stream rpc

gRPC 持三种流式接口,参数前加上 stream 关键字

  • 请求流(推送或者短信)
  • 响应流(订阅消息通知)
  • 双向流(实时语音转字幕)
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  rpc SayHello (stream HelloRequest) returns (HelloReply) {}
  rpc SayHello (HelloRequest) returns (stream HelloReply) {}
  rpc SayHello (stream HelloRequest) returns (stream HelloReply) {}
}

引入Length-Prefixed Message,同一个 gRPC 请求的不同消息共用 HTTP 头信息,给每个消息单独加五字节前缀来表示压缩和长度信息

HTTP/1.1 也支持复用 TCP 连接,但所有请求必须排队(请求、等待、响应)顺序进行。先到先服务。而在实际的业务场景中肯定会有一些请求响应时间很长,客户端在收到响应之前会一直霸占着TCP连接。在这段时间里别的请求要么等待,要么发起新的 TCP 连接。一言以蔽之,HTTP/1.1 不能充分地复用 TCP 连接

HTTP/2 引入 stream概念 ,解决 TCP 连接复用的问题(同样有取舍问题)。可简单理解为逻辑上的 TCP 连接,在一条 TCP 连接上并行收发 HTTP 消息,而无需像 HTTP/1.1 那样等待

base64
发布于
coding

base64 作用

二进制数据,每个字符取值范围[0, 255],作为ascii码解析时,只有部分可显示(打印)

肉眼查看/作为文本拷贝这份数据,16进制优于二进制ascii码格式

但16进制表示法需两个字节才能表示表示原始数据的一个字节,即大小增加了一倍

base64算法保持编码后可打印特性的同时,大小只增加 1/3

算法原理

将二进制数据每三个字节(24位)看成一个单元,按每6位进行一次切割,切割成4个字节。切割后每个字节的范围是[0, 63]

[0, 63]的ascii码也并不都是可打印的,将[0, 63]再映射成可打印的字符

RFC 4648 映射关系定义:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

0对应A,1对应B,63对应 /

换算之后,三个字节变成可打印的四个字节内容

解码逻辑,将每个可打印的字符按映射表对应,每4个字节看成一个单位,按位运算还原出原始3个字节

原始数据长度不是3的倍数?

一种是最后剩1个字节,另一种是剩两个字节:

  • 剩余1个字节时,1个字节编码成2个字节,剩余2个字节填充为 ==
  • 剩余2个字节时,2个字节编码成3个字节,剩余1个字节填充为 =

即base64保证了编码后的字符串长度为4的倍数

作为url参数问题

base64编码后可能会出现 +/= 三个字符,会影响到整个url串的解析

例,https://example.com/all?key=1/2=

RFC 4648 中给出另一张映射表, + 替换成 -,/ 替换成 _

acme.sh with dnspod
发布于
work

安装

curl https://get.acme.sh | sh
source ~/.bashrc

Wildcard Certificate

Let’s Encrypt Wildcard Certificate 必须用 DNS TXT 记录验证方式,且注意加2个 -d ddatsh.com -d *.ddatsh.com

其他 dns 或手工见 acme github wiki

export DP_Id="1xxx"
export DP_Key="xxxx"
acme.sh --issue --dns dns_dp -d ddatsh.com -d *.ddatsh.com --renew-hook "/root/.acme.sh/acme.sh --install-cert -d ddatsh.com  --key-file       /etc/nginx/conf.d/ssl/ddatsh.com.rsa.key    --fullchain-file /etc/nginx/conf.d/ssl/ddatsh.com.rsa.cer    --reloadcmd      \"systemctl force-reload nginx\""

acme.sh --issue --dns dns_dp -d ddatsh.com -d *.ddatsh.com -k ec-384  --renew-hook "/root/.acme.sh/acme.sh --install-cert -d ddatsh.com --ecc --key-file       /etc/nginx/conf.d/ssl/ddatsh.com.ecc.key    --fullchain-file /etc/nginx/conf.d/ssl/ddatsh.com.ecc.cer    --reloadcmd      \"systemctl force-reload nginx"\" --force

cron log

[root@VM-0-7-centos ~]# acme.sh --cron
[Tue Dec 15 12:04:51 CST 2020] ===Starting cron===
[Tue Dec 15 12:04:51 CST 2020] Renew: 'ddatsh.com'
[Tue Dec 15 12:04:52 CST 2020] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Tue Dec 15 12:04:52 CST 2020] Multi domain='DNS:ddatsh.com,DNS:*.ddatsh.com'
[Tue Dec 15 12:04:52 CST 2020] Getting domain auth token for each domain
[Tue Dec 15 12:04:57 CST 2020] Getting webroot for domain='ddatsh.com'
[Tue Dec 15 12:04:57 CST 2020] Getting webroot for domain='*.ddatsh.com'
[Tue Dec 15 12:04:58 CST 2020] ddatsh.com is already verified, skip dns-01.
[Tue Dec 15 12:04:58 CST 2020] *.ddatsh.com is already verified, skip dns-01.
[Tue Dec 15 12:04:58 CST 2020] Verify finished, start to sign.
[Tue Dec 15 12:04:58 CST 2020] Lets finalize the order.
[Tue Dec 15 12:04:58 CST 2020] Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/105392664/6749057114'
[Tue Dec 15 12:05:00 CST 2020] Downloading cert.
[Tue Dec 15 12:05:00 CST 2020] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/04b7648ffb2c2a2887a2b85e7ed662421226'
[Tue Dec 15 12:05:01 CST 2020] Cert success.
-----BEGIN CERTIFICATE-----
MIIFKxxx
-----END CERTIFICATE-----
[Tue Dec 15 12:05:01 CST 2020] Your cert is in  /root/.acme.sh/ddatsh.com/ddatsh.com.cer 
[Tue Dec 15 12:05:01 CST 2020] Your cert key is in  /root/.acme.sh/ddatsh.com/ddatsh.com.key 
[Tue Dec 15 12:05:01 CST 2020] The intermediate CA cert is in  /root/.acme.sh/ddatsh.com/ca.cer 
[Tue Dec 15 12:05:01 CST 2020] And the full chain certs is there:  /root/.acme.sh/ddatsh.com/fullchain.cer 
[Tue Dec 15 12:05:02 CST 2020] Run renew hook:'/root/.acme.sh/acme.sh --install-cert -d ddatsh.com  --key-file       /etc/nginx/conf.d/ssl/ddatsh.com.rsa.key    --fullchain-file /etc/nginx/conf.d/ssl/ddatsh.com.rsa.cer    --reloadcmd      "systemctl force-reload nginx"'
[Tue Dec 15 12:05:02 CST 2020] Installing key to:/etc/nginx/conf.d/ssl/ddatsh.com.rsa.key
[Tue Dec 15 12:05:02 CST 2020] Installing full chain to:/etc/nginx/conf.d/ssl/ddatsh.com.rsa.cer
[Tue Dec 15 12:05:02 CST 2020] Run reload cmd: systemctl force-reload nginx
[Tue Dec 15 12:05:03 CST 2020] Reload success
[Tue Dec 15 12:05:03 CST 2020] Renew: 'ddatsh.com'
[Tue Dec 15 12:05:04 CST 2020] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Tue Dec 15 12:05:04 CST 2020] Multi domain='DNS:ddatsh.com,DNS:*.ddatsh.com'
[Tue Dec 15 12:05:04 CST 2020] Getting domain auth token for each domain
[Tue Dec 15 12:05:10 CST 2020] Getting webroot for domain='ddatsh.com'
[Tue Dec 15 12:05:10 CST 2020] Getting webroot for domain='*.ddatsh.com'
[Tue Dec 15 12:05:10 CST 2020] ddatsh.com is already verified, skip dns-01.
[Tue Dec 15 12:05:10 CST 2020] *.ddatsh.com is already verified, skip dns-01.
[Tue Dec 15 12:05:10 CST 2020] Verify finished, start to sign.
[Tue Dec 15 12:05:10 CST 2020] Lets finalize the order.
[Tue Dec 15 12:05:10 CST 2020] Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/105392664/6749062076'
[Tue Dec 15 12:05:12 CST 2020] Downloading cert.
[Tue Dec 15 12:05:12 CST 2020] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/038811d00702ddb48ba0ab38fce9fc554a9e'
[Tue Dec 15 12:05:13 CST 2020] Cert success.
-----BEGIN CERTIFICATE-----
MIIEezxxx
-----END CERTIFICATE-----
[Tue Dec 15 12:05:13 CST 2020] Your cert is in  /root/.acme.sh/ddatsh.com_ecc/ddatsh.com.cer 
[Tue Dec 15 12:05:13 CST 2020] Your cert key is in  /root/.acme.sh/ddatsh.com_ecc/ddatsh.com.key 
[Tue Dec 15 12:05:13 CST 2020] The intermediate CA cert is in  /root/.acme.sh/ddatsh.com_ecc/ca.cer 
[Tue Dec 15 12:05:13 CST 2020] And the full chain certs is there:  /root/.acme.sh/ddatsh.com_ecc/fullchain.cer 
[Tue Dec 15 12:05:13 CST 2020] Run renew hook:'/root/.acme.sh/acme.sh --install-cert -d ddatsh.com --ecc  --key-file       /etc/nginx/conf.d/ssl/ddatsh.com.ecc.key    --fullchain-file /etc/nginx/conf.d/ssl/ddatsh.com.ecc.cer    --reloadcmd      "systemctl force-reload nginx"'
[Tue Dec 15 12:05:13 CST 2020] Installing key to:/etc/nginx/conf.d/ssl/ddatsh.com.ecc.key
[Tue Dec 15 12:05:13 CST 2020] Installing full chain to:/etc/nginx/conf.d/ssl/ddatsh.com.ecc.cer
[Tue Dec 15 12:05:13 CST 2020] Run reload cmd: systemctl force-reload nginx
[Tue Dec 15 12:05:13 CST 2020] Reload success
[Tue Dec 15 12:05:13 CST 2020] ===End cron===
java spi
发布于
java

Service Provider Interface

“接口+策略模式+配置文件” 组合实现的动态加载机制

SPI 应用之一是可替换的插件机制

  1. 定义一组接口

  2. 写接口的一个或多个实现

  3. src/main/resources/META-INF/services/接口名文件, 内容是要应用的实现类

  4. 用 ServiceLoader 加载配置文件中指定的实现


主要被框架的开发人员使用,如 java.sql.Driver 接口,不同厂商可以针对同一接口做出不同的实现

mysql 隔离级别测试
发布于
mysql

Read UnCommited

可解决丢失更新

create table users (
    id int auto_increment not null primary key,
    name char(10) not null,
    state int not null
); 
insert into users values(1,'dd',0);

事务1

set autocommit = 0;
set global transaction isolation level read uncommitted ;
set session transaction isolation level read uncommitted ; 
start transaction;
update users set state=state+1 where id=1;
select sleep(10);
commit;

事务2

set autocommit = 0;
set global transaction isolation level read uncommitted ;
set session transaction isolation level read uncommitted ; 
start transaction;
update users set state=state+1 where id=1;
commit;

数据库的一级封锁锁(修改前加X锁,事务结束释放X锁,读不加锁)

事务1先执行修改,修改前申请持有X锁,事务结束释放X锁;事务2也执行修改操作,修改前也申请持有X锁

事务1,10秒才提交释放锁,事务2申请持锁需要等待,直到事务1结束才能获取到锁的持有权进行修改

这样对同一数据的修改会变成串行化的修改,所以不会出现因为并发只进行一次+1的情况,也就不会出现丢失修改的问题

RU 不能解决脏读和不可重复读

另一个事务回滚就会产生脏读

set autocommit = 0;
set global transaction isolation level read uncommitted ;
set session transaction isolation level read uncommitted ; 
start transaction;
update users set state=1 where id=1;
select sleep(5);
rollback;
set autocommit = 0;
set global transaction isolation level read uncommitted ;
set session transaction isolation level read uncommitted ; 
start transaction;
select * from users where id=1;
commit; 

事务2结果=1

事务1和事务2都执行结束时,再进行一次查询=0

事务1先修改,修改前申请持有X锁,

事务2读,不需要申请持锁,读出的数据是事务1修改后的,而此时事务1回滚,修改的数据被还原,产生脏读现象

mysql复制
发布于
mysql

5.6

引入GTID,server uuid(auto.cnf)和事务ID组成

并行只基于库(Schema)

  1. Crash Safe 不好做,可能后执行的事务由于并行复制先完成执行
  2. 性能不高单库多表比多库多表更常见

基于GTID的Replication好处

传统复制

发生故障后,主从切换,需找到binlog和pos点,然后change master to指向新的master,麻烦易错

GTID后只需要知道master ip,port,自动找点同步

A 宕机,需要切到 B上。同时又需要将C的复制源改成B

CHANGE MASTER TO MASTER_HOST='xxx', MASTER_LOG_FILE='xxx', MASTER_LOG_POS=nnnn

难点在于,同一个事务在每台机器上所在的binlog名字和位置都不一样,怎么找到C当前同步停止点,对应B的master_log_file和master_log_pos是什么

M-S复制集群需要使用 MMM/MMA 这样的额外管理工具的一个重要原因

多线程复制(基于库) MGR

5.6基于库

5.7基于表(真正意义上多线程复制)

slave-parallel-type

  • DATABASE:默认值,基于库的并行复制方式
  • LOGICAL_CLOCK:基于组提交的并行复制方式(last_committedsequence_number)

binlog 字段 last_committedsequence_number

下一个事务在主库配置好组提交以后,last_committed 和上一个事务的 sequence_number 相等,因为事务是顺序提交的

最后两个事务的 last_committed 相同,意味着这两个事务作为一个组提交,两个事务在 Perpare 阶段获取相同的 last_committe 而且相互不影响,最终是会作为一个组进行提交

组提交是并行复制的基础

组提交的事务可以在slave并行回放

master

  • binlog_group_commit_sync_delay

全局动态变量,单位微妙,默认 0,范围:0~1000000(1秒)

binlog 提交后等待延迟多少时间再同步到磁盘,默认0 ,不延迟

0 以上时,允许多个事务的日志同时一起提交,就是组提交。组提交是并行复制的基础,大于 0 就代表打开了组提交的功能

  • binlog_group_commit_sync_no_delay_count

全局动态变量,单位个数,默认 0,范围:0~1000000

等待延迟提交的最大事务数,如果上面参数的时间没到,但事务数到了,则直接同步到磁盘。若 binlog_group_commit_sync_delay 没有开启,则该参数也不会开启

slave

slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=4

MGR不是强同步的,但是最终会一致的

确切的说:事务会按照相同的顺序发送给这个group的所有成员,但是事务的执行、commit完全由成员自行处理,并不是同步进行的

Group Replication Limitations

MGR在GTID基础上构建,GTID的限制不能使用event的checksums

--binlog-checksum=NONE 必须这样设置

Gap locks , 建议设置隔离级别为 READ COMMITTED

认证阶段无法使用gap lock,所以建议使用隔离级别为READ COMMITTED,READ COMMITTED 不适用gap locks

SERIALIZABLE , MGR不支持SERIALIZABLE隔离级别

  • 并发DDL和DML在同一个对象上的操作,会有问题
举例: 
	A实例 表t进行DDL  
	B实例 表t进行dml
	会导致冲突无法检测到,会有很高的风险  
	这种情况一般在multi-primary模式下容易遇到(因为多实例写嘛的原因嘛),所以DDL要特别小心
  • 外键级联约束

  • 大事务

在5秒钟的世界窗口中如果无法将事务copy到其他成员的话,那么MGR的通信会失败,重传,会有严重影响  
建议切分、限制 事务大小
  • multi-primary的死锁检测
多主模式下,如果使用SELECT .. FOR UPDATE 会导致死锁  

主要是lock无法跨越多服务器
  • 复制过滤
MGR中不要使用任何复制的filter

FAQ

MGR成员数量最大9个

MGR来scale-out写压力

a)并不是直接的扩展方式,每一个成员都有完整的数据copy

b)但是其他server并不是做完全一样的写动作,MGR通过ROW模式复制,其他server只需要apply row即可,并不是re-executed事务了,因此会快且压力小很多

c)更进一步讲,row-based应用都是经过压缩过的,可以减少很多IO动作,相比master上的执行压力会小很多的

d)总结,可以scale-out写,在没有写冲突事务的时候在多台服务器上执行事务是可以做到scale-out的

如果网络临时有问题,组成员会自动重新加入group吗

取决于是什么网络问题 短暂,瞬间,MGR错误检测机制根本还没来得及探测到此问题,该成员不会被移除出组 长时间问题,错误检测机制最终会认为它除了问题,将此server移除出组

一旦移除出组,需要让他重新加入一次,换句话说,需要手工来处理,或用脚本来自动处理

如果一个节点严重延迟,会产生什么问题

没有一个很好的策略来自动判断什么时候去驱逐一个成员 需要找到为什么它会延迟,并解决它,或移除它 否则,当一个server慢到触发流控,然后整个group都会变的慢下来

java singleton
发布于
java
  • 懒汉,线程不安全

适合单线程程序,多线程需要保护getInstance(),否则可能产生多个Singleton对象实例

public class Singleton {

    private Singleton() {
    }

    private static Singleton instance = null;

    public static Singleton getInstance() {
        if (Singleton.instance == null) {
            Singleton.instance = new Singleton();
        }
        return Singleton.instance;
    }
}
os 5 io
发布于
os

Linux I/O体系七层:

  • VFS

    适配各种文件系统,对外提供统一API

    磁盘:EXT,XFS …

    网络:NFS, CIFS …

    特殊:/proc,裸设备

  • 磁盘缓存

    磁盘数据驻留 RAM

    • Dentry cache
    • Page cache
    • Buffer cache
  • 映射层

    确定数据在物理设备上的位置

  • 通用块层

    绝大多数I/O操作是跟块设备打交道

    下层对接各种不同属性的块设备,对上提供统一的Block IO请求标准

  • I/O调度层

    管理块设备的请求队列,有利于减少磁盘寻址时间,提高全局吞吐量

    大多数块设备都是磁盘设备

    根据设备及应用特点设置不同的调度器

  • 块设备驱动

    设备操作接口

  • 物理硬盘

分布式一致性
发布于
concurrent

分布式系统面临的问题

  • 通信异常

    不可用、延时、丢失

  • 网络分区(脑裂)

    系统分化出两个网络组,组内都正常通讯,但组间通讯被阻隔

  • 三态

    成功,失败和超时时(请求者无法判断当前请求是否成功处理)

  • 节点故障

    宕机,僵死,器件损坏等