Tuesday, August 6, 2013

Giới thiệu về Unix process

Là một kỹ sư lập trình hệ thống, một server guy, hay là một sys admin, sys dev, sys ops,… phần lớn thời gian bạn sẽ phải làm việc trên hệ thống Unix. Để làm việc trên Unix, chúng ta tương tác với hệ điều hành thông qua các lệnh (command). Mỗi lệnh trên Unix khi thực thi sẽ run một process hoặc một group các processes. Process là một trong những đơn vị cơ bản cấu thành nên hệ điều hành Unix.

Trong bài viết này mình giới thiệu các kiến thức và kỹ thuật cơ bản để làm việc với Process trên Unix. Bài viết sẽ trình bày với code minh hoạ bằng Ruby (rồi bạn sẽ thấy Ruby rất đơn giản). Tất cả các code mình hoạ được chạy trên môi trường Unix (Linux của chính là Unix – nếu bạn chưa biết, vì thế đừng ngần ngại thử nó trên máy bạn).

I. Một số kiến thức tổng quan
Tất cả các chương trình trong Unix thực chất đều là các processes. terminal bạn chạy, apache, nginx, vim, hay bất cứ lệnh nào bạn gõ vào terminal. Process chính là đơn vị cấu thành nên Unix. Nó chính là một instance của chương trình bạn viết ra. Nói cách khác mỗi dòng code của bạn, sẽ được thực thi trên một process.
Unix cung cấp tool `ps` để list ra tất cả các process đang chạy trên hệ thống cho bạn
$> ps -e -opid,ppid,user,rss,command
PID PPID USER RSS COMMAND
1 0 root 152 init [2]
1695 1 root 428 /usr/sbin/sshd
1863 1 root 48 /sbin/getty 38400 tty1
1864 1 root 48 /sbin/getty 38400 tty2
1865 1 root 48 /sbin/getty 38400 tty3
1866 1 root 48 /sbin/getty 38400 tty4
1867 1 root 48 /sbin/getty 38400 tty5
1868 1 root 48 /sbin/getty 38400 tty6
24477 1695 root 2888 sshd: vagrant [priv]
24479 24477 vagrant 1996 sshd: vagrant@pts/0
24480 24479 vagrant 2328 -bash
24591 24480 vagrant 1060 ps -e -opid,ppid,user,rss,command
Ở đây, mình chạy lênh `ps` và show ra các thuộc tính `pid,ppid,user,rss,command` của process (chú ý (1) `ps` có rất nhiều option để chạy, nếu bạn muốn hiểu chỉ tiết, hãy sử dụng `man ps` để biết, (2) kểt quả trả về chỉ là một phần các process trên máy mình). Các thông tin mình muốn hiện thị ở đây bao gồm:
1. PID – Process ID (id của process),
2. PPID – Parent Process ID (id process cha của process đó),
3. USER (tên user trên Unix start process),
4. RSS (Resident Set Size) có thể coi bộ nhớ mà process sử dụng,
5. COMMAND – command mà user sử dụng để chạy processs
Chú ý rằng dòng cuối trong kết quả trả về show ra COMMAND là `ps -e -opid,ppid,user,rss,command` – chính là lệnh mà chúng ta dùng để chạy. Điều đó chứng tỏ, mỗi một command chính là một process !?
Ngoài ra lệnh ps cũng cho chúng ta thấy, mỗi một Process sẽ có một Process ID, và thuộc về một Process cha nào đó.
Process ID là duy nhất đối với mỗi một process, tức là 2 process khác nhau chắc chắn phải có PID khác nhau. Ngoài ra Process ID là không thể thay đổi trong khi chạy process.
1. Làm sao hệ điều hành đánh số các Process ID?
Process ID được đánh số theo thứ tự tăng dần. Bắt đầu từ 0 và tăng lên cho tới khi gặp giá trị maximum.
Giá trị maximum của Process ID là có thể cấu hình được tuỳ vào từng hệ thống.
Trên Linux bạn có thể xem và thay đổi giá trị mặc định của Process ID maximum bằng cách thay đổi file `/proc/sys/kernel/pid_max`
# read current maximum value of process id
$> cat /proc/sys/kernel/pid_max
32768

