Donnerstag Apr 14, 2016

Sockel, Core, Strand - Wo laufen meine Zonen?

Konsolidierung mit Solaris Zonen ist weit verbreitet.  Oft werden dabei, um die beste Auslastung zu erreichen, alle Zonen auf allen verfuegbaren CPUs betrieben.  In diesem Fall kuemmert sich Solaris darum, dass Programme auf der am besten geeigneten CPU ausgefuehrt werden und die vorhandenen Resourcen fair aufgeteilt werden.  Es gibt jedoch auch Faelle, in denen man einer oder mehreren Zonen einige CPUs fest zuweisen will, z.B. aus Lizenzgruenden oder um eine staerkere Trennung der Lasten zu erreichen.  Diese Trennung erreicht man entweder mit der Einstellung "dedicated-cpu" in der Zonen-Konfiguration, oder durch die Bindung an einen bestehenden Resource-Pool, der wiederum ein Prozessorset enthaelt.  Da im ersten Fall beim Start der Zone ein temporaerer Resource-Pool angelegt wird, ist die technische Umsetzung in beiden Faellen die gleiche.  Der Effekt eines solchen Prozessorsets ist, dass die darin enthaltenen CPUs exklusiv fuer die dem Set zugeordneten Zonen verfuegbar sind.  D.h. diese Zonen haben nicht mehr, aber auch nicht weniger CPUs zur Verfuegung, und alles andere (die Global Zone, alle anderen Zonen) koennen nicht mehr auf diesen CPUs ausgefuehrt werden.

Dieser Artikel widmet sich der Frage, welche CPUs man in ein solches Prozessorset legen sollte, und wie man feststellen kann, welche Zone derzeit auf welchen CPUs laeuft.

Vorab jedoch ein paar Definitionen, da auch hier wieder unterschiedliche Namen fuer verschiedene Konzepte ueblich sind:

  • Eine CPU ist ein Prozessor, bestehend aus ein oder mehreren Kernen, Cache sowie evtl. IO Controller und/oder Memory Controller
  • Ein Kern ist eine Recheneinheit auf einer CPU.
  • Ein Strand ist ein Einstiegspunkt in einen Kern, der die Rechenleistung des Kerns dem Betriebsystem verfuegbar macht.

Eine SPARC M7 CPU beispielsweise hat 32 Kerne, jeder Kern bietet 8 Strands, so dass eine M7 CPU dem Betriebsystem 32*8=256 Strands zur Verfuegung stellt.  Das Betriebsystem sieht jeden dieser Strands als vollwertige Ausfuehrungseinheit und zeigt deswegen 256 "CPUs" an.

Alle moderneren multi-core CPUs wenden bei den Caches verschiedene Lokalitaets-Ebenen an.  Waehrend der L3 Cache von allen Kernen gemeinsam benutzt wird, sind L2 und L1 Caches idR. pro Kern vorhanden. (Die M7 CPU wendet hier unterschiedliche Strategien an, aber auch hier nutzt jeder Kern einen exklusiven L1 Cache.)  Werden nun unterschiedliche Strands eines Kerns von der gleichen Anwendung genutzt, kann dies zu hoeheren Trefferraten in den entsprechenden Caches fuehren.  Werden diese Strands jedoch von unterschiedlichen Anwendungen genutzt, ist idR. das Gegenteil der Fall.  Die beiden Programme konkurieren dann um den Cache und verdraengen die Daten des jeweils anderen Programms regelmaessig aus den kleinen, lokalen Caches.  Man spricht hier von "Cache Thrashing".  Um dem entgegen zu wirken, wird allgemein empfohlen, verschiedene Zonen auf unterschiedliche Kerne zu binden, und zwar jeweils auf ganze Kerne.  Dies ist auch im Hinblick auf eventuelle Lizenzierung sinnvoll, die ja idR. ebenfalls kernweise erfolgt.

Wie kann man nun sicherstellen, dass die jeweiligen Zonen korrekt auf ganze, exklusive Kerne gebunden sind?

