basura



Hi there /guru/programmer's i return today with an exciting question....

As system administrator and newbie

PHP

  developer:
I have some

php

  code that can allow a lot of users connected at same time (800 users), its a basic CMS with auth on mysql database,
its done some optimizations on the code, for example using eaccelerator, mysql_max_connections... on a dedicated server with 1Gb RAM -only-
and other dedicated server behind serving images.

Its not round robin enabled, so when the maximum users get connected i can afford more at same time his sessions...
I have peaks of users asking for images.

I have 2 solutions, one are buying more expensive servers (+100$ each one with 100mbps SLA) and the others are asking for same same problem on expert's to try to get an easy solution.

Do you have some problem like mine?

I would be in contact with high-heavy-traffic

SEO

 's to see how are resolving this issue.

It would be nice how to optimize

PHP

  code, or routines, and try to avoid this on the future...

^_^  Thanks in advance SlimeL0RD

perkiset

How'z eAccellerator treating you? I chose APC over it for performance reasons.

Are you doing your own caching? I have a CMS for my users that allows them to manage large websites on their own. If the page has not changed it is held in RAM for easy return. Pseudocode looks something like (bear in mind this is APC based, eA would be slightly different):


<?

php

 

if ($pageBuff = apc_fetch($_SERVER['REQUEST_URI']))
{
echo $pageBuff;
exit;
}

// process page completely...

apc_store($_SERVER['REQUEST_URI'], $theCompletedPageString);

// end of

php

 ...

?>


This little bit essentially avoids almost my entire

PHP

  routine for pages that don't need to be reconstructed and also avoids the fast, but more kludgy-in-this-situation use of squid. In most cases this has increased throughput by a factor of 10, no lie. Downside: RAM. Big site? you'll need to be careful about your usage. You could consider ram-zipping the file if you wanted to, but you'd need to see how heavy that is under load. Another option is, if your site is header/footer/content or theme/content based (all of mine are) is to store the header/footer in one cached item and the body-content in another. This would reduce the memory footprint of your pages considerably, particularaly since the outer HTML (header/footer or theme) is essentially redundant.

You could even avoid the memory concatenation of this process with this:


<?

php

 

if ($content = apc_fetch($_SERVER['REQUEST_URI']))
{
$header = apc_fetch('myHeader');
$footer = apc_fetch('myFooter');
echo $header, $content, $footer;
exit;
}

?>


The thing you're really looking for is high throughput, because 800 concurrent users in an

Erlang

  matrix is an awful lot of page pulls. (

Erlang

  math essentially can be used to describe chaotic or clumpy usage of a resource - we used it to calculate load against our callcenters) - think about it this way: if you can halve the time it takes to produce halve of your pages, you can return 150% of the pages you currently are with the same resources. With a 10-to-1 ratio the benefit is 1000% increase in performance and everything will feel generaly snappier in general because of the way the resource is used. Of course YMMV, but this is how I go at it and get very good results.

/p

<edit>
I forgot to mention, that as of APC 3.0.13, you can supply an array for apc_fetch, so you could get multiple items at once ie., apc_fetch(array('header', 'footer')) which would return an array with both items instead of two distinct pulls.
</edit>

chide

Perk - purely out of curiosity, how many page loads do you see a day over all your

net

 works?

thedarkness

quote author=perkiset link=topic=736.msg5135#msg5135 date=1201550525

<edit>
I forgot to mention, that as of APC 3.0.13, you can supply an array for apc_fetch, so you could get multiple items at once ie., apc_fetch(array('header', 'footer')) which would return an array with both items instead of two distinct pulls.
</edit>


I think it's worth noting perk that this was restricted to one dimensional arrays last time I checked so if you need to store a multi serialize it first.

This looked to be an interesting approach on the last modified/ttl front but I haven't tested it yet;

http://

php

 

.net

 /manual/en/function.apc-store.

php

 #70896

Cheer,
td

perkiset

quote author=thedarkness link=topic=736.msg5182#msg5182 date=1202099692

I think it's worth noting perk that this was restricted to one dimensional arrays last time I checked so if you need to store a multi serialize it first.

Lost me on that one TD - the requesting array must be one dimensional or course - because it wouldn't make sense to use an array of names you want to request in a multi dimensional format... but you can store multi dimensionals in APC no problem... the only thing I know of that doesn't store right is references and system handles (file handles and such) - unless I'm way off base here... am I missing something?

thedarkness

I got my info. from the last two posts here perk;

http://au.

php

 

.net

 /manual/en/function.apc-store.

php

 #70822

Is this not right?

Confused,
td

perkiset

Well first off, that post is from Oct '06 LOL...