# set maximum value for process id
$> echo 40000 > /proc/sys/kernel/pid_max
Khi process ID tăng đến giá trị maximum value, hệ điều hành (OS) sẽ quay trở lại đánh số từ một giá trị cụ thế (một số tài liệu nói giá trị này với Linux là 300, và với Mac OS là 100 – mình chưa biết cách để kiểm nghiệm điều này một cách an toàn)
UNIX cung cấp syscall `getpid` trả về Process ID của process hiện tại. Bạn có thể viết một chương trình C đơn gian để lấy ra process id với `getpid`. Tuy nhiên, bài viết này của tôi sẽ tập trung vào ngôn ngữ Ruby
Trong Ruby, muốn lấy Process ID của process hiện tai, bạn sử dụng `Process.pid`.
# file test_pid.rb
puts "Process pid: #{Process.pid}"
Dòng code trên gọi tới hàm `puts` – hàm này có tác dụng in một String ra màn hình.
Chúng ta có thể manipulate các String trong Ruby thông qua các syntax #{}. Code ruby trong #{ } sẽ được thực hiện trước khi truyền cho String
$> irb

irb(main):001:0> puts "Example for String manipulate: 1 + 2 = #{1 + 2}"
Example for String manipulate: 1 + 2 = 3
=> nil
(Các file Ruby có extension là .rb. Để chạy một file ruby, bạn dùng lệnh `ruby`. Không cần phải compile, rất đơn giản phải không)
2. Liệu có phải process nào cũng có Process cha?
Ở  trên tôi đã nói rằng, mỗi một process đều thuộc về một Process cha nào đó.  Nếu bạn suy nghĩ kỹ, bạn sẽ thấy có điều gì đó không ổn? À, thực ra điều này liên quan đến quá trình khởi động của UNIX. Khi UNIX được khởi động, nó sẽ start một process số 0 (với PID = 0) (process này là process của Kernel UNIX). Process 0 sẽ tạo ra cho nó một Process con, Process 1. Trong phần lớn hệ thống, Process 1 được đặt tên là init process, các process khác được tạo ra đều từ init process.
Hãy quay lại ví dụ về lệnh `ps` như ở phần đầu mục I. Bạn có thể để ý thấy PPID của dòng đầu tiên là 0.
Đó chính là process đầu tiên của OS.
Vậy là process trong Unix thực chất được tổ chức dưới dạng cây. Mỗi một node trong cây đại diện cho một process trong
Unix. Gốc chính là process 0, các con của một node chính là các process con của process ứng với node đó.
Trong Ruby, để lấy ra parent process id của một process, chúng ta sử dung `Process.ppid`
# file test_ppid.rb
puts "Process id #{Process.pid}, parent process id #{Process.ppid}"
Cũng rõ ràng đấy chứ. Liệu tôi có quên gì nữa không nhỉ?
Vấn đề là làm sao một process  có thể sinh ra một process con? À đừng lo, tôi sẽ nói kỹ về điều này ở phần 2
3. Process Resource
Ngoài ra lệnh `ps` của chúng ta còn cho thấy, mỗi Process đều có RSS khác nhau. RSS chính là bộ nhớ mà Process sử dụng. Các process khác nhau, có bộ nhớ khác nhau. Nói cách khác, không gian địa chỉ của các Process là riêng biệt. Nhớ thiết kế này mà các Process là độc lập với nhau. Nếu một Process bị chết, thì nó cũng không ảnh hưởng gì tới các Process khác.
Ngoài bộ nhớ, hệ điều hành còn cấp phát cho Process các tài nguyên khác đó là các file descriptor. Nhớ rằng trên UNIX, mọi thứ đều là file.  Điều đó có nghĩa là, devide được coi như file, socket được coi như file, pipe cũng là file, và file cũng là file.  Để cho đơn giản, chúng ta sẽ dùng Resource thay cho khái niệm file nói chung, và file đại diện cho khái niệm file thông thường.
Bất cứ khi nào bạn mở một Resource trong một process, resource đó sẽ được gán với một số file descriptor. File descriptor là không được chia sẽ giữa các process không liên quan. Các resource sẽ sống và tồn tại cùng  với process mà nó thuộc về. Khi process chết đi, các resource gắn với nó sẽ được close và exit.
Mỗi một process sẽ có 3 files descriptor mặc định, bạn hẳn rất quen thuộc với chúng, đó chính là stdin, stdout và stderr. Các file descriptor được đánh số tăng dần từ 0 đến giá trị lớn nhất. Mỗi một process sẽ có một số giới hạn các file descriptor nó được quyền sử dụng.
II. forking
Ở phần I.2, chúng ta đã nói về  process cha và process con, và đưa ra câu hỏi, làm sao một process có thể sinh ra các process khác.
UNIX cung cấp một công cụ tuyệt vời để làm điều đó. Bạn chắc đã đoán ra, đó chính là `fork`.
Theo cá nhân tôi, `fork` có lẽ là một trong những chức năng tốt nhất của UNIX. Vì sao ư?
Vì process con được tạo ra với fork có 2 đặc điểm:
+ process con được copy tất cả các memory từ process cha.
+ process con sẽ được kế thứa từ process cha các resource
Điều này có nghĩa là nếu trong process cha, bạn đã định nghĩa biến a, và gán giá trị cho nó, process con cũng có thể sử dụng biến đó.
Uhm… Không phải như thế sẽ dẫn đến tình trạng 2 process cùng thay đổi một biến hay sao, vả lại chẳng phải các process là độc lập về bộ nhớ.
À, tức là thế này, khi fork một process mới, bộ nhớ của process con và process cha vẫn là độc lập, nhưng hệ điều hành sẽ sử dụng cơ chế copy-on-wright (COW) để thực hiện việc đó. Tức là nếu process con không thay đổi các giá trị trong process cha, process con và process cha sẽ vẫn dùng chung bộ nhớ. Điều này làm cho các process con chỉ đọc, sẽ có memory rất nhỏ. Hay nói cách khác, UNIX cung cấp cho chúng ta một công cụ để chạy các multiprogram với một lượng resource vửa đủ.
Điều này đặc biết tốt khi bạn cần load các library. Process cha sẽ đảm nhiệm việc load các library khác nhau. Sau khi load xong, nó fork ra các process con, và thực hiện việc điều khiển các process con. Các process con nhờ cơ chế COW, không cần phải tốn thời gian load library nữa mà vẫn có thể truy xuất vào các library
Ngoài ra các process cha chia sẻ với process con các resource cũng dẫn đến một kỹ thuật khá thú vị: pre-forking – đặc biệt hiệu quả trong việc lập trình server. Kỹ thuật này được mô tả như sau:
+ Main process khởi tạo một listening socket
+ Main process fork ra một list các children process. Chú ý các children process này cũng sẽ listen trên socket mà main process tạo ra. Nhưng việc dispatch các incomming connection tới các children process là được thực hiện trên kernel. Điều này làm cho việc dispatch các incomming connection là rất nhanh
+ Mỗi process sẽ accept các connection từ shared socket và xử lý chúng riêng biệt
+ Main process sẽ kiểm soát các children process. (cung cấp lệnh để tắt tất cả các children process, tạo một child process mới khi một child process bị crash…)
Kỹ thuật pre-forking được sử dụng rất nhiều. ví dụ: apache (httpd), nginx, celery, postgresql, rabbitmq, ….
Process trong Unix là một lĩnh vực rất thú vị, đặc biệt là trong lập trình hệ thống và lập trình server.
Bài viết của mình chỉ mới đề cập đến một vài kiến thức và kỹ thuật ban đầu với Process. Còn rất nhiều vấn đề mình chưa đề cập, như
+ Tương tác giữa các process (IPC)
+ Điều khiển các process
+ Orphaned, daemon, zoombie, process …