Solaris kennt die Zusammenhaenge zwischen Strand, Kern, CPU (und auch die Memory-Hierarchie, auf die ich hier jedoch nicht eingehen werde).  Diese kann man mit "kstat" abfragen.  Aus historischen Gruenden (aus der Zeit als es noch keine multi-core oder multi-strand CPUs gab) verwendet Solaris den Begriff "CPU" fuer einen Strand:

root@mars:~# kstat -m cpu_info -s core_id -i 150
module: cpu_info                        instance: 150   
name:   cpu_info150                     class:    misc
        core_id                         18

root@mars:~# kstat -m cpu_info -s chip_id -i 150
module: cpu_info                        instance: 150   
name:   cpu_info150                     class:    misc
        chip_id                         1

D.h die "CPU" mit der ID 150 ist ein Strand des Kerns 18 und der CPU 1.  Auf die gleiche Weise kann man natuerlich die gesamte vorhandene Infrastruktur erkunden.

Bei der Konfiguration von Prozessorsets fuer Resource Pools werden in der Regel einfach Minimum und Maximum der zu verwendenden Strandanzahl angegeben.  Alternativ kann man auch entweder CPU-IDs (also Strands) oder (seit Solaris 11.2) auch Core-IDs verwendet.  Die Kommandos hierfuer sind "pooladm" und "poolcfg".  (Es gibt auch das Kommando "psrset", das jedoch nur ein Prozessorset erzeugt, keinen Resource Pool, und deswegen nach jedem Reboot erneut ausgefuehrt werden muss.)  Die Verwendung dieser Kommandos habe ich bereits vor einiger Zeit beschrieben.  Um nun die Zuordnung von Strands, Kerne bzw. CPUs zu Zonen zu ermitteln, muss man die Strand-IDs des der Zone zugewiesenen Prozessorsets mittels kstat auf die Kerne und Prozessoren zurueckfuehren.  Das ist ein wenig muehsam, weswegen ich dafuer ein kleines Script geschrieben habe:

root@mars:~# ./zonecores -h
usage: zonecores [-Sscl] 
       -S report whole Socket use
       -s report shared use
       -c report whole core use
       -l list cpu overview

Dieses Script gibt mit "./zonecores -l" einen Ueberblick ueber die vorhandenen CPUs und die darauf laufenden Zonen aus.  Hier ein Beispiel von einem SPARC System mit 2 16-core CPUs:

root@mars:~# ./zonecores -l
#
# Socket, Core, Strand and Zone Overview
#
Socket Core Strands Zones
0      0    0,1,2,3,4,5,6,7 db2,
0      1    8,9,10,11,12,13,14,15 db2,
0      2    16,17,18,19,20,21,22,23 none
0      3    24,25,26,27,28,29,30,31 db2,
0      4    32,33,34,35,36,37,38,39 db2,
0      5    40,41,42,43,44,45,46,47 db2,
0      6    48,49,50,51,52,53,54,55 db2,
0      7    56,57,58,59,60,61,62,63 coreshare,db1,
0      8    64,65,66,67,68,69,70,71 db2,
0      9    72,73,74,75,76,77,78,79 none
0     10    80,81,82,83,84,85,86,87 none
0     11    88,89,90,91,92,93,94,95 none
0     12    96,97,98,99,100,101,102,103 none
0     13    104,105,106,107,108,109,110,111 none
0     14    112,113,114,115,116,117,118,119 none
0     15    120,121,122,123,124,125,126,127 none
1     16    128,129,130,131,132,133,134,135 none
1     17    136,137,138,139,140,141,142,143 none
1     18    144,145,146,147,148,149,150,151 none
1     19    152,153,154,155,156,157,158,159 none
1     20    160,161,162,163,164,165,166,167 none
1     21    168,169,170,171,172,173,174,175 none
1     22    176,177,178,179,180,181,182,183 none
1     23    184,185,186,187,188,189,190,191 none
1     24    192,193,194,195,196,197,198,199 none
1     25    200,201,202,203,204,205,206,207 none
1     26    208,209,210,211,212,213,214,215 none
1     27    216,217,218,219,220,221,222,223 none
1     28    224,225,226,227,228,229,230,231 none
1     29    232,233,234,235,236,237,238,239 none
1     30    240,241,242,243,244,245,246,247 db2,
1     31    248,249,250,251,252,253,254,255 none

