# Benutzer verwaltung



## Generic1 (20. Dez 2010)

Hallo,

ich bin gerade dabei, mich schlau zu machen, wie das z.B.: Xing oder Facebook machen, dass ein User nur die Kommentarte seiner Freunde/Bekannten sieht.
Mir ist nicht ganz klar wie man sowas aufbauen kann, macht man das in der Datenbank oder macht man das über ein Security- Framework (Spring Security), oder ...
Hat da jemand eine Ahnung wie man das angehen kann,
Was ich genau möchte ist, dass sich ein User bei meinem System anmelden kann und dann Bekannte hinzufügen kann, dieser User kann dann sehen, was seine Freunde so machen.

lg


----------



## ARadauer (20. Dez 2010)

Ich persönlich würde das nicht über ein Security Framework machen.
Also über die Datenbank... grob:
select * from messages where userid in(select friendid from friends where userid = 'ich')
performt wharscheinlich nicht sehr berauschend, aber was besseres fällt mir nicht ein...

Wie Facebook das macht? Die nehmen ja keine Standard SQL Datenbank, die haben ja irgend ein selber geschriebenes map and reduces dings ähnlich hadoop oder? Bin mir da nicht sicher, jedenfalls wenn ich mir das so vorstelle ist da für mich ziehmlich viel magie dahinter... keine ahnung wie das funktioniert mit 500 mio benutzer keine ahnung wie viele milliarden nachrichten täglich.... hammer das das überhaupt funktioniert...


----------



## tagedieb (20. Dez 2010)

Die 'Datemraumauthorisierung' kannst du auch mit Spring Security implementieren.
Schau mal Domain Objects Security und Spring Recipes

Wie auch immer, du musst trotzdem irgendwo den Datenzugriffkontrollliste pro User speichern; und das machst du am besten mit einer Datenbank


----------



## ARadauer (21. Dez 2010)

ARadauer hat gesagt.:


> performt wharscheinlich nicht sehr berauschend, aber was besseres fällt mir nicht ein...



