Skip to content

Commit

Permalink
refactor chap4-03-06, ch4-09
Browse files Browse the repository at this point in the history
  • Loading branch information
phamtai97 committed Aug 11, 2019
1 parent 958e595 commit c784d37
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 37 deletions.
10 changes: 5 additions & 5 deletions ch4-rpc/ch4-03-fun-fpc.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 4.3 RPC trong Golang

Chúng ta có thể sử dụng RPC cho nhiều mục đích khác nhau, vì vậy cộng đồng opensource đã tạo ra khá nhiều framework RPC để hỗ trợ cho việc lập trình. Trong phần này, chúng ta sẽ sử dụng một framework RPC tích hợp sẵn trong Go.
Chúng ta có thể sử dụng RPC cho nhiều mục đích khác nhau, vì vậy cộng đồng opensource đã tạo ra khá nhiều framework RPC để hỗ trợ cho việc lập trình. Trong phần này, chúng ta sẽ sử dụng framework RPC tích hợp sẵn trong Go cho các hiện thực của một số trường hợp.

## 4.3.1 Hiện thực RPC phía Client

Expand Down Expand Up @@ -203,11 +203,11 @@ func doClientWork(client *rpc.Client) {
}
```

Server sẽ trả về khóa đã thay đổi thông qua phương thức `Watch`. Bằng cách này chúng ta có thể giám sát việc thay đổi trạng thái của khóa.
Server sẽ trả về key đã thay đổi thông qua phương thức `Watch`. Bằng cách này chúng ta có thể giám sát việc thay đổi trạng thái của key.

## 4.3.3 Reverse RPC

RPC bình thường dựa trên cấu trúc client-server. Server của RPC tương ứng với server của mạng và client của RPC cũng tương ứng với client mạng. Tuy nhiên, đối với một số trường hợp đặc biệt, chẳng hạn như khi cung cấp dịch vụ RPC trên mạng nội bộ, nhưng mạng bên ngoài không thể kết nối với server mạng nội bộ.
RPC thường được sử dụng trong mô hình client-server. Trong đó server và client cần dùng chung một network. Tuy nhiên, đối với một số trường hợp đặc biệt, chẳng hạn như khi cung cấp dịch vụ RPC trên mạng nội bộ, nhưng mạng bên ngoài không thể kết nối với server mạng nội bộ.

<div align="center">

Expand Down Expand Up @@ -294,9 +294,9 @@ func doClientWork(clientChan <-chan *rpc.Client) {
}
```

## 4.3.4 RPC theo ngữ cảnh
## 4.3.4 RPC theo ngữ cảnh (context)

Dựa trên ngữ cảnh (context) chúng ta có thể cung cấp những RPC services thích hợp cho những client khác nhau. Ta có thể hỗ trợ các tính năng theo ngữ cảnh bằng cách cung cấp các RPC service cho từng link kết nối.
Dựa trên ngữ cảnh chúng ta có thể cung cấp những RPC services thích hợp cho những client khác nhau. Ta có thể hỗ trợ các tính năng theo ngữ cảnh bằng cách cung cấp các RPC service cho từng link kết nối.

Đầu tiên thêm vào thành phần `conn``HelloService` cho link tương ứng:

Expand Down
22 changes: 9 additions & 13 deletions ch4-rpc/ch4-04-grpc.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<br/>