But this code returns a multi-dim array, as would be expected:


<?

php

 

$outer = array();
$inner1 = array(1,2,3,4);
$inner2 = array(2,3,4,5);
$inner3 = array(4,5,6,7);


$outer['inner1'] = $inner1;
$outer['inner2'] = $inner2;
$outer['inner3'] = $inner3;

apc_store('outerArray', $outer);

echo "Stored...<br><br>";

$arr = apc_fetch('outerArray');
echo "<pre>", print_r($arr, true), "</pre>";


?>


jammaster82

(lemonheads)

Its a shame about 'array'.


well i tried 9 puns before this,
they didnt work, and this one
did kinda so i guess:

One pun, in ten did. (intended..)

Applause

perkiset

Applause

thedarkness

quote author=perkiset link=topic=736.msg5197#msg5197 date=1202165036

Well first off, that post is from Oct '06 LOL...



Applause

basura

[Just tunning]

Here is an interesting document:

Im happy and burned out  my dedies!!!! ^_^  You must try.

Tunning:
[MYSQL] (/etc/my.cnf)
[

LINUX

 ] kernel /etc/sysctl.conf    --> restart after changes on /sbin/sysctl -p
[

APACHE

 ] inside /etc/httpd/conf/httpd.conf), KeepAlive, Timeout, MaxClients, MaxKeepAliveRequests, KeepAliveTimeout...





[MYSQL]
MySQL w 1Gb RAM:


fine tuning of MySQL 4.1.9 and here is what my.cnf file looks like for a 2GHz

mac

 hine with 1GB of memory.

[mysqld]
socket=/path/to/mysql.sock
datadir=/var/lib/mysql
skip-locking
skip-innodb
# MySQL 4.x has query caching available.
# Enable it for vast improvement and it may be all you need to tweak.
query_cache_type=1
query_cache_limit=1M
query_cache_size=32M
# max_connections=500
# Reduced to 200 as memory will not be enough for 500 connections.
# memory=key_buffer+(sort_buffer_size+read_buffer_size)*max_connections
# which is now: 64 + (1 + 1) * 200 = 464 MB
# max_connections = approx. MaxClients setting in httpd.conf file
# Default set to 100.
#max_connections=200
#interactive_timeout=180
interactive_timeout=100
#wait_timeout=180
#wait_timeout=100
# Reduced wait_timeout to prevent idle clients holding connections.
#wait_timeout=30
wait_timeout=15
connect_timeout=10
# max_connect_errors is set to 10 by default
#max_connect_errors=10
#table_cache=256
#table_cache=1024
# Checked opened tables and adjusted accordingly after running for a while.
table_cache=512
#tmp_table_size=32M by default
#thread_cache=128
# Reduced it to 32 to prevent memory hogging. Also, see notes below.
thread_cache=32
# key_buffer=258M
# Reduced it by checking current size of *.MYI files, see notes below.
key_buffer=128M
# Commented out the buffer sizes and keeping the default.
# sort_buffer_size=2M by default.
#sort_buffer_size=1M
# read_buffer_size=128K by default.
#read_buffer_size=1M
# read_rnd_buffer_size=256K by default.
#read_rnd_buffer_size=1M
# myisam_sort_buffer_size=8M by default.
#myisam_sort_buffer_size=64M
# thread_concurrency = 2 * (no. of CPU)
thread_concurrency=2
# log slow queries is a must. Many queries that take more than 2 seconds.
# If so, then your tables need enhancement.
log_slow_queries=/var/log/mysqld.slow.log
long_query_time=2

[mysql.server]
user=mysql
basedir=/var/lib

[safe_mysqld]
err-log=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
open_files_limit=8192

[mysqldump]
quick
max_allowed_packet=16M