nö performt nicht.. hab mir gerade eine kleine mysql mit ein 2 Mio Benutzer angelegt, jeder Benutzer hat 20 Freunde und 20 Nachrichten...  Query wird nicht fertig.. ;(

Naja meine xampp standard mysql installation ist wahrscheinlich auch nicht für 82 Mio Datensätze ausgelegt...

FB = Magic...


----------



## Generic1 (21. Dez 2010)

ARadauer hat gesagt.:


> nö performt nicht.. hab mir gerade eine kleine mysql mit ein 2 Mio Benutzer angelegt, jeder Benutzer hat 20 Freunde und 20 Nachrichten...  Query wird nicht fertig.. ;(
> 
> Naja meine xampp standard mysql installation ist wahrscheinlich auch nicht für 82 Mio Datensätze ausgelegt...
> 
> FB = Magic...



Was heißt das jetzt, was würdest Du dann machen bzw. kannst du vielleicht dein Beispiel veröffentlichen? Was würdest du raten für so einen Problemfall?
lg


----------



## ARadauer (21. Dez 2010)

Mhn naja Grundsätzlich ist es ja richtig. Ich probier das jetzt nochmal mit "nur" 10000 Benutzer. Was ja auch schon nicht wenig ist. Ich denke da wird es funktionieren... ja sind insgesammt mit auch 410,000 Datensätze da dauerts 1.8 Sekunden...

Was ist wenn man mehr Daten hat? 
Naja Einstellungen halt....  es gibt sicher noch einiges an optimierungs Möglichkeiten. Ich hab das letzte mal vor 5 Jahren in der my.ini herumgespielt. Meine Datenbank ist natürlich jetzt nichit für diese Datenbank konfiguriert. Wenn man mal auf die Millionen Grenze an Benutzer hinkommt muss man sich in dem Bereich sowieso an Spzialisten wenden, die hier nochmal optimieren.

Welche Datenbank? Ich denke das eine Oracle vielleicht noch besser wäre als MySQL
Hardware! Ich arbeite hier auf meinem Stand PC, ein fetter Oracle Cluster mit 3 Rack Server im Rechnzentrum macht das sicher besser!
RAM!!! Was hilft mir ein 2 GB großer Index wenn er auf der Platte herum liegt... 

Ich weiß nicht ob ich meine Indizies optimal sind...
also ich denke da steckt noch potential drinnen...


----------



## Generic1 (3. Jan 2011)

Hallo,

vielen Dank mal für die Antworten, was mir noch sehr helfen würde, wenn ihr die Spalten der 2 Tabellen auflisten könntet von 
	
	
	
	





```
select * from messages where userid in(select friendid from friends where userid = 'ich')
```

Das ist mir nicht ganz klar, wie diese aussehen, wenn ich es mal versucht nachzustellen, dann müsste es so sein:

Tabelle1 (messages)
[XML]
<id>           <!-- pk -->
<userid>      <!-- was ist das für eine userid -> die id des users, welche die message geschrieben hat? fk -->
<message>
[/XML]

Tabelle2 (friends)
[XML]
<friendid>  <!-- mir ist nicht ganz klar was friendid und userid sind bzw. wie diese in zusammenhang stehen? -->
<userid>
<name>
[/XML]

ist das so gemeint gewesen bzw. wie ist das gemeint?
Ich möchte ja dann auch noch, das ein User die befreundeten User auflisten lassen kann. Das wäre dann in der Tabelle "friends" eine Referenz auf sich selbst, oder?
lg und vielen Dank,
Generic1


----------



## AlexSpritze (3. Jan 2011)

Du kannst ja auch mal bei Diaspora reinschauen, eine Art quellenoffenes, soziales Netzwerk. Die müssen das ja auch irgendwie machen.


----------



## fastjack (3. Jan 2011)

```
select * from messages where userid in(select friendid from friends where userid = 'ich')
```

performt nicht, weil das DBMS meiner Meinung nach für jede gefundene Zeile das innere Select durchführt. Ich würde das Query dynamisch zusammenbauen, so etwa in dieser Form:

1. alle friends ermitteln:

```
select friendid from friends where userid = 'ich'
```

2. alle nachrichten ermitteln:

```
select * from messages where userid in(1, 2, 3, 4, 5)
```

dann müßte das wesentlich schneller laufen.


----------



## fastjack (3. Jan 2011)

oder einfach geschickt joinen...


----------



## ARadauer (3. Jan 2011)

> Das ist mir nicht ganz klar, wie diese aussehen, wenn ich es mal versucht nachzustellen, dann müsste es so sein:


naja wie diese aussehen. Das ist jetzt nicht "die eine Wahrheit" ich hab mir das halt so kurz überlegt

user:
userid (pk)
name

message:
messageid (pk)
userid (fk zur user tabelle, wer hat die nachricht geschrieben)

friends: (freundschaft verknüpfung)
userid (fk zur user tabelle)
friendid (die id des users der sein freund ist)

jeder user hat in der friends tablle dann mehrer einträge.. je nach dem welche freunde er hat..



> was friendid und userid sind bzw. wie diese in zusammenhang stehen


ja die sind halt freunde...

sich  Diaspora anzusehen ist sicher auch eine gute idee... werd ich heute abend mal machen...


----------



## Generic1 (3. Jan 2011)

OK, ein bisschen klarer ist es mir geworden, was ich  immer noch nicht versteh ist, user können ja auch friends sein und friends können auch user sein. 
Hab ich dann nicht Einträge doppelt (einmal in user und einmal in friends)?
lg

PS: ist Dispora in "JAVA" programmiert?


----------



## ARadauer (3. Jan 2011)

fastjack hat gesagt.:


> performt nicht, weil das DBMS meiner Meinung nach für jede gefundene Zeile das innere Select durchführt. Ich würde das Query dynamisch zusammenbauen, so etwa in dieser Form:



ahhhh ... ja dann kannst ja nicht funktionieren...
interessant .. jetzt klappts, wenn man das inner query nur einmal ausführ und das äussere dynamisch baut... mhn kann man der DB nicht irgendwie mitteilen, dass sie das nur einmal ausführen soll?



> user können ja auch friends sein und friends können auch user sein.
> Hab ich dann nicht Einträge doppelt (einmal in user und einmal in friends)?


doppelt ja klar, hoffen wir halt mal das unsere user auch freunde haben


also user:
id: name
1: max
2: hans
3: willi

friends:
userid:friendid
1:2 hans ist freund von max
1:3 willi ist feund von max
2:1 max ist auch freund von hans
usw...


----------



## Generic1 (3. Jan 2011)

OK, das ist ja dann genau eine Tabellen- Referenz auf sich selber.


----------



## AlexSpritze (3. Jan 2011)

Generic1 hat gesagt.:


> PS: ist Dispora in "JAVA" programmiert?



Zu spät gesehen: ist in Ruby programmiert. Aber vielleicht lässt sich daraus ja trotzdem etwas an der Vorgehensweise ableiten.


----------



## Generic1 (4. Jan 2011)

>> sich Diaspora anzusehen ist sicher auch eine gute idee... werd ich heute abend mal machen... 

Wäre super, wenn du das mit uns sharen würdest,
lg


----------



## ARadauer (7. Jan 2011)

Generic1 hat gesagt.:


> >> sich Diaspora anzusehen ist sicher auch eine gute idee... werd ich heute abend mal machen...
> 
> Wäre super, wenn du das mit uns sharen würdest,
> lg



bin leider noch nicht dazu gekommen.... habe aber mit unserem Datenbank Guru gesprochen...


```
select m.message, u.name from message m
join (select friendid from friends where userid = 20) f on f.friendid = m.userid
join user u on(u.id= f.friendid)
```

das im "select friendid from friends where userid = 20" im join nennt sich pseudo tabelle... whnsinnig schnell ist die sache nun!

ich denk diaspora wird das auch so machen...

ach ja ich hab natürlich die entsprechenden indizes gesetzt... wobei das hatte ich ganz am anfang schon...


also nochmal

select * from messages where userid in(select friendid from friends where userid = 'ich')
- geht nicht. das innere select für jede zeile in messages ausgeführt wird


SELECT * FROM message m JOIN (SELECT friendid FROM friends  WHERE userid = 'ich') f ON f.friendid = m.userid
-geht super, da das innere select nur einmal ausgeführt wird...


----------



## kama (7. Jan 2011)

Hallo,


ARadauer hat gesagt.:


> Wie Facebook das macht? Die nehmen ja keine Standard SQL Datenbank, die haben ja irgend ein selber geschriebenes map and reduces dings ähnlich hadoop oder? Bin mir da nicht sicher, jedenfalls wenn ich mir das so vorstelle ist da für mich ziehmlich viel magie dahinter... keine ahnung wie das funktioniert mit 500 mio benutzer keine ahnung wie viele milliarden nachrichten täglich.... hammer das das überhaupt funktioniert...


Ich habe auf der Devoxx (2010) in Antwerpen einen Vortrag von Facebook gehört.

Man man höre und Staune die Benutzen MySQL  als Datenbank und PHP, MemCache ...weiterhin nutzen die Hadoop nicht irgendetwas ähnliches sondern tatsächlich Hadoop (Apache Hadoop) mit entsprechenden DWH Teilen Hive, HBase, Thrift und Scribe..

Weiterhin kann man einiges zum Thema Infrastuktur etc. im Engineering Blog lesen..sehr interessante sachen 

Hier mal ein paar Quellen:
Inside Facebook's Open Source Infrastructure - Developer.com

Und hier ein paar technische Hintergründe:
The Facebook Data Center FAQ (Page 2) « Data Center Knowledge

Gruß
Karl Heinz Marbaise


----------



## JohannisderKaeufer (8. Jan 2011)

ARadauer hat gesagt.:


> select * from messages where userid in(select friendid from friends where userid = 'ich')
> - geht nicht. das innere select für jede zeile in messages ausgeführt wird
> 
> 
> ...



Das das erste Statement mit MySQL unnötig beschäftigt ist kann ich noch gut verstehen. Mit einer Oracle DB könnte ich mir gut vorstellen, das das Subselect auch nur einmal aufgerufen wird und die DB dann so schlau ist und verstanden hat, das da immer das gleiche rauskommen sollte.

Eine Alternative die genausoschnell läuft und ohne Subselect auskommt sollte das hier sein:

select m.message, u.name from message m
join friends f ON (f.userid = 20 and f.friendid = m.userid)
join user u on(u.id= f.friendid)

Würde mich interessieren ob das genausoschnell läuft wie die Geschichte mit dem Subselect



> ich denk diaspora wird das auch so machen...



Ich denke nicht das Diaspora das so macht. Schaut man sich die Anforderungen eines Diaspora Servers an, dann steht, da recht deutlich MongoDB.
Also keine Relationale DB sondern eine Dokumentenorientierte. Da gibt es keine Joins.
Dort wird man nicht umherkommen 2 Requests abzusetzen, außer man denormalisiert seinen Datenbestand entsprechend.

Ich hab das ganze mal auf Basis von Apache CouchDB, was vergleichbar zu MongoDB ist, nachgebaut. Der wesentliche Unterschied liegt darin das Couchdb auf Erlang und MongoDB auf C++ aufbaut.

Die Dokumente sehen so aus

```
{"_id":"user_id",
"type":"user",
"friends":["user_id","user_id",...]
}
sowie
{"_id":"message_id",
"type":"message",
"author":"user_id",
"text":"Die Message"
}
```

Dazu eine Map-Funktion:

```
function(doc){
  if(doc.type=="message"){
    emit(doc.author, doc.text);
  }
}
```

Würde man noch zusätzlich mit einem Usernamen arbeiten, würde ich eine weiter map-Funktion hinzufügen, die die User-Dokumente auf den usernamen mappt.

Getestet habe ich das ganze mit 10000 Usern, 20 Freunden pro User und 20 Nachrichten/User.

Das Schreiben ging recht lang, ca. eine gute Stunde bis das ganze in der DB war.
Auf der Platte hat es etwa 1,4 Gigabyte in Anspruch genommen.
Der erste Aufruf der Map funktion brauchte etwa 1 - 2 Minuten und hat weiteren Platz auf der Festplatte veranschlagt. Das ist vergleichbar mit dem Anlegen eines Indexes in einer Relationalen DB.
Jeder wietere Aufruf ist allerdings sehr schnell (<1 Sekunde) ohne das das Programm schwer im RAM liegt.

Die Daten werden auf der Festplatte in einer vorsortierten Baumstruktur angelegt und können daher in log n abgerufen werden.

Das Problem ist aber das Einfügen, da es hier oftmals von nöten ist den Baum zu reorganisieren.

Ich gehe davon aus, dass selbst mit einem noch größeren Datenbestand weiterhin kurze Zugriffszeiten beim Lesen zu erzielen sind, da auch hier schon sogut wie alles von der Platte geladen wird. 

Die herangehensweise unterscheidet sich aber deutlich im Gegensatz zu einer Relationalen DB.


----------