Mit den Optionen -S, -s und -c wird geprueft, ob die Zonen ganze Sockel bzw. CPUs (-S) oder ganze Kerne (-c) verwenden.  Mit -s schliesslich wird geprueft, ob mehrere Zonen sich einen Kern teilen - was erwuenscht sein kann, oder auch nicht.  Hier ein Beispiel mit diversen Pools und Zonen auf dem selben System:

root@mars:~# ./zonecores -Ssc
#
# Checking Socket Affinity (16 cores per socket)
#
INFO - Zone db2 using 2 sockets for 8 cores.
OK - Zone db1 using 1 sockets for 1 cores.
OK - Zone capped7 using default pool.
OK - Zone coreshare using 1 sockets for 1 cores.
#
# Checking Core Resource Sharing
#
OK - Core 0 used by only one zone.
OK - Core 1 used by only one zone.
OK - Core 3 used by only one zone.
OK - Core 30 used by only one zone.
OK - Core 4 used by only one zone.
OK - Core 5 used by only one zone.
OK - Core 6 used by only one zone.
INFO - Core 7 used by 2 zones!
-> coreshare
-> db1
OK - Core 8 used by only one zone.
#
# Checking Whole Core Assignments
#
OK - Zone db2 using all 8 strands of core 0.
OK - Zone db2 using all 8 strands of core 1.
OK - Zone db2 using all 8 strands of core 3.
OK - Zone db2 using all 8 strands of core 30.
OK - Zone db2 using all 8 strands of core 4.
OK - Zone db2 using all 8 strands of core 5.
FAIL - only 7 strands of core 6 in use for zone db2.
FAIL - only 1 strands of core 8 in use for zone db2.
OK - Zone db1 using all 8 strands of core 7.
OK - Zone coreshare using all 8 strands of core 7.

Info: 1 instances of core sharing found.
Info: 1 instances of socket spanning found.
Warning: 2 issues found with whole core assignments.

Diese Ausgabe sollte recht selbsterklaerend sein, hier noch ein paar Worte dazu:

  • Die Zone db01 verwendet einen Resource Pool mit 8 Strands aus einem Kern.
  • Die Zone coreshare verwendet ebenfalls diesen Pool.
  • Die Zone db02 verwendet einen Resource Pool mit 64 Strands, die ueber Kerne aus zwei verschiedenen CPUs verteilt sind.  Einer der Kerne (Kern 6) wird nur mit 7 Strands verwendet, der letzte Strand liegt auf Kern 8.  Dies ist sicherlich so nicht gewuenscht.  Sinnvoller waere es, ganze Kerne sowie alle 8 Kerne aus der selben CPU zu verwenden.  Nicht nur muesste man so einen Kern wenige lizenzieren, Solaris wuerde dann beim Start der Zone auch versuchen, das zu den Prozessen gehoerende Memory so zu allokieren, dass moeglichst nur lokale Memory-Zugriffe notwendig werden - ein weiterer Grund, nach Moeglichkeit lokal zu bleiben.
  • Die Zone capped7 ist mit der Directive "capped-cpu: ncpus=7" konfiguriert.  Diese wird ueber den Fair Share Scheduler implementiert und bedient sich aus dem Default Pool.

Hier gibt es das Script zum Download: zonecores

Eine etwas ausfuehrlichere Besprechung mit Beispielen, wie man seine Poolkonfiguration veraendert, gibt es in MOS DocID 2116794.1

Weitere Links zum Thema:

Dienstag Okt 01, 2013

CPU-DR fuer Zonen

