Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Sign in
Toggle navigation
S
solarium
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
common
solarium
Commits
f36394a4
Commit
f36394a4
authored
Mar 13, 2012
by
Bas de Nooijer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Updated loadbalancer plugin to use endpoints
Unittests not yet updated...
parent
b76a148e
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
119 additions
and
140 deletions
+119
-140
examples/7.1-plugin-loadbalancer.php
examples/7.1-plugin-loadbalancer.php
+15
-14
library/Solarium/Core/Client/Client.php
library/Solarium/Core/Client/Client.php
+1
-1
library/Solarium/Plugin/Loadbalancer/Loadbalancer.php
library/Solarium/Plugin/Loadbalancer/Loadbalancer.php
+103
-125
No files found.
examples/7.1-plugin-loadbalancer.php
View file @
f36394a4
...
...
@@ -3,16 +3,17 @@ require('init.php');
htmlHeader
();
// create a client instance and
get loadbalancer plugin instance
// create a client instance and
create endpoints
$client
=
new
Solarium\Client
(
$config
);
$loadbalancer
=
$client
->
getPlugin
(
'loadbalancer'
);
$endpoint1
=
$client
->
createEndpoint
(
'local1'
);
//normally you would add endpoint specific settings...
$endpoint2
=
$client
->
createEndpoint
(
'local2'
);
$endpoint3
=
$client
->
createEndpoint
(
'local3'
);
// apply loadbalancer settings
$optionsSolrOne
=
array
(
'host'
=>
'127.0.0.1'
,
'port'
=>
8983
);
$optionsSolrTwo
=
array
(
'host'
=>
'127.0.0.1'
,
'port'
=>
7574
);
$loadbalancer
->
addServer
(
'solr1'
,
$optionsSolrOne
,
100
);
$loadbalancer
->
addServer
(
'solr2'
,
$optionsSolrTwo
,
200
);
$loadbalancer
->
addServer
(
'solr3'
,
$optionsSolrTwo
,
1
);
// get loadbalancer plugin instance and add endpoints
$loadbalancer
=
$client
->
getPlugin
(
'loadbalancer'
);
$loadbalancer
->
addEndpoint
(
$endpoint1
,
100
);
$loadbalancer
->
addEndpoint
(
$endpoint2
,
100
);
$loadbalancer
->
addEndpoint
(
$endpoint3
,
1
);
// create a basic query to execute
$query
=
$client
->
createSelect
();
...
...
@@ -22,26 +23,26 @@ for($i=1; $i<=8; $i++) {
$resultset
=
$client
->
select
(
$query
);
echo
'Query execution #'
.
$i
.
'<br/>'
;
echo
'NumFound: '
.
$resultset
->
getNumFound
()
.
'<br/>'
;
echo
'Server: '
.
$loadbalancer
->
getLast
ServerKey
()
.
'<hr/>'
;
echo
'Server: '
.
$loadbalancer
->
getLast
Endpoint
()
.
'<hr/>'
;
}
// force a server for a query (normally solr 3 is extremely unlikely based on it's weight)
$loadbalancer
->
setForced
ServerForNextQuery
(
'solr
3'
);
$loadbalancer
->
setForced
EndpointForNextQuery
(
'local
3'
);
$resultset
=
$client
->
select
(
$query
);
echo
'Query execution with server forced to
solr
3<br/>'
;
echo
'Query execution with server forced to
local
3<br/>'
;
echo
'NumFound: '
.
$resultset
->
getNumFound
()
.
'<br/>'
;
echo
'Server: '
.
$loadbalancer
->
getLast
ServerKey
()
.
'<hr/>'
;
echo
'Server: '
.
$loadbalancer
->
getLast
Endpoint
()
.
'<hr/>'
;
// test a ping query
$query
=
$client
->
createPing
();
$client
->
ping
(
$query
);
echo
'Loadbalanced ping query, should display a loadbalancing server:<br/>'
;
echo
'Ping server: '
.
$loadbalancer
->
getLast
ServerKey
()
.
'<hr/>'
;
echo
'Ping server: '
.
$loadbalancer
->
getLast
Endpoint
()
.
'<hr/>'
;
// exclude ping query from loadbalancing
$loadbalancer
->
addBlockedQueryType
(
Solarium\Client
::
QUERY_PING
);
$client
->
ping
(
$query
);
echo
'Non-loadbalanced ping query, should not display a loadbalancing server:<br/>'
;
echo
'Ping server: '
.
$loadbalancer
->
getLast
ServerKey
()
.
'<hr/>'
;
echo
'Ping server: '
.
$loadbalancer
->
getLast
Endpoint
()
.
'<hr/>'
;
htmlFooter
();
\ No newline at end of file
library/Solarium/Core/Client/Client.php
View file @
f36394a4
...
...
@@ -300,7 +300,7 @@ class Client extends Configurable
* Get an endpoint by key
*
* @param string $key
* @return
string
* @return
Endpoint
*/
public
function
getEndpoint
(
$key
=
null
)
{
...
...
library/Solarium/Plugin/Loadbalancer/Loadbalancer.php
View file @
f36394a4
...
...
@@ -43,6 +43,7 @@ namespace Solarium\Plugin\Loadbalancer;
use
Solarium\Core\Plugin
;
use
Solarium\Core\Exception
;
use
Solarium\Core\Client\Client
;
use
Solarium\Core\Client\Endpoint
;
use
Solarium\Core\Client\HttpException
;
use
Solarium\Core\Query\Query
;
use
Solarium\Core\Client\Request
;
...
...
@@ -52,14 +53,14 @@ use Solarium\Core\Client\Response;
* Loadbalancer plugin
*
* Using this plugin you can use software loadbalancing over multiple Solr instances.
* You can add any number of
server
s, each with their own weight. The weight influences
* the probability of a
server
being used for a query.
* You can add any number of
endpoint
s, each with their own weight. The weight influences
* the probability of a
endpoint
being used for a query.
*
* By default all queries except updates are loadbalanced. This can be customized by setting blocked querytypes.
* Any querytype that may not be loadbalanced will be executed by Solarium with the default
adapter settings
.
* In a master-slave setup the default
adapter should be connecting to the master server
.
* Any querytype that may not be loadbalanced will be executed by Solarium with the default
endpoint
.
* In a master-slave setup the default
endpoint should be connecting to the master endpoint
.
*
* You can also enable the failover mode. In this case a query will be retried on another
server
in case of error.
* You can also enable the failover mode. In this case a query will be retried on another
endpoint
in case of error.
*
* @package Solarium
* @subpackage Plugin
...
...
@@ -78,11 +79,11 @@ class Loadbalancer extends Plugin
);
/**
* Registered
server
s
* Registered
endpoint
s
*
* @var array
*/
protected
$
server
s
=
array
();
protected
$
endpoint
s
=
array
();
/**
* Query types that are blocked from loadbalancing
...
...
@@ -94,33 +95,33 @@ class Loadbalancer extends Plugin
);
/**
*
Key of the last used server
*
Last used endpoint key
*
* The value can be null if no queries have been executed, or if the last executed query didn't use loadbalancing.
*
* @var null|string
*/
protected
$last
ServerKey
;
protected
$last
Endpoint
;
/**
*
Server
to use for next query (overrules randomizer)
*
Endpoint key
to use for next query (overrules randomizer)
*
* @var string
*/
protected
$next
Server
;
protected
$next
Endpoint
;
/**
*
Presets of the client adapter
*
Default endpoint key
*
* Th
ese settings are used to restore the adapter to it's original status for queries
*
that cannot be loadbalanced
(for instance update queries that need to go to the master)
* Th
is endpoint is used for queries that cannot be loadbalanced
* (for instance update queries that need to go to the master)
*
* @var
array
* @var
string
*/
protected
$
adapterPresets
;
protected
$
defaultEndpoint
;
/**
* Pool of
server
s to use for requests
* Pool of
endpoint key
s to use for requests
*
* @var WeightedRandomChoice
*/
...
...
@@ -138,7 +139,7 @@ class Loadbalancer extends Plugin
*
* @var array
*/
protected
$
server
Excludes
;
protected
$
endpoint
Excludes
;
/**
* Initialize options
...
...
@@ -152,8 +153,8 @@ class Loadbalancer extends Plugin
{
foreach
(
$this
->
options
AS
$name
=>
$value
)
{
switch
(
$name
)
{
case
'
server
'
:
$this
->
set
Server
s
(
$value
);
case
'
endpoint
'
:
$this
->
set
Endpoint
s
(
$value
);
break
;
case
'blockedquerytype'
:
$this
->
setBlockedQueryTypes
(
$value
);
...
...
@@ -205,138 +206,131 @@ class Loadbalancer extends Plugin
}
/**
* Add a
server
to the loadbalacing 'pool'
* Add a
n endpoint
to the loadbalacing 'pool'
*
* @param string $key
* @param array $options
* @param Endpoint|string $endpoint
* @param int $weight Must be a positive number
* @return self Provides fluent interface
*/
public
function
add
Server
(
$key
,
$options
,
$weight
=
1
)
public
function
add
Endpoint
(
$endpoint
,
$weight
=
1
)
{
if
(
array_key_exists
(
$key
,
$this
->
servers
))
{
throw
new
Exception
(
'A server for the loadbalancer plugin must have a unique key'
);
if
(
!
is_string
(
$endpoint
))
{
$endpoint
=
$endpoint
->
getKey
();
}
if
(
array_key_exists
(
$endpoint
,
$this
->
endpoints
))
{
throw
new
Exception
(
'An endpoint for the loadbalancer plugin must have a unique key'
);
}
else
{
$this
->
servers
[
$key
]
=
array
(
'options'
=>
$options
,
'weight'
=>
$weight
,
);
$this
->
endpoints
[
$endpoint
]
=
$weight
;
}
// reset the randomizer as soon as a new
server
is added
// reset the randomizer as soon as a new
endpoint
is added
$this
->
randomizer
=
null
;
return
$this
;
}
/**
*
Get servers in the loadbalancing pool
*
Add multiple endpoints
*
* @return array
* @param array $endpoints
* @return self Provides fluent interface
*/
public
function
getServers
(
)
public
function
addEndpoints
(
array
$endpoints
)
{
return
$this
->
servers
;
foreach
(
$endpoints
AS
$endpoint
=>
$weight
)
{
$this
->
addEndpoint
(
$endpoint
,
$weight
);
}
return
$this
;
}
/**
* Get
a server entry by key
* Get
the endpoints in the loadbalancing pool
*
* @param string $key
* @return array
*/
public
function
get
Server
(
$key
)
public
function
get
Endpoints
(
)
{
if
(
!
isset
(
$this
->
servers
[
$key
]))
{
throw
new
Exception
(
'Unknown server key'
);
}
return
$this
->
servers
[
$key
];
return
$this
->
endpoints
;
}
/**
*
Set servers, overwriting any existing server
s
*
Clear all endpoint entrie
s
*
* @param array $servers Use server key as array key and 'options' and 'weight' as array entries
* @return self Provides fluent interface
*/
public
function
setServers
(
$servers
)
public
function
clearEndpoints
(
)
{
$this
->
clearServers
();
$this
->
addServers
(
$servers
);
return
$this
;
$this
->
endpoints
=
array
();
}
/**
*
Add multiple servers
*
Remove an endpoint by key
*
* @param
array $servers
* @param
Endpoint|string $endpoint
* @return self Provides fluent interface
*/
public
function
addServers
(
$servers
)
public
function
removeEndpoint
(
$endpoint
)
{
foreach
(
$servers
AS
$key
=>
$data
)
{
$this
->
addServer
(
$key
,
$data
[
'options'
],
$data
[
'weight'
]);
if
(
!
is_string
(
$endpoint
))
{
$endpoint
=
$endpoint
->
getKey
();
}
if
(
isset
(
$this
->
endpoints
[
$endpoint
]))
{
unset
(
$this
->
endpoints
[
$endpoint
]);
}
return
$this
;
}
/**
*
Clear all server entrie
s
*
Set multiple endpoint
s
*
* @return self Provides fluent interface
*/
public
function
clearServers
()
{
$this
->
servers
=
array
();
}
/**
* Remove a server by key
* This overwrites any existing endpoints
*
* @param string $key
* @return self Provides fluent interface
* @param array $endpoints
*/
public
function
removeServer
(
$key
)
public
function
setEndpoints
(
$endpoints
)
{
if
(
isset
(
$this
->
servers
[
$key
]))
{
unset
(
$this
->
servers
[
$key
]);
}
return
$this
;
$this
->
clearEndpoints
();
$this
->
addEndpoints
(
$endpoints
);
}
/**
* Set a forced
server
(by key) for the next request
* Set a forced
endpoints
(by key) for the next request
*
* As soon as one query has used the forced
server
this setting is reset. If you want to remove this setting
* As soon as one query has used the forced
endpoint
this setting is reset. If you want to remove this setting
* pass NULL as the key value.
*
* If the next query cannot be loadbalanced (for instance based on the querytype) this setting is ignored
* but will still be reset.
*
* @param string|null
$key
* @param string|null
|Endpoint $endpoint
* @return self Provides fluent interface
*/
public
function
setForced
ServerForNextQuery
(
$key
)
public
function
setForced
EndpointForNextQuery
(
$endpoint
)
{
if
(
$key
!==
null
&&
!
array_key_exists
(
$key
,
$this
->
servers
))
{
throw
new
Exception
(
'Unknown server forced for next query'
);
if
(
!
is_string
(
$endpoint
))
{
$endpoint
=
$endpoint
->
getKey
();
}
if
(
$endpoint
!==
null
&&
!
array_key_exists
(
$endpoint
,
$this
->
endpoints
))
{
throw
new
Exception
(
'Unknown endpoint forced for next query'
);
}
$this
->
next
Server
=
$key
;
$this
->
next
Endpoint
=
$endpoint
;
return
$this
;
}
/**
* Get the Forced
Server
ForNextQuery value
* Get the Forced
Endpoint
ForNextQuery value
*
* @return string|null
*/
public
function
getForced
Server
ForNextQuery
()
public
function
getForced
Endpoint
ForNextQuery
()
{
return
$this
->
next
Server
;
return
$this
->
next
Endpoint
;
}
/**
...
...
@@ -418,15 +412,15 @@ class Loadbalancer extends Plugin
}
/**
* Get the key of the
server
that was used for the last query
* Get the key of the
endpoint
that was used for the last query
*
* May return a null value if no query has been executed yet, or the last query could not be loadbalanced.
*
* @return null|string
*/
public
function
getLast
ServerKey
()
public
function
getLast
Endpoint
()
{
return
$this
->
last
ServerKey
;
return
$this
->
last
Endpoint
;
}
/**
...
...
@@ -451,28 +445,19 @@ class Loadbalancer extends Plugin
$adapter
=
$this
->
client
->
getAdapter
();
// save adapter presets (once) to allow the settings to be restored later
if
(
$this
->
adapterPresets
==
null
)
{
$this
->
adapterPresets
=
array
(
'host'
=>
$adapter
->
getHost
(),
'port'
=>
$adapter
->
getPort
(),
'path'
=>
$adapter
->
getPath
(),
'core'
=>
$adapter
->
getCore
(),
'timeout'
=>
$adapter
->
getTimeout
(),
);
if
(
$this
->
defaultEndpoint
==
null
)
{
$this
->
defaultEndpoint
=
$this
->
client
->
getEndpoint
()
->
getKey
();
}
// check querytype: is loadbalancing allowed?
if
(
!
array_key_exists
(
$this
->
queryType
,
$this
->
blockedQueryTypes
))
{
return
$this
->
getLoadbalancedResponse
(
$request
);
}
else
{
$options
=
$this
->
adapterPresets
;
$this
->
lastServerKey
=
null
;
// apply new settings to adapter
$adapter
->
setOptions
(
$options
);
$endpoint
=
$this
->
client
->
getEndpoint
(
$this
->
defaultEndpoint
);
$this
->
lastEndpoint
=
null
;
// execute request and return result
return
$adapter
->
execute
(
$request
);
return
$adapter
->
execute
(
$request
,
$endpoint
);
}
}
...
...
@@ -484,21 +469,19 @@ class Loadbalancer extends Plugin
*/
protected
function
getLoadbalancedResponse
(
$request
)
{
$this
->
server
Excludes
=
array
();
// reset for each query
$this
->
endpoint
Excludes
=
array
();
// reset for each query
$adapter
=
$this
->
client
->
getAdapter
();
if
(
$this
->
getFailoverEnabled
()
==
true
)
{
for
(
$i
=
0
;
$i
<=
$this
->
getFailoverMaxRetries
();
$i
++
)
{
$options
=
$this
->
getRandomServerOptions
();
$adapter
->
setOptions
(
$options
);
$endpoint
=
$this
->
getRandomEndpoint
();
try
{
return
$adapter
->
execute
(
$request
);
return
$adapter
->
execute
(
$request
,
$endpoint
);
}
catch
(
HttpException
$e
)
{
// ignore HTTP errors and try again
// but do issue an event for things like logging
$e
=
new
Exception
(
'Maximum number of loadbalancer retries reached'
);
$this
->
client
->
triggerEvent
(
'LoadbalancerServerFail'
,
array
(
$options
,
$e
));
$this
->
client
->
triggerEvent
(
'LoadbalancerEndpointFail'
,
array
(
$endpoint
->
getOptions
(),
$e
));
}
}
...
...
@@ -508,31 +491,30 @@ class Loadbalancer extends Plugin
}
else
{
// no failover retries, just execute and let an exception bubble upwards
$options
=
$this
->
getRandomServerOptions
();
$adapter
->
setOptions
(
$options
);
return
$adapter
->
execute
(
$request
);
$endpoint
=
$this
->
getRandomEndpoint
();
return
$adapter
->
execute
(
$request
,
$endpoint
);
}
}
/**
* Get
options array for a randomized server
* Get
a random endpoint
*
* @return
array
* @return
Endpoint
*/
protected
function
getRandom
ServerOptions
()
protected
function
getRandom
Endpoint
()
{
// determine the
server
to use
if
(
$this
->
next
Server
!==
null
)
{
$
serverKey
=
$this
->
nextServer
;
// reset forced
server
directly after use
$this
->
next
Server
=
null
;
// determine the
endpoint
to use
if
(
$this
->
next
Endpoint
!==
null
)
{
$
key
=
$this
->
nextEndpoint
;
// reset forced
endpoint
directly after use
$this
->
next
Endpoint
=
null
;
}
else
{
$
serverKey
=
$this
->
getRandomizer
()
->
getRandom
(
$this
->
server
Excludes
);
$
key
=
$this
->
getRandomizer
()
->
getRandom
(
$this
->
endpoint
Excludes
);
}
$this
->
serverExcludes
[]
=
$serverK
ey
;
$this
->
last
ServerKey
=
$serverK
ey
;
return
$this
->
servers
[
$serverKey
][
'options'
]
;
$this
->
endpointExcludes
[]
=
$k
ey
;
$this
->
last
Endpoint
=
$k
ey
;
return
$this
->
client
->
getEndpoint
(
$key
)
;
}
/**
...
...
@@ -543,11 +525,7 @@ class Loadbalancer extends Plugin
protected
function
getRandomizer
()
{
if
(
$this
->
randomizer
===
null
)
{
$choices
=
array
();
foreach
(
$this
->
servers
AS
$key
=>
$settings
)
{
$choices
[
$key
]
=
$settings
[
'weight'
];
}
$this
->
randomizer
=
new
WeightedRandomChoice
(
$choices
);
$this
->
randomizer
=
new
WeightedRandomChoice
(
$this
->
endpoints
);
}
return
$this
->
randomizer
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment