Kafka Note

Offsets and Consumer Position

Message lưu trữ trong partition sẽ đi kèm với 1 số ID tự tăng hay còn gọi là offset. Offset về bản chất là 1 dạng unique identifier của message trong partition đồng thời nó cũng thể hiện vị trí của consumer trong partition. Do vậy, nếu 1 consumer có vị trí 5 thì có nghĩa là consumer này đã consume hết những message có offset từ 0 đến 4, message kế tiếp nhận được sẽ có offset là 5.

Có 2 khái niệm về postion liên quan đến consumer cần nắm rõ:

position or current offset – vị trí của message kế tiếp consumer sẽ nhận được khi consume. Nó luôn lớn hơn offset lớn nhất của message mà consumer đã consume được trong partition. Nó sẽ tự động tăng mỗi khi consumer nhận được message thông qua phương thức poll(long) (Java Kafka Client Consumer).

commited position or commited offset – là offset mới nhất đã được lưu giữ an toàn, offset này thể hiện vị trí mà consumer gửi xác nhận đã xử lý xong message này. Lấy ví dụ: Consumer nhận được 20 message, consumer sẽ xử lý lần lượt từng message, sau khi xử lý xong message, consumer sẽ thông báo lại với Kafka offset của message đã xử lý. Consumer tự động commit offsets theo định kỳ hoặc developer có thể chủ động commit thông qua phương thức commitSync hoặc commitAsync.

committed position có ý nghĩa quan trọng khi partition rebalance. Khi một consumer crashé hoặc một consumer mới join group sẽ kích hoạt sự kiện rebalance. Sau khi rebalance, mỗi consumer có thể sẽ được gán với một tập partitions mới. Lúc này consumer sẽ dựa vào committed position mới nhất. của mỗi partition để tiếp tục công việc của mình.

Nếu committed position nhỏ hơn position thì message có offset nằm giữa committed positionposition sẽ được xử lý lại, đồng nghĩa với việc những message này sẽ được xử lý 2 lần.

Message được xử lý lại

Trái lại nếu committed position lớn hơn position, thì toàn bộ message giữa position và committed position sẽ không được xử lý.

Message giữa 2 position sẽ bị mất

Kafka Consumer Group Offset Retention

Có một config trong Kafka Consume là auto.offset.reset. Nó là cấu hình chính sách được sử dụng để quyết định vị trí của message sẽ lấy về khi consume lần đầu tiên join group hoặc sau khi re-join group mà không xác định được offset hiện tại ở bất kỳ đâu trên server (Kafka or Zookeeper). Kafka hiện cung cấp 3 kiểu giá trị để quyết định chính sách auto.offset.reset .

Earliest – khi consumer lần đầu tiên join group và muốn consume toàn bộ message của topic. Consumer sẽ cấu hình auto.offset.reset = earliest.

Latest – Đây là giá trị mặc định, consumer sẽ chỉ nhận được message đến topic từ thời điểm sau khi đã subscribed thành công tới topic hoặc từ thời điểm cuối cùng (last committed offset) sau khi consumer re-joins group.

None – Consumer sẽ nhận được 1 ngoại lệ nếu không xác định được offset hiện tại khi join group. Developer cần quyết định làm gì tiếp theo.

Ok, rồi có một lưu ý nhỏ ở đây, đó là giá trị offsets.retention.minutes được cấu hình trong broker. Giá trị này quyết định sau bao nhiêu lâu thì offset sẽ bị discard, tính từ thời điểm tất cả consumer leave group hoặc từ lần commit cuối cùng nếu consumer này độc lập.

Việc này có ý nghĩa gì, giả sử consumer down trong khoảng thời gian > offset.retention.minutes thì khi consumer này re-join group với cấu hình chính sách mặc định auto.offset.reset = latest thì consumer này sẽ mất toàn bộ message trong khoảng thời gian chết và chỉ nhận được message từ sau thời điểm đã join thành công.

Từ phiên bản Kafka 2.0.0 giá trị này được thiết lập tương đương 7 ngày offsets.retention.minutes=10080. Các phiên bản trước đó chỉ có 1 ngày.

Kafka Connect

Kafka Connect là một framework cho phép stream data in/out tới Apache Kafka. Confluent Platform cung cấp sẵn một số connectors có thể dùng để stream data in/out tới 1 số hệ thống như hệ quản trị cơ sở dữ liệu quan hệ (MySQL, Oracle…) hoặc HDFS.