In meinem letzten Beitrag habe ich beschrieben, wie man die Memory-Konfiguration einer Zone im laufenden Betrieb veraendert.  Die naheliegende Frage ist natuerlich, ob das auch mit einer eventuellen CPU-Begrenzung funktioniert.  Die Antwort lautet natuerlich "Ja".

Manch einer wird sich fragen, warum das ueberhaupt notwendig ist, kann man Zonen doch bspw. mit dem Fair-Share Scheduler ganz hervoragend mit CPU versorgen und gleichzeitig unter Kontrolle halten.  Es gibt jedoch auch Gruende, Zonen mit exklusiven CPUs auszustatten - Lizenzierung oder  SLAs, die eine eher physische Partitionierung der Resourcen vorschreiben.  In solchen Faellen werden Zonen mit einer festen Anzahl von CPUs (oder vielmehr Strands) konfiguiert.  Und dann kann es natuerlich auch wuenschenswert sein, diese Konfiguration zu aendern, ohne die Zone dabei zu booten.  Wie das geht, soll hier beschrieben werden.

Grundsaetzlich gibt es zwei Moeglichkeiten, eine Zone mit einer festen Anzahl von CPUs zu betreiben.  Die klassische ist ein Resource Pool mit einem dazu gehoerenden Prozessorset, an den die Zone gebunden wird.  Eleganter geht das mit der Einstellung "dedicated-cpu" direkt in der Zonenkonfiguration.  In diesem zweiten Fall wird beim Start der Zone ein temporaerer Pool angelegt.  D.h. in beiden Faellen ist die Umsetzung die gleiche.  Und damit ist auch klar, wie die Loesung in beiden Faellen aussieht:  Die Konfiguration des Pools wird geaendert.  In der klassischen Variante ist diese Aenderung persistent.  In der zweiten Variante muss zusaetzlich die Konfiguration der Zone angepasst werden, damit die neue Anzahl von CPUs auch nach einem Zonen-Neustart erhalten bleibt.

Wird eine Zone mit "dedicated-cpu" konfiguriert, wird beim Start der Zone ein temporaerer Pool angelegt.  Dieser, und auch das dazu gehoerende Prozessorset, heisst idR. SUNWtmp_<zonenname>.  Das weitere Vorgehen ist damit fuer beide Faelle gleich:

Nehmen wir an, unsere Zone heisst orazone und hat derzeit 1 CPU.  Sie soll auf 2 CPUs erweitert werden.  Die aktuelle Pool-Konfiguration sieht wie folgt aus:

root@benjaminchen:~# pooladm                

system default
	string	system.comment 
	int	system.version 1
	boolean	system.bind-default true
	string	system.poold.objectives wt-load

	pool pool_default
		int	pool.sys_id 0
		boolean	pool.active true
		boolean	pool.default true
		int	pool.importance 1
		string	pool.comment 
		pset	pset_default

	pool SUNWtmp_orazone
		int	pool.sys_id 5
		boolean	pool.active true
		boolean	pool.default false
		int	pool.importance 1
		string	pool.comment 
		boolean	pool.temporary true
		pset	SUNWtmp_orazone

	pset pset_default
		int	pset.sys_id -1
		boolean	pset.default true
		uint	pset.min 1
		uint	pset.max 65536
		string	pset.units population
		uint	pset.load 687
		uint	pset.size 3
		string	pset.comment 

		cpu
			int	cpu.sys_id 1
			string	cpu.comment 
			string	cpu.status on-line

		cpu
			int	cpu.sys_id 3
			string	cpu.comment 
			string	cpu.status on-line

		cpu
			int	cpu.sys_id 2
			string	cpu.comment 
			string	cpu.status on-line

	pset SUNWtmp_orazone
		int	pset.sys_id 2
		boolean	pset.default false
		uint	pset.min 1
		uint	pset.max 1
		string	pset.units population
		uint	pset.load 478
		uint	pset.size 1
		string	pset.comment 
		boolean	pset.temporary true

		cpu
			int	cpu.sys_id 0
			string	cpu.comment 
			string	cpu.status on-line