Saturday, August 3, 2013

Compress and Uncompress Files

1) To compress files:
Examples:

tar cvf abc.tar a1.ps a2.tex adir/* # compress files to the file abc.tar
gzip -9 abc.tar /* # create abc.tar.gz file.
tar cvfz abc.tar.gz a1.ps a2.tex adir/* # directly create abc.tar.gz file
zip abc.zip a1.ps a2.tex adir/* # directly create abc.zip file

Note that -9 means the slowest compression method (best compression). By default, -6 is used. -1 means fastest compression method (less compression). The command zip is compatible with PKUNZIP on pc. Thus, the file abc.zip can be uncompressed by WinZip.

2) To uncompress files:
Examples:

tar xvf abc.tar # uncompress abc.tar file
gunzip abc.tar.gz # after uncompress, get abc.tar
tar xvfz abc.tar.gz #unzip and utar *.tar.gz file
unzip abc.zip #unzip .zip file

To view the content of the compressed file:
Examples:

tar tvf abc.tar
tar tvfz abc.tar.gz
unzip -l abc.zip

Khoá nhanh IP đang tấn công DDos

Bước 1: Lấy danh sách những top connection:
netstat -anp |grep 'tcp\|udp' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n
Bước 2: chạy command
route add IP_ADDRESS reject
Bước 3: Gỡ bỏ IP khỏi bảng cấm:

route delete IP_ADDRESS reject

Friday, August 2, 2013

Fix cứng DNS resolver trên Linux

Hầu hết các  hệ thống GNU/Linux đều được tích hợp và sử dụng DHCP Client. DHCP Client cung cấp phương thức cho việc cấu hình một hay nhiều card mạng sử dụng địa chỉ động (DHCP). Tuy nhiên nó lại làm thay đổi tệp tin /etc/resolv.conf mỗi khi khởi động DHCP Client hay kết nối vào một mạng khác. Trong một số trường hợp như DNS server cục bộ trong mạng LAN của bạn không thể phân giải một địa chỉ trên Internet, bạn cần nhờ một nameserver khác phân giải địa chỉ này (chẳng hạn một public DNS server). Do vậy bạn cần giữ cho tệp tin /etc/resolv.conf không thay đổi mỗi khi kết nối mạng. Trong bài viết này Wikilinux xin giới thiệu một số cách để giúp việc giữ cố định nội dung tệp tin /etc/resolv.conf theo ý của bạn.

Giả sử bạn có tập tin /etc/resolv.conf với nội dung:
nameserver 8.8.8.8
nameserver 8.8.4.4
và mục đích là bạn muốn giữ cố định nội dung này.

Cách 1: Gán thuộc tính Read-Only cho /etc/resolv.conf
Ngoài các quyền đọc, ghi, thực thi bình thường; hệ thống Linux còn cung cấp một số thuộc tính đặc biệt cho các tệp tin như read-only… Như vậy khi gán thuộc tính read-only cho tệp tin thì tệp tin đó sẽ không bị thay đổi bởi các chương trình khác nếu chưa xóa bỏ thuộc tính này đi. Để gán thuộc tính read-only ta làm như sau:
sudo chattr +i /etc/resolv.conf
Lưu ý: Đối với Ubuntu tệp tin /etc/resolv.conf là liên kết mềm tới /run/resolvconf/resolv.conf, vì vậy trước khi thực hiện lệnh trên thì bạn cần bỏ liên kết mềm và tạo lại file /etc/resolv.conf trước:
sudo cp /run/resolvconf/resolv.conf /etc/resolv.conf.orig
sudo unlink /etc/resolv.conf
sudo cp /etc/resolv.conf.orig /etc/resolv.conf
sudo chattr +i /etc/resolv.conf
Kết quả: Sau khi gán thuộc tính này, chúng ta yên tâm là nội dung của file /etc/resolv.conf sẽ không bao giờ thay đổi.
Cách 2: Sử dụng đoạn mã bẫy sự kiện trong DHCP.
DHCP không cung cấp cách thức để chỉnh sửa các cấu hình ban đầu, tuy nhiên nếu việc sửa đổi là bắt buộc cần thiết thì chúng ta có thể sử dụng các bẫy sự kiện để ghi đè lên các cấu hình ban đầu. Ban đầu dhcpclient sẽ sử dụng hàm make_resolv_conf() để tạo tệp /etc/resolv.conf mặc định. Nếu muốn thay đổi chúng ta có thể định nghĩa lại hàm này như sau:
# vim /etc/dhcp/dhclient-enter-hooks.d/nodnsupdate
Rồi thêm vào nội dung sau:
#!/bin/sh
make_resolv_conf(){
 echo "nameserver 8.8.8.8" > /etc/resolv.conf
 echo "nameserver 8.8.4.4" >> /etc/resolv.conf
}
Sau đó cấp quyền thực thi cho đoạn mã đó.
 # chmod +x /etc/dhcp/dhclient-enter-hooks.d/nodnsupdate
Cách 3. Sử dụng tệp tin cấu hình dhclient.conf
Tệp tin /etc/dhclient.conf hoặc /etc/dhcp/dhclient.conf chứa các thông tin cấu hình cho client. Bạn có thể bật tắt các thay đổi DNS và các lựa chọn khác cho một card mạng hoặc tất cả các card mạng thông qua tệp tin này.
Để thêm lựa chọn bạn có thể add nội dung như sau:
option domain-name-servers 8.8.8.8, 8.8.4.4
Các chọn lựa khác bạn có thể xem trong man của DHCLIENT.CONF
Cách 4. Cấu hình trong /etc/network/interfaces
Bạn có thể cấu hình DNS namerserver cho một card mạng cố định thông qua việc chỉnh sửa trong /etc/network/interfaces bằng cách thêm trường DNS như sau (trên Debian/Ubuntu):
auto eth0
iface eth0 inet static
     address 192.168.1.10
     network 192.168.1.0
     netmask 255.255.255.0
     broadcast 192.168.1.255
     gateway 192.168.1.254
     dns-nameservers 8.8.8.8 8.8.4.4
Hi vọng bạn có thể sử dụng bài viết này để áp dụng được vào trường hợp cụ thể của mình.
Chúc các bạn thành công.
Wikilinux.vn

Sưu tập lệnh linh tinh

1.Xem service nào đang sử dụng port
getent services <port>

2.Xem trạng thái tất cả dịch vụ:
service --status-all hay ps -A
3.Xem các gói phần mềm đã cài
yum grouplist
chkconfig --list | grep :on
4.

Website share command


http://linuxcommand.org/
Nếu bạn là người hoàn toàn mới, nghĩa là chưa có chút khái niệm nào về Linux command thì đây là 1 trong những địa chỉ phù hợp nhất. Có thể so sánh website này như 1 ngôi trường dạy nghề, từ những điều cơ bản nhất, ví dụ như: câu lệnh – shell là gì, cho tới những phần nâng cao dành cho người đã có kinh nghiệm như làm thế nào để tự viết 1 câu lệnh của riêng bạn?

masterLin  02

2.

http://www.commandlinefu.com/
Có rất nhiều trường hợp bạn định làm 1 việc gì đó với Terminal nhưng lại không thể nhớ chính xác câu lệnh là gì. Nếu lâm vào tình huống như vậy, các bạn hãy nhớ đến CommandLineFu – với mô hình khác giống với 1 “mạng xã hội” thu nhỏ. Tại đây, mọi người chia sẻ các câu lệnh và cú pháp cơ bản, và bạn chỉ việc tham khảo, copy, paste và áp dụng thay vì phải ngồi gõ từng ký tự.

3.

 http://www.shell-fu.org/lister.php
Khá giống với CommandlineFu, ShellFu là 1 lựa chọn khá tốt nếu bạn muốn tự mình tìm hiểu về các dòng lệnh, cú pháp, chức năng... qua ví dụ và hướng dẫn cụ thể. Đối với nhiều người, ShellFu có vẻ giống như 1 trang blog hơn nếu đem so sánh với mô hình mạng xã hội, được quản lý, điều tiết cẩn thận nhưng không có chức năng vote bên trong.

4.

http://www.oreillynet.com/linux/cmd/ và http://ss64.com/bash/
2 địa chỉ hoàn hảo và toàn diện, với nội dung đa dạng, được sắp xếp theo thứ tự bảng chữ cái, người sử dụng sẽ cảm thấy thuận tiện hơn rất nhiều với chức năng tìm kiếm



5. CLI Companion:

Có thể coi đây là sự thay thế khá tốt cho ứng dụng Terminal mặc định của hệ thống. Được chia làm 2 phần chính, bên trên là thư viện các câu lệnh, cú pháp, và dưới là phần thực hiện. Bạn có thể cuộn chuột lên xuống trong thư viện, chọn cú pháp lệnh phù hợp, kích chuột phải và chọn Apply:

masterLin  03

Hoặc sử dụng lệnh sau để cài đặt trong hệ điều hành Ubuntu:

sudo add-apt-repository ppa:clicompanion-devs/clicompanion-nightlies
sudo apt-get update
sudo apt-get install clicompanion


6. Ebook – Bash Guide For Beginners:

Dành cho những người mới bắt đầu tìm hiểu về cấu trúc lệnh cơ bản, các bạn hãy tải cuốn sách điện tử Bash Guide For Beginners này và đọc ở bất cứ đâu, trên máy tính hoặc điện thoại di động. Cuốn sách này chứa hầu hết các điều cơ bản nhất về cú pháp lệnh, được trình bày đơn giản, dễ hiểu và phù hợp với nhiều người (cơ bản và nâng cao).



7. Bash Autocompletion:

1 mẹo được sử dụng khá phổ biến và rộng rãi ở đây là chức năng tự động hoàn thiện cú pháp theo chuẩn – autocompletion. Phím tắt sử dụng ở đây là Tab, ví dụ khi bạn gõ được 1 nửa câu lệnh, khi nhấn Tab hệ thống sẽ tự động hoàn chỉnh cú pháp này cho bạn.

masterLin  04

8. Tạo các alias:

Nếu bạn thường xuyên sử dụng những câu lệnh giống nhau nhiều lần, hãy sử dụng alias. Tương tự như việc khai báo 1 biến dành cho 1 cụm mã chức năng, thay thế dòng lệnh dài bằng ký tự bất kỳ của bạn:

masterLin  05

9. Quản lý các quá trình làm việc của câu lệnh:

Trong phần này, hệ thống lưu trữ tất cả danh sách các câu lệnh bạn đã từng sử dụng trước kia. Sử dụng phím mũi tên di chuyển lên xuống để xem lại các lệnh ở trên, khá đơn giản và hiệu quả.

10. Sử dụng các chức năng lệnh khác nhau:

Là kết quả khi người sử dụng thực hiện 1 cú pháp câu lệnh nào đó, hầu hết mọi người đều sử dụng màu sắc mặc định (màu nâu) của hệ thống mà không hề biết rằng có thể thay đổi thiết lập cơ bản, qua đó dễ dàng phân biệt giữa những dữ liệu khác nhau như cú pháp của câu lệnh hoặc kết quả khi được thực hiện.

Nano

Nano là một trình soạn thảo văn bản dựa trên curse hoạt động trên Unix. Nano vốn dựa trên một bản nhánh (clone) của pico, và là một phần mềm tự do.
Nano là một trình soạn thảo rất dễ sử dụng (dễ hơn nhiều so với vi hay emacs). Nano cải tiến Pico, hỗ trợ UTF-8, cải tiến mầu sắc, copy văn bản mà không cần cắt, lưu lại phiên tìm kiếm cuối, kiểm tra lỗi, canh lề, tìm kiếm trong trình duyệt file, … Nano là một trình soạn thảo đáng tin cậy. Không giống như Pico, việc cài đặt Nano rất dễ dàng và bạn có thể cài đặt Nano trên hầu hết các bản phân phối.
Trong Linux, bản nano thường dùng là GNU nano, phát hành theo giấy phép GPL.
Tính năng:
nano cho phép soạn thảo kí tự với các tính năng đơn giản (mở file, lưu file, v.v...). Do sử dụng thư viện curse hiện đại, nano đọc được các kí tự Unicode.
Từ dấu nhắc hệ thống có thể gọi nano bằng cách gõ lệnh:

$ nano demo.txt
Phím tắt:
Ctrl-O: Lưu file (giữ phím Ctrl và bấm O)
Ctrl-G: Gọi trợ giúp
Ctrl-R: Mở file
Ctrl-C: Thông tin về vị trí hiện thời của con trỏ
Ctrl-X: Thoát khỏi nano
Các phím này bạn cũng không cần nhớ bởi vì nano hiện nó ở phần chân của màn hình soạn thảo