JDBC connector trong Kafka Connect cho phép lấy dữ liệu (source) từ cơ sở dữ liệu đẩy vào Kafka topic và đẩy dữ liệu (sink) từ Kafka topic tới cơ sở dữ liệu. Nó hỗ trợ toàn bộ các hệ quản trị cơ sở dữ liệu có implement JDBC driver như Oracle, SQL Server, DB2, MySQL, Postgres…

Tables in RDBMS - Kafka Connect --> Kafka | Stream of table change events | Kafka topics

Một số khái niệm cơ bản trong Kafka Connector:

Connectors định nghĩa nguồn hoặc đích đến của dữ liệu. Một connector instance chịu trách nhiệm sao chép dữ liệu giữa Kafka và hệ thống khác. Toàn bộ classses implement hoặc sử dụng bơi connector đều được định nghĩa trong connector plugin.

Confluent Platform đã cung cấp sẵn khá nhiều Source Connector. Ví dụ: JDBC, AWS S3, HDFS… Tuy nhiên nếu cần chúng ta vẫn có thể viết thêm các connector mới. Flow cơ bản thì như hình bên dưới đây:

../_images/connector-model-simple.png

Về cơ bản chúng ta sẽ cần implement 2 interface là Connector và Task.

Class implement Connector sẽ chịu trách nhiệm về nguồn dữ liệu cần trích xuất còn classs implement Task chịu trách nhiệm đọc dữ liệu từ nguồn sau đó tạo các bản ghi dữ liệu để đẩy vào topic của Kafka.

Task là thành phần chính trong kiến trúc của Connector. Mỗi connector instance điều phối một nhóm các task thực thi việc đọc dữ liệu từ nguồn chỉ định. (JDBC, S3…). Bằng việc cho phép chia nhỏ job thành nhiều task, Kafka Connect cung cấp sẵn khả năng xử lý song song và mở rộng việc đọc dữ liệu thông qua cầu hình. Để làm được việc này thì trạng thái của Task được lưu trong Kafka topic là: config.storage.topic và status.storage.topic và quản lý bởi connector. Do vậy mà task có thể khởi động, tạm dừng hoặc khởi động lại bất kỳ lúc nào.

Task Rebalancing khi một connector tham gia vào cụm, những worker sẽ tự động reblance toàn bộ connector trong cụm và những task của connector đó, mục đích để đảm bão mỗi worker sẽ đảm nhận số lượng công việc giống nhau. Quá trình reblancing này cũng diễn ra khi một connecto tăng hoặc giảm số lượng task hoặc khi connector cập nhật lại cấu hình. Khi một worker chết, task sẽ tự động rebalance với những worker đang hoạt động. Trái lại một task nếu chết sẽ bị coi là trường hợp ngoại lệ, do vậy task sẽ không tự động khởi động lại mà cần được khởi động lại thông qua REST API.

../_images/task-failover.png
Task rebalance khi một worker chết.

Workers Connectors và task những phần việc sẽ được lập lịch để thực thi trong 1 tiến trình. Một tiến trình khi khởi chạy sẽ được gọi là 1 worker. Có 2 chế độ cho phép lựa chọn khi start worker là Standalone và Distributed.

Standalone

Distributed cung cấp khả năng mở dộng và tự động và khả năng chịu lỗi (auto failover) cho Kafka Connect. Trong mode distributed, chúng ta có thể chạy nhiều worker với chung group.id, tất cả các worker đang hoạt động sẽ tự động phối hợp cùng nhau lên lịch thực hiện task.

Converters chịu trách nhiệm chuyển đổi định dạng dữ liệu từ dạng byte sang định dạng quy định trong Connector. VD: Json, Protobuf…

How converters are used for a source and sink data transfer
Dữ liệu đọc bởi JDBC Source Connector, ghi vào Kafka và ghi vào HDFS sử dụng HDFS Sink Connector

Transforms

Dead Letter Queue

Cần đốt bao nhiêu calories để giảm 2kg mỗi tháng

