פלאנט תוכנה חופשית בישראל (Planet FOSS-IL)

20 אפריל, 2014

Shlomi Noach

The mystery of MySQL 5.6 excessive buffer pool flushing

I'm experimenting with upgrading to MySQL 5.6 and am experiencing an unexplained increase in disk I/O utilization. After discussing this with several people I'm publishing in the hope that someone has an enlightenment on this.

We have a few dozens servers in a normal replication topology. On this particular replication topology we've already evaluated that STATEMENT based replication is faster than ROW based replication, and so we use SBR. We have two different workloads on our slaves, applied by two different HAProxy groups, on three different data centres. Hardware-wise, servers of two groups use either Virident SSD cards or normal SAS spindle disks.

Our servers are I/O bound. A common query used by both workloads looks up data that does not necessarily have a hotspot, and is very large in volume. DML is low, and we only have a few hundred statements per second executed on master (and propagated through replication).

We have upgraded 6 servers from all datacenters to 5.6, both on SSD and spindle disks, and are experiencing the following phenomena:

The faster replication speed motivates us to continue with the experiment, and is of a significant factor in our decision. However we are concerned about the I/O utilization and excessive flushing.

The above graphs depict the 5.6 status without any configuration changes as compared to 5.5. I took some days to reconfigure the following variables, with no change to the rate of flushed pages (though some changes visible in double-wite buffer writes):

And more... Have done patient one-by-one or combinations of the above where it made sense. As you see I began with the usual suspects and moved on to more esoteric stuff. I concentrated on new variables introduced in 5.6, or ones where the defaults have changed, or ones we have explicitly changed the defaults from.

The above is consistent on all upgraded servers. On SSD the disk utilization is lower, but still concerning.

Our use case is very different from the one presented by Yoshinori Matsunobu. and apparently not too many have experienced upgrading to 5.6. I'm hoping someone might shed some light.

20 אפריל, 2014 06:14 AM

19 אפריל, 2014

Hetz Ben Hemo

כמה מילים על הדרייבר של nVidia ועל מסכים בעייתיים

ישנו דרייבר אחד בלינוקס שיש לו היסטוריה ארוכה של בעיות "פוליטיות" והגדרות טכניות – זהו הדרייברים של כרטיסי המסך של nVidia. רבות כבר נכתב על הדרייברים של nVidia, כמה הם סגורים, מורכבים, לא תואמים תמיד, ו"עקשנים" בסירובם לרוץ בסביבות מסויימות. … להמשיך לקרוא

הטקסט המלא

19 אפריל, 2014 12:11 PM

Shlomi Noach

Monitoring DML/slow queries with graphite

pt-query-digest, Anemometer or "Anemomaster" do a great job of analysing your queries and giving you visibility into what's going on with your MySQL servers. However, the place where the query digests are written is just some MySQL tables on some server. Do you have monitoring/alerts on that table? How will you verify a specific query does not exceed some runtime/execution count threshold, and get notified when it does?

At Outbrain we use Graphite to collect almost all of our data. We like it for its simplicity and for the fact it has a "push" strategy as opposed to "pull" strategy: every service/server/collectd writes (pushes) its own data to Graphite, as opposed to having some centralized monitoring service trying to pull data from thousands of servers & services. We also have a great Graphite dashboard (developed at our company by Erez Mazor) called graphitus, which is a very sophisticated and easily configurable visualization solution (see documentation).