Wir sehen in der Definition von pset SUNWtmp_orazone, dass CPU #0 diesem zugeordnet ist. Um den Pool um CPU #1 zu erweitern, sind folgende Kommandos notwendig:
root@benjaminchen:~# poolcfg -dc 'modify pset SUNWtmp_orapset \
                     (uint pset.max=2)' 
root@benjaminchen:~# poolcfg -dc 'transfer to pset \
                     orapset (cpu 1)'

Um umgekehrt diese CPU wieder aus dem Pool zu entfernen, diese Kommandos:

root@benjaminchen:~# poolcfg -dc 'transfer to pset pset_default \
                     (cpu 1)'
root@benjaminchen:~# poolcfg -dc 'modify pset SUNWtmp_orapset \
                     (uint pset.max=1)' 

Nun bleibt nur noch, die korrekte Anzahl von CPUs fuer den naechsten Zonen-Neustart in die Zonenkonfiguration einzutragen.

Fuer den Fall eines eigenen Pools fuer die Zone (klassische Variante) ist in diesem Verfahren lediglich der entsprechende Poolname zu verwenden.

Literatur:

Montag Aug 19, 2013

Memory-DR fuer Zonen

Zonen bieten unter Anderem die Moeglichkeit, den Hauptspeicher zu begrenzen.  Das geht idR. mit dem Zonen-Parameter "capped-memory", bei dem man die drei Werte "physical", "swap" und "locked" jeweils einzeln setzen kann.  "Physical" entspricht dabei der Resource-Control "zone.max-rss", also dem tatsaechlich belegten Hauptspeicher.  "Swap" entspricht "zone.max-swap" - dem belegten Swapspace und "locked" entspricht "zone.max-locked-memory", dem nicht pagebaren Speicher, typischerweise sind das shared memory Segmente.  Swap und Locked Memory sind dabei recht harte Grenzen, beim physischen Speicher ist es etwas "weicher".   Der physische Speicher wird durch rcapd ueberwacht, der ggf. versucht, Speicherseiten jenseits der erlaubten Menge auf das Swapdevice auszulagern.  Je nach Aktivitaet der Prozesse, die diesen Speicher verwenden, ist das mehr oder weniger erfolgreich, hat aber in jedem Fall zur Folge, dass diese Prozesse durch Paging stark beeintraechtigt werden.

Aendert man diese Werte mittels zonecfg, werden die neuen Werte erst nach einem Neustart der Zone wirksam.  Wirklich dynamisch, wie man das z.B. bei LDoms gewohnt ist, ist das nicht.  Es geht aber auch anders, wie ich an einem kleinen Beispiel zeigen moechte:

Gegeben sei eine kleine Zone, deren Speicherkonfiguration wie folgt aussieht:

root@benjaminchen:~# zonecfg -z orazone info capped-memory
capped-memory:
    physical: 512M
    [swap: 256M]
    [locked: 512M]

Um diese Werte im Betrieb zu aendern, muss an zwei verschiedenen Stellen eingegriffen werden.  Fuer den physischen Speicher beim rcapd, der diesen verwaltet.  Fuer swap und locked memory mit dem normalen Resource Control Kommando prctl.  Um also bspw. alle drei Grenzen zu verdoppeln, brauche ich folgende Kommandos:

root@benjaminchen:~# prctl -n zone.max-swap -v 512m -r -i zone orazone
root@benjaminchen:~# prctl -n zone.max-locked-memory -v 1g -r -i zone orazone
root@benjaminchen:~# rcapadm -z orazone -m 1g

Diese neuen Werte werden sofort, bzw. nach dem naechsten Rekonfigurations-Intervall des rcapd wirksam. Dieses kann man ebenfalls mit rcapadm veraendern. Wichtig ist dabei, dass diese Aenderungen nicht persistent sind. D.h. fuer den naechsten Zonen-Neustart gelten die Werte, die mittels zonecfg gesetzt wurden. Will man beides - persistente Aenderung und sofortige Wirkung, muss man an beiden Stellen eingreifen.