Mỡ cơ thể (body fat) dự trữ năng lượng dưới dạng lipids. Lipids được đốt cháy để cung cấp năng lượng cho các hoạt động hàng ngày của cơ thể. Quá trình này diễn ra xuyên suốt trong 24h trong ngày kể cả khi ngủ. Lipid profile trong mỡ cơ thể chiếm ~87%. Do vậy 1kg mỡ cơ thể sẽ có 0.87kg lipid-fat. Tại sao lại chỉ có 87% vì trong mỡ cơ thể cũng bao gồm cả nước nữa.

1g lipid-fat khi sử dụng sinh ra 9 calories. Do vậy để đốt 1kg mỡ cơ thể hay 0.87kg lipid-fat thì lượng calories cần tiêu hao là:

1000 * 0.87 * 9 = 7830 calories

Ok, vậy nếu muốn giảm 1kg mỗi 2 tuần thì số calories cần thâm hụt hàng ngày sẽ là:

7830 / 14 = 559 calories (khoảng 400gram cơm trắng)

Nhẩm nhanh với một người 70kg sẽ cần chạy bộ 10km/ngày ở cường độ cao (threshold pace) để burn khoảng ~550 calories

The twelve-factor app

Disclaimer: Đây không phải bản dịch của 12-Factor. Đây là bản mô tả lại theo cách hiểu của cá nhân mình. Phiên bản đầy đủ của 12-Factor có thể truy cập tại đây: https://12factor.net/

12-Factor app là một phương pháp luận cho việc xây dựng các ứng dụng phân tán triển khai trên môi trường cloud, phân phối dưới dạng như một service. Cách tiếp cận này được pháp triển bởi Adam Wiggins,  co-founder của Heroku một platform-as-a-service. Mục tiêu của Wiggin là tổng hợp các thực tiễn tốt nhất để triển khai một ứng dụng trên Heroku hoặc bất kỳ nền tảng cloud nào.

12-Factor áp dụng cho ứng dụng viết bởi bất kỳ ngôn ngữ nào, sử dụng bất kỳ sự kết hợp nào của backing services (Database, queue, memory cache…).

Code base

Ứng dụng 12-Factor chỉ có duy nhất một codebase được theo dõi bởi version control system như Git, Mercurial hoặc Subversion nhưng sẽ có nhiều bản triển khai trên nhiều môi trường khác nhau (staging, dev, production …).

codebase-deploys
Mỗi codebase có nhiều phiên bản triển khai

Hiểu đơn giản thì nếu bạn đang có nhiều hơn 1 codebase thì nó không phải một ứng dụng mà là một hệ thống phân tán. Nhiều ứng dụng chia sẻ code giống nhau sẽ vi phạm 12-Factor. Giải pháp ở đây là đóng gói thành thư viện và sử dụng thông qua dependency manager.

Dependencies

Một ứng dụng 12-Factor cần khai báo rõ ràng các dependencies của nó. Đã qua rồi cái thời developer cần tìm kiếm các file jars/dependencies thả vào project và cố gắng biên dịch nó. Ngày nay hầu hết các ngôn ngữ lập trình đều có hệ thống quản lý gói cho việc phân phối các thư viện hỗ trợ. Ví dụ như NPM cho NodeJS, Pip cho Python, Maven Repositories cho Java, Rubygems cho Ruby… Những thư viện này được cài đặt thông qua một hệ thống quản lý gói có thể được cài đặt trong phạm vi toàn hệ thống (được biết đến như là “site packages”) hoặc giới hạn phạm vi trong thư mục chứa ứng dụng (được biết đến như là “vendoring” hay “bundling”).

Ứng dụng 12-Factor cũng không được sử dụng bất kỳ công cụ hệ thống nào. Ví dụ: shell out đến ImageMagick hoặc curl. Mặc dù những công cụ này tồn tại trên nhiều hệ thống tuy nhiên không có gì đảm bảo rằng chúng sẽ tồn tại trên tất cả hệ thống nơi ứng dụng sẽ triển khai hoặc liệu phiên bản được tìm thấy trên hệ thống sẽ tương thích với ứng dụng. Nếu ứng dụng cần shell out đến một công cụ hệ thống thì công cụ này nên được đóng gói cùng ứng dụng.

Config

Lưu trữ cấu hình trong biến môi trường. Một cấu hình ứng dụng là mọi thứ mà có khả năng thau đổi giữa các bản triển khai (staging, production, developer….). Bao gồm:

  • Đặc tả kết nối đến cơ sở dữ liệu, memcached và các dịch vụ phía sau
  • Ủy quyền đến các dịch vụ bên ngoài như Amazon services hay Google cloud
  • Các giá trị trên mỗi triển khai ví dụ như hostname chính thức cho bản triển khai.=