[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates

[isamchk]
key_buffer=64M
sort_buffer=64M
read_buffer=16M
write_buffer=16M

[myisamchk]
key_buffer=64M
sort_buffer=64M
read_buffer=16M
write_buffer=16M

[mysqlhotcopy]
interactive-timeout

[client]
socket=/path/to/mysql.sock

Below are notes on some of the important variables, I took down while tuning the config file.

  1. query_cache_size:
          * MySQL 4 provides one feature that can prove very handy - a query cache. In a situation where the database has to repeatedly run the same queries on the same data set, returning the same results each time, MySQL can cache the result set, avoiding the overhead of running through the data over and over and is extremely helpful on busy servers.
  2. key_buffer_size:
          * The value of key_buffer_size is the size of the buffer used with indexes. The larger the buffer, the faster the SQL command will finish and a result will be returned. The rule-of-thumb is to set the key_buffer_size to at least a quarter, but no more than half, of the total amount of memory on the server. Ideally, it will be large enough to contain all the indexes (the total size of all .MYI files on the server).
          * A simple way to check the actual performance of the buffer is to examine four additional variables: key_read_requests, key_reads, key_write_requests, and key_writes.
          * If you divide the value of key_read by the value of key_reads_requests, the result should be less than 0.01. Also, if you divide the value of key_write by the value of key_writes_requests, the result should be less than 1.
  3. table_cache:
          * The default is 64. Each time MySQL accesses a table, it places it in the cache. If the system accesses many tables, it is faster to have these in the cache. MySQL, being multi-threaded, may be running many queries on the table at one time, and each of these will open a table. Examine the value of open_tables at peak times. If you find it stays at the same value as your table_cache value, and then the number of opened_tables starts rapidly increasing, you should increase the table_cache if you have enough memory.
  4. sort_buffer:
          * The sort_buffer is very useful for speeding up myisamchk operations (which is why it is set much higher for that purpose in the default configuration files), but it can also be useful everyday when performing large numbers of sorts.
  5. read_rnd_buffer_size:
          * The read_rnd_buffer_size is used after a sort, when reading rows in sorted order. If you use many queries with ORDER BY, upping this can improve performance. Remember that, unlike key_buffer_size and table_cache, this buffer is allocated for each thread. This variable was renamed from record_rnd_buffer in MySQL 4.0.3. It defaults to the same size as the read_buffer_size. A rule-of-thumb is to allocate 1KB for each 1MB of memory on the server, for example 1MB on a

mac

 hine with 1GB memory.
  6. thread_cache:
          * If you have a busy server that's getting a lot of quick connections, set your thread cache high enough that the Threads_created value in SHOW STATUS stops increasing. This should take some of the load off of the CPU.
  7. tmp_table_size:
          * "Created_tmp_disk_tables" are the number of implicit temporary tables on disk created while executing statements and "created_tmp_tables" are memory-based. Obviously it is bad if you have to go to disk instead of memory all the time.

-->

[mysqld]

connect_timeout=15

interactive_timeout=100

join_buffer_size=1M

key_buffer=256M

max_allowed_packet=16M

max_connections=500

max_connect_errors=10

myisam_sort_buffer_size=64M

read_buffer_size=2M

read_rnd_buffer_size=2M

sort_buffer_size=2M

table_cache=1024

thread_cache_size=100

thread_concurrency=4

wait_timeout=300

query_cache_size=128M

query_cache_limit=1M

query_cache_type=1

skip-innodb


For people with a single CPU be sure to set thread_concurrency to 2 (4 is for Dual CPUs). People with 1GB of RAM, you might want to consider lowering the key_buffer to 64M and the myisam_sort_buffer_size to 32M. This really just depends on how much free memory your system has during peak traffic hours. If you increase these too much and your system runs out of physical RAM and starts swapping to disk, your system is going to eat it hard.

For more information about Mysqld variables, please read the following articles as they explain all the settings in-depth and how to fine-tune them: Article 1 and Article 2 and Article 3
http://www.databasejournal.com/features/mysql/article.

php

 /1402311
http://www.databasejournal.com/features/mysql/article.

php

 /3367871
http://www.databasejournal.com/features/mysql/article.

php

 /3110171





With Dual 2.0GHz Xeon with 2GB of RAM running RedHat Enterprise:

[

Linux

 ]

/etc/sysctl.conf

tcp_window_scaling, sack, fack, etc, turned off, but I leave them on

/etc/sysctl.conf
CODE
# Kernel sysctl configuration file for Red Hat Enterprise

Linux

 

# Controls IP packet forwarding
>net .ipv4.ip_forward = 0

# Controls source route verification
>net .ipv4.conf.default.rp_filter = 1
>net .ipv4.conf.all.rp_filter = 1

# Disables IP source routing
>net .ipv4.conf.default.accept_source_route = 0
>net .ipv4.conf.all.accept_source_route = 0

# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0

# Controls whether core dumps will append the PID to the core filename.

# Useful for debugging multi-threaded applications.
kernel.core_uses_pid = 1

# Increase maximum amount of memory allocated to shm
# Only uncomment if needed!
# kernel.shmmax = 67108864

# Disable ICMP Redirect Acceptance
>net .ipv4.conf.default.accept_redirects = 0
>net .ipv4.conf.all.accept_redirects = 0

# Enable Log Spoofed Packets, Source Routed Packets, Redirect Packets
>net .ipv4.conf.default.log_martians = 1
>net .ipv4.conf.all.log_martians = 1

# Decrease the time default value for tcp_fin_timeout connection
>net .ipv4.tcp_fin_timeout = 25

# Decrease the time default value for tcp_keepalive_time connection
>net .ipv4.tcp_keepalive_time = 1200

# Turn on the tcp_window_scaling
>net .ipv4.tcp_window_scaling = 1

# Turn on the tcp_sack
>net .ipv4.tcp_sack = 1

# tcp_fack should be on because of sack
>net .ipv4.tcp_fack = 1

# Turn on the tcp_timestamps
>net .ipv4.tcp_timestamps = 1

# Enable TCP SYN Cookie Protection
>net .ipv4.tcp_syncookies = 1

# Enable ignoring broadcasts request
>net .ipv4.icmp_echo_ignore_broadcasts = 1

# Enable bad error message Protection
>net .ipv4.icmp_ignore_bogus_error_responses = 1

# Make more local ports available
#

net

 .ipv4.ip_local_port_range = 1024 65000

# Set TCP Re-Ordering value in kernel to '5'
>net .ipv4.tcp_reordering = 5

# Lower syn retry rates
>net .ipv4.tcp_synack_retries = 2
>net .ipv4.tcp_syn_retries = 3

# Set Max SYN Backlog to '2048'
>net .ipv4.tcp_max_syn_backlog = 2048

# Various Settings
>net .core

.net

 dev_max_backlog = 1024

# Increase the maximum number of skb-heads to be cached
>net .core.hot_list_length = 256

# Increase the tcp-time-wait buckets pool size
>net .ipv4.tcp_max_tw_buckets = 360000

# This will increase the amount of memory available for socket input/output queues
>net .core.rmem_default = 65535
>net .core.rmem_max = 8388608
>net .ipv4.tcp_rmem = 4096 87380 8388608
>net .core.wmem_default = 65535
>net .core.wmem_max = 8388608
>net .ipv4.tcp_wmem = 4096 65535 8388608
>net .ipv4.tcp_mem = 8388608 8388608 8388608
>net .core.optmem_max = 40960




=== >After you make the changes to the file, you can make them effective immediately by typing in /sbin/sysctl -p

Also, you will need to issue /sbin/sysctl -w

net

 .ipv4.route.flush=1 to flush the routing table to make some of these changes happen instantly.


[...]

basura

[

Apache

 ]


httpd.conf:

Timeout 60
KeepAlive On
MaxKeepAliveRequests 1000
KeepAliveTimeout 10

Setting KeepAliveTimeout low you won't have all those lingering connections.

Increasing MaxClients to 256 consumes memory and its not really necessary. every

apache

  process consumes memory, if it gets out of memory it would use HD disk...lowering performance..

remove and Dynamic Shared Object (DSO) modules that you do not use

set the AllowOverride option to None, prevents check .htaccess file in every directory.

A security tip is to Mask your

Apache

  version by using the following settings:
ServerSignature Off
ServerTokens ProductOnly

Its recommended to Hide your

PHP

  info by setting expose_

php

  = Off in your /etc/

php

 .ini file.




Cache Tunning:

Using eAccelerator as its said before on this post. Applause For

php

  files to help reduce overhead and increase performance.





[

Linux

 ]


-

net

 .ipv4.tcp_fin_timeout = 1800
-

net

 .ipv4.tcp_keepalive_time = 1800

The above noted rules would create an undesired situation allowing attackers to easily D/DoS a system and overflow the

net

 work table with absurd amount of connections before they even begin to timeout.

I would recommend the following sysctl

net

 working paramters:

# Decrease time between keepalives
>net .ipv4.tcp_keepalive_time = 1200

# Decrease the time default value for tcp_fin_timeout connection
>net .ipv4.tcp_fin_timeout = 25

# Allow more SYN backlog
>net .ipv4.tcp_max_syn_backlog = 1048

# Lower syn retry rates
>net .ipv4.tcp_synack_retries = 2
>net .ipv4.tcp_syn_retries = 3


As with regards to rpfilter, source route, icmp, martians and similar you do not need to add the context for every interface -- simply add it for default and all so it will auto adapt to all interfaces on the system.

Beyond that nice set of sysctl rules; minus the later performance related sysctl rules which one would be advised to express caution when setting up.


Security MODS:

Mod_security and Mod_dosevasive  compiled and activated.



[Mysql tip]

MaxClients = RAM available for web server / MAX child's process size



.


Applause Keep on this thread if its interested in tunning or giving more performance on compiling

PHP

  with some modules.

(I'm system adimnistrator...and i guess all uses

Linux

  distros, im into

Solaris

  too...)


Regards, aka SlimeLORD

perkiset

Great stuff both of you... gonna go over that with a fine toothed comb and see where my stuff can benefit.

Thanks!


Perkiset's Place Home   Politics @ Perkiset's