Đầu tiên, mỗi khi cập nhậtthông tin, lịch trình quảng cáo thì nhân viên của công ty sẽ đến thiết lập thủ công trên từng thiết bị vì họ không có hệ thống quản lý, điều khién tat cả thiết
Kiến trúc hệ thống o.cceccecceccescessesseessessessessssssessessesssessessessesssssessessessesseeseesess 51 1 _ Kiến trúc tổng quan -¿©2+k+EE+EE++EE+EEeEEerErrkrrkerkerree 51 2 Mụ hỡnh cẽuSf€T Gv SH ng Hệ 52 3 Mô hình thiết bị hiển thị - Signage Content Player (SCP)
Kiến trúc Dashboard cc:cc+esrrkrrrrrrtrrrrrrrrrrrkee 58 3.2 Các giải pháp xử lý đề xuất ¿+2+¿+cx+2zxtEESEkrErkrrkkerkrerkerrree 60 3.2.1 _ Xử lý real-time với SOCK€(.1O SG Gv ereg 60 3.2.2 Xác thực người dùng và thiết bị -¿2cs+cxecxe+r+rxerxerree 62 3.2.3 Quản lý User, Role va Permission 5+5 <<+£+<£+s++x+ 64 3.2.4 Quản lý và giám sát thiết bị ¿- 5x c++zvExerkerkrrxerxerkerree 67 3.2.5 Quan lý quảng cáo, danh sách phát quảng cáo - - ô 67
Kiến trúc của dashboard được minh hoạ trong hình 3.7 được xây dựng bằng ReactJS Về cơ bản thì mỗi thành phan trong dashboard được xây dựng dựa vào từng việc quản lý các tài nguyên khác nhau: Quản lý nhân viên, quản lý thiết bị, quản lý quảng cáo, quản lý roles và permissions, quản lý các danh sách phát, Trong đó giao diện thiết kế giao diện quảng cáo sử dụng React- grid-layout là một thư viện Javascript hỗ trợ linh hoạt trong việc thiết kế giao diện.
Morogement View Ads |_ Component Š Component & | Delete Asset
3.2 Các giải pháp xử lý đề xuất.
3.2.1 Xử lý real-time với Socket.io
Khi làm việc và xử lý thông tin có liên quan đến thời gian thực thì việc sử dụng HTTP là không thích hợp vì nó cần một khoảng thời gian dé có được thông tin dữ liệu và sẽ bị ngắt kết nối giữa Client và Server khi request hoàn thành Chính vi ly do đó chúng tôi đã chon Socket.io (Websocket) dé triển khai hệ thống quản lý thiết bị real-time.
Với kiến trúc hệ thống Cluster sử dung Socket sẽ gặp phải hai van dé lớn:
Van đề thứ nhất xảy ra khi sử dụng Nginx Load Balancer với nhiều Node.js
Server va Client sử dung Polling transport Nginx sử dung logic round-robin dé điều phối các request, gia sử có ba Node.js Server Client gửi request kết nối Server bang cách sử dung Polling, Nginx điều phối request đó tới Node.js Server 1 và Server đăng ky Session ID của Client dé thông báo với Client đã được kết nối với Server này Lần thứ hai, khi Client thực hiện bắn bất kỳ event nao, Client sẽ gửi một request mới mà lúc này Nginx chuyền tiếp tới Node.js Server 2 Lúc này Node.js Server 2 nhận event từ Client không được kết nối với nó, Server sẽ trả về một thông báo lôi Session ID unknown.
Page 1 OC )© https:/draw.io
Polling Req 2 Session ID unknown
Hình 3.8: Load Balancer & Polling Transport
Với Websocket transport, sẽ không gặp bat kỳ lỗi nào như thé này bởi vi Client với Server kết nối một lần và sau đó nhận / gửi frame thông qua giao thức
Dé khắc phục được van dé này hiện tại có một số cách đó là sử dung Sticky session dé dam bao răng tat cả các request được liên kết với session ID cụ thể đều được gửi đến Server ban đầu Cách thứ hai đơn giản hơn và cũng là cách chúng tôi sử dụng trong luận văn này đó là ép Client kết nối với Server chỉ bằng Websocket transport, hạn chế ở cách này là sẽ không hỗ trợ cho các trình duyệt cũ.
Van đề thứ hai: Mỗi Client kết nối với một Server Tình huống xảy ra khi Client 1 kết nối với Node.js Server 1 và Client 2 kết nối với Node.js Server 2. Client 1 muốn bắn event tới cho Client 2, lúc này Node.js Server 1 nhận event từ Client 1 nhưng không thể gửi cho Client 2 vi Node.js Server 1 không kết nôi với Client 2.
C1 emits data for C2 C2 connected to N2
Hình 3.9: Emit event với hệ thống cluster
Chi có một giải pháp duy nhất, có thé được thực hiện theo nhiều cách dé khắc phục vấn đề này Tạo một layer giao tiếp nội bộ giữa các Server, nó có nghĩa là moi Server sẽ có thê gửi request đên các Server khác.
Bang cách nay, Node.js Server 1 sẽ gửi một request đến Node.js Server 2 và 3 và chúng kiểm tra xem Client 2 có được kết nối với chúng hay không Nếu Client 2 được kết nối, Server đó sẽ băn ra dữ liệu được cung cấp bởi Node.js
Trong luận văn nay, chúng tôi sử dung tính năng Pub/Sub của Redis dé giao tiếp giữa các Server Bằng package socket.io-redis, chúng tôi thiết một Socket adapter dé các Server giao tiếp với nhau thông qua Redis.
Node.js 3 sŸ al ol
Hình 3.10: Hệ thống Cluster sử dung Socket với Redis 3.2.2 Xác thực người dùng và thiết bi
HTTP là một giao thức stateless Mỗi khi Client gửi request, trước tiên nó sẽ thiết lập kết nối với Server, sau đó ngắt kết nối sau khi request hoàn tất. Phương pháp này có thê tiết kiệm tài nguyên kết nối bị chiếm dụng trong quá trình truyền, nhưng cũng có một vấn đề: mỗi request là độc lập và Server không thé xác định liệu request này và request trước đó có phải từ cùng một người dùng hay không và do đó không thé xác định người dùng là ai va từ đâu.
Có rat nhiêu cách đê xác thực người dùng vi dụ: lưu session, cookie, JWT, mục đích chính là tránh đê người dùng cung cap lại tài khoản và mật khâu sau khi đăng nhập.
Chúng tôi sử dụng Json Web Token (JWT) để xác thực Ý tưởng đăng sau
JWT khá đơn giản: Khi người dùng đăng nhập, Server tạo token về cơ bản là mã hóa base64 của đối tượng JSON có chứa payload, cộng với signature được hash bang secret key do Server sở hữu Payload có thé chứa dit liệu được sử dụng dé xác thực và ủy quyền người dùng, ví dụ: userld JWT được gửi lại cho Client và được nó sử dụng để xác thực mọi yêu cầu API.
Khi Server xử lý một request, nó sẽ nhận payload của token và tạo lại signature bằng secret key của nó Nếu hai signature khớp nhau, payload có thê được coi là hợp lệ, không bị thay đổi và người dùng đó được xác minh.
Client có thể lưu token ở localStorage sau đó gắn vào Authorization Header dé xác thực nhưng cách này sẽ khiến token bị mat bat cứ khi nào trang được làm mới hoặc đóng và sau đó mở lại Điều này dẫn đến trải nghiệm người dùng kém Vì vậy lựa chọn lưu JWT ở cookie có thê giải quyết được vấn đề trên và có thê đễ dàng thiết lập bảo mật: chỉ có HTTPS hoặc chung domain mới được sử dụng cookie.
1 POST /users/login with username and password
2 Creates a JWT expire in 30 minutes with a secret
3 Returns the JWT to Browser on Cookie
4 Calls request and sends the JWT on Cookie
6 Sends response to client from the JWT
Hình 3.11: Xác thực bằng Json Web Token Trong quá trình xác thực, Server không cần truy cập session được lưu trữ ở đâu đó, vì vậy mỗi request có thé được xử lý bởi các Node.js Server khác nhau theo cách rất hiệu quả Không có dữ liệu nào được lưu trong RAM và không cần thực hiện disk I/O, vì vậy cách tiếp cận này thực sự hữu ích khi sử kiến trúc hệ thông Cluster Trong luận văn này chúng tôi chỉ cho phép JWT hợp lệ trong thời gian 30 phút Sau khoảng thời gian này người dùng phải cung cấp thông tin tài khoản dé đăng nhập lại.
Upload tài nguyém oe eeccscecenecesneceseeceseeesaeeeseeceaeeseaeeseaeceeeesaes 69 3.2.7 Tối ưu hóa hiệu suất React ở môi trường Production .- 69 3.3 Phân tích yêu cầu . -¿-+-©©£++++EE£EEEEE2E12E127171121121127171.211 11T, 73
Chúng tôi sử Presigned URL dé Client có thé upload file trực tiếp lên Storage. Cách này có thể khắc phục được các hạn chế sau: Không bị lộ Secret key của Storage nếu upload file trực tiếp từ Client + secret key và không upload thông qua trung gian backend.
Cloudinary có một giải pháp dé vừa có thé đảm bảo tính bảo mật và backend cũng không cần tốn băng thông Đó là Presigned URL, là một URL với các thông số bảo mật, cung cấp một permission tạm thời đề upload file lên Storage.
Dé tạo thành công Presigned URL, chúng ta cần backend làm điều nay Client có thé dùng URL này dé upload file trực tiếp lên storage, như vay backend không cần phải "trung chuyển" file nữa Từ đó van dé băng thông được giải quyết.
1 Request Cloudinary Signature with parameters
2 After authenticate success, creates a signature key with parameters expire in
3 Returns signature key and parameters.
4 Make Presigned URL and use it to upload file
Hinh 3.13: Diagram upload file bang Presigned URL 3.2.7 Tối wu hóa hiệu suất React ở môi trường Production
Dé tối ưu được hiệu suất chúng tôi đã tuần tự thực hiện 3 biện pháp sau:
- Su dụng Webpack dé bundle thành file tĩnh: Khi triển khai React ở môi trường Production, chúng tôi dùng WebPack dé bundle các mã nguồn thành các file tinh có dung lượng file nhẹ Sau đó dùng Nginx Server đê serve các file tĩnh này Browser truy cập vào website sẽ thực hiện
69 download các file tĩnh này về thực thi vì vậy các file tĩnh này càng nhẹ tôc độ load càng cao.
- Nén file nh dưới định dang Gzip: Các file tinh sau khi được bundle tuy là đã giảm được kích thước nhưng vẫn chưa tối ưu được hiệu suất vì kích thước file vẫn còn lớn Biết rằng hầu hết tất cả các trình duyệt đều hỗ trợ chấp nhận các tệp tĩnh ở định dạng nén như Gzip, Brotli và Deflate Chúng tôi chon Gzip vì theo nghiên cứu của chúng tôi, tất cả các trình duyệt hiện đại đều hỗ trợ định dạng đó.
Chúng tôi sử dung package gzipper dé nén thủ công các file này dưới định dang Gzip hoặc thiết lập Nginx dé nén file tự động nhưng chúng tôi muôn giảm tải cho Nginx nên đã nén file san. e