Ứng dụng lưu trữ cấu hình như hằng số trong code vi phạm 12-Factor. Trên thực tế cấu hình thay đổi tùy theo phiên bản triển khai, code thì không.

Ứng dụng 12-Factor lưu cấu hình trong biến môi trường (thường viết ngắn gọn là env vars hoặc env ). Các biến môi trường dễ dàng thay đổi giữa các triển khai mà không phải thay đổi code, không giống như tệp cấu hình, chúng chỉ có nguy cơ nhỏ khong may bị đánh dấu trong code repo, và cũng không giống như tệp cấu hình tùy chỉnh, hay các cơ chế cấu hình khác ví dụ Java System Properties, chúng là theo chuẩn không thể biết của ngôn ngữ lập trình và hệ điều hành.

Backing services

Một backing services là bất kỳ một service nào mà ứng dụng này sử dụng qua mạng như một phần của hoạt động bình thường. Backing services bao gồm các local service hoặc từ bên thứ ba như cơ sở dữ liệu, message queues, cache services.

Mỗi một backing service là một resource. Ví dụ: một cơ sở dữ liệu MySQL là một resource, hai cơ sở dữ liệu MySQL (shardung at the application layer) được xác định là 2 resources riêng biệt. Ứng dụng 12-Factor coi những cơ sở dữ liệu này như những tài nguyên đính kèm, giảm thiểu sự phụ thuộc của chúng với phiên bản triển khai của ứng dụng.

attached-resources
Một phiên bản production được gắn vào 4 backing services

Resource có thể gắn vào hoặc tách ra từ các bản triển khai nếu muốn. Ví dụ nếu CSDL của ứng dụng bị lỗi, người quản trị có thể chuyển sang một CSDL khác mà không cần thay đổi bất kỳ dòng code nào.

Build, release, run

Ứng dụng 12-Factor có 3 giai đoạn chính: build, release, run.

  • Build là quá trình compile code từ VCS và đóng gói thành một phiên bản ứng dụng.
  • Giai đoạn release là khi kết hợp bạn build có được từ trước cùng với các cầu hình cần thiết của ứng dụng. Sẵn sàng cho việc triển khai trên môi trường thực tế.
  • Giai đoạn run là khi ứng dụng đã triển khai và hoạt động trên môi trường thực tế.

release
Compile code -> build sau đó kết hợp với cấu hình tạo ra 1 bản release

Mọi bản phát hành luôn có một ID duy nhất. Có thể sử dụng timestamp phát hành như 2019-21-03-16:11:03 hoặc một số tự nhiên tăng dần như v1001. Bất kỳ thay đổi nào đến bản build (ví dụ: bug fixes) cũng cần một bản release mới.

Processes

Thực thi ứng dụng như một hoặc nhiều tiến trình phi trạng thái. Các tiến trình theo 12-Factor thì không có trạng thái và không chia sẻ bất kỳ thứ gì. Bất kỳ dữ liệu cần được duy trì phải được lưu ở một backing service, thông thường là CSDL.

Dữ liệu phiên làm việc (session state) nên được lưu trữ thông qua một backing service có time-based expiration. Ví dụ: Hazelcast, Redis, Memcached

Port binding

Ứng dụng 12-Factor không bao gồm web server mà thay vào đó sử dụng giao thức HTTP như một service bằng cách binding đến một cổng và lắng nghe request đến cổng đó. Điều này đảm bảo ứng dụng hoàn toàn khép kín và không dựa vào một web server cụ thể.

HTTP không phải là dịch vụ duy nhất có thể sử dụng port binding. Hầu như bất kì kiểu server software nào cũng có thể chạy thông qua tiến trình binding port và chờ request đến cổng này. Ví dụ: Redis, Memcached

Concurrency

Trong ứng dụng 12-Factor các loại công việc khác nhau được xử lý bởi các tiến trình khác nhau. Các tiến trình trong ứng dụng 12-Factor lấy các gợi ý mạnh mẽ từ mô hình tiến trình của unix cho các dịch vụ daemon đang chạy. Sử dụng mô hình này, nhà phát triển có thể kiến trúc ứng dụng của họ để xử lý các workload đa dạng bằng cách gán mỗi kiểu công việc cho một kiểu tiến trình. Ví dụ, các HTTP request có thể được xử lý bởi các tiến trình web, và các task (nhiệm vụ) chạy nền thời gian dài được xử lý bởi một tiến trình worker.