Literatur:

  • Solaris Admin Guide:
    http://docs.oracle.com/cd/E19683-01/817-1592/rm.rcapd-1/index.html

Dienstag Apr 17, 2012

Solaris Zones: Virtualisierung beschleunigt Benchmarks!

Wenn ich mich mit Kunden ueber Virtualisierung unterhalte ist eine der ersten Fragen oft die nach dem Overhead.  Nun wissen wir ja alle, dass Virtualisierung mit Hypervisoren nicht ohne Overhead zu machen ist.  Was wir ebenfalls alle wissen sollten ist, dass es stark vom Lastprofil und dem verwendeten Hypervisor abhaengt, wie gross dieser Overhead jeweils ausfaellt.  Zwar gab es schon einige Versuche, dies in standardisierten Benchmarks zu quantifizieren.  Dennoch bleibt die Antwort auf diese Frage noch immer in den Nebeln von Marketing und Benchmark-Unschaerfe verborgen.  Erstaunen erlebe ich jedoch regelmaessig, wenn ich zu Solaris Zonen (bei Solaris 10 hiessen sie noch Container) als Alternative zur Virtualisierung mit Hypervisoren komme. Solaris Zonen sind, grob vereinfacht, nichts weiter sind als eine Menge von Unix Prozessen, abgegrenzt durch einen Regelsatz der vom Solaris Kernel durchgesetzt wird.  Daher ist es einleuchtend, dass hier nicht besonders viel Overhead anfallen kann.  Dennoch wird die Behauptung von "Zero Overhead" oft angezweifelt, gerade auch weil vielen heute Virtualisierung per Hypervisor sehr nahe ist.  Und so sehr ich die Erklaerung mit technischen Details ueberzeugend finde, so sehr verstehe ich auch, dass sehen viel besser ist als glauben.   Daher:

Die Benchmark-Teams bei Oracle sind so ueberzeugt von den Vorteilen der Solaris Zonen, dass sie diese fuer die veroeffentlichten Benchmarks verwenden.  Das Solaris Resource Management funktioniert natuerlich auch ohne Zonen, aber Zonen machen es so viel einfacher, insb. in Verbindung mit den teilweise recht komplexen Benchmark-Konfigurationen.  Es gibt zahlreiche Benchmark-Veroeffentlichungen bis zurueck in die Tage der T5440, in denen Solaris Container zur Anwendung kommen.  Einige aktuelle Beispiele, alles Weltrekorde, sind:

Die genaue verwendung der Zonen ist in der jeweiligen Benchmark-Beschreibung dokumentiert.

Darueber hinaus hat das Benchmark-Team in einem Blogeintrag beschrieben, wie sie das Solaris Resource Management und Zonen verwenden, um die Anwendungsleistung zu erhoehen.  Das verleitet fast dazu, von "negativem Overhead" zu sprechen, waere der Begriff nicht so irrefuehrend.

Donnerstag Apr 02, 2009

Paralleles Patchen von Zonen - Licht am Horizont

CMT-Systeme sind eine ideale Virtualisierungsplatform.  Und Solaris Container sind die preiswerteste und effizienteste Virtualisierungstechnik.  Ein Pferdefuss dabei war bisher, dass das Patchen grosser Anzahl von Containern nicht gerade schnell war.  Hier ist endlich Abhilfe in Aussicht: Zonen koennen bald parallel gepatched werden.  Was das an Performance bringt, beschreibt Jeff Victor ein seinem excellenten Blog-Beitrag.

About

Neuigkeiten, Tipps und Wissenswertes rund um SPARC, CMT, Performance und ihre Analyse sowie Erfahrungen mit Solaris auf dem Server und dem Laptop.

This is a bilingual blog (most of the time). Please select your prefered language:
.
The views expressed on this blog are my own and do not necessarily reflect the views of Oracle.

Search

Categories
Archives
« Juli 2016
MoDiMiDoFrSaSo
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
       
Heute