gRPC là một framework RPC opensource đa ngôn ngữ được Google phát triển dựa trên Protobuf và giao thức HTTP/2. Phần này sẽ giới thiệu một số cách sử dụng gRPC đơn giản.
[gRPC](https://grpc.io/) là một framework RPC opensource đa ngôn ngữ được Google phát triển dựa trên [Protobuf](https://developers.google.com/protocol-buffers/) và giao thức HTTP/2. Phần này sẽ giới thiệu một số cách sử dụng gRPC để xây dựng service đơn giản.

## 4.4.1 Kiến trúc gRPC

Expand Down Expand Up @@ -78,7 +78,7 @@ func (p *HelloServiceImpl) Hello(
}
```

Quá trình khởi động của gRPC service tương tự như quá trình khởi động RPC service của thư viện chuẩn:
Quá trình khởi động của gRPC service tương tự như quá trình khởi động RPC service của thư viện chuẩn:

```go
func main() {
Expand Down Expand Up @@ -122,9 +122,9 @@ Có một sự khác biệt giữa gRPC và framework RPC của thư viện chu

## 4.4.3 gRPC flow

RPC là lời gọi hàm từ xa, vì vậy các tham số hàm và giá trị trả về của mỗi cuộc gọi không thể quá lớn, nếu không thời gian phản hồi của mỗi lời gọi sẽ bị ảnh hưởng nghiêm trọng. Do đó, các lời gọi phương thức RPC truyền thống không phù hợp để tải lên và tải xuống trong trường hợp khối lượng dữ liệu lớn. Đồng thời RPC truyền thống không áp dụng cho các mô hình đăng ký và phát hành không chắc chắn về thời gian. Để khắc phục điểm này, framework gRPC cung cấp các flow cho server và client tương ứng.
RPC là lời gọi hàm từ xa, vì vậy các tham số hàm và giá trị trả về của mỗi cuộc gọi không thể quá lớn, nếu không thời gian phản hồi của mỗi lời gọi sẽ bị ảnh hưởng nghiêm trọng. Do đó, các lời gọi phương thức RPC truyền thống không phù hợp để tải lên và tải xuống trong trường hợp khối lượng dữ liệu lớn. Đồng thời RPC truyền thống không áp dụng cho các mô hình đăng ký và phát hành không chắc chắn về thời gian. Để khắc phục điểm này, framework gRPC cung cấp các stream cho server và client tương ứng.

Flow một chiều của server hoặc client là trường hợp đặc biệt của flow hai chiều. Chúng tôi thêm phương thức channel hỗ trợ luồng hai chiều trong `HelloService`:
Stream một chiều của server hoặc client là trường hợp đặc biệt của stream hai chiều. Chúng tôi thêm phương thức channel hỗ trợ stream hai chiều trong `HelloService`:

```protobuf
service HelloService {
Expand Down Expand Up @@ -197,7 +197,7 @@ func (p *HelloServiceImpl) Channel(stream HelloService_ChannelServer) error {
}
```

Server nhận dữ liệu được gửi từ client trong vòng lặp. Nếu gặp `io.EOF`, client stream sẽ đóng. Nếu hàm exit, Server stream sẽ đóng. Dữ liệu trả về được gửi đến client thông qua stream và việc gửi nhận dữ liệu stream hai chiều là hoàn toàn độc lập. Cần lưu ý rằng thao tác gửi và nhận không cần sự tương ứng một-một và người dùng có thể tổ chức code theo ngữ cảnh thực tế.
Server nhận dữ liệu được gửi từ client trong vòng lặp. Nếu gặp `io.EOF`, client stream sẽ đóng. Nếu hàm exit, stream Server sẽ đóng. Dữ liệu trả về được gửi đến client thông qua stream và việc gửi nhận dữ liệu stream hai chiều là hoàn toàn độc lập. Cần lưu ý rằng thao tác gửi và nhận không cần sự tương ứng một-một và người dùng có thể tổ chức code theo ngữ cảnh thực tế.

Client cần gọi phương thức Channel để lấy đối tượng stream trả về:

Expand Down Expand Up @@ -238,9 +238,9 @@ for {

## 4.4.4 Mô hình Publishing - Subscription

Trong phần trước chúng ta đã hiện thực phiên bản đơn giản của phương thức `Watch` dựa trên thư viện RPC dựng sẵn của Go. Ý tưởng đó có thể sử dụng cho hệ thống publish-subscribe, nhưng bởi vì RPC thiếu đi cơ chế streaming nên nó chỉ có thể trả về 1 kết quả trong 1 lần. Trong chế độ publish-subscribe, hành động publish đưa ra bởi *caller* giống với lời gọi hàm thông thường, trong khi subscriber bị động thì giống với *receiver* trong gRPC client flow một chiều. Bây giờ ta có thể thử xây dựng một hệ thống publish - subscribe dựa trên đặc điểm stream của gRPC.
Trong phần trước chúng ta đã hiện thực phiên bản đơn giản của phương thức `Watch` dựa trên thư viện RPC dựng sẵn của Go. Ý tưởng đó có thể sử dụng cho hệ thống publish-subscribe, nhưng bởi vì RPC thiếu đi cơ chế streaming nên nó chỉ có thể trả về 1 kết quả trong 1 lần. Trong chế độ publish-subscribe, hành động publish đưa ra bởi *caller* giống với lời gọi hàm thông thường, trong khi subscriber bị động thì giống với *receiver* trong gRPC client stream một chiều. Bây giờ ta có thể thử xây dựng một hệ thống publish - subscribe dựa trên đặc điểm stream của gRPC.

Publishing - Subscription là một mẫu thiết kế thông dụng và đã có nhiều hiện thực của mẫu thiết kế này trong cộng đồng opensource. Docker project cung cấp hiện thực tối giản của pubsub như đoạn code sau đây hiện thực cơ chế publish - subscription dựa trên package pubsub:
Publishing - Subscription là một mẫu thiết kế thông dụng và đã có nhiều hiện thực của mẫu thiết kế này trong cộng đồng opensource. Đoạn code sau đây hiện thực cơ chế publish - subscription dựa trên package pubsub:

```go
import (
Expand Down Expand Up @@ -285,7 +285,7 @@ func main() {

Trong đó `pubsub.NewPublisher` xây dựng một đối tượng để release, ta có thể subscribe các topic thông qua `p.SubscribeTopic()`.

Giờ thử cung cấp một hệ thống publishing-subscription khác mạng dựa trên gRPC và pubsub package. Đầu tiên định nghĩa một service publish subscription interface bằng protobuf:
Giờ chúng ta thử cung cấp một hệ thống publishing-subscription khác mạng dựa trên gRPC và pubsub package. Đầu tiên định nghĩa một service publish subscription interface bằng protobuf:

```protobuf
service PubsubService {
Expand Down Expand Up @@ -314,7 +314,7 @@ type PubsubService_SubscribeServer interface {
}
```

Bởi vì `Subscribe`flow 1 chiều phía server nên chỉ có phương thức `Send` được tạo ra trong interface `HelloService_SubscribeServer`.
Bởi vì `Subscribe`stream 1 chiều phía server nên chỉ có phương thức `Send` được tạo ra trong interface `HelloService_SubscribeServer`.

Sau đó có thể hiện thực các service publish và subscribe như sau:

Expand Down Expand Up @@ -389,8 +389,6 @@ func main() {
}
```

[>> mã nguồn clientpub](../examples/ch4/ch4.4/4-pubsub/clientpub/main.go)

Sau đó có thể subscribe thông tin đó từ một client khác:

```go
Expand Down Expand Up @@ -423,6 +421,4 @@ func main() {
}
```

[>> mã nguồn clientsub](../examples/ch4/ch4.4/4-pubsub/clientsub/main.go)

Cho đến giờ chúng ta đã hiện thực được service publishing và subscription khác mạng dựa trên gRPC. Trong phần kế tiếp chúng ta sẽ xét một số ứng dụng nâng cao hơn của Go trong gRPC.
10 changes: 5 additions & 5 deletions ch4-rpc/ch4-05-grpc-advanced.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# 4.5 gRPC Nâng cao

Các framework RPC cơ bản thường gặp phải nhiều vấn đề về bảo mật và khả năng mở rộng. Phần này sẽ mô tả ngắn gọn một số cách xác thực an toàn bằng gRPC. Sau đó giới thiệu tính năng interceptor trên gRPC và cách triển khai cơ chế xác thực Token một cách tốt nhất, theo dõi các lời gọi RPC và bắt các Panic thông qua interceptor. Cuối cùng là cách gRPC service kết hợp với Web service khác như thế nào.
Các framework RPC cơ bản thường gặp phải nhiều vấn đề về bảo mật và khả năng mở rộng. Phần này sẽ mô tả ngắn gọn một số cách xác thực an toàn bằng gRPC. Sau đó giới thiệu tính năng interceptor trên gRPC và cách triển khai cơ chế xác thực Token một cách tốt nhất, theo dõi các lời gọi RPC và bắt các lỗi panic thông qua interceptor. Cuối cùng là cách gRPC service kết hợp với Web service khác như thế nào.

## 4.5.1 Xác thực qua chứng chỉ
## 4.5.1 Xác thực bằng chứng chỉ (certificate)

gRPC được xây dựng dựa trên giao thức HTTP/2 và hỗ trợ TLS rất tốt. gRPC service trong chương trước chúng tôi không cung cấp hỗ trợ chứng chỉ, vì vậy client `grpc.WithInsecure()` có thể thông qua tùy chọn mà bỏ qua việc xác thực chứng chỉ trong server được kết nối. gRPC service không có chứng chỉ được kích hoạt sẽ phải giao tiếp hoàn toàn bằng plain-text với client và có nguy cơ cao bị giám sát bởi một bên thứ ba khác. Để đảm bảo rằng giao tiếp gRPC không bị giả mạo hoặc giả mạo bởi các bên thứ ba, chúng ta có thể kích hoạt mã hóa TLS trên server.

Bạn có thể tạo private key và certificate (chứng chỉ) cho server và client riêng biệt bằng các lệnh sau:
Bạn có thể tạo private key và certificate cho server và client riêng biệt bằng các lệnh sau:

```sh
$ openssl genrsa -out server.key 2048
Expand Down Expand Up @@ -112,7 +112,7 @@ Server cũng sử dụng hàm `credentials.NewTLS` để tạo chứng chỉ, ch

Như vậy chúng ta đã xây dựng được một hệ thống gRPC đáng tin cậy để kết nối giữa Client và Server thông qua xác thực chứng chỉ từ cả 2 chiều.

## 4.5.2 Xác thực token
## 4.5.2 Xác thực bằng token

Xác thực dựa trên chứng chỉ được mô tả ở trên là dành cho từng kết nối gRPC. Ngoài ra gRPC cũng hỗ trợ xác thực cho mỗi lệnh gọi gRPC, để việc quản lý quyền có thể thực hiện trên các kết nối khác nhau dựa trên user token.

Expand Down Expand Up @@ -351,7 +351,7 @@ func main() {
if strings.Contains(
r.Header.Get("Content-Type"), "application/grpc",
) {
grpcServer.ServeHTTP(w, r) // gRPC Server
grpcServer.ServeHTTP(w, r)
return
}

Expand Down
Loading

0 comments on commit c784d37

Please sign in to comment.