process-types
Scale thể hiện tiến trình đang chạy. Work load thể hiện các kiểu của tiến trình

Về cơ bản ứng dụng 12-Factor phải có khả năng mở rộng theo chiều ngang, áp dụng các tiến trình phi trạng thái, không chia sẻ ứng dụng có thể mở rộng liên tục.

Disposability

Tiến trình của ứng dụng 12-Factor cần có tính sẵn sàng có nghĩa là có thể bậ hặc tắt khi có thông báo tại một thời điểm nào đấy. Điều này dễ dàng cho việc mở rộng, triển khai nhanh chóng khi thay đổi code hoặc cấu hình.

Các tiến trình nên cố gắng giảm tối đa thời gian khởi động. Lý tưởng là một tiến trình mất vài giây tính từ lúc khởi động đến khi sẵn sáng nhận request và job.

Dev/prod parity

Tính tương đồng giữa các phiên bản. Giữ môi trường development, staging và product ion giống nhau nhất có thể. Trong lịch sử, đã có những lỗ hổng thực tế giữa development và production. Ứng dụng 12-Factor được thiết kế để triển khai liên tục bằng việc giảm thiểu khoảng cách giữa development và production.

  • Developer có thể viết code và triển khai ngay sau đó.
  • Developer viết code chịu trách nhiệm deploy và theo dõi trong môi trường production.
  • Giữa môi trường development và production giống nhau nhất có thể. Ví dụ sử dụng docker.

Logs

Theo 12-Factor log là một luồng các sự kiện được sắp xếp theo thứ tự thời gian thu thập từ các luồng đầu ra của toàn bộ các tiến trình đang chạy và các backing services. Quá trình này diễn ra liên tục miễn là ứng dụng còn đang hoạt động.

Một ứng dụng 12-Factor không chịu trách nhiệm định tuyến hoặc lưu trữ dòng dữ liệu đầu ra của nó. Nó không cố gắng ghi hay quản lý các logfile. Thay vào đó mỗi tiến trình đang chạy sẽ ghi trực tiếp luồng sự kiện của nó, không sử dụng bộ đệm (unbuffered) tới stdout.

Developer có thể view log trên terminal hoặc điều hướng tới log collector. Ví dụ: Logplex, Fluentd, Logstash…

Admin processes

Chạy các task admin/management như các tiến trình one-off (một lần).

Processes formation là một loạt các tiến trình mà được sử dụng để thực hiện công việc thường lệ của app (ví dụ xử lý các web request) khi nó chạy. Các nhà phát triển sẽ thường thực hiện các task mang tính quản trị hoặc bảo trì cho ứng dụng. Ví dụ:

  • Database migration, backup.
  • Run shell console
  • Run script

 

Chuẩn hóa vector

Ta có vector x và y. Phép nhân hoặc chia làm thay đổi chiều dài của vector mà không ảnh hướng đến phương và hướng. OK, câu hỏi ở đây là làm thế nào chúng ta biết được chiều dài của một vector? Nếu biết trước các thành phần (x và y).

Hiểu được cách tính chiều dài (hay còn gọi là độ lớn) của vector là vô cùng quan trọng và hữu ích.

9150ff25c140f6abd6da845d59533880324158a9

Chiều dài hoặc độ lớn của vector v được ký hiệu là ss_15

Hình vẽ trên cho thấy mũi tên nối 2 điểm x,y tạo thành một tam giác vuông. Các cạnh bên là các thành phần với cạnh huyền chính là mũi tên. Với tam giác vuông này chúng ta có thể áp dụng công thức của nhà toán học Pythagoras mô tả mối quan hệ giữa các cạnh và cạnh huyền trong một tam giác vuông.

Trong tam giác vuông, bình phương cạnh huyền bao giờ cũng bằng tổng bình phương hai cạnh còn lại.

f400c601f9a8be82ce642b4d0fc6f4962802bbd9

Áp dụng công thức trên ta có mã hiện thực như sau:

/**
 * Compute magnitude of vector
 */
public double length() {
    return Math.sqrt(dX * dX + dY * dY);
}