Our love/hate relationship with Nagios boil down to having a single Nagios plugin: one that reads data from Graphite. We use Nagios to generate our alerts, and dream of the day we will substitute it with something else (there's not too much love in this love/hate relationship).

Graphite is a numeric timeseries data monitoring solution. How do you throw MySQL query analysis into Graphite, then?

The answer lies within the flexible structure of a Graphite metric entry, which is a freely composed path, such as collectd.hosts.us-east.myhost01.mysql.gauge-Threads_running.value. Graphite does not require you to pre-define paths, and you can use anything that makes sense to you. Thus, you can use a slow query's text, for example, as part of the Graphite entry path. This is not entirely simple as the graphite path limits the allowed characters. So this is what we do:

Any query that is written to Graphite is transformed into a "canonical form". We strip it of excessive information and write enough of it that still makes sense to us. Actually, we found out that we usually do well with just the bare bones of "what type of query this is and what tables are involved". For better drill down we then go to Anemometer/Anemomaster. Hence, the canonical form of the following query:

UPDATE my_documents SET document_owner='Wallace'  WHERE document_domain='Gromit'

is simply

update_my_documents

Thankfully the pt-query-digest report tables are already timestamp based, and are already aggregated by query "fingerprints". This makes writing this data to graphite just a matter of text normalizing. The following script is a slightly modified version of what we use. Do note that we have the notion of "clustername" which is the name of the replication topology we're looking at. We have many topologies, like OLTP, OLAP, Metadata, etc. etc. We support this notion by adding a clustername_max column to the report tables and instructing pt-query-digest fill in this value.

We run the following shell script by cron every 10 minutes (based on the 10 minute interval of analysing our masters' DML):

#!/bin/bash

#
# This script should run on the anemomaster machine every 10 minutes, shortly after
# binary logs / relay logs are analyzed via pt-query-digest.
#

unixtime=$(date +%s)

# Get stats for the last round 10 minutes
# The query only takes one representative from each cluster
query=" select clustername_max, sum(ts_cnt), replace(fingerprint, '\n', ' ') from global_query_review_history join global_query_review using (checksum), (select date(now()) + interval hour(now()) hour + interval (minute(now()) div 10 *10) minute as search_to_timestamp) as search_to_timestamp_sel where ts_min >= search_to_timestamp - interval 10 minute and ts_min < search_to_timestamp and hostname_max in ( select min(hostname_max) from global_query_review_history where ts_min >= search_to_timestamp - interval 10 minute and ts_min < search_to_timestamp group by clustername_max) group by clustername_max, fingerprint order by sum(ts_cnt) desc "

mysql -umyself -psecret anemomaster --silent --silent --raw -e "$query" | while IFS=$'\t' read -r -a result_values
    do
        fingerprint_cluster=${result_values[0]} ;
        fingerprint_count=${result_values[1]} ;
        fingerprint_query=${result_values[2]} ;
        fingerprint_query=$(echo $fingerprint_query | sed -r -e "s/^(-- .*)]//g")
        fingerprint_query=$(echo $fingerprint_query | tr '\n' ' ' | tr '\r' ' ' | tr '\t' ' ')
        fingerprint_query=${fingerprint_query%%(*}
        fingerprint_query=${fingerprint_query%%,*}
        fingerprint_query=${fingerprint_query%% set *}
        fingerprint_query=${fingerprint_query%% SET *}
        fingerprint_query=${fingerprint_query%% where *}
        fingerprint_query=${fingerprint_query%% WHERE *}
        fingerprint_query=${fingerprint_query%% join *}
        fingerprint_query=${fingerprint_query%% JOIN *}
        fingerprint_query=${fingerprint_query%% using *}
        fingerprint_query=${fingerprint_query%% USING *}
        fingerprint_query=${fingerprint_query%% select *}
        fingerprint_query=${fingerprint_query%% SELECT *}
        fingerprint_query=$(echo $fingerprint_query | tr -d "\`")
        fingerprint_query=$(echo $fingerprint_query | tr -d "*")
        fingerprint_query=$(echo $fingerprint_query | tr -d "?")
        fingerprint_query=$(echo $fingerprint_query | tr " " "_")
        fingerprint_query=$(echo $fingerprint_query | tr "." "__")
        echo "data.mysql.dml.${fingerprint_cluster}.${fingerprint_query}.count ${fingerprint_count} $unixtime" | nc -w 1 my.graphite.server 2003
    done

If you don't need the "clustername stuff", modify the query to read:

select 'mysql' as clustername_max, sum(ts_cnt), replace(fingerprint, '\n', ' ') from global_query_review_history join global_query_review using (checksum), (select date(now()) + interval hour(now()) hour + interval (minute(now()) div 10 *10) minute as search_to_timestamp) as search_to_timestamp_sel where ts_min >= search_to_timestamp - interval 10 minute and ts_min < search_to_timestamp and hostname_max in ( select min(hostname_max) from global_query_review_history where ts_min >= search_to_timestamp - interval 10 minute and ts_min < search_to_timestamp) group by fingerprint order by sum(ts_cnt) desc

The graphite metric path will look like data.mysql.dml.oltp.update_my_documents.count, which makes for a perpefctly valid metric to monitor, graphically visualize and get alerts on.

19 אפריל, 2014 06:27 AM

18 אפריל, 2014

Shlomi Noach

"Anemomaster": DML visibility. Your must-do for tomorrow

Here's our take of master DML query monitoring at Outbrain (presented April 2014). It took a half-day to code, implement, automate and deploy, and within the first hour of work we managed to catch multiple ill-doing services and scripts. You might want to try this out for yourself.

What's this about?

What queries do you monitor on your MySQL servers? Many don't monitor queries at all, and only look up slow queries on occasion, using pt-query-digest. Some monitor slow queries, where Anemometer (relying on pt-query-digest) is a very good tool. To the extreme, some monitor TCP traffic on all MySQL servers -- good for you! In between, there's a particular type of queries that are of special interest: DML (INSERT/UPDATE/DELETE) queries issued against the master.

They are of particular interest because they are only issued once against the master, yet propagate through replication topology to execute on all slaves. These queries have a direct impact on your slave lag and on your overall replication capacity. I suggest you should be familiar with your DMLs just as you are with your slow queries.

In particular, we had multiple occasions in the past where all or most slaves started lagging. Frantically we would go to our metrics; yes! We would see a spike in com_insert. Someone (some service) was obviously generating more INSERTs than usual, at a high rate that the slaves could not keep up with. But, which INSERT was that? Blindly, we would look at the binary logs. Well, erm, what are we looking for, exactly?

Two such occasions convinced us that there should be a solution, but it took some time till it hit us. We were already using Anemometer for monitoring our slow logs. We can do the same for monitoring our binary logs. Thus was born "Anemomaster".

Quick recap on how Anemometer works: you issue pt-query-digest on your slow logs on all MySQL hosts (we actually first ship the slow logs to a central place where we analyse them; same thing). This is done periodically, and slow logs are then rotated. You throw the output of pt-query-digest to a central database (this is built in with pt-query-digest; it doesn't necessarily produce human readable reports). Anemometer would read this central database and visualize the slow queries.

Analysing DMLs

But then, pt-query-digest doesn't only parse slow logs. It can parse binary logs. Instead of asking for total query time, we ask for query count, and on we go to establish the same mechanism, using same pt-query-digest and same Anemometer to store and visualize the DMLs issued on our masters.

When analysing DMLs we're interested in parsing binary logs -- and it makes no sense to do the same on all slaves. All slaves just have same copy of binlog entries as the master produces. It only takes one server to get an accurate picture of the DMLs on your replication topology.

One server could be the master, and this can indeed be done: just FLUSH MASTER LOGS, parse the binary logs with pt-query-digest, and you're done. But like others, we tend to look at our masters as tender babies. We care for them, and do not wish to overload them unnecessarily. We chose to get the binlog entries from our slaves, instead. We also chose to get the entries from the relay logs, since these are unaffected by slave performance and as long as network is good, we can expect the relay logs to be very up to date. At any given time we have two slaves that take this role (this is automated and verified). On a 10 minute period we would flush the relay logs on these servers, and analyse whatever relay logs we have not analysed as yet.

The script below is a slightly modified version of our own, and should work for the standard installation. Modify to fit your own data (in particular, it assumes relay logs are named mysqld-relay-bin; datadir is specified in /etc/my.cnf, and please don't ask me how to do this on Windows):

#!/bin/bash

# 
# Digest latest relay logs file, write results to "anemomaster"
#
# This script can run from any machine; it only needs to execute on a single machine per mysql cluster, but for
# analysis availability it should execute on at least two hosts per cluster.
#

DATADIR=`grep datadir /etc/my.cnf|awk -F= '{print $2}'`
TMPDIR=/tmp
DIGESTED_RELAY_LOGS_FILE=${DATADIR}/digested_relay_logs.txt

touch $DIGESTED_RELAY_LOGS_FILE
chown mysql:mysql $DIGESTED_RELAY_LOGS_FILE

hostname=$(hostname)

echo "deleting old relay logs from ${TMPDIR}"
rm ${TMPDIR}/mysqld-relay-bin.[0-9]*

echo "Getting current relay log files"
existing_relay_log_files=$(ls -tr ${DATADIR}/mysqld-relay-bin.[0-9]* | head -n -1)
for existing_relay_log_file in $existing_relay_log_files
do
    cp -u $existing_relay_log_file $TMPDIR
done
echo "flushing relay logs"
/usr/bin/mysql -umyself -psecret -e 'flush relay logs\G;' 2>/dev/null
# sleep because the log file takes some time to disappear
sleep 1

echo "Getting current relay log files"
existing_relay_log_files=$(ls -tr ${DATADIR}/mysqld-relay-bin.[0-9]* | head -n -1)
for existing_relay_log_file in $existing_relay_log_files
do
    cp -u $existing_relay_log_file $TMPDIR
done

cd $TMPDIR
for relay_log_file in mysqld-relay-bin.[0-9]*
do
    # Filter this relay log file, since it's already been digested
    grep $relay_log_file $DIGESTED_RELAY_LOGS_FILE && rm $relay_log_file
done

for relay_log_file in mysqld-relay-bin.[0-9]*
do
    echo "digesting $relay_log_file"
    mysqlbinlog $relay_log_file | /usr/bin/pt-query-digest \
      --type binlog --order-by Query_time:cnt --group-by fingerprint --limit 100 \
      --review  P=3306,u=anemomaster,p=secret,h=anemomaster_host,D=anemomaster,t=global_query_review \
      --history P=3306,u=anemomaster,p=secret,h=anemomaster_host,D=anemomaster,t=global_query_review_history \
      --filter=" \$event->{Bytes} = length(\$event->{arg}) and \$event->{hostname}=\"$(hostname)\" " \
      --no-report
    echo "$relay_log_file" >> $DIGESTED_RELAY_LOGS_FILE
    rm $relay_log_file
done
# make sure the file does not bloat. 20 entries is more than enough.
tail -n 20 $DIGESTED_RELAY_LOGS_FILE > ${TMPDIR}/DIGESTED_RELAY_LOGS_FILE
cat ${TMPDIR}/DIGESTED_RELAY_LOGS_FILE > $DIGESTED_RELAY_LOGS_FILE
echo "done"

As for Anemometer, we patched it to support multiple environments ("clusters") -- but irrelevant to the DML change. If you just want to make it visualize DMLs, here's the major configuration changes to config.inc.php (marked with bold):

$conf['history_defaults'] = array(
	'output'		=> 'table',
	'fact-group'	=> 'date',
	'fact-order'	=> 'date DESC',
	'fact-limit' => '90',
	'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime( '-90 day')),
	'dimension-ts_min_end'	=> date("Y-m-d H:i:s"),
	'table_fields' => array('date', 'query_time_avg','ts_cnt','Query_time_sum')
);

$conf['report_defaults'] = array(
	'fact-group'	=> 'checksum',
	'fact-order'	=> 'ts_cnt DESC',
	'fact-limit' => '20',
	'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime( '-1 day')),
	'dimension-ts_min_end'	=> date("Y-m-d H:i:s"),
	'table_fields' => array('checksum','snippet', 'query_time_avg','ts_cnt','Query_time_sum'),
	'dimension-pivot-hostname_max' => null,
	'dimension-pivot-clustername_max' => null
);

$conf['graph_defaults'] = array(
	'fact-group'	=> 'minute_ts',
	'fact-order'	=> 'minute_ts',
	'fact-limit' => '',
	'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime( '-7 day')),
	'dimension-ts_min_end'	=> date("Y-m-d H:i:s"),
	'table_fields' => array('minute_ts'),
	// hack ... fix is to make query builder select the group and order fields,
	// then table fields only has to contain the plot_field
	'plot_field' => 'ts_cnt',
);

With a 10 minute rotation & digestion, we are able to analyze near real-time what's been done on our masters. If we see a spike in com_insert/com_update/com_delete, or just see slave lags, we turn to Anemomaster and within a couple minutes know exactly what service is guilty of abusing our database. We are also working to protect our database against abuse, but that's for another discussion.

18 אפריל, 2014 06:02 PM

Ilan Shavit

מתדולוגיות של הפצות – חלק שני

במאמר המשך זה אסקור תכונות וסוגים שונים של הפצות המתגלגלות:

הפצות מתגלגלות למחצה (part-rolling, semi-rolling, or half-rolling):
בהפצות אלו קיימים חלקים שלא מתגלגלים. מדובר בדר"כ ברכיבי ליבה (קרנל, xorg והמעטפת הגרפית). דוגמאות: PCLinuxOS, Chakra Linux, Aurora OS

הפצות מתגלגלות באופן מלא: (full-rolling )
בהפצות אלו כל מרכיבי ההפצה מתגלגלים. דוגמאות: Arch, Gentoo

הפצות מתגלגלות באופן מדומה (pseudo-rolling):
בהפצות אלו מנסים ליצב את הענף הלא יציב באמצעות תיקוני תוכנה (patches) המוכנסים אליו ואמורים לספק תכונות הקיימות בהפצות המתגלגלות. דוגמאות: aptosid, siduction, Semplice, antiX

הפצות מתגלגלות לפי בחירה (opt-rolling):
להפצות אלו יש גרסאות להורדה של הפצות מתגלגלות ושל הפצות לא מתגלגלות.
דוגמא: OpenSuse

הפצות מתגלגלות באופן מחזורי (cyclic-rolling):
הפצות אלו מפותחות במחזוריות (בעיקר בחלקיהם הלא מתגלגלים). לפיכך גיל החבילות והיציבות שלהם לא זהה בחלקים שונים של ההפצה. דוגמאות: antiX and LMDE

מקור

My Signature

18 אפריל, 2014 11:00 AM

Diego Iastrubni

חופש -שימוש ב־owncloud

כל משתמש אנדרויד שחובב חופש מנסה להימנע מהידיים של גוגל. אז מתקינים רומים נקיים (אני משתמש ב־cyanogenmod שאני בונה בעצמי). השלב הבא הוא להוציא את השירותים של גוגל. נתחיל מהמרק, במקומו נשתמש ב־fdroid והיא תוכנה שמתקינים על הסלולרי ומהווה חנות וירטואלית שמכילה רק תוכנות חופשיות. התוכנות שם די מאעפנות... זה לא מה שאני רגיל אליו ב"לינוקס". אני מניח שהעולם הזה עוד מתפתח ואני יכול לצפות לטובה. (דיברתי על זה בפוסט אחר, http://cucomania.dyndns.info/node/236).

אני משתמש גם ב־owncloud בתור שרת. זה מחליף את dropbox היומנים של גוגל ואנשי הקשר. הבעייה כאן, היא שיש המון הגדרות לעשות ידנית במכשיר, ואין תוכנה אחת שמטפלת בכל הפונקציונליות. 

התוכנות המדוברות כאן תוכנות חופשיות, וזמינות בשרתים של FDroid (אפשר להתקין הכל מהתוכנה).

הטקסט המלא

18 אפריל, 2014 10:50 AM

17 אפריל, 2014

Yaniv Gershoni

עתיקות...


מצאתי (אחרי שכל העולם כבר פרסם את זה...) את המקלדת הוירטואלית עם קיצורי הדרך של בלנדר.
(למי שלא ראה, זה כאן: http://waldobronchart.be/blenderkeyboard)

הסתובבתי קצת בין קיצורי הדרך וראיתי פתאום שאם לוחצים על Ctrl+Alt+מקש הרווח נכנסים למצב של...
"Create Orientation"

לחצתי וקיבלתי תפריט קטנצי'ק בצד שמאל למטה שנראה כך:


מיותר לציין שזה לא עשה משהו מיוחד...
אז חיפשתי בגוגל מה זה השד הזה ולמדתי משהו חדש שלמעשה קיים עוד מהגרסאות הקדומות של בלנדר (לפחות 2.49):

פרטים נוספים »

הטקסט המלא

17 אפריל, 2014 07:21 PM

ik

anti patterns של מתודולוגיות עבודה

לפני מספר שבועות קראתי פוסט מאוד מעניין על כך שבשנות ה70 יצאו 2 ניסויים בעולם התוכנה על הרעיון של איך לבנות עורך טקסט:

בעוד שהלימוד מemacs תפס, הלימוד של vi מעולם לא לקח באמת כתצורת מימוש של עורכי טקסט.

מה זה אומר בעצם ? ובכן בemacs יש פקודה ללכת למעלה, ויש פקודה ללכת למטה. כלומר סוג של API כזה לכל פעולה שאפשר לבצע בעורך, עם האפשרות לקחת אותה וליצור סוג של תוספים שונים.
אבל vi לגמרי שונה בגישה שלו מהגישה הזו שemacs יצר.

הגישה של vi אומרת כי לתזוזה יש יותר ממשמעות אחת. רוצים תזוזה של מילה ? השתמשו ב w. רוצים תזוזה של התחלת המסמך לחצו על gg רוצים תזוזה לסוף המסמך ? לחצו על GG והרשימה עוד ארוכה.

כפי שניתן לראות, המשמעות בשוני מאוד פשוט להסבר, אך החשיבה מאחוריו מאוד לא.
אז אנסה להסביר את זה בצורה אחרת.
קפיצה ממילה למילה נעשת על ידי w. כלומר המציאה של גבולות המילה.
מחיקה נעשת על ידי d. אז כיצד מוחקים מילה ב vi ? ‏dw.
בשביל להעתיק אנחנו משתמשים במקדם y. איך מעתיקים מילה ? yw.
כלומר צריך לדעת מה המקדם של הפעולה שרוצים לבצע (מחיקה או העתקה וכיוב'), והכללים לאחר הפעולה עצמה זהים.
רוצים לבצע העתקה שתשפיע על 10 מילים ? אין פשוט מזה, תלחצו על 10 ואז על yw, כלומר 10yw.

עוד משהו נחמד:
התו ^ מייצג "התחלה של שורה". אז אם אני עומד באמצע שורה, ועושה d^‎, כלומר קודם מחיקה ואז ^, מה יקרה ? הוא ימחק מהנקודה שעומדים בה עד לתחילת השורה את הכל.
התו $ מייצג "סוף של שורה". אני בטח שאתם כבר יכולים לנחש מה יקרה באותה הסיטואציה בהדגמה של ^ אם נחליף אותו ב $.

חשוב לזכור כי במידה ותלחצו רק על ^ או רק על $, אתם תגיעו להתחלת השורה או לסופה.

בemacs בשביל להעתיק יש לך API כזה שנקרא copy, אבל הוא מעתיק מה שמסומן. כך גם ב gedit, kate, notepad, sublime וכמעט כל עורך טקסט בעולם התוכנה.
אבל מה קורה כאשר אני רוצה לסמן 10 מילים ולמחוק רק אותם ?
ובכן במידה ואתם עובדים ב vi, אתם תעשו את זה ככה 10dw. לא צריך לסמן כלום בשביל זה. כיצד בעורך טקסט מבוסס רעיון emacs ? ובכן, סמנו 10 מילים ואז תמחקו אותם.
כלומר אין api דווקא בשביל מספר מילים. בעוד שבגישה של vi זה אינו משנה.

גם אין התנהגות מדוייקת למחיקה כדוגמת d^‎ ו d$‎. אתם תעמדו במיקום שאתם רוצים, תעשו סימון עם העכבר או מקלדת, ואז תלחצו על מחיקה, כי אין פקודת API מדוייקת לבצע את זה בצורה הרגילה.

הגישה הזו של vi מאפשרת ליצור עכשיו מערכת שעושה עבור מילה המרה של rot13 למשל. אבל למעשה המושג "מילה" אינו נכון, אפשר למפות מקשים שכאשר הם מתרחשים זה ימיר לקידוד, דבר שאומר שאינני צריך להמציא את הבחירה מה מומר, אלא רק את הפקודה ל rot13.

בגישה של emacs, ובכן למעט מה שהAPI מספק, אני צריך לכתוב בעצמי, אם עורך הטקסט מאפשר זאת.

והעיקר

מרבית התעשייה עובדת בגישות אשר למראית עין נראות הגיוניות, אבל לרוב זה מרגיש כאילו הדרך/מסלול/טכנולוגיות האלו אינן באמת מתאימות או הנכונות ביותר לעבודה. אבל בגלל שיש עובדה ש "כולם"tm משתמשים בהם, אז זה כנראה אומר כי צריך או שיש לכך סיבה, אך למה בעצם ?
כמה פעמים אנחנו מגיעים למצב בו אנחנו שואלים את עצמנו "האם הדרך הזו היא הנכונה ?", או יותר חשוב "למה הדרך הזו נכונה/מתאימה לנו ?"

לפני מספר חודשים, ראיתי הרצאה של אחד מיוצרי go (אינני זוכר בדיוק היכן, את שמה או את שם המרצה), והוא הסביר מדוע הוא הרגיש שהיה צורך ליצור שפה חדשה.
הוא למשל לקח את כל הגישה הקיימת ב C ו ++C של לבצע include, ועשה בדיקה כמה פרוייקט של מליוני שורות קוד עושה מעבר על אותם קבצי include, והגיע למצב מדהים. מדובר באלפי מעברים ולפעמים אף יותר !

לעומת זאת יש שפות שבהם מראש זה לא קורא (בPHP ניסו להתחכם לזה, אבל הם לא שינו את התפיסה של include): בשפות כמו פסקל (לא, לא חזרתי אליה) ו go.
המעבר הוא חד פעמי בלבד, דבר שלא רק מוריד את בעיות הקימפול וניהול התלויות (שלא לדבר על מהירות קימפול גבוהה יותר), אלא מאפשר להשיג המון כוח. למשל גם בפסקל וגם בgo נוצר בעצם סוג של namespace. היצירה של namespace מאוד חשובה היות וזה נרשם פעם אחת בצורה בינארית, ופשוט יש מיפוי לכל המקומות אשר מבקשים להשתמש בקוד עצמו לקפוץ לאיזור המוגדר. ועכשיו אין צורך יותר בhack של ifndef ואז define רק בשביל לגרום לקומפיילר לא להוסיף שוב פעם את הקוד. כמו כן, היות וכבר הnamespace נכנס לאיזשהו עץ בקומפיילר, במקום לקרוא שוב את התוכן, פשוט מסמנים שגם בנקודה הזו שהצהרנו שוב על fmt (למשל) צריך להשתמש ב namespace הזה.

שינוי גישה כזו בשפת תכנות אינו דבר של מה בכך. הרי "כולםtm" יודעים ש++C זה הדבר לפתח אפליקציות (שהן לא ווב). אבל מסתבר שזה לא בדיוק המצב. כלומר זו שפה מסובכת מידי לתחזוקה, להבנה, ובעיקר לבניה (יש מליארד כלים שנועדו לסייע לבנות קוד הכתוב ב C ו ++C שפשוט לא נחוץ בשפות אשר משנות את התפיסה הזו).

עוד משהו מהעולם שלנו, הוא שכולם חושבים כי SQL הפירוש שלו ניהול מידע בעל קשרי גומלין. כלומר, אפשר לנהל קשרי גומלין בין טבלאות שונות בצורה טובה ויעילה.
העניין הוא שזה לא כזה פשוט כמו שזה נשמע.
זו הסיבה ששאילתות join כל כך מסובכות, ויש במסדי נתונים רציניים, גם הרבה סוגים מהם, עם המון משמעויות שונות ומשונות (inner/outer left/right/natural וכיוב'). אם לא מודעים להבדלים הנכונים בין קשרי הגומלין לפי השאילתא (לא לפי כוונת מתכנן הטבלאות, אלא לפי פרשנות מסד הנתונים את השאילתא), המידע לא מגיע בצורה יעילה, אבל יותר חמור, לפעמים הסיבה שהמידע מגיע שגויה, או נראה כאילו אין מידע מתאים, ואז לא תמיד מגלים שזה בעצם שגוי.

זו הסיבה שיש מסדי נתונים אחרים אשר בנויים לגישה של קשרי גומלין. לא בהכרח no-sql, אבל יכול להיות שכן. הענין הוא שהן יוצרות גישה מסויימת המתאימה יותר למה שחשוב לך לבצע.
כך למשל אם יש הרבה מידע היררכי, לפעמים מסד נתונים שהוא בנוי כעץ מתאים יותר.
אם מידע שצריך להישמר פעם אחת אבל אינו שייך לטבלה הראשית, בSQL הוא יהיה צריך pivot table, אבל גם כאן, יש מסדי נתונים שבהם עדיין אפשר לשמור את זה כרשומה בודדת ולחסוך את התפיסה הזו.

אז כמה אנחנו בעצם תקועים עם מצב של anti-pattern ?
כלומר, עד כמה בעבודה שלנו, אנחנו תקועים במצב בו אנחנו מחליטים שהדרך של "כולםtm" מתאימה כי "כולם" משתמשים בה, ומתי אנחנו באמת בוחנים את הדברים בצורה שהיא מתאימה עבורינו ?
אני שואל את עצמי בכל פעם את השאלות בנושא, וממליץ גם לכם לעצור לרגע ולשאול בפעם הבאה לפני שאתם בוחרים בגישה, מתודולוגיה, שפה או אפילו פרוייקט.

מוקדש כחומר למחשבה.


תויק תחת:nosql, טיפים וטריקים, טכנולוגיה, מסדי נתונים, פיתוח, קהילה, קוד פתוח, תוכנה, תכנות

17 אפריל, 2014 02:38 PM

16 אפריל, 2014

Oz Nahum

Revive and old Smartphone with Cyanogenmod!

I recently installed Cyanogenmod on an old Samsung Galaxy II and I just wanted to share my thoughts. ... continue reading...

16 אפריל, 2014 11:45 AM

Quick Tip - Tiling Windows manager in Mate-Desktop

Here is how you can achieve Tiling windows management without leaving a full blown Desktop Environment such as Mate-Desktop using x-tile ... continue reading...

16 אפריל, 2014 11:45 AM

Dell is not serious about Linux

How serious Dell is about Linux? I think it is not that serious, and it is using Ubuntu fans as free advertising platform ... continue reading...

16 אפריל, 2014 11:45 AM

Git tip - git describe

Earlier I posted a tip how to count commits between tags, this post suggests a better way to do it ... continue reading...

16 אפריל, 2014 11:45 AM

Git tip - Count commits between tags

Once every N commits I would like to release a new version of pwman3, so here is how to keep a track of this number between releases ... ... continue reading...

16 אפריל, 2014 11:45 AM

Localizing applications with gettext

I was always interested in how I can add translations to pwman3 or to my little PyGTK tutorial, these are summerizing of my gettext experiences ... continue reading...

16 אפריל, 2014 11:45 AM

PyGTK CD Ripper Tutorial - Part 7

Part 6 of this tutorial completed the Preferences dialog and introduced gtk.Frames and gtk.Expanders. This part of the tutorial will add some more polish to th UI, introducing icons and completing the About Dialog ... continue reading...

16 אפריל, 2014 11:45 AM

PyGTK CD Ripper Tutorial - Part 6

Part 5 of this tutorial added a gtk.Notebook and other widgets to the Preferences dialog. This part of the tutorial introduces the gtk.Frame and gtk.Expander widgets and completes the Preferences dialog. ... continue reading...

16 אפריל, 2014 11:45 AM

Installing Oracle's JAVA on Debian

There are many solutions floating around to install Oracle's JAVA on Debian based systems. Most of them involve too many manual steps. Here is one that does not, and it simply works! ... continue reading...

16 אפריל, 2014 11:45 AM

PyGTK CD Ripper Tutorial - Part 5

The last part of this tutorial added some polish to the main window of the CD Ripper, and showed how to create an empty Preferences dialog. This part of the tutorial will complete the Presences exploring gtk.Notebook and other widgets. ... continue reading...

16 אפריל, 2014 11:45 AM