Việc tính toán được độ lớn của vector mở ra nhiều khả năng, đầu tiên là chuẩn hóa vector. Trong một số trường hợp ta chỉ quan tâm đến hướng của vector đó mà bỏ qua độ lớn của nó. Với trường hợp như vậy ta thay đổi độ lớn của vector đó về 1. Những vector có tính chất như trên ta gọi chúng là vector đơn vị. 

6ade290db694921cc465883fb070d8a1dbb3447e

Ta chuẩn hóa vector bằng cách chia mỗi thành phần cho độ lớn cuả nó. Kí hiệu làss_18:

ss_17

/**
 * Normalize a vectors length....
 *
 * @return normal vector
 */
public Vector normalize() {
    Vector vn = new Vector();

    double length = Math.sqrt(this.dX * this.dX + this.dY * this.dY);
    if (length != 0) {
        vn.dX = this.dX / length;
        vn.dY = this.dY / length;
    }
    return vn;
}

Tích vô hướng hai vector

Giả sử ta có 2 vector
ss_8

ss_10

tích vô hướng của hai vector này (hay còn gọi là dot product vì được biểu diến bằng một dấu chấm) được tính bởi công thức sau:

ss_19

Bằng việc áp dụng các phương pháp hình học, ta chứng minh được mối quan hệ giữa tích vô hướng và góc giữa các vector này như sau:

ss_20

Dựa theo công thức trên, ta có thể suy ra một số đặc điểm của 2 vector khi có tích vô hướng của chúng:

  • Nếu ss_22 : 2 vector vuông góc với nhau.
  • Nếu ss_23 : góc giữa 2 vector nhỏ hơn 90 độ.
  • Nếu ss_24: góc giữa 2 vector lớn hơn 90 độ.

Giả sử ta có 2 vector
ss_8

ss_10

tích vô hướng của hai vector này (hay còn gọi là dot product vì được biểu diến bằng một dấu chấm) được tính bởi công thức sau:

ss_19

Bằng việc áp dụng các phương pháp hình học, ta chứng minh được mối quan hệ giữa tích vô hướng và góc giữa các vector này như sau:

ss_20

Dựa theo công thức trên, ta có thể suy ra một số đặc điểm của 2 vector khi có tích vô hướng của chúng:

  • Nếu ss_22 : 2 vector vuông góc với nhau.
  • Nếu ss_23 : góc giữa 2 vector nhỏ hơn 90 độ.
  • Nếu ss_24: góc giữa 2 vector lớn hơn 90 độ.

Tại sao khi vận động mạnh bạn lại có thể bị đau cơ?

Trong phần lớn các trường hợp đau cơ, nguyên nhân chính là do sự tích tụ acid lactic trong cơ. Khi đó, pH của các tế bào cơ thay đổi và toàn bộ cơ bị ảnh hưởng. Đau cơ làm cho chúng ta mệt mỏi, ngại vận động và chỉ muốn nghỉ ngơi, nằm ngủ.

Vậy tại sao acid lactic lại bị tích tụ? Khi chúng ta hoạt động mạnh, cơ thể không cung cấp đủ O2 cho các tế bào cơ hô hấp hiếu khí tạo ATP dùng trong quá trình co cơ. Để khắc phục vấn đề này, các tế bào cơ lên men lactic mà không cần O2, cung cấp lượng ATP cần thiết trong khi máu chưa đưa được O2 đến cơ. Kết quả là acid lactic bị tích tụ trong cơ.

Nhưng cơ thể con người là một hệ thống thông minh và hoạt động hiệu quả! Acid lactic tích tụ trong cơ được vận chuyển về gan và chuyển hoá lại thành glucose. Toàn bộ chu trình chuyển hoá này có tên là chu trình Cori.

13439089_659256224222750_4595931950515692394_n

Nếu lượng acid lactic trong cơ bị tích tụ quá nhiều, không được chuyển hoá (do các nguyên nhân khác nhau) sẽ gây ra các cơn đau khủng khiếp. Muốn tránh được điều này, cách tốt nhất là bạn nên tập thể dục đều đặn. Việc tập thể dục sẽ tăng cường hoạt động của hệ hô hấp và hệ tuần hoàn, qua đó làm tăng lượng O2 máu đưa đến cơ, giảm lượng acid lactic tích tụ.
2 người tìm ra chu trình Cori là Gerty Cori và Carl Cory, cả 2 cùng nhận giải Nobel năm 1947 nhưng không phải là do khám phá ra Cori cycle.

Java concurrency (multi-threading)

1. ExecutorService

ExecutorService là một framework sinh ra với mục đích đơn giản hóa việc thực thi các task theo cơ chế bất đồng bộ. Về cơ bản ExecutorService tự động khởi tạo thread pool và cung cấp các API cho phép developer assigning task tới pool.

ExecutorService không tự động destroyed khi không có task nào thực thi. Nó sẽ alivewait for new work. Điều này cũng hữu ích trong một số trường hợp khi số lượng task là không cố định và không biết trước tại thời điểm compile. VD: 1 program SocketServer.

Trong các trường hợp khác sẽ không thể kiểm soát khi chương trình đã thực thi xong nhiệm vụ nhưng không thể dừng lại chỉ bởi ExecutorService  vẫn alive và tiếp tục wait for new work. Để tránh trường hợp này java cung cấp 2 API là shutdown() và shutdownNow()

shutDown() sẽ dừng việc tiếp nhận các task mới và shut down hoàn toàn sau khi những submitted task được thực thi.

shutdownNow() sẽ ngay lập tức destroy ExecutorService và trả lại danh sách các task đang đợi để thực thi. Developer cần quyết định sẽ làm gì với những task này.

Oracle khuyến cáo sử dụng cả 2 phương thức shutdown của ExecutorService. Sử dụng shutdown() trước để vô hiệu hóa việc tiếp nhận các task mới. Đợi trong 1 khoảng thời gian nhất định để toàn bộ các task được thực thi. Sau quãng thời gian này thực hiện lệnh shutdownNow()

 void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }
 }

awaitTermination(long timeout, TimeUnit unit) sẽ block thread cho đến khi toàn bộ task được thực thi sau lệnh shutdown()  hoặc khi hết thời gian đã định trước.

2. Futures and Callables

Trong trường hợp thread cần trả về 1 kết quả chúng ta cần implement interface  java.util.concurrent.Callable. Callable object cho phép trả về một giá trị sau khi task hoàn thành.  Sau khi submit object Callable tới ExecutorService sẽ nhận lại một object type java.util.concurrent.Future cho phép chờ lấy kết quả hoặc kiểm tra trạng thái thực thi task.

Callable<Long> task = new SampleCallable();
    Future<Long> result = executorService.submit(task);

    // A special blocking method
    // Calling the get() method while the task is still running will
    // cause execution to block until the task is properly executed and
    // the result is available.
    logger.debug("Result {}", result.get());
}

JVM Ecosystem Report 2018

Công ty Snyk và Java Magazine vừa mới công bố bản báo cáo về JVM Ecosystem. Hơn 10k developer từ khắp nơi trên thế giới đã tham gia khảo sát. Có rất nhiều điều thú vị trong bản report này.  Chi tiết của report có thể download tại đây

1. Which Java vendor’s JDK do you use in production for your main applications?

2018-10-18-14-00-snyk.io

Dễ hiểu khi có tới 70% developers lựa chọn Oracle JDK tuy nhiên điều này có thể sẽ thay đổi trong tương lai khi Oracle chính thức yêu cầu commercial license để sử dụng Java SE

6. Which IDE do you develop with?

ide-popularity-intellij-idea-eclipse-netbeans

Có thể thấy sự hiện diện của Visual Studio Code ở đây mặc dù chỉ 1%. Hơi bất ngờ khi vẫn còn tới 3% developer sử dụng vi/vim/Emacs/etc để làm việc. Mình có dùng notepad để coding một thời gian hồi còn đi học. Đúng là một ác mộng

9. Do you use static security tools in your testing?

do-you-use-static-security-tools-in-your-testing_-1

72% developers không sử dụng security tools khi kiểm thử. Có lẽ Synk không thích điều này :).  Snyk.io là công ty về network security, phát triển các công cụ chịu trách nhiệm giám sát, phát hiện sớm các lỗ hổng từ những dependencies mà developer sử dụng trong project.

10. Which CI server do you use?

ci-tool-popularity-jenkins-bamboo-teamcity

Continuous integration gần như đã trở thành tiêu chuẩn trong phát triển phần mềm. Việc tích hợp CI cũng đã dễ dàng hơn rất nhiều tuy nhiên vẫn có đến 21% developers không sử dụng CI trong dự án.

12. Which code repository do you use for your main project?

code-repository-popularity-github-bitbucket-gitlab

Trái với suy nghĩ của mình Github không dẫn đầu thị phần repository hosting service. Không rõ việc Microsft mua lại Github có ảnh hưởng đến quyết định sử dụng repository của developer không?

30. How old are you?

how-old-are-you

 

Garmin activities comapre

Mình vừa phát hiện ra Garmin cho phép comapre 2 activities cùng loại với nhau.

Điều này khá thú vị khi bạn muốn kiểm tra lại thành tích ở lần chạy trước đó để coi khả năng mình đang tiến bộ hay thụt lùi 🙂 . Rất tiếc là hiện tại chỉ hỗ trợ compare tối đa 4 hoạt động cùng loại. Nếu Garmin có thể tự động xuất báo cáo dạng biểu đồ của tất cả hoạt động thì sẽ tốt hơn rất nhiều.

Mình vừa chén xong 2 buổi long run vào 2 cuối tuần vừa rồi. Có vẻ mọi thứ đang dần trở lại, mình chủ động nghỉ sau hơn 1 giờ để giữ chân. Thời gian sau chấn thương mình duy trì lịch tập với 1 buổi leg strength và 1 long run. Tuần này mình sẽ bổ sung thêm 1 buổi interval nữa. Như vậy 1 tuần sẽ có 2 buổi chạy, nếu mọi thứ ok mình sẽ thêm vào 1 buổi easy run vào giữa tuần.

 

Hồi phục… IT Band

Cuối tuần vừa rồi mình đã có 2 buổi chạy bộ liên tiếp ngay gần nhà. Mình chủ động tính toán thời gian để buổi chạy không vượt quá 1 giờ. Chấn thương khiến mình cẩn trọng trong từng bước chạy, cảm nhận trọng lực dồn đều từ bàn chân lên cơ tứ đầu, hamstring.

Mình cảm nhận được rõ điều này vì toàn bộ các nhóm cơ chân tới mông của mình vẫn còn khá căng cứng. Hậu quả của Leg day từ hôm thứ 4 tuần trước, đáng lẽ mình không nên chạy bộ vào cuối tuần này tuy nhiên mình vẫn quyết định xỏ giầy. “Mình đã nghỉ 1 tuần rồi. Cùng lắm đau 1 chút sẽ nghỉ 1 tuần nữa”, mình đã nghĩ vậy.

Hôm nay là ngày thứ 2 sau buổi chạy chân cẳng mình vẫn ổn. Có vẻ đầu gối của mình đã dần ổn định trở lại :). Để nói về cái việc này có ý nghĩa như thế nào thì phải quay trở lại buổi chạy 1 tuần trước. Mình bị đau IT band ngay sau 2 bài chạy nhỏ (20phút/bài) và tuần trước nữa đó thì mình không thể chạy nổi 3km mặc dù đã lê lết ở pace 8:50-9.

Cái chấn thương IT Band này đã đeo đẳng với mình suốt từ tháng 8 đến giờ.  Để chuẩn bị cho Tràng An Marathon mình đã tăng số buổi chạy trong tuần lên từ tháng 7. Giữa tuần có 1 buổi Interval, cuối tuần là Long run. Có điều vì lười dậy sớm ra công viên nên mình đã tập Interval trên treatmill tại phòng gym. Chạy trên treadmill mình không thể đẩy tốc độ lên cao ngay lập tức, nguyên tắc an toàn treadmill là sau khi tăng speed thì tốc độ của máy mới được đẩy lên sau vài giây. Do vậy mà nhịp chạy nhanh của mình chỉ ở mức bình thường, hear rate trung bình loanh quanh ở cuối zone 3.  Kết quả cải thiện đáng kể, ở buổi Long run cuối tuần mình chạy khá ổn và mình quyết định tăng pace vào mỗi buổi Long run cuối tuần. Cần phải nói thêm là mình vẫn duy trì Leg day mỗi tuần ở phòng Gym. Nghĩ lại giai đoạn này đôi chân của mình bị hành hạ tương đối với mỗi tuần 2 buổi chạy treadmill + 1 buổi full leg + 1 long run vào cuối tuần.

Và kết quả là chấn thương